Загрузка собственной неуправляемой C++ DLL в управляемое приложение C# приводит к тому, что DLL выводит мусор
У меня есть собственная, неуправляемая C++ DLL (symulator.dll), которую я должен загрузить и вызвать из управляемого приложения C#.
DLL использует классы C++ и динамическое выделение памяти (через new
оператор).
Экспортирует функцию под названием Init
и его определение заключается в следующем:
extern "C" __declspec( dllexport ) int Init( void )
{
sym = new CSymulator();
sym->Init();
return 0;
}
CSymulator
Класс, содержащийся в DLL, имеет довольно простой конструктор:
CSymulator::CSymulator( void )
{
memset( mem, 0, sizeof( mem ) );
memset( &rmr, 0, sizeof( rmr ) );
md = 0;
ma = 0;
tacts = 0;
}
CSymulator::Init()
метод, вызываемый Init()
Функция, экспортируемая DLL, определяется следующим образом:
int CSymulator::Init( void )
{
int *a = new int;
*a = 1;
FILE *f = fopen( "tmp.log", "wb" );
fprintf( f, "%i", *a );
fclose( f );
delete a;
return 0;
}
Я загружаю нативную C++ DLL в управляемое приложение C#, используя этот код:
public partial class Form1 : Form
{
public IntPtr SimHandle;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr LoadLibrary(string libname);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
delegate int SimInit();
SimInit DLL_Init;
public void InicjujDLL()
{
IntPtr adres;
adres = GetProcAddress(SimHandle, "Init");
DLL_Init = (SimInit)Marshal.GetDelegateForFunctionPointer(adres, typeof(SimInit));
int rc = DLL_Init();
}
private void WczytajDLL()
{
String fileName = "D:\\prg\\kompilator\\Debug DLL\\symulator.dll";
SimHandle = LoadLibrary(fileName);
if (SimHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Exception(string.Format("Blad przy wczytywaniu biblioteki ({0})", errorCode));
}
else
{
InicjujDLL();
}
}
private void Form1_Load(object sender, EventArgs e)
{
WczytajDLL();
}
}
Этот код должен создать файл с именем tmp.log с содержимым 1
в этом. Но по какой-то причине tmp.log содержит мусорные данные (случайное 32-разрядное целое значение вместо 1; например, 2550276
).
Это не единственная функция, которая производит вывод мусора. Любая функция DLL, которая пытается выделить память динамически, не может использовать ее после этого.
Это как если бы C++ DLL как-то очищала свою память сборщиком мусора C#.
Как предотвратить это поведение?
1 ответ
Подождите секунду: посмотрите на ссылку ниже:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate int MultiplyByTen(int numberToMultiply);
Я не заметил, что ваш делегат не имеет такой же атрибут.
Для справки, я не вижу ничего необычного в том, как вы делаете LoadLibrary: динамически загружать собственную библиотеку
Я сделал это сам, используя точную ссылку без проблем. Я бы предложил временно удалить ВСЕ код, который выполняется внутри DLL, и просто выполнить простое сквозное значение. Прямо сейчас Init() всегда возвращает 0. Попробуйте что-то еще, поскольку вы обнуляли память раньше, возврат нуля может быть просто побочным эффектом операции mem-zero. Вернуться 1974 или что-то.
Убедитесь, что разрешен небезопасный код, и используйте средство просмотра памяти для просмотра стека (вы получаете указатель назад, поэтому у вас есть отправная точка). Если вы сделаете это рядом с IL, вы можете заметить, где ваша память разрушается.
НТН