为什么会引发InvalidProgramException?我看到的不同变体都说:
JIT遇到内部限制。
公共语言运行时检测到一个无效程序。
我已经将这个例子简化到我能复制这个问题的最低限度。您应该能够获取下面的代码并将其粘贴到VS2010中以重现此代码。
下面的基本结构是CppReferenceTest是一个CLR DLL程序集,它包含一个返回本机结构的方法。Referere是试图调用此方法的CLR控制台应用程序。reference有一个对CppReferenceTest的项目引用。
我从其他测试中了解到,调用CppReferenceTest内部的方法不会引发InvalidProgramException。我还知道,如果我将方法签名更改为使用引用参数而不是返回值,则不会引发异常。
程序集1-CppReferenceTest(CLR dll库)
文件:NativeHeader.h
#pragma managed(push, off)
typedef struct _NativeStruct {
int val1;
int val2;
} NativeStruct;
#pragma managed(pop)
文件:CppReferenceTest.h
#pragma once
#include "NativeHeader.h"
using namespace System;
#pragma make_public(_NativeStruct)
namespace CppReferenceTest {
public ref class Class1
{
public:
static NativeStruct GetNativeEnum();
};
}
文件:CppReferenceTest.cpp
#include "stdafx.h"
#include "CppReferenceTest.h"
using namespace CppReferenceTest;
NativeStruct Class1::GetNativeEnum()
{
NativeStruct ns = {1, 2};
return ns;
}
程序集2-裁判(CLR控制台应用程序)
文件:Refree.cpp
#include "stdafx.h"
#include "NativeHeader.h"
using namespace System;
using namespace CppReferenceTest;
int main(array<System::String ^> ^args)
{
NativeStruct ns = Class1::GetNativeEnum();
Console::WriteLine(L"Hello World");
return 0;
}
在.NET中,类型标识包括从中加载类型的程序集。因此,不应将#include
与托管引用一起使用,而应仅使用#import
("项目设置"中的"引用"选项卡等效于#import
)。
现在发生的情况是,通过#include
处理头文件,您可以保证当前程序集中有一个_NativeStruct
类型。main
函数使用此类型。
然后,在运行时,CLR发现Class1::GetNativeEnum()
返回不同的_NativeStruct
类型,该类型在CppReferenceTest.dll
中定义。这些类型不兼容,因此会出现异常。
只需使用您引用的程序集的元数据中提供的类型。
除此之外,不要在C++中执行typedef struct _NativeStruct NativeStruct
。这是不必要的,它会破坏错误消息,更糟糕的是,它与保留的标识符冲突。