Сбой в режиме отладки (F5) при вызове собственного метода C++

Я пытаюсь вызвать метод C++ с помощью LoadLibrary, GetProcAddress и GetDelegateForFunctionPointer.

Все в порядке (в выпуске и отладке), если я запускаю приложение.NET 4.0 (Ctrl + F5). Но когда я запускаю режим отладки (F5), происходит сбой программы при вызове метода C++.

.Cpp:

#include "PointEntree.h"
#include <stdio.h>
extern "C" __declspec( dllexport ) int Test1(int a)
{
    printf("coucou\n");
    return 0;
}

.H:

extern "C" __declspec( dllexport ) int Test1(int);

.Cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace NETProgram
{
static class NativeMethods
{
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string dllToLoad);

    [DllImport("kernel32.dll")]
    public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);

    [DllImport("kernel32.dll")]
    public static extern bool FreeLibrary(IntPtr hModule);
}

class Program
{      
    delegate int Bambou_Test1(int i);

    static void Main(string[] args)
    {
        IntPtr pDll = NativeMethods.LoadLibrary(@"E:\Dev\C#\ImportC++\Bambou\Release\Bambou.dll");
        IntPtr pAddressOfFunctionToCall = NativeMethods.GetProcAddress(pDll, "Test1");

        Bambou_Test1 method = (Bambou_Test1)Marshal.GetDelegateForFunctionPointer(pAddressOfFunctionToCall, typeof(Bambou_Test1));
        method.Invoke(12);
    }
}
}

Если я использую классический импорт DLL, как показано ниже, он работает, но это не то, чего я хочу достичь:

[DllImport(@"E:\Dev\C#\ImportC++\Bambou\Debug\Bambou.dll", EntryPoint = "Test1",  CallingConvention=CallingConvention.Cdecl)]
public static extern int Test1(int a);

Если у кого-то есть идеи, было бы здорово!

1 ответ

Решение

P/Invoke был в основном разработан для взаимодействия с Windows API, поэтому в StdCall соглашение по умолчанию. C использует Cdecl соглашение по умолчанию. Вам нужно изменить одну из сторон, чтобы явно указать соглашение о вызовах, чтобы оно совпадало с обеими сторонами.

Ваш классический импорт DLL определяет соглашение с [DllImport(..., CallingConvention=CallingConvention.Cdecl)Вариант, основанный на GetDelegateForFunctionPointer не определяет соглашение о вызовах (и, следовательно, использует StdCall). Вы должны указать это с [UnmanagedFunctionPointer(CallingConvention.Cdecl)],

Ваш код такой же неправильный без отладчика, он просто скрывает ошибку. Обычно такое несоответствие нарушает балансировку указателя стека, приводя к мгновенному сбою, но код маршаллинга.net, кажется, имеет специальную обработку для указателя стека, избегая этого сбоя. Без отладчика молча глотает ошибку, с помощью отладчика она ее отображает.

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