Странный сбой при загрузке C DLL, скомпилированной с GCC в cygwin, в приложение C # .NET - PullRequest
1 голос
/ 24 сентября 2010

Я пытаюсь загрузить простую DLL, скомпилированную с GCC в cygwin, в приложение 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.Я запускаю его в режиме отладки, но я даже не получаю исключения.Отладчик просто останавливается, как будто я сам его остановил!

Я также пытался загрузить foo.dll в тот же самый стек, где я загружаю cygwin1.dll.То же самое!

Любые намеки, почему это происходит, и что я могу сделать, чтобы это работало?

Обновление 1: мы используем последние версии cygwin и Visual Studio 2010.

Обновление2: предположение, что это имеет отношение с синхронизацией и сборкой мусора.Мне кажется, что время между загрузкой cygwin1.dll и загрузкой foo.dll имеет значение.Чем короче время между двумя вызовами LoadLibrary, тем больше вероятность того, что оно сработает.

Обновление 3: если загрузка foo.dll завершается успешно в первый раз, она всегда выполняется во время сеанса.Я могу нажимать на button1 так часто, как хочу.

Примечание: LoadLibrary ("foo.dll") не просто не может загрузить foo.dll.Это было бы хорошо.У меня вылетает и отладчик перестает работать.Даже исключение не выбрасывается. И не всегда сбой.Иногда это работает!

Ответы [ 3 ]

1 голос
/ 28 сентября 2010

Посмотрите на "ОБНОВЛЕННУЮ" часть моего старого ответа о закрытой проблеме.Я рекомендую вам скомпилировать вашу DLL с учетом инструментов MinGW вместо инструментов CygWin.Если с тех пор ничего не изменилось, то требование « Убедитесь, что в нижней части стека имеется 4K пустого пространства », что делает библиотеки CygWin несовместимыми с .NET .Я не знаю, как реализовать требование в приложении .NET.

0 голосов
/ 29 сентября 2010

Попробуйте следующее ...

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

, возможно, даже используйте

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

и проверьте значения, возвращаемые из ваших вызовов LoadLibrary и GetProcAddress, прежде чем пытаться их использовать.

0 голосов
/ 28 сентября 2010

Вы должны попробовать монитор процесса из msft. Скорее всего, это вызвано сбоем загрузки зависимых DLL. Монитор процесса покажет вам, что dll и почему он не загружается.

...