【问题标题】:Using DLL compiled with Cygwin inside Visual Studio 2010在 Visual Studio 2010 中使用 Cygwin 编译的 DLL
【发布时间】:2014-09-14 03:43:16
【问题描述】:

我已经阅读了大量关于如何解决我的问题的文章、教程和说明,但仍然没有收获。我就是不能把它付诸实践。

我的目标很简单:我想使用 Cygwin gcc 工具编译一个 DLL 文件,然后在 MSVC2010 中使用它。我实际上想用我自己的 DLL 代码来做,但为了简单起见——我在 Cygwin 的网站上尝试了非常基本的例子——但也失败了..

到目前为止我做了什么: (大部分内容来自 Cygwin 用户指南,DLL section

  1. 创建mydll.c文件如下:

    #include <stdio.h>
    
    int hello()    {
      printf ("Hello World!\n");
    }
    
  2. 使用gcc -c mydll.cgcc -shared -o mydll.dll mydll.omydll.c 编译成mydll.dll

  3. 在 Visual Studio 中打开了一个空的 Win32 控制台项目,代码如下:test.c(代码取自Oleghere 中的代码,基于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();
    }
    
  4. 在 Windows 系统上设置路径变量以包含“Cygwin\bin\”目录。

  5. 构建并运行。

我最终遇到了以下异常:0xc0000005: Access violation reading location 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,所以 @987654346 @ 不是必需的)。

我真的希望问题不在于堆栈定义,因为 over here:

“确保堆栈底部有 4K 的暂存空间”

因为我不知道如何在 MSVC2010 上实现这一点(显然,Oleg...:) 也不知道

现在,我知道在Hans Passant 的话中直接提到了我的问题而不是here - 仍然 - 我不明白如何解决我的问题。

更新:我正在更新这个,因为我想我知道问题的原因,我只是不知道如何解决它。请原谅我,Arkady,但我真的不认为它与你提到的所有内容有任何关系。我正在使用非常简单的 .dll 文件,它只有一个功能,所以没有什么可以“包装”在那里..
无论如何,我认为我的问题是使用 msvcrt.dll 文件,而不是 here 所说的:

问:我可以同时链接 MSVCRT*.DLL 和 cygwin1.dll 吗?
A:不,你必须使用其中一个,它们是互斥的。

我知道我正在链接他们两个,我只是不知道如何说服 Visual Studio 仅链接到 cygwin1.dll 单独..

我会回答这个问题。

【问题讨论】:

标签: c++ visual-studio-2010 gcc dll cygwin


【解决方案1】:

要使用 gcc 创建 DLL 并在 Visual Studio 中使用它,您需要执行以下步骤:

1) 检查您的包装是否相同。我的意思是:

#pragma pack(push, N) 
#pragma pack(pop)

对于您要导出的所有结构、函数和数据类型。避免不同的默认数据打包。

2) 检查您是否不使用外部头文件(即您的导出头文件不包含取自外部头文件的任何内容)。我的意思是“windows.h”在 VS2010 和 CygWin 中可能并且将会有所不同。通常差异并不重要,但既然存在差异,您可能会遇到问题。 与 STL 和其他版本相同,版本可能不(也不会!)兼容,因此您会遇到内存问题。

3) 检查您是否只导出简单的结构和全局函数。所以,你真的必须导出类 C 的接口。 理论告诉你,如果你还要导出抽象接口,例如:

#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 分配器分配的都必须由 gcc 释放器释放。

它必须正常工作,因为会在DLL内部通过调用GlobalFunction进行初始化,并且会有析构函数,在DLL内部实现。尽管如此,我还是建议避免它,使用类似 C 的风格,只使用简单的数据和全局函数。

4) 您还必须确保 gcc 中的 int 和 VS2010 中的 int 具有相同的大小。你设置了相同的架构。例如,为避免该问题,您应该使用 int32_t。

5) 你应该确保所有导出的 dll 函数都不会抛出异常。完全没有。由于相同的内存问题原因。

【讨论】:

    猜你喜欢
    • 2021-03-13
    • 2013-12-03
    • 1970-01-01
    • 2011-03-04
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    相关资源
    最近更新 更多