29

出于部署原因,我尝试使用 IJW 在 C++ 中包装 C# 程序集,而不是使用 COM Callable Wrapper。

我在其他项目上做过,但在这个项目上,我得到了一个 EEFileLoadException。任何帮助,将不胜感激!

托管 C++ 包装代码(在 DLL 中):

extern "C" __declspec(dllexport) IMyObject* CreateMyObject(void)
{
    //this class references c# in the constructor
    return new CMyWrapper( );
}

extern "C" __declspec(dllexport)  void DeleteMyObject(IMyObject* pConfigFile)
{
    delete pConfigFile;
}

extern "C" __declspec(dllexport) void TestFunction(void)
{
    ::MessageBox(NULL, _T("My Message Box"), _T("Test"), MB_OK);
}

测试代码(这是一个EXE):

typedef void* (*CreateObjectPtr)();
typedef void (*TestFunctionPtr)();

int _tmain testwrapper(int argc, TCHAR* argv[], TCHAR* envp[])
{
    HMODULE hModule = ::LoadLibrary(_T("MyWrapper"));
    _ASSERT(hModule != NULL);

    PVOID pFunc1 = ::GetProcAddress(hModule, "TestFunction");
    _ASSERT(pFunc1 != NULL);
    TestFunctionPtr pTest = (TestFunctionPtr)pFunc1;

    PVOID pFunc2 = ::GetProcAddress(hModule, "CreateMyObject");
    _ASSERT(pFunc2 != NULL);
    CreateObjectPtr pCreateObjectFunc = (CreateObjectPtr)pFunc2;

    (*pTest)();  //this successfully pops up a message box
    (*pCreateObjectFunc)();  //this tosses an EEFileLoadException

    return 0;
}

值得一提的是,事件日志报告以下内容:.NET 运行时版本 2.0.50727.143 - 致命执行引擎错误 (79F97075) (80131506)

不幸的是,微软没有关于该错误的信息。

4

6 回答 6

35

问题在于 DLL 所在的位置。

  • c:\dlls\managed.dll
  • c:\dlls\wrapper.dll
  • c:\exe\my.exe

我通过将 managed.dll 复制到 c:\exe 中确认了这一点,并且没有问题。显然,CLR 不会在非托管 DLL 的路径中查找托管 DLL,而只会在可执行文件所在的位置查找它。(或在 GAC 中)。

由于不值得讨论的原因,这是我需要的结构,这意味着我需要让 CLR 帮助定位托管 dll。请参见下面的代码:

组装解析器.h:

/// <summary>
/// Summary for AssemblyResolver
/// </summary>
public ref class AssemblyResolver
{
public:

static Assembly^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args )
{
    Console::WriteLine( "Resolving..." );

    Assembly^ thisAssembly = Assembly::GetExecutingAssembly();
    String^ thisPath = thisAssembly->Location;
    String^ directory = Path::GetDirectoryName(thisPath);
    String^ pathToManagedAssembly = Path::Combine(directory, "managed.dll");

    Assembly^ newAssembly = Assembly::LoadFile(pathToManagedAssembly);
    return newAssembly;
}

};

包装器.cpp:

#include "AssemblyResolver.h"

extern "C" __declspec(dllexport) IMyObject* CreateMyObject(void)
{
    try
    {
        AppDomain^ currentDomain = AppDomain::CurrentDomain;
        currentDomain->AssemblyResolve += gcnew ResolveEventHandler( AssemblyResolver::MyResolveEventHandler );

        return new CMyWrapper( );
    }
    catch(System::Exception^ e)
    {
        System::Console::WriteLine(e->Message);

        return NULL;
    }
}
于 2008-09-18T20:36:41.560 回答
10

第一个问题是确保调试器类型设置为混合。然后你会得到有用的例外。

于 2008-09-18T16:44:00.840 回答
5

对于使用混合模式 dll(您的 EXE)的本机应用程序,请将 **“调试器类型”更改为“混合”模式。(转到项目属性 -> 配置属性 -> 调试)

还有其他一些要点(可能与您无关),但根据我的经验,它们可能会导致问题。- 在 Windows 8(具有更严格的安全性)上,请尝试以管理员身份启动您的 VS。- 确保对于 x86 配置,您使用的是 x86 二进制文件。- 注意 StrongName 验证,如果您在托管 C++ 中使用的 C# 程序集已签名,请考虑对混合模式 dll 进行签名。

希望这会有所帮助。

于 2015-07-30T11:53:20.650 回答
1

万一其他人偶然发现了这个问题,并且您使用的是动态程序集名称:请确保您正在剥离程序集名称,它可能包含您可能不使用的版本、文化和其他内容。

即,您的 MyResolveEventHandler 应采用以下形式:

static Assembly^ MyResolveEventHandler( Object^ sender, ResolveEventArgs^ args )
{
    Console::WriteLine( "Resolving..." );

    String^ assemblyName = args->Name;

    // Strip irrelevant information, such as assembly, version etc.
    // Example: "Acme.Foobar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    if( assemblyName->Contains(",") ) 
    {
        assemblyName = assemblyName->Substring(0, assemblyName->IndexOf(","));
    }

    Assembly^ thisAssembly = Assembly::GetExecutingAssembly();
    String^ thisPath = thisAssembly->Location;
    String^ directory = Path::GetDirectoryName(thisPath);
    String^ pathToManagedAssembly = Path::Combine(directory, assemblyName );

    Assembly^ newAssembly = Assembly::LoadFile(pathToManagedAssembly);
    return newAssembly;
}
于 2013-07-20T12:35:12.323 回答
1

在调试 ASP.NET MVC 应用程序期间,iisexpress.exe 抛出了很多 C++ EEFileLoadException。调用堆栈和 C++ 异常本身对帮助我解决问题并没有太大帮助。

在直接查看 C++ 异常中给出的指针地址后,我最终发现了一个库字符串,它指向不再使用的旧版本。这又是由于我的 web.config 文件中的一个过期条目:

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
    <assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" />
    <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
  </dependentAssembly> </assemblyBinding> </runtime>

我已通过 NuGet 将各种 Microsoft.Own 安全库升级到版本 4.0.30319,但配置中的这一行指示服务器将调用重定向到版本 3.0.1.0,现在不再是我项目的一部分。更新配置解决了我的问题。

于 2016-10-24T16:47:50.547 回答
-5

当您在使用 C++ 托管 dll 的调试器 C++ 本机项目中运行时,您可能会遇到此异常。当 VS2010 捕获它并且您的应用程序在某些链异常之后将被中止时,您可以尝试在异常过滤器 (Menu|Debug|Excpetion) 中禁用所有 C++ 异常。您仍会在输出中看到此异常,但您的应用程序不会中止

于 2011-01-11T22:25:39.547 回答