我已经阅读了大量关于如何解决我的问题的文章、教程和说明 - 但仍然 - 没有收获。我就是不能把它投入工作。
我的目标很简单:我想使用 Cygwin gcc 工具编译一个 DLL 文件,然后在 MSVC2010 中使用它。我实际上想用我自己的 DLL 代码来完成它,但为了简单起见 - 我已经尝试了 Cygwin 网站上的非常基本的示例 - 但也失败了......
到目前为止我做了什么: (大部分取自Cygwin用户指南,DLL section)
创建的
mydll.c
文件如下:#include <stdio.h> int hello() { printf ("Hello World!\n"); }
使用
gcc -c mydll.c
和gcc -shared - 将
mydll.c
编译成mydll.dll
o mydll.dll mydll.o在 Visual Studio 中打开一个空的 Win32 控制台项目,代码如下
test.c
(代码取自 Oleg 中 here 的代码,基于 this ):#include <windows.h> typedef int (*PFN_HELLO)(); typedef void (*PFN_CYGWIN_DLL_INIT)(); int main() { PFN_HELLO fnHello; HMODULE hLib, h = LoadLibrary(TEXT("cygwin1.dll")); PFN_CYGWIN_DLL_INIT init = (PFN_CYGWIN_DLL_INIT)GetProcAddress(h,"cygwin_dll_init"); init(); hLib = LoadLibrary (TEXT("D:\\test\\mydll.dll")); fnHello = (PFN_HELLO) GetProcAddress (hLib, "hello"); return fnHello(); }
在 Windows 系统上设置路径变量以包含“Cygwin\bin\”目录。
构建并运行。
我最终遇到以下异常:0xc0000005:访问冲突读取位置 0x003a0048。
这是完整的 MSVC2010 调试输出:
'CygwinDLLTest.exe': Loaded 'C:\Users\xxxx\Documents\Visual Studio 2010\Projects\CygwinDLLTest\Debug\CygwinDLLTest.exe', Symbol loaded.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\ntdll.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\kernel32.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\kernelBase.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\msvcr100d.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'D:\Cygwin\bin\cygwin1.dll', Binary was not built with debug information.
cYgFFFFFFFF 6119F510 0cYgstd 0x27a70b d 3'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\user32.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\gdi32.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\lpk.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\usp10.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\msvcrt.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\advapi32.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\sechost.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\rpcrt4.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\sspicli.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\cryptbase.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\imm32.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'C:\Windows\SysWOW64\msctf.dll', cannot find or open the PDB file.
'CygwinDLLTest.exe': Loaded 'D:\test\mydll.dll', Binary was not built with debug information.
First-chance exception at 0x611075a8 in CygwinDLLTest.exe: 0xc0000005: Access violation reading location 0x003a0048
Unhandled exception at 0x611075a8 in CygwinDLLTest.exe: 0xc0000005: Access violation reading location 0x003a0048
The program '[784] CygwinDLLTest.exe: Native' has exited with code 0 (0x0).
现在,重要的是要注意问题不在于加载那些 DLL,因为它们的处理程序都获得了一个不同于 NULL 的地址。导致异常的代码行是在 DLL 文件中调用 hello 函数。
在你去说任何关于 extern "C"
或 __declspec(dllimport/dllexport)
之前 - 没有帮助。我已经尝试了所有这些但没有帮助。(虽然,AFAIK - 我在 MS 方面使用 Explicit Linking,或在 UNIX 方面使用 Dynamic Loading,所以 __declspec(dllimport/dllexport)
不是必需的)。
我真的希望问题不在堆栈定义上,因为它位于 over here 处:
"Make sure you have 4K of scratch space at the bottom of your stack"
因为我不知道如何在 MSVC2010 上实现这一点(显然,Oleg ...:)
现在,我知道 Hans Passant 超过 here 的话直接引用了我的问题 - 仍然 - 我无法理解如何解决我的问题。
更新:我正在更新这个,因为我想我知道是什么导致了这个问题,我只是不知道如何解决它。请原谅我, Arkady ,但我真的不认为它与您提到的所有内容有任何关系。我正在处理 非常简单 .dll 文件,只有一个功能,所以没有什么可以“包装”在那里..
无论如何,我认为我的问题是使用 msvcrt.dll 文件,而不是 here 所述的:
Q: Can I link with both MSVCRT*.DLL and cygwin1.dll?
A:No, you must use one or the other, they are mutually exclusive.
我知道我要链接到他们两个,我只是不知道如何说服 Visual Studio 只链接到 cygwin1.dll 单独..
我会对此给予答复。
最佳答案
要使用 gcc 创建 DLL 并在 Visual Studio 中使用它,您需要执行以下步骤:
1) 检查您的包装是否相同。我的意思是:
#pragma pack(push, N)
#pragma pack(pop)
对于您要导出的所有结构、函数和数据类型。避免不同的默认数据打包。
2) 检查您没有使用外部头文件(即您的导出头文件不包含任何从外部头文件中获取的内容)。我的意思是“windows.h”在 VS2010 和 CygWin 中可能会有所不同。通常差异并不重要,但既然存在,你可能会遇到问题。 与 STL 和其他版本一样,版本可能不会(也不会!)兼容,因此您会遇到内存问题。
3) 检查您是否仅导出简单的结构和全局函数。所以,你真的必须导出类 C 接口(interface)。 理论告诉你,如果你也将导出抽象接口(interface),例如在示例中:
#pragma pack(push, 4)
struct A
{
virtual ~A() {}
virtual int32_t DoA() = 0;
virtual int32_t PrepareA(const char* settings) = 0;
};
void GlobalFunction(A** ret);
#pragma pack(pop)
或者完全避免虚拟析构函数,并添加全局函数来释放在 DLL 中分配的对象的内存。因为 gcc 和 msvc-10.0 会有不同的数据管理,所以所有用 gcc allocators 分配的都必须由 gcc deallocators 释放。
它必须正确工作,因为将通过调用 GlobalFunction 在 DLL 内部初始化,并且将具有析构函数,在 DLL 内部实现。尽管如此,我还是建议避免使用它,使用类似 C 的风格,只包含简单的数据和全局函数。
4) 您还必须确保 gcc 中的 int 和 VS2010 中的 int 具有相同的大小。你设置相同的架构。例如,为避免该问题,您应该使用 int32_t。
5) 并且您应该确保所有导出的 dll 函数都不会抛出异常。完全没有。由相同的内存问题原因。
关于c++ - 在 Visual Studio 2010 中使用通过 Cygwin 编译的 DLL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25787344/