【发布时间】:2021-01-30 11:50:01
【问题描述】:
尝试使用 mingw 使用 C++ 代码构建 DLL 无法正常工作...
我正在尝试将更大的 C++ 类包装在 dll 中,以便在其他 .net 环境中使用。 但是调用的时候老是闪退。
这与 .net 无关,因为首先我尝试从一个用 C 和 Visual Studio 制作的小测试程序调用 DLL。
我制作的小测试程序打开库,获取函数指针,并调用一个添加 2 个整数的函数。 到那里它工作。 下一个调用传入一个字符串,它会跳转到 invliad 内存空间。
我感觉 Mingw 构建的库在其 libstdc++ 中包含需要初始化的部分? (在程序中调用 main() 之前通常由框架代码调用的东西?)
使用 Mingw g++ 10.2.0 和这个命令行来构建小 DLL:
g++ -o gehtnichdll.dll -s -Wl,--subsystem,windows src/dllmain.cpp
我点了一个奇怪的事情是我需要添加一个名为'WinMain'的函数,否则G++会抱怨它丢失了。
我从https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/ 获取了有关构建 DLL 的信息。
注意到 mingw 有一个选项 -mdll ,我尝试了一下,得到了一个不再加载的 dll(LoadLibrary 失败 193)
我找到了一个指向页面 http://mingw.org/wiki/MSVC_and_MinGW_DLLs 的链接,但该页面不再可用。
这里是 DLL 的源代码。剥离到几乎最低限度以显示问题。我试图包装的类也被完全删除了,因为即使是这里的简单调用也已经失败了。
#include <windows.h>
#include <stdint.h>
#include <stdio.h>
#include <string>
extern "C" __declspec(dllexport)
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
#define IID_OFFSET 0x07C007EC
typedef float A; // removed class A, not related to problem.
extern "C" __declspec(dllexport)
uint64_t AA__create(int var)
{
A *a;
a = new A(var); // There was the class constructor here.
// Removed as it is not related to the problem.
printf("called create (%d)\n",var);
return (uint64_t)a;
}
extern "C" __declspec(dllexport)
void AA__destroy(uint64_t iid)
{
A *a = (A*)iid;
if(!a)return;
delete a;
}
extern "C" __declspec(dllexport)
void AA__reset(uint64_t iid)
{
A *a = (A*)iid;
if(!a)return;
}
extern "C" __declspec(dllexport)
void AA__step(uint64_t iid)
{
A *a = (A*)iid;
if(!a)return;
(*a)++;
}
extern "C" __declspec(dllexport)
uint16_t strlen2(const char *str)
{
uint16_t res=0;
while( str && str[res] )res++;
return res;
}
extern "C" __declspec(dllexport)
void printstring(const char *str)
{
printf("string: '%s'\n",str);
}
// Without this WinMain, G++ exits with undefined reference to `WinMain'
// So providing a dummy function. Never called when loading as DLL.
extern "C" __declspec(dllexport)
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR pCmdLine, int nCmdShow)
{
printf("dll as main.\n");
uint64_t iid = AA__create(100);
AA__destroy(iid);
return 0;
}
extern "C" __declspec(dllexport)
int dummy_add(int a,int b)
{
return a+b;
}
用 MSVC++ 调用这个的 C 程序是这个(是 C,不是 C++):
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <Windows.h>
typedef void __declspec(dllimport) (*c_step)(uint64_t);
typedef uint64_t __declspec(dllimport) (*c_create)(int);
typedef int __declspec(dllimport) (*c_add)(int,int);
typedef void __declspec(dllimport) (*c_print)(const char *);
typedef uint16_t __declspec(dllimport) (*c_strlen)(const char *);
int main()
{
printf("Hello World!\n");
HMODULE h;
h = LoadLibrary("C:\\muell\\gehtnichdll\\gehtnichdll.dll");
if(!h)
{
int er = GetLastError();
fprintf(stderr,"loadlib failed, err = %d\n",er);
return 1;
}
c_create func_create = (c_create)GetProcAddress(h,"AA__create");
c_step func_step = (c_step)GetProcAddress(h,"AA__step");
c_add func_add = (c_add)GetProcAddress(h,"dummy_add");
c_print func_prn = (c_print)GetProcAddress(h,"strlen2");
c_strlen func_strl = (c_strlen)GetProcAddress(h,"printstring");
if(!(func_create&&func_step&&func_add&&func_prn&&func_strl))
{fprintf(stderr,"could not get function pointers.\n");return 1;}
int x = func_add(4,7);
printf("x = %d\n",x);
// this function call fails with an invalid jump.
uint16_t l = func_strl("lenth of this string");
printf("l = %u\n",(unsigned int)l);
// this call passes, but does not do output.
func_prn("hello world");
// These calls also fail (if commenting out the ones before)
uint64_t iid = func_create(0xBB1BE);
printf("Created, iid = 0x%" PRIXPTR "\n",(void*)iid);
func_step(iid);
return 0;
}
【问题讨论】:
-
你的函数指针缺少
extern "C"。 -
在 DLL 导出中,每个函数都有 extern "C" ,我忘了说客户端编译为 C,而不是 C++。将其添加到指针不会编译。 (刚刚将该提示添加到问题文本中)