c++ - 在 Visual Studio 2010 中使用通过 Cygwin 编译的 DLL

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

我已经阅读了大量关于如何解决我的问题的文章、教程和说明 - 但仍然 - 没有收获。我就是不能把它投入工作。

我的目标很简单:我想使用 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 - 将 mydll.c 编译成 mydll.dll o mydll.dll mydll.o

  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:访问冲突读取位置 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/

相关文章:

c++ - 如何使用 Makefile 变量作为文件包含在 g++ 命令中?

c# - 将 Textbox 和 MessageBox 添加到类库

c - 来自 gcc 编译器的错误

c - Newlib 在 ARM 嵌入式系统中首次调用时无法分配堆

c++ - 我可以将enable_if替换为decltype吗

c++ - C++ 应用程序中基于系统语言环境的国际化

c++ - 取消引用指向句柄的指针给我 "illegal, right operand.."?

c++ - 如何在 Windows 中获取屏幕比例?

c++ - 文件打开问题

.net - GalaSoft.MvvmLight.WP71 编译错误,需要为 RelayCommand 添加对 System.Windows 的引用