__stdcall в dll функциях
От: Loerosim  
Дата: 09.10.12 05:25
Оценка:
Уважаемые гуру, подскажите, пожалуйста, почему если в dll объявить функцию через stdcall:
extern "C" __declspec(dllexport) UINT __stdcall DllTestFunc();

то эта функция не найдется при вызове GetProcAddress:
typedef UINT (* __stdcall PointerDllTestFunc)();
HINSTANCE test_dll = LoadLibrary("test_dll.dll");
dll_test_func = (PointerDllTestFunc)GetProcAddress(test_dll, "DllTestFunc");

Если же убрать __stdcall, то всё будет хорошо...
Re: __stdcall в dll функциях
От: icWasya  
Дата: 09.10.12 05:29
Оценка: 3 (1)
Здравствуйте, Loerosim, Вы писали:

L>Уважаемые гуру, подскажите, пожалуйста, почему если в dll объявить функцию через stdcall:

L>
L>extern "C" __declspec(dllexport) UINT __stdcall DllTestFunc();
L>

L>то эта функция не найдется при вызове GetProcAddress:
L>
L>typedef UINT (* __stdcall PointerDllTestFunc)();
L>HINSTANCE test_dll = LoadLibrary("test_dll.dll");
L>dll_test_func = (PointerDllTestFunc)GetProcAddress(test_dll, "DllTestFunc");      
L>

L>Если же убрать __stdcall, то всё будет хорошо...

Используй def — файл
Re[2]: __stdcall в dll функциях
От: Loerosim  
Дата: 09.10.12 05:58
Оценка:
Здравствуйте, icWasya, Вы писали:
W>Используй def — файл
Я же экспортирую функции, используя __declspec(dllexport), а не def-файл. Соответственно и вопрос у меня не связан с def-файлом... Мне важно понять причину, почему так происходит.
Re[3]: __stdcall в dll функциях
От: что  
Дата: 09.10.12 06:49
Оценка:
Здравствуйте, Loerosim, Вы писали:

L>Я же экспортирую функции, используя __declspec(dllexport), а не def-файл. Соответственно и вопрос у меня не связан с def-файлом... Мне важно понять причину, почему так происходит.

Посмотри PE вьювером (или просто в текстовом редакторе), какое имя функции получилось в DLL.
Re[4]: __stdcall в dll функциях
От: Loerosim  
Дата: 09.10.12 07:00
Оценка:
Здравствуйте, что, Вы писали:

что>Здравствуйте, Loerosim, Вы писали:


L>>Я же экспортирую функции, используя __declspec(dllexport), а не def-файл. Соответственно и вопрос у меня не связан с def-файлом... Мне важно понять причину, почему так происходит.

что>Посмотри PE вьювером (или просто в текстовом редакторе), какое имя функции получилось в DLL.
Dumpbin'ом увидел, что добавляя __stdcall, получаю имя функции с окончанием @0.
Тогда как при создании dll задавать соглашения вызовов?
Re[5]: __stdcall в dll функциях
От: icWasya  
Дата: 09.10.12 07:11
Оценка:
Здравствуйте, Loerosim, Вы писали:

L>Здравствуйте, что, Вы писали:


что>>Здравствуйте, Loerosim, Вы писали:


L>>>Я же экспортирую функции, используя __declspec(dllexport), а не def-файл. Соответственно и вопрос у меня не связан с def-файлом... Мне важно понять причину, почему так происходит.

что>>Посмотри PE вьювером (или просто в текстовом редакторе), какое имя функции получилось в DLL.
L>Dumpbin'ом увидел, что добавляя __stdcall, получаю имя функции с окончанием @0.
L>Тогда как при создании dll задавать соглашения вызовов?

Так тебе «важно понять причину», «задавать соглашения вызовов» или «экспортировать функцию с нужным именем» ?
Re: __stdcall в dll функциях
От: okman Беларусь https://searchinform.ru/
Дата: 09.10.12 07:12
Оценка: 71 (4) +1
Здравствуйте, Loerosim, Вы писали:

L>Уважаемые гуру, подскажите, пожалуйста, почему если в dll объявить функцию через stdcall:

L>
L>extern "C" __declspec(dllexport) UINT __stdcall DllTestFunc();
L>

L>то эта функция не найдется при вызове GetProcAddress:
L>
L>typedef UINT (* __stdcall PointerDllTestFunc)();
L>HINSTANCE test_dll = LoadLibrary("test_dll.dll");
L>dll_test_func = (PointerDllTestFunc)GetProcAddress(test_dll, "DllTestFunc");      
L>

L>Если же убрать __stdcall, то всё будет хорошо...

Дело в том, что компилятор [VC++], чтобы отличать одну функцию от другой, — а C++ допускает
такую перегрузку, — хранит все имена в специальном внутреннем формате. Это называется декорацией
имен (name decoration или name mangling). Декорированное имя формируется в зависимости от имени функции,
от количества и типов ее аргументов, от типа соглашения о выховах (stdcall/cdecl/fastcall), а также от
того, используется ли C или C++.
Кое-какая полезная информация здесь — http://msdn.microsoft.com/en-us/library/deaxefa7(v=vs.100).aspx

До тех пор, пока функция не экспортируется, эта особенность нас не беспокоит, так как все вопросы
"стыковки" решаются компилятором. При экспорте функции, в зависимости от того, какой был выбран
способ экспорта, — def-файл или __declspec(dllexport), — в секцию экспорта попадает либо ее
оригинальное имя, либо уже декорированное. В первом случае GetProcAddress сможет найти функцию по
ее оригинальному имени, во втором — нет.

