将cygwin中使用GCC编译的C DLL加载到C#.NET应用程序时发生奇怪的崩溃

将cygwin中使用GCC编译的C DLL加载到C#.NET应用程序时发生奇怪的崩溃,c#,.net,dll,cygwin,loadlibrary,C#,.net,Dll,Cygwin,Loadlibrary,我尝试将在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

我尝试将在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
函数栏()只返回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成功,则始终在会话期间加载成功。我可以随时点击按钮1


注意:LoadLibrary(“foo.dll”)并不能简单地加载foo.dll。那太好了。I崩溃,调试器停止工作。甚至没有抛出异常它并不总是崩溃。有时它是有效的

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

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

您应该尝试使用msft中的process monitor。这很可能是由于加载依赖dll失败造成的。Process monitor将向您显示什么dll以及它未加载的原因。

您应该尝试使用msft中的Process monitor。这很可能是由于加载依赖dll失败造成的。Process monitor将向您显示什么dll以及它未加载的原因。

请尝试以下操作

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();
  }
}
  [DllImport("kernel32", CharSet=CharSet.Unicode)]
  static extern IntPtr LoadLibrary(string lpLibFileName);
甚至可以使用

  [DllImport("kernel32", CharSet=CharSet.Unicode, SetLastError=true)]
并在尝试使用LoadLibrary和GetProcAddress之前检查调用返回值。

请尝试以下操作

  [DllImport("kernel32", CharSet=CharSet.Unicode)]
  static extern IntPtr LoadLibrary(string lpLibFileName);
甚至可以使用

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

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

我们必须使用cygwin。我们想在Windows上编译Hadoop ZooKeeper客户端。ZooKeeper C接口依赖于Windows中的cygwin。@Fair Dinkum Thinkum:那么在您的情况下,编写EXE而不是DLL并与EXE就任何已知方法进行通信会更容易(要推荐一种方法,我需要您提供更多信息)。在我看来,解决“在堆栈底部有4K的暂存空间”的问题要容易得多。@Fair Dinkum Thinkum:我不知道如何控制.NET应用程序的堆栈。堆栈不是应用程序的一部分。它属于线。托管线程将作为非托管线程进行少量控制。CygWin对当前线程中运行的非托管代码的要求对于托管应用程序来说似乎太难了。有时堆栈可以是自由的,您的DLL调用可以工作,但我不知道允许控制CygWin的堆栈要求的.NET互操作属性(选项)。@Oleg,您需要什么信息?我们必须将C#模块连接到ZooKeeper集群。它需要对ZooKeeper进行读写访问。实际上,我们现在的解决方案是一个可执行文件。exe将信息写入C#模块读取的文件。但这种解决方案似乎是“错误的”,我们很容易出错。此外,它不考虑将数据从C*模块写入动物园管理员。我们不想在那个方向也使用文件。@Fair Dinkum Thinkum:我远非动物园管理员。所以说我不多。您可以在CygWin内部使用哪些IPC方法?你能使用COM/DCOM吗?共享内存、命名管道、套接字、窗口消息?调用Web服务是否更容易?您可以使用任何IPC(进程间通信)方法向.NET应用程序发送信息并接收响应。您应该选择最可靠、最简单的实现通信方式。我们必须使用cygwin。我们想在Windows上编译Hadoop ZooKeeper客户端。ZooKeeper C接口依赖于Windows中的cygwin。@Fair Dinkum Thinkum:那么在您的情况下,编写EXE而不是DLL并与EXE就任何已知方法进行通信会更容易(要推荐一种方法,我需要您提供更多信息)。在我看来,解决“在堆栈底部有4K的暂存空间”的问题要容易得多。@Fair Dinkum Thinkum:我不知道如何控制.NET应用程序的堆栈。堆栈不是应用程序的一部分。它属于线。托管线程将作为非托管线程进行少量控制。CygWin对当前线程中运行的非托管代码的要求对于托管应用程序来说似乎太难了。有时堆栈可以是自由的,您的DLL调用可以工作,但我不知道允许控制CygWin的堆栈要求的.NET互操作属性(选项)。@Oleg,您需要什么信息?我们必须连接你