Могу ли я изменить искаженные символы экспорта C ++ DLL? (Двоично-совместимый, но несовместимый с исходным кодом)

Наш проект 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 ++.

Есть другие идеи?

2

Решение

Это нормально, они бинарно совместимы.

Единственная стена, с которой вы можете столкнуться — это искажение имени экспортируемой функции. Если библиотеки 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

Другие решения

Благодаря @HansPassant’s ответ Я был в состоянии осуществить это.

Полные шаги здесь для справки:

  1. Генерация экспортных символов для DLL: dumpbin /EXPORTS ddao35u.dll
  2. заменить все типы беззнаковых коротких указателей на wchar_t: это означает замену PAG (за unsigned short*) а также PBG (за unsigned short const*) с помощью строки-чара wchar_t PA_W а также PB_W
  3. Напишите новый файл 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
    ...
    
  4. Создать библиотеку импорта из файла def: lib /DEF:ddao35u.def
  5. Ссылка на этот новый 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);
}
0

По вопросам рекламы [email protected]