c++ - 使用 Mingw G++ 构建的 DLL,调用时崩溃
问题描述
尝试使用 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;
}
解决方案
我现在已经解决了我的问题。不是很满意,因为我真的不知道出了什么问题。
将 mingw G++ 调用更改为静态链接并使用 -mdll 修复它。然后我可以调用函数。我假设链接器现在生成正确的初始化代码。
g++ -o gehtnichdll.dll -mdll -static-libstdc++ -static src/dllmain.cpp
仅使用 -mdll 而不是静态生成的 dll 取决于 libstdc++-6.dll ,即使放置在正确的文件夹中也不接受。使用 ProcessMonitor,我可以观察到它再次被打开和关闭 - 然后在其他地方进行更多搜索。如果没有 -mdll 选项,生成的 dll 在同一位置接受该版本的 libstdc++-6.dll。
奇怪的是我现在可以删除 DllMain 和 WinMain,但为什么它与 MinGW 引入的 DllMain 没有冲突?
无论如何,更改构建命令行可以修复它。
此外,我发现在 Stackoverflow 上多次引用了 transmissionzero.co.ok 的链接,但似乎不起作用(使用 MinGW 10)
留下许多悬而未决的问题。现在工作......
推荐阅读
- aws-java-sdk - AWS S3 Java SDK 的性能问题
- actionscript-3 - AS3 语法错误:在 var 之前需要标识符
- excel - Excel vlookup 函数没有给出
- javascript - 如何在实时模板中大写变量的一个实例?
- html - 响应式 iframe 仅适用于 Youtube,不适用于 Vimeo
- c++ - 计算有有效 0 位(最高 1 位以下)的数组元素
- visual-studio - 如何更改服务安装程序的安装注册表位置
- python-3.x - 交换numpy数组中元素的位置
- python - Matplotlib 直方图,其中 bin 定义了 FLOATS 的范围并由它着色?
- azure-active-directory - 无法访问 AAD Microsoft App 的访问代码和刷新令牌