2013-12-11 25 views
1

我想通過使用LoadLibrary,GetProcAddress和GetDelegateForFunctionPointer來調用C++方法。在調用本機C++方法時調試模式(F5)時崩潰

如果我運行.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); 

如果有人有任何想法,這將是偉大的!

+2

您的基於'GetProcAddress'的示例沒有將調用約定指定爲'Cdecl'。你有沒有試過向你的代理添加'[UnmanagedFunctionPointer(CallingConvention.Cdecl)]'? – CodesInChaos

+0

它的作品...非常感謝你! 我永遠不會找到這個把戲。 – NicoGDF

回答

4

P/Invoke主要是爲了與Windows API進行互操作而設計的,所以默認使用StdCall約定。 C默認使用Cdecl約定。您需要改變雙方以明確指定調用約定,以便它在兩邊都匹配。

您的經典DLL導入指定的慣例爲[DllImport(..., CallingConvention=CallingConvention.Cdecl),基於GetDelegateForFunctionPointer的變體未指定調用約定(因此使用StdCall)。您需要使用[UnmanagedFunctionPointer(CallingConvention.Cdecl)]來指定它。

你的代碼在沒有附加調試器的情況下也是錯誤的,它只是隱藏了錯誤。通常,這種不匹配會使堆棧指針不平衡,導致即時崩潰,但.net編組代碼似乎對堆棧指針有特殊的處理方式,以避免崩潰。沒有調試器就會默默吞下錯誤,用調試器顯示它。