我遇到了类似的情况:我将一个指向托管回调的指针传递给非托管代码,并且当调用回调被调用时,该函数运行一次,然后程序崩溃。
我没有得到一个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