我遇到了類似的情況:我將一個指向託管回調的指針傳遞給非託管代碼,並且當調用回調被調用時,該函數運行一次,然後程序崩潰。
我沒有得到一個AccessViolationException - 我沒有得到的任何例外 - 但也許你的問題的原因是我的一樣。
我的問題的解決方法如下:
根據文獻[1]也有不同的函數調用約定:老__cdecl
和新__stdcall
;非託管C/C++默認使用__cdecl
,默認情況下C#使用__stdcall
。
我猜你的非託管代碼使用默認的__cdecl
約定。如果您可以在非託管代碼中更改慣例,那麼這可能是您的修補程序。
對我來說不幸的是,我使用的是第三方DLL,無法更改其中的非託管調用約定。我的程序需要做的是告訴C#我所通過的代表是使用__cdecl
慣例。
不幸的是,沒有辦法直接告訴C#。 (你會認爲會有一個可以使用的屬性,但顯然MS沒有爲C#實現,儘管我相信託管的C++有一個)。
爲了解決這個位需要一個劈的使用:
需要使用在Visual Studio命令提示的ildasm
命令被反編譯程序(DLL/EXE)的輸出:
cmd> ildasm /out=output.il OUTPUT.EXE
一個屬性,然後加入到在IL代碼委託的調用方法來告訴它使用__cdecl
調用約定:
// output.il
.
.
.
.class public auto ansi sealed NAMESPACE.ManagedDelegate
extends [mscorlib]System.MulticastDelegate
{
.custom instance void NAMESPACE.UseCCallingConventionAttribute::.ctor() = (01 00 00 00)
.method public hidebysig specialname rtspecialname
instance void .ctor(object 'object',
native int 'method') runtime managed
{
} // end of method ManagedDelegate::.ctor
.method public hidebysig newslot virtual
instance void Invoke(native int pUser,
int32 state) runtime managed
{
} // end of method ManagedDelegate::Invoke
.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult
BeginInvoke(native int pUser,
.
.
.
變成:
.
.
.
.class public auto ansi sealed NAMESPACE.ManagedDelegate
extends [mscorlib]System.MulticastDelegate
{
.custom instance void NAMESPACE.UseCCallingConventionAttribute::.ctor() = (01 00 00 00)
.method public hidebysig specialname rtspecialname
instance void .ctor(object 'object',
native int 'method') runtime managed
{
} // end of method ManagedDelegate::.ctor
.method public hidebysig newslot virtual
instance void #####modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl)##### Invoke(native int pUser,
int32 state) runtime managed
{
} // end of method ManagedDelegate::Invoke
.method public hidebysig newslot virtual
instance class [mscorlib]System.IAsyncResult
BeginInvoke(native int pUser,
.
.
.
沒有散列。 (在這個例子中代理類型的名稱是ManagedDelegate - 我不確定你的類型名稱是什麼。)
(注意:[1]和[2]建議在代表上放置一個佔位符屬性,讓你不難發現,在.il內文件的方法; UseCCallingConventionAttribute
是我)
然後代碼文件被重新編譯ilasm
:根據您的輸出類型
cmd> ilasm output.il
與/DLL
或/EXE
, - 。默認爲/EXE
。
這是我的項目工作的修復程序。
這整個過程在[1]中有更詳細的概述,有人在[2]中發佈了一個Perl腳本。我還沒有自動化的東西,而且是一個VS n00b,所以我不知道這是否可以作爲構建中的一個步驟添加,但它是。
希望這會有所幫助。
[1] http://www.codeproject.com/KB/cs/cdeclcallback.aspx
[2] http://www.dotnet247.com/247reference/msgs/17/87210.aspx
不可能沒有看到ManagedDelegateRef的聲明來猜測。肯定是錯的。 – 2011-03-01 21:20:29
是的,請提供有關ManagedDelegateRef的更多詳細信息。 – Coincoin 2011-03-01 21:23:44