弁財天

ゴフマン「専門家を信じるのではなく、自分自身で考えて判断せよ」

Private Declare Function Hoge_TpCall Lib "Hoge01.dll" ( _

VB6からC/C++言語で書かれた.DLLを呼び出すのはこんなかんじ。 _ アンダースコア記号は継続行の意味なのだとかw。 なんてアホな言語なんだ。

Private Declare Function Hoge_TpCall Lib _
 "Hoge01.dll" ( _
  ByVal TxCode As String, _
  ByVal SendMsg As String, _
  ByVal SendMsgLen As Long, _
  ByVal RecvMsg As String, _
  ByRef RecvMsgLen As Long) As Long

約2200本の.basファイルから.DLLを呼び出す関数定義を抽出するにはこんなかんじ。

#!/usr/bin/perl

use strict;
use warnings;
use File::Path;
use Fcntl;
use File::Find;
use Encode;

my $cnt = 0;

find(\&grep_file_full_name, ".");

sub grep_file_full_name{
  my $fn = $File::Find::name;
  return if ($fn !~ /.bas/);
  open(F, $_) or die("$_ $!");
  $cnt++;
  while(<F>) {
        s/\r//;
        my $line = decode('SJIS', $_);
        chomp($line);
        if ($line =~ /declare\Wfunction/i && $line !~ /\'/) {
                while($line =~ /_$/) {
                        my $line_c = decode('SJIS', scalar(<F>));
                        $line =~ s/_$//;
                        $line .= $line_c;
                        chomp($line);
                }
                $line =~ tr/ / /s;
                print $File::Find::name . " ".encode('UTF-8', $line) . "\n";
        }
  }
  close(F);
}

print STDERR "cnt $cnt ...\n";

# End of FILE.

$ find . -name "*.bas" -exec dos2unix {} \;
…
$ perl find.pl
./common/template/basufg_Com_General.bas Private Declare Function Hoge_TpCall Lib "Hoge01.dll" ( ByVal TxCode As String, ByVal SendMsg As String, ByVal SendMsgLen As Long, ByVal RecvMsg As String, ByRef RecvMsgLen As Long) As Long
...
みたいな出力になる。

C言語と.DLLの世界のlddとかobjdumpでVBの.DLLや.EXEの依存会見を調べることはできない。
すべて DLL Name: MSVBVM60.DLL ポッキリで表示されるだけだ。 まぁ当たり前か。

$ find hgprjct -name "*.dll" -exec objdump.sh {} \; -print
        DLL Name: KERNEL32.dll
        DLL Name: USER32.dll
        DLL Name: ole32.dll
        DLL Name: XlsReport.dll
        DLL Name: hgqnap05.dll
        DLL Name: COMCTL32.dll
        DLL Name: GDI32.dll
        DLL Name: WINSPOOL.DRV
        DLL Name: OLEAUT32.dll

hgprjct/hgap/dll/HGA080CD.dll
        DLL Name: MSVBVM60.DLL

Visual Basicのソース.basだけでは依存関係がわからない。 依存関係を調べるには .vbpファイルのReference=とModule=を拾い読みする必要がある。

#!/usr/bin/perl

use strict;
use warnings;
use File::Find;

use utf8;
use Encode;

my $cnt = 0;
my $BASE_DIR = "10/Client/本番環境/";

find(\&grep_file_full_name, $BASE_DIR."hglb");

sub grep_file_full_name{
	my $fn = $File::Find::name;
	$fn = decode('UTF-8', $fn);
	my $c = $_;
	return if ($fn =~ /カスタマイズ対応前/);
	return if ($fn =~ /マージ前/);
	return if ($fn =~ /コピー/);
	return if ($fn =~ /戻し前/);
	return if ($fn =~ /現行最新/);
	return if ($fn =~ /\/old\//i);
	&parse_bas($c) if ($c =~ /.bas$/);
	&parse_vbp($c) if ($c =~ /.vbp$/);
}

print STDERR "cnt $cnt ...\n";

sub parse_bas {
	my ($fn) = @_;
	open(F, $fn) or die("$fn $!");
	$cnt++;
	while(<F>) {
		s/\r//;
		my $line = decode('SJIS', $_);
		chomp($line);
		if ($line =~ /declare\Wfunction/i && $line !~ /\'/) {
			while($line =~ /_$/) {
				my $line_c = decode('SJIS', scalar(<F>));
				$line =~ s/_$//;
				$line .= $line_c;
				chomp($line);
			}
			$line =~ tr/ / /s;
			my $f = $File::Find::name;
			my $e = $BASE_DIR;
			$e =~ s/\//\\\//g;
			$f =~ s/$e//g;
			my $func_line = $line;
			$func_line =~ s/Public //;
			$func_line =~ s/Private //;
			my @items = split(/ /, $func_line);
			my $func = $items[2];
			my $dll = $items[4];
			$dll =~ s/\"//g;
			next if ($dll =~ /^kernel/i);
			next if ($dll =~ /^user32/i);
			next if ($dll =~ /^shell32/i);
			next if ($dll =~ /^wininet/i);
			next if ($dll =~ /^wsock32/i);
			next if ($dll =~ /^advapi32/i);
			next if ($dll =~ /^gdi32/i);
			next if ($dll =~ /^olepro32/i);
			next if ($dll =~ /^icmp.dll/i);
			if ($func ne "Lib") {
				print "$f $dll $func\n"
			} else {
			    print $f . " ".encode('UTF-8', $line) . "\n";
			}
		}
	}
	close(F);
}

sub parse_vbp {
	my ($fn) = @_;
	my $fp = $File::Find::name;
	$fp = decode('UTF-8', $fp);
	if ($fp =~ /_bak2014/i
		||$fp =~ /バックアップ/
		||$fp =~ /\/old\//i
		||$fp =~ /現行最新/
		||$fp =~ /bk\//
		||$fp =~ /DEL\)/
		||$fp =~ /msg034cmbk.vbp/
		||$fp =~ /20[0-9][0-9][0-9][0-9][0-9][0-9]/) {
		#print STDERR "skip ".encode('UTF-8', $fp)." ...\n";
		return;
	}
    #print STDERR $fn."\n";
	open(F, $fn) or die("$fn $!");
	$cnt++;
	my $f = $File::Find::name;
	my $e = $BASE_DIR;
	$e =~ s/\//\\\//g;
	$f =~ s/$e//g;
	my $type = "N/A";
	my $exename32 = "N/A";

	my $ref = "N/A";
	my @refs = ();

	my $module = "N/A";
	my @modules = ();

	while(<F>) {
		s/\r//;
		my $line = decode('SJIS', $_);
		chomp($line);
		if ($line =~ /^type=/i) {
			$type = $line;
			$type =~ s/^Type=//;
			#print $f . " ".encode('UTF-8', $line) . "\n";
		}
		if ($line =~ /^exename32=/i) {
			$exename32 = $line;
			$exename32 =~ s/ExeName32=//;
			$exename32 =~ s/\"//g;
		}
		if ($line =~ /^reference=/i) {
			$ref = $line;
			$ref =~ s/Reference=//;
			if ($ref =~ /hgprjct/) {
				my @items = split(/#/, $ref);
				my $f = $items[$#items - 1];
				@items = split(/\\/, $f);
				push(@refs,$items[$#items]);
			}
		}
		if ($line =~ /^module=/i) {
			$module = $line;
			$module =~ s/Module=//;
			my @items = split(/;/, $module);
			my $f = $items[$#items];
			$f =~ s/^ //;
			@items = split(/\\/, $f);
			push(@modules,$items[$#items]);
		}
	}
	my $l = $f." ".$type." ".$exename32;
	my $rl = "";
	foreach my $r (@refs) {
		$rl .= " ".$r;
	}
	$rl =~ s/^ //;
	$l .= " References(".$rl.")" if ($rl ne "");

	$rl = "";
	foreach my $m (@modules) {
		$rl .= " ".$m;
	}
	$rl =~ s/^ //;
	$l .= " Modules(".$rl.")" if ($rl ne "");

	print $l."\n";
	close(F);
}

# End of FILE.
$ perl find.pl
…
hglb/common/template/basufx_Com_General.bas hgqnac01.dll HGQNAC_TrStart
hglb/common/template/basufx_Com_General.bas hgqnac01.dll HGQNAC_TpCall
hglb/common/template/basufx_Com_General.bas hgqnac01.dll HGQNAC_TrEnd
hglb/common/template/basufx_Com_General.bas hgqnac01.dll HGQNAC_GetMessage
hglb/common/template/basufx_Com_General.bas hgqnac01.dll HGQNAC_PutMessage
hglb/common/template/basufx_Com_General.bas hgqnac02.dll HGQNAC_SendFile
…
hglb/hga/Hga010cm/HGA010CM.vbp Exe HGA010CM.exe References(HGZ001CD.dll HGZ002CD.exe) Modules(basufHGA010CM_AppMain.bas basufHGA010CM_SPA.bas basufHGA010CM_TUXEDO.bas basufx_Com_General.bas basufx_HGZ001CD.bas basufx_HGZ002CD.bas)
…
ここまでやると VB6 の HGA010CM.exe が basufx_Com_General.bas をモジュールとして使って、 basufx_Com_General.bas で hgqnac01.dll の HGQNAC_TrStart をDeclare Function定義して使っていると追跡できる。ドキュメントが信用できないのでソースコードからVB6のモジュール構造を把握したいのだw。

			next if ($dll =~ /^kernel/i);
			next if ($dll =~ /^user32/i);
			next if ($dll =~ /^shell32/i);
			next if ($dll =~ /^wininet/i);
			next if ($dll =~ /^wsock32/i);
			next if ($dll =~ /^advapi32/i);
			next if ($dll =~ /^gdi32/i);
			next if ($dll =~ /^olepro32/i);
			next if ($dll =~ /^icmp.dll/i);
C言語で書いたアプリの.DLL以外にもVBから直接WindowsのAPIをシステムの.DLL経由で呼び出しているのだけど、レイジーキャットの人達はこの辺りをどーしたのかすら?何も報告なしw

これやるのに.basと.vbpで2700本くらい解析して。これから何をやるにもスクリプトを書かなければならなくなるのだろう。

投稿されたコメント:

コメント
コメントは無効になっています。