Наш проект C ++ (до сих пор) использует опцию Treat wchar_t as Built-in: No (/Zc:wchar_t-)
с тех времен, когда он был скомпилирован на VS6.
Это приводит к wchar_t
быть просто typedef для unsigned short
(WORD
).
Мы хотели бы изменить это так, чтобы wchar_t
обрабатывается как правильный встроенный тип — это значительно облегчит интеграцию (современных) библиотек.
Проблема в том, что мы делаем ссылку на несколько DLL, которые мы не могу перекомпилировать, которые выставляют свои строки как unsigned short*
и их заголовки используют wchar_t*
, Это приведет к ошибкам компоновщика, когда wchar_t является встроенным типом, поскольку очевидно, что символы экспорта отличаются.
Изменение заголовков потребовало бы добавления своего рода слоя приведения — я, конечно, не хочу добавлять приведения ко всему коду, который вызывает классы в этих заголовках.
Можно ли исправить DLL так, чтобы их символы экспорта «притворялись» экспортировать встроенные wchar_t
вместо WORD
? В конце концов, эти два типа совместимы на 100% в VC ++.
Есть другие идеи?
Это нормально, они бинарно совместимы.
Единственная стена, с которой вы можете столкнуться — это искажение имени экспортируемой функции. Если библиотеки 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, чтобы понять, как именно вы должны переименовать искаженное имя.
Благодаря @HansPassant’s ответ Я был в состоянии осуществить это.
Полные шаги здесь для справки:
dumpbin /EXPORTS ddao35u.dll
PAG
(за unsigned short*
) а также PBG
(за unsigned short const*
) с помощью строки-чара wchar_t 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
от вас wchar_t-нативные опции компоновщика проекта VS вместо исходного файла 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);
}