Вопрос

Создана базовая C++ DLL и экспортированы имена с помощью файла определения модуля (MyDLL.def).После компиляции я проверяю имена экспортированных функций, используя dumpbin.exeЯ ожидаю увидеть:

SomeFunction

но вместо этого я вижу это:

SomeFunction = SomeFunction@@@23mangledstuff#@@@@

Почему?

Экспортированная функция выглядит недекорированной (особенно по сравнению с отсутствием использования файла Module Def), но что насчет остальных вещей?

Если я использую dumpbin.exe против DLL из любого коммерческого приложения вы получаете чистую информацию:

SomeFunction

и ничего больше...

Я также попытался удалить определение модуля и экспортировать имена, используя стиль экспорта «C», а именно:

extern "C" void __declspec(dllexport) SomeFunction();

(Простое использование «extern «C» не привело к созданию экспортированной функции)

Однако это по-прежнему создает тот же результат, а именно:

SomeFunction = SomeFunction@@@23mangledstuff#@@@@

Я также попробовал #define dllexport __declspec(dllexport) вариант и без проблем создал LIB.Однако я не хочу предоставлять файл LIB людям, использующим DLL в своих приложениях на C#.

Это обычная DLL C++ (неуправляемый код), скомпилированная с C++, состоящая только из простого заголовка и кода.Без Module Def я получаю искаженные экспортированные функции (я могу без проблем создать статическую библиотеку и использовать LIB.Я стараюсь этого избегать).Если я использую extern "C" __declspec(dllexport) ИЛИ Определение модуля. Я получаю то, что выглядит как недекорированное имя функции...единственная проблема в том, что за ним следует знак "=" и что-то вроде декорированной версии функции.Я хочу избавиться от материала после "=" - или хотя бы понять, почему он там.

В нынешнем виде я почти уверен, что смогу вызвать функцию из C#, используя P/Invoke...Я просто хочу избежать этого мусора в конце "=".

Я открыт для предложений о том, как изменить настройки проекта/компилятора, но я просто использовал стандартный шаблон DLL Visual Studio - ничего особенного.

Это было полезно?

Решение

Вы можете получить то, что хотите, отключив создание отладочной информации.Проект + Свойства, Компоновщик, Отладка, Создать информацию об отладке = Нет.

Естественно, вам нужно сделать это только для сборки Release.Где опция уже установлена ​​таким образом.

Другие советы

Вместо использования файла .def просто вставить pragma comment так

#pragma comment(linker, "/EXPORT:SomeFunction=_SomeFunction@@@23mangledstuff#@@@@")

Редактировать: или даже проще: внутри тела использования функции

#pragma comment(linker, "/EXPORT:"__FUNCTION__"="__FUNCDNAME__)

. Отказ Отказ Отказ Если у вас есть проблемы, найденные украшенные названия функции. Эта последняя прагма может быть дополнительно уменьшена с помощью простого определения макроса.

Вы должны объявить функции как extern "C" Если вы не хотите, чтобы их имена были проникновенными.

От опыта, будьте осторожны, если вы используете __stdcall В вашей функции подпись. С участием __stdcall, Имя будет оставаться упорно до некоторой степени (вы обнаружите достаточно быстро). Видимо, есть два уровня погибших, один extern "C" имеет дело с уровнем C ++, но он не имеет дело с другим уровнем поклонников, вызванного __stdcall. Отказ Дополнительное поклонение, по-видимому, имеет отношение к перегрузке - но я не уверен этого.

Извините за ответ на старую тему, но то, что было помечено как ответ не работал для меня.

Как указал ряд людей, важно украшение Extern «C». Изменение «Project / Properties / Linker / Debugging / Generate INFO INFORE для отладки» выполнено абсолютно никакой разницы в Mangled Names, создаваемых для меня в режиме отладки или выпуска.

Настройка: VS2005 Компиляция проекта Visual C ++ Class Library Project. Я проверял компиляцию .dll вывод с помощью инструмента Walker Walker.

Вот пример рецепта, который работал для меня ...

В проекте .H:

#define DllExport extern "C" __declspec( dllexport )

DllExport bool API_Init();
DllExport bool API_Shutdown();

В Project.cpp:

#include "project.h"

bool API_Init()
{
  return true;
}

bool API_Shutdown()
{
  return true;
}

Затем называются из C # Управляемого кода, Class.cs:

using System.Runtime.Interopservices;
namespace Foo
{
    public class Project
    {
        [DllImport("project.dll")]
        public static extern bool API_Init();

        [DllImport("project.dll")]
        public static extern bool API_Shutdown();
    }
}

Вышеупомянутое выше, предотвратило уплотненные имена в режиме отладки, так и в режиме выпуска, независимо от настройки информации об отладке Generate. Удачи.

Даже без поклонников 32-битное и 64-битное создание названия экспортирует по-разному, даже с Extern «C». Проверьте это с Defends.exe.

Это может означать большие проблемы для любого клиента, который делает LoadLibrary + GetProcadress для доступа к вашей функции.

Итак, на вершине всех остальных используйте файл определения модуля следующим образом:

LIBRARY MYDLL
EXPORTS
myFunction=myFunction

Yeap, это немного боли для обслуживания, но тогда сколько экспортируемых функций вы пишете в день?

Более того, я обычно меняю макросы, как показано ниже, поскольку мои DLL экспортируют функции не C ++, и я хочу, чтобы они были Callable по большинству среды программирования:

#ifdef WTS_EXPORTS
#define WTS_API(ReturnType) extern "C" __declspec(dllexport) ReturnType WINAPI
#else
#define WTS_API(ReturnType) extern "C" __declspec(dllimport) ReturnType WINAPI
#endif

WTS_API(int) fnWTS(void);