Тут еще вот какая особенность — функция C (не C++), имеющая соглашение о вызовах cdecl,
при экспорте будет иметь декорированное имя, совпадающее с оригинальным, и поэтому ее можно будет
находить посредством GetProcAddress, вне зависимости от типа экспорта. А компилятор VC++, если не
указано иное, считает все функции объявленными с соглашением cdecl. Как раз Ваш случай.

Вообще, тема не самая простая, поэтому набросаю ссылочек:
http://msdn.microsoft.com/en-us/library/x7kb4e2f(v=vs.100).aspx
http://msdn.microsoft.com/en-us/library/zkwh89ks(v=vs.100).aspx
http://msdn.microsoft.com/en-us/library/zxk0tw93(v=vs.100).aspx
http://msdn.microsoft.com/ru-ru/library/a90k134d(v=vs.100).aspx
http://msdn.microsoft.com/ru-ru/library/d91k01sh(v=vs.100).aspx
http://msdn.microsoft.com/ru-ru/library/900axts6(v=vs.90).aspx
Re[6]: __stdcall в dll функциях
От: Loerosim  
Дата: 09.10.12 07:34
Оценка: +1
Здравствуйте, icWasya, Вы писали:
W>Так тебе «важно понять причину», «задавать соглашения вызовов» или «экспортировать функцию с нужным именем» ?
Мне всё важно. =)
Теперь вот я осознал, что Ваш намек про def файл был правильным путем решения моей проблемы. Принцип "на любой вопрос даю любой ответ" имеет место быть, но всё же для новичка не всегда очевидны сухие ответы без пояснения.
Re[2]: __stdcall в dll функциях
От: Loerosim  
Дата: 09.10.12 07:38
Оценка:
Здравствуйте, okman, Вы писали:

O>такую перегрузку, — хранит все имена в специальном внутреннем формате. Это называется декорацией

O>имен (name decoration или name mangling).
Спасибо большое за пояснения и за ссылки, буду разбираться!
А про name mangling я читал и даже встречался при вызове С++ кода из C файла. Но решение было extern "C". В dll функция я такое прописал, но имена все равно обернулись...
Re[5]: __stdcall в dll функциях
От: Erop Россия  
Дата: 09.10.12 08:59
Оценка:
Здравствуйте, Loerosim, Вы писали:

L>Dumpbin'ом увидел, что добавляя __stdcall, получаю имя функции с окончанием @0.

L>Тогда как при создании dll задавать соглашения вызовов?

Используй DEF файл
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: __stdcall в dll функциях
От: Erop Россия  
Дата: 09.10.12 09:02
Оценка:
Здравствуйте, okman, Вы писали:

O>Дело в том, что компилятор [VC++], чтобы отличать одну функцию от другой, — а C++ допускает

O>такую перегрузку, — хранит все имена в специальном внутреннем формате. Это называется декорацией
O>имен (name decoration или name mangling). Декорированное имя формируется в зависимости от имени функции,
O>от количества и типов ее аргументов, от типа соглашения о выховах (stdcall/cdecl/fastcall), а также от
O>того, используется ли C или C++.
O>Кое-какая полезная информация здесь — http://msdn.microsoft.com/en-us/library/deaxefa7(v=vs.100).aspx

Для extern "C" функции перегрузка недоступна, так что причина декорирования имён другая -- совместимость с тем, как это было принято делать в С.
А в С так принято было делать из соображений надёжности. Что бы тип декорирования имения, гарантировал тип соглашения о вызове...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: __stdcall в dll функциях
От: Loerosim  
Дата: 09.10.12 10:09
Оценка: +1
Здравствуйте, Erop, Вы писали:
E>Для extern "C" функции перегрузка недоступна, так что причина декорирования имён другая -- совместимость с тем, как это было принято делать в С.
E>А в С так принято было делать из соображений надёжности. Что бы тип декорирования имения, гарантировал тип соглашения о вызове...
И Вам спасибо за ответ. =) Я поработал с гуглом и просветился, что extern "C" защищает от name mangling, но при объявлении соглашений вызова уже имеет место быть decorations. Всё решил просто — через __cdecl, что по умолчанию. Иначе, как мне сразу подсказали, нужен def-файл.

PS: Странно, что dot-net C# загружал функции и работал с ними без проблем не зависимо от объявленного соглашения вызовов. А проблему удалось установить только при отладке в C++ проекте.
Re[4]: __stdcall в dll функциях
От: Erop Россия  
Дата: 09.10.12 10:53
Оценка:
Здравствуйте, Loerosim, Вы писали:

L>PS: Странно, что dot-net C# загружал функции и работал с ними без проблем не зависимо от объявленного соглашения вызовов.


Ну он просто и так и сяк пробует искать, за одно и соглашение о вызове выясняет
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: __stdcall в dll функциях
От: Mr.Delphist  
Дата: 09.10.12 10:55
Оценка:
Здравствуйте, Loerosim, Вы писали:

L>PS: Странно, что dot-net C# загружал функции и работал с ними без проблем не зависимо от объявленного соглашения вызовов. А проблему удалось установить только при отладке в C++ проекте.


Рискну предположить, что C# код использовал тот же манглинг (кстати, во времена древних компилеров манглинг был manufacturer-specific), либо загружал функцию по ординалу
Re: __stdcall в dll функциях
От: Pavel Dvorkin Россия  
Дата: 10.10.12 16:15
Оценка: +1
Здравствуйте, Loerosim, Вы писали:

Все, что ответили про декорацию — верно. Могу лишь посоветовать еще запускать dumpbin с ключом /EXPORTS, увидишь, по какому имени функция экспортируется, после чего возьми это имя (как бы оно тебя ни пугало) и используй в GetProcAddress
With best regards
Pavel Dvorkin
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.