我们的C ++项目(仍然)在VS6上编译时使用了Treat wchar_t as Built-in: No (/Zc:wchar_t-)
选项。
这导致wchar_t
只是unsigned short
(WORD
)的typedef。
我们想要更改它,以便wchar_t
作为一个合适的内置类型处理 - 这将极大地简化(现代)库的集成。
问题是,我们链接到一些我们无法重新编译的DLL,这些DLL将其字符串公开为unsigned short*
,其标题使用wchar_t*
。当wchar_t是内置类型时,这将导致链接器错误,因为显然导出符号是不同的。
更改标题需要添加一种强制转换层 - 我当然不希望将强制转换添加到调用这些标题中的类的所有代码中。
是否可以修复DLL,使其导出符号“假装”导出内置wchar_t
而不是WORD
?毕竟,这两种类型在VC ++中是100%二进制兼容的。
还有其他想法吗?
答案 0 :(得分:1)
很好,它们是二进制兼容的。
您可能遇到的唯一一个墙是导出函数的名称修改。如果您无法更改的DLL使用其修饰的C ++名称导出这些函数,那么当客户端无法找到导出的名称时,您将在运行时获得失败的鲸鱼。当程序员不使用extern "C"
或未使用.def文件重命名导出时,就会发生这种情况。否则很容易看到Dumpbin.exe / exports。解决这个问题很痛苦,你需要修改DLL头来将wchar_t更改为WORD,宏可以这样做,并编写一些带有wchar_t的小适配器函数,并通过强制转换来调用WORD函数。
如果这些是导出的C ++类,那么你就会遇到更大的问题。您需要为这些DLL创建一个新的导入库。从Dumpbin.exe / exports获得的输出开始,为您提供原始名称。并从中创建一个.def文件,使用其foo = bar选项重命名符号。使用lib.exe / def选项创建导入库。创建一个小测试DLL,以确切地确定如何重命名受损名称。
答案 1 :(得分:0)
感谢@HansPassant的answer我能够解决这个问题。
此处的完整步骤供参考:
dumpbin /EXPORTS ddao35u.dll
PAG
(对于unsigned short*
)和PBG
(对于unsigned short const*
) PA_W
和PB_W
使用所有符号编写新的def文件,其中带有字符串的函数被替换为名称。例如:
LIBRARY ddao35u
EXPORTS
??0CdbBSTR@@QAE@PA_W@Z=??0CdbBSTR@@QAE@PAG@Z @1 ... replaced
^^^^ = ^^^
??0CdbBookmark@@QAE@ABV0@@Z @2 ... no strings, no replacement needed
...
lib /DEF:ddao35u.def
ddao35u.lib
,而不是原始lib文件。我将转储我以前在这里执行此操作的整个perl脚本函数:
sub fixModuleLib {
my $basename = shift;
my $dllpath = shift;
# my $basename = "ddao35u";
print "\n\n";
my $cmdExport = "dumpbin /EXPORTS $dllpath";
print "Running >> $cmdExport << for export symbols ...\n";
die "Input file $dllpath not found!" unless -f "$dllpath";
my @exports = qx/$cmdExport/;
print "Open $basename.def for writing ...\n";
open(my $defh, ">", "$basename.def") or die "Unable to open basename.def for writing: $!";
print $defh "LIBRARY $basename"."\n";
print $defh "EXPORTS"."\n";
my @expEntries;
my $usCount = 0;
foreach (@exports) {
# 1 0 00002050 ??0CdbBSTR@@QAE@PAG@Z
my $ws = '\s+';
my $hnum = '[ABCDEFabcfed0123456789]+';
if (m/$ws(\d+)$ws$hnum$ws$hnum$ws(\?\S+)/) {
my $ord = $1;
my $mangle = $2;
my $defline;
# PAG = unsigned short*
# PBG = unsigned short const*
# at least two @ signs before parameter list (at least in our case)
if ($mangle =~ m/(.+@.*@.*)(P[AB]G)(.*)/) { # case sensitive
my $pre = $1;
my $uptr = $2;
my $post = $3;
# print "$ord\t$pre>>>$uptr<<<$post\n";
my $wptr = $uptr;
$wptr =~ s/G/_W/;
my $wchartMangle = "$pre$wptr$post";
$defline = " $wchartMangle=$mangle \@$ord";
print "CHANGED: $defline\n";
$usCount += 1;
} else {
# line doesn't contain unsigned short ptr
$defline = " $mangle \@$ord";
}
push @expEntries, $defline;
}
}
print "There are ".scalar(@expEntries)." export lines and $usCount of them contain an unsigned-short-pointer.\n";
die "No entries found!" unless $usCount>0;
print "Writing entries to $basename.def ...\n";
foreach my $entry (@expEntries) {
print $defh $entry."\n";
}
close($defh);
my $cmdLib = "lib /DEF:$basename.def";
print "Generate Export Lib from DEF-File: >> $cmdLib << ...\n";
system($cmdLib);
}