Как оформленные имена попадают в библиотеки импорта, когда я предоставляю только недекорированное имя?

Я работаю в Visual C++, VS2015 Community. Я написал эту крошечную DLL:

#include "stdafx.h"

int showMsgBox(wchar_t* caption, wchar_t* message)
{
    MessageBox(NULL, message, caption, 0);
    return 0;
}

И этот крошечный маленький клиент:

#include "stdafx.h"

__declspec(dllimport) int showMsgBox(wchar_t* caption, wchar_t* message);

int main()
{
    showMsgBox(L"SimpleDLLClient", L"Hello DLL World!");
    return 0;
}

Чтобы экспортировать функцию showMsgBox, я создал этот файл определения модуля:

LIBRARY SimpleDLL

EXPORTS
    showMsgBox

Когда я связываю свой клиент, я передаю ему библиотеку импорта, которая была создана, когда я связывал свою DLL. Все компилируется и ссылки отлично.

И это озадачивает меня.

Согласно MSDN, "поскольку компилятор Visual C++ использует оформление имени для функций C++, вы должны либо использовать оформленное имя в качестве имени записи или внутреннего имени, либо определить экспортируемые функции, используя extern "C"в исходном коде".

Но я не экспортирую украшенное имя, не так ли?

Если бы вместо использования файла определения модуля я должен был поставить префикс функции с расширенным атрибутом __declspec(dllexport), я бы не удивился (так как это должно иметь любое оформление имени, применяемое компилятором, совпадающее с тем же оформлением, примененным компилятор для клиента).

Аналогичным образом, если я поставил перед функцией "extern "C"" в коде DLL и клиентского кода, это также должно работать (и оно работает: я проверял это), потому что, опять же, символы должны совпадать.

Но я бы ожидал, что неокрашенный экспорт в файле определения модуля не сможет разрешить ссылку клиента на одно и то же недекорированное имя, когда ни DLL, ни клиентский код не используют "extern "C", что, по-видимому, также говорит MSDN. Я должен ожидать. Тем не менее, экспорт недекорированного имени через файл определения модуля работает, даже когда я нигде не использую 'extern "C".

Может кто-нибудь сказать мне, почему это работает?

ОБНОВИТЬ

Просматривая файлы, созданные компоновщиком, я вижу, что помещение недекорированного имени в файл определения модуля, очевидно, приводит к тому, что декорированное имя включается в библиотеку импорта. Когда я использую dumpbin /exports для этого файла, вот что я получаю:

Тип файла: БИБЛИОТЕКА

     Exports

       ordinal    name

                  ?showMsgBox@@YAHPEA_W0@Z (int __cdecl showMsgBox(wchar_t  *,wchar_t *))

Теперь, несколько удивительно (для меня, во всяком случае), если я явно назову псевдоним оформленного имени, например:

LIBRARY SimpleDLL

EXPORTS
    showMsgBox=?showMsgBox@@YAHPEA_W0@Z

dumpbin говорит мне, что это то, что появляется в библиотеке импорта:

File Type: LIBRARY

     Exports

       ordinal    name

                  showMsgBox

Использование этого в качестве входных данных для компоновщика при сборке клиента также работает нормально, при условии, что я использую 'extern "C", когда объявляю свою импортированную функцию:

extern "C" int showMsgBox(wchar_t* caption, wchar_t* message);

Это имеет смысл, поскольку символ, который сейчас ищет компоновщик, - это недоукрашенный "showMsgBox", и я связал этот символ с декорированным именем, созданным при компиляции моей DLL.

Тааак...

Мне кажется, что страницы и страницы документации MSDN, в которых все говорят, что вы должны использовать оформленные имена в файлах определений модулей, ошибочны. Скорее, кажется, что если вы используете недокорированное имя в файле определения модуля, то это оформленное имя, которое фактически включено в вашу библиотеку импорта, что разрешит ссылку на соответствующее оформленное имя, созданное при компиляции кода клиента. Это, конечно, то, что я бы предпочел, вместо того, чтобы извлекать украшенные имена и использовать их в моих файлах определений модулей. Это просто не соответствует тому, что неоднократно говорится на страницах MSDN.

Мне нравится думать, что я умный мальчик, но довольно высокомерно говорить, что Microsoft не знает, как работают ее собственные продукты.

Что мне здесь не хватает?

ОБНОВЛЕНИЕ 2

С DLL и клиентом, использующими декорированные имена (то есть нигде не использующие 'extern "C"), все прекрасно работает с недекорированным именем в файле определения модуля, как я уже сказал. Но, что интересно, без каких-либо изменений в исходном коде все складывается одинаково хорошо, если я использую оформленное имя в файле определения модуля:

LIBRARY SimpleDLL

EXPORTS
    ?showMsgBox@@YAHPEA_W0@Z

На двоичном уровне создаваемая библиотека импорта практически идентична библиотеке, созданной при использовании недекорированного имени в файле определения модуля. Единственными различиями являются временные метки, за исключением одного байта в конце. Все еще пытаюсь разобраться в этом, но становится все более уверенным, что каким-то образом компоновщик экспортирует декорированное имя, даже когда файл определения модуля ссылается исключительно на недекорированное имя.

0 ответов

Другие вопросы по тегам