Последняя строка, используемая для смущения VisualAStistx пару лет назад, я не знаю, если это правильно переваривает его сейчас :-)

Я знаю, сколько раз я пытался заставить имена функций с помощью кода и # Pragma's. И я всегда заканчиваю то же самое, используя файл модуля-определения (* .def) в конце. И вот причина:

//---------------------------------------------------------------------------------------------------
// Test cases built using VC2010 - Win32 - Debug / Release << doesn't matter
//---------------------------------------------------------------------------------------------------
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = Yes (/DEBUG)
//  || (or, also doesn't matter)
// SET: Project > Properties > Linker > Debugging > Generate Debug Info = No + delete PDB file!

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> _SetCallback@4

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> ?SetCallback@@YAXP6AXHPADPAX@Z@Z

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> ?SetCallback@@YGXP6GXHPADPAX@Z@Z    

//---------------------------------------------------------------------------------------------------
// this also big is nonsense cause as soon you change your calling convention or add / remove
// extern "C" code won't link anymore.

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases
#pragma comment(linker, "/EXPORT:SetCallback=SetCallback")
extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=_SetCallback@4")
extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YAXP6AXHPADPAX@Z@Z")
__declspec(dllexport) void SetCallback(LPCALLBACK function);

// doesn't work on other cases / creates alias
#pragma comment(linker, "/EXPORT:SetCallback=?SetCallback@@YGXP6GXHPADPAX@Z@Z")
__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);

//---------------------------------------------------------------------------------------------------
// So far only repetable case is using Module-Definition File (*.def) in all possible cases:
EXPORTS
  SetCallback

extern "C" __declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

extern "C" __declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void SetCallback(LPCALLBACK function);
> SetCallback

__declspec(dllexport) void __stdcall SetCallback(LPCALLBACK function);
> SetCallback

// And by far this is most acceptable as it will reproduce exactly same exported function name 
// using most common compilers. Header is dictating calling convention so not much trouble for
// other sw/ppl trying to build Interop or similar.

Интересно, почему никто не сделал это, потребовалось всего 10 минут, чтобы проверить все случаи.

Некоторые @@@ 23mangledStuff # @@@@ потрясены, чтобы дать типы и класс функции C ++. Простые экспорта являются функциями, которые Callable Callable из C, т.е. записываются в C или остальные, объявляются extern «C» в C ++. Если вы хотите простой интерфейс, который вы должны сделать функции, которые вы экспортируете, используете только такие типы и сделать их Функции не-члена в глобальном пространстве имен.

В основном, когда вы используете функции в C ++, части своих имен теперь включают в себя свою подпись и подобное, чтобы облегчить языковые функции, такие как перегрузка.

Если вы пишете DLL, используя __declspec (dllexport), то она также должна производить lib. Ссылка на эту lib, и вы будете автоматически связаны, и функции, зарегистрированные CRT при запуске времени (если вы вспоминаете, чтобы изменить все свой импорт в экспорт). Вам не нужно знать о названии, если вы используете эту систему.

На случай, если из сотен строчек вафель было непонятно на тему испорченного экспорта.Вот моя стоимость 2c :)

После создания проекта под названием Win32Project2 с использованием VS 2012 и выбора экспорта всех символов в мастере.У вас должно быть 2 файла с именами Win32Project2.cpp и Win32project2.h.

Оба они будут ссылаться на пример экспортируемой переменной и пример экспортируемой функции.

В Win32Project2.h у вас будет следующее:

#ifdef WIN32PROJECT2_EXPORTS
#define WIN32PROJECT2_API __declspec(dllexport)
#else
#define WIN32PROJECT2_API __declspec(dllimport)
#endif

extern WIN32PROJECT2_API int nWin32Project2;
WIN32PROJECT2_API int fnWin32Project2(void);

Чтобы распутать CHANGE последние две строки для extern объявлений "C":

extern "C" WIN32PROJECT2_API int nWin32Project2;
extern "C" WIN32PROJECT2_API int fnWin32Project2(void);

В Win32Project2.cpp у вас также будут следующие определения по умолчанию:

// This is an example of an exported variable
WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

Чтобы распутать, ИЗМЕНИТЕ ЭТО НА:

// This is an example of an exported variable
extern "C" WIN32PROJECT2_API int nWin32Project2=0;

// This is an example of an exported function.
extern "C" WIN32PROJECT2_API int fnWin32Project2(void)
{
    return 42;
}

По сути, вы должны использовать префикс extern «C» перед объявлениями, чтобы заставить компоновщик создавать неискаженные имена, подобные C.

Если вы предпочитаете использовать искаженные имена для дополнительной запутывания (на случай, если информация об искажении кому-то будет полезна), используйте «dumpbin /exports Win32Project2.dll» из командной строки VC, чтобы найти фактические ссылочные имена.Он будет иметь форму «?fnWind32Project2@[param bytes]@[other info] .Существуют также другие инструменты просмотра DLL, если запуск командной оболочки VC не помогает вам.

Почему именно MS не придерживается этого соглашения по умолчанию, остается загадкой.Фактическая информация об искажении означает что-то (например, размер параметра в байтах и ​​т. д.), что может быть полезно для проверки и отладки, но в остальном это чушь.

Чтобы импортировать функцию DLL, указанную выше, в проект C# (в данном случае базовое приложение Windows C# с формой, содержащей кнопку «button1»), вот пример кода:

using System.Runtime.InteropServices;



    namespace AudioRecApp
    {

      public partial class Form1 : Form
      {
        [ DllImport("c:\\Projects\test\Debug\Win32Projects2.dll")] 
        public static extern int fnWin32Project2();

        public Form1()
        {
          InitializeComponent();
        }


        private void button1_Click(object sender, EventArgs e)
        {
          int value;

          value = fnWin32Project2();
        }
      }
    }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top