BadImageFormatException 遇到 WcfSvcHost 和 IIS WCF 主机

Geo*_*kos 5 c++ wcf interop iis-6 was

引用 x86 DLL 时,在 Vista x64 上的 Visual Studio 2008 中创建 WCF 服务库很麻烦。调用 32 位 DLL 的服务需要具有 x86 平台目标才能在 64 位操作系统上运行。执行此操作时,WcfSvcHost 会在您尝试调试服务时引发 BadImageFormatException。有一个关于 MS 连接的错误报告。我使用的解决方法是将WcfSvcHost 核心标记为 32-bit

清单问题

我遇到的主要问题是这个第三方本机 32 位 DLL 无法使用某些 WCF 主机加载。当调用使用第三方 DLL的服务操作时,我收到以下错误:

System.TypeInitializationException: '' 的类型初始值设定项引发异常。

.ModuleLoadExceptionHandlerException:在导致 C++ 模块无法加载的主要异常之后发生嵌套异常。

System.BadImageFormatException:该模块应包含程序集清单。(来自 HRESULT 的异常:0x80131018)

嵌套异常:

句柄无效。(来自 HRESULT 的异常:0x80070006 (E_HANDLE))

WcfSvcHost 启动时不会引发此异常,而是在调用引用 32 位 DLL 的服务操作时引发。非常有趣的是,在控制台应用程序上使用相同的 app.config 托管相同的服务没有例外并且可以完美运行:

using (ServiceHost host = new ServiceHost (typeof (MsgBrokerService))) {
    host.Open ();
    Console.WriteLine ("running");
    Console.ReadLine ();
Run Code Online (Sandbox Code Playgroud)

此异常发生在:

“WcfSvcHost.exe”(托管):已加载“C:\Windows\WinSxS\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_none_d08d7bba442a9b36.dll”

同样,控制台应用程序没有异常并加载相同的 DLL:

“ConsoleApp.vshost.exe”(托管):加载“C:\Windows\WinSxS\x86_microsoft.vc80.crt_1fc8b3b9a1e18e3b_8.0.50727.3053_none_d08d7bba442a9b306.dll”

请参阅 Microsoft 产品支持的回答

更新 #1:控制台应用程序和 WcfSvcHost.exe 主机进程都在同一会话和登录用户(我)下运行。我已经将 WcfSvcHost.exe 复制到服务的目录中,手动启动并遇到相同的结果。我还检查了 Windows 事件日志以获取其他信息并使用sxstrace,但没有记录任何内容。

运行进程资源管理器,我已经验证以下两个进程之间是相同的:

  • 图像:32 位
  • 当前目录
  • 用户/SID
  • 会议
  • 安全性(组被拒绝,权限被禁用)

运行进程监视器并配置符号,我看到 WcfSvcHost 查找以下注册表和文件,而控制台主机则没有。进程监视器记录了大量数据,我不确定我在寻找什么:(

HKLM \ SOFTWARE \微软\融合\ PublisherPolicy \ DEFAULT \ policy.8.0.msvcm80__b03f5f7f11d50a3a C:\ WINDOWS \装配\ GAC_32 \ msvcm80 \ 8.0.50727.3053__b03f5f7f11d50a3a C:\ WINDOWS \装配\ GAC_MSIL \ msvcm80 \ 8.0.50727.3053__b03f5f7f11d50a3a C:\ Windows\assembly\GAC\msvcm80\8.0.50727.3053__b03f5f7f11d50a3a

更新 #2:当服务在 IIS 6/Windows Server 2003 上托管在生产中时,会发生同样的异常。

更新 #3:第 3 方 32 位 .NET 程序集是StreamBase API

  • sbclient.dll(托管)
  • monitor.netmodule(托管)
  • dotnetapi.dll(非托管)
  • pthreads-vc8.dll(非托管)

更新 #4:添加清单但没有成功:

  1. 已验证 dotnetapi.dll 和 pthreads-vc8.dll 是否具有 RT_MANIFEST。sbclient.dll .NET 程序集没有清单
  2. 从 GAC 中删除了 sbclient.dll
  3. 注册 sbclient.dll 用于验证跳过
  4. 通过mt.exe向 sbclient.dll 和 monitor.netmodule添加了一个清单
  5. 添加了经过验证的清单,并且在测试期间加载了预期的文件(通过 Visual Studio - 调试模块窗口)
  6. 在 BackgroundWorker.OnDoWork() 下抛出相同的 BadImageFormatException,并且调用堆栈显示对 dotnetapi.dll...DefaultDomain.Initalize() 的调用。

我已经验证 msvcm80.dll 没有清单,我相信这是唯一一个没有清单的加载文件:)

有趣的发现

当我在Reflector 中加载 monitor.netmodule 时,它说:

“monitor.netmodule”不包含程序集清单。

即使它显示错误,反射器仍然能够反汇编托管代码。

Geo*_*kos 2

Microsoft 产品支持已经解决了这个问题:这是设计使然。使用 WcfSvcHost 或 IIS WCF 主机时,非托管代码不会加载到默认 AppDomain 中。

纯映像将使用 C 运行时库的 CLR 版本。但是,CRT 不可验证,因此在使用 /clr:safe 编译时无法使用 CRT。有关详细信息,请参阅 C 运行时库。

http://msdn.microsoft.com/en-us/library/k8d11d4s.aspx