代码之家  ›  专栏  ›  技术社区  ›  Jan Deinhard

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

  •  1
  • Jan Deinhard  · 技术社区  · 15 年前

    我尝试将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
    

    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. 我在调试模式下运行它,但我甚至没有得到一个异常。调试器停止了,就好像我自己停止了一样!

    我也试着装了foo.dll在我加载cygwin1.dll的同一堆栈帧中。同样的事情!

    更新2:一个假设是它必须与定时和垃圾收集相结合。在我看来,从加载cygwin1.dll到加载foo.dll事项。两个LoadLibrary调用之间的时间越短,它似乎越有可能工作。

    更新3:如果加载foo.dll第一次成功总是在会话期间成功。我可以随时点击按钮1。

    加载库(“foo.dll)不会简单地加载失败foo.dll. 那太好了。我 撞车 以及 它并不总是崩溃。有时它是有效的!

    3 回复  |  直到 15 年前
        1
  •  1
  •   Community Mohan Dere    9 年前

    看看我的“更新”部分 old answer 确保堆栈底部有4K的暂存空间 . 我不知道如何在.NET应用程序中实现这个要求。

        2
  •  0
  •   Mike    15 年前

        3
  •  0
  •   Les    15 年前

    请尝试以下操作。。。

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

    甚至可以使用

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

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