1

我尝试将在 cygwin 中使用 GCC 编译的简单 DLL 加载到 C#.NET 应用程序中。DLL 看起来像这样

#ifndef __FOO_H
#define __FOO_H

#if _WIN32
  #define EXPORT extern "C" __declspec(dllexport)
#else //__GNUC__ >= 4
  #define EXPORT extern "C" __attribute__((visibility("default")))
#endif

EXPORT int bar();

#endif  // __FOO_H

函数 bar() 只返回 42。

我编译并链接了 DLL

g++ -shared -o foo.dll foo.cpp

现在我想将这个超级简单的 DLL 加载到 C# WinForms 应用程序中。

public partial class Form1 : Form
{
  [DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
  static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

  [DllImport("kernel32", SetLastError = true)]
  static extern IntPtr LoadLibrary(string lpFileName);

  public delegate IntPtr Action2();

  unsafe public Form1()
  {
    InitializeComponent();

    IntPtr pcygwin = LoadLibrary("cygwin1.dll");
    IntPtr pcyginit = GetProcAddress(pcygwin, "cygwin_dll_init");
    Action init = (Action)Marshal.GetDelegateForFunctionPointer(pcyginit, typeof(Action));
    init();
  }

  unsafe private void button1_Click(object sender, EventArgs e)
  {
    IntPtr foo = LoadLibrary("foo.dll");         // CRASH ... sometimes
    IntPtr barProc = GetProcAddress(foo, "bar");
    Action2 barAction = (Action2)Marshal.GetDelegateForFunctionPointer(barProc, typeof(Action2));
    IntPtr inst = barAction();
  }
}

现在奇怪的是:有时它起作用,有时它不起作用。当它不工作时,它会在加载 foo.dll 时崩溃。我在调试模式下运行它,但我什至没有得到异常。调试器就像我自己停止一样停止!

我还尝试在加载 cygwin1.dll 的同一堆栈框架中加载 foo.dll。一样!

任何提示为什么会发生这种情况以及我可以做些什么来使它工作?

更新 1:我们使用最新的 cygwin 和 Visual Studio 2010。

更新 2:假设它必须与时间和垃圾收集有关。在我看来,加载 cygwin1.dll 和加载 foo.dll 之间的时间很重要。两个 LoadLibrary 调用之间的时间越短,它似乎就越有可能起作用。

更新 3:如果加载 foo.dll 第一次成功,它总是在会话期间成功。我可以随心所欲地单击 button1。

注意: LoadLibrary("foo.dll") 不会简单地加载 foo.dll 失败。那会很好。我崩溃了,调试器停止工作。甚至没有抛出异常。而且它并不总是崩溃有时它有效!

4

3 回答 3

1

查看我关于关闭问题的旧答案的“更新”部分。我建议您使用 MinGW 工具而不是 CygWin 工具来编译您的 DLL。如果从那时起没有任何变化,“确保堆栈底部有 4K 的暂存空间”要求会使 CygWin DLL与 .NET 不兼容。我不知道如何实现 .NET 应用程序中的要求。

于 2010-09-28T10:39:14.047 回答
0

尝试以下...

  [DllImport("kernel32", CharSet=CharSet.Unicode)]
  static extern IntPtr LoadLibrary(string lpLibFileName);

甚至可能使用

  [DllImport("kernel32", CharSet=CharSet.Unicode, SetLastError=true)]

并在尝试使用它们之前检查您对 LoadLibrary 和 GetProcAddress 的调用的返回值。

于 2010-09-28T23:24:16.783 回答
0

您应该尝试使用 msft 的进程监视器。这很可能是由于加载依赖 dll 失败引起的。进程监视器将向您显示什么 dll 以及它未加载的原因。

于 2010-09-28T17:13:53.403 回答