Как оформленные имена попадают в библиотеки импорта, когда я предоставляю только недекорированное имя?
Я работаю в 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
На двоичном уровне создаваемая библиотека импорта практически идентична библиотеке, созданной при использовании недекорированного имени в файле определения модуля. Единственными различиями являются временные метки, за исключением одного байта в конце. Все еще пытаюсь разобраться в этом, но становится все более уверенным, что каким-то образом компоновщик экспортирует декорированное имя, даже когда файл определения модуля ссылается исключительно на недекорированное имя.