C++/CLI 委託作為函式指針 (System.AccessViolationException)
我一直在嘗試使用 C++/CLI 委託(因為我正在嘗試製作一個 .NET 參考庫),並且一直遇到以下問題。
我在 C++/CLI 中定義了一個委託,然後在 C# 中創建了一個委託的實例,然後通過函式指針通過非託管 C++ 呼叫該委託的實例。這一切都按預期工作。
說明這一點的程式碼(首先是我的 C#)
using System; namespace TestProgram { class Program { static void Main(string[] args) { Library.Test.MessageDelegate messageDelegate = new Library.Test.MessageDelegate(Message); Library.Test test = new Library.Test(messageDelegate); test.WriteMessage(); Console.Read(); } static void Message() { Console.WriteLine(1024); } } }接下來是我的託管 c++ 文件 (Managed.cpp)
#include "Unmanaged.hpp" #include <string> namespace Library { using namespace System; using namespace System::Runtime::InteropServices; public ref class Test { public: delegate void MessageDelegate(); internal: MessageDelegate^ Message; void* delegatePointer; public: Test(MessageDelegate^ messageDelegate) { delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer(); } void WriteMessage() { Unmanaged::WriteMessage(delegatePointer); } }; }還有我的非託管 C++ 文件 (Unmanaged.cpp)
#include "Unmanaged.hpp" namespace Unmanaged { typedef void (*WriteMessageType)(); WriteMessageType WriteMessageFunc; void WriteMessage(void* Function) { WriteMessageType WriteMessageFunc = (WriteMessageType)(Function); WriteMessageFunc(); } }此程式碼按預期工作,輸出為“1024”,因為 Method() 由指向委託方法的函式指針呼叫。
當嘗試對帶參數的委託應用相同的方法時,會出現我的問題,即:
delegate void MessageDelegate(int number);我的程式碼現在如下(C#):
using System; namespace AddProgram { class Program { static void Main(string[] args) { Library.Test.MessageDelegate messageDelegate = new Library.Test.MessageDelegate(Message); Library.Test test = new Library.Test(messageDelegate); test.WriteMessage(1024); Console.Read(); } static void Message(int number) { Console.WriteLine(number); } } }我的託管 C++ 文件:
#include "Unmanaged.hpp" #include <string> namespace Library { using namespace System; using namespace System::Runtime::InteropServices; public ref class Test { public: delegate void MessageDelegate(int number); internal: MessageDelegate^ Message; void* delegatePointer; public: Test(MessageDelegate^ messageDelegate) { delegatePointer = (void*)Marshal::GetFunctionPointerForDelegate(messageDelegate).ToPointer(); } void WriteMessage(int number) { Unmanaged::WriteMessage(delegatePointer, number); } }; }還有我的非託管 C++ 文件:
#include "Unmanaged.hpp" namespace Unmanaged { typedef void (*WriteMessageType)(int number); WriteMessageType WriteMessageFunc; void WriteMessage(void* Function, int number) { WriteMessageType WriteMessageFunc = (WriteMessageType)(Function); WriteMessageFunc(number); } }當我執行程序時,我收到以下錯誤:
非託管庫 Test.dll 中出現“System.AccessViolationException”類型的未處理異常
附加資訊:試圖讀取或寫入受保護的記憶體。這通常表明其他記憶體已損壞。
順便說一句,控制台視窗確實顯示 1024,但後面跟著一個隨機整數(~1000000),然後我得到了錯誤。
我可以開始想像我收到此錯誤的一些原因,但我不確定並且很難找出。如果有人能告訴我為什麼會出現這個錯誤,以及我能做些什麼來解決它,我將不勝感激。
void WriteMessage(void* Function, int number)將函式指針作為 void* 傳遞是一個非常糟糕的主意。它可以防止編譯器檢查你做錯了什麼。儘管在這種特定情況下編譯器無法檢測到,但還是有問題。委託被編組為使用 __stdcall 呼叫約定的函式指針,您的實際函式指針使用 __cdecl 呼叫約定,本機程式碼的預設值。這會導致堆棧在呼叫時變得不平衡。
您可以通過將[UnmanagedFunctionPointer] 屬性應用於委託聲明來修復它,指定 CallingConvention::Cdecl。