2013-12-11 3 views
1

Я пытаюсь вызвать метод C++ с помощью LoadLibrary, GetProcAddress и GetDelegateForFunctionPointer.Сбой в режиме отладки (F5) при вызове собственного метода C++

Все нормально (в выпуске и отладке), если я запускаю приложение .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; 
} 

заголовочных:

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); 

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

+2

В вашем примере на основе GetProcAddress не указано соглашение о вызове как 'Cdecl'. Вы пытались добавить '[UnmanagedFunctionPointer (CallingConvention.Cdecl)]' вашему делегату? – CodesInChaos

+0

Он работает ... спасибо вам большое! Я бы никогда не нашел этот трюк. – NicoGDF

ответ

4

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

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

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

Смежные вопросы