Загрузка собственной неуправляемой 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, вы можете заметить, где ваша память разрушается.

НТН

Другие вопросы по тегам