为什么本机返回类型抛出System.InvalidProgramException



为什么会引发InvalidProgramException?我看到的不同变体都说:

  1. JIT遇到内部限制。

  2. 公共语言运行时检测到一个无效程序。

我已经将这个例子简化到我能复制这个问题的最低限度。您应该能够获取下面的代码并将其粘贴到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。这是不必要的,它会破坏错误消息,更糟糕的是,它与保留的标识符冲突。

相关内容

最新更新