0

当我尝试将 HTML 转换为 XHTML 标记时,我收到以下错误...

错误:检索具有 CLSID {59939390-0E6A-4F1B-A742-20C5459501F7} 的组件的 COM 类工厂失败,原因是以下错误:80040154。

谷歌搜索后,我发现了一些解决方案:

将 DLL 注册到 regsvr32 "E:Source Code\bin\Interop.HTML2XHTMLLib.dll"

我只是试图注册dll。但是E:Source Code\bin\Interop.HTML2XHTMLLib.dll被加载了。但是找不到 DllRegisterServer 入口点,显示此错误消息。为什么..?

为 x86 和 x64 重新编译了我的项目..没用..

VB.NET 代码:

Dim xhtmlUtil As New XHTMLUtilities // Here itself im getting the above error.

sFormattedOutput = xhtmlUtil.convertToXHTML(sInputline) //Send it for conversion

我的操作系统是 Windows XP 32 位 Service Pack 3。我的应用程序是在 VS2008 中完成的。目前我正在使用 VS2010。

这是我所缺少的。任何人都可以帮我解决这个问题吗?

提前致谢。

4

1 回答 1

4

我只是试图注册 dll。但是 E:Source Code\bin\Interop.HTML2XHTMLLib.dll 已加载。但是找不到 DllRegisterServer 入口点,显示此错误消息。为什么?

Interop .HTML2XHTMLLib.dll 文件不是您要使用 regsvr32 注册的库。它只是托管互操作程序集,生成的 COM 对象可用于您的 .NET 应用程序。您实际上需要为 HTML2XHTMLLib.dll 注册类型库。

为此,您有两种选择:

  1. 找到包含该库的可再分发包并将其与您的应用程序一起安装。
  2. 在您的开发系统上,打开 Visual Studio 的“添加引用”对话框。选择 COM 选项卡并搜索库(就像添加引用时所做的那样)。在那里你会找到图书馆的绝对路径。将库复制到客户端系统并使用regsvr32.

由于我不知道 HTML2XHTMLLib 的来源,我只能建议那些方法。你应该更喜欢第一个。

既然你已经开始对此进行赏金,我想更详细地介绍一下 COM 和 InterOp。

COM 和 .NET 程序集之间的差异

COM 中有两种类型的服务器:InProc-servers 和 OutProc-servers。InProc (In Process) 是我们通常知道的DLL的服务器。OutProc(Out of Process)服务器是独立的,在它们自己的进程中运行。我们将它们称为EXE可切割文件。

您想使用 InProc 服务器。您的 COM 服务器 ( HTML2XHTMLLib ) 由两部分组成:

  1. 一个类型库 ( .tlb),包含有关服务器的元信息,它包含对象及其可访问性。
  2. 一个库,包含实现所有对象的代码。该库还导出以下静态函数:
    • DllGetClassObject– 尝试创建对象的实例,在服务器内部定义
    • DllCanUnloadNow– 告诉 COM 环境,是否可以释放服务器,因为它不再被任何其他进程使用。
    • DllRegisterServer– 调用regsvr32以在 Windows 注册表中注册前面提到的类型库,以使其对客户端和 COM 环境可见。
    • DllUnregisterServer– 当通过 调用时,完全相反regsvr32 -u

类型库也可以是DLL或EXE文件的资源,这样就只有一个文件了。对于 C# 开发人员来说,这似乎有点令人困惑,因为元信息直接编译成 .NET 程序集并可以通过反射访问。

InterOp:.NET 和 COM 之间的包装器

因此,基本上类型库描述了 .NET 反射访问通过 COM 公开的对象所需的一切。但问题是,COM 组件以不同的格式存储:

  • 通常它们被直接编译成机器代码:你不能链接一个 .NET 程序集,用AnyCPU对 COM 服务器编译。COM 服务器直接编译为 x86-assembler 或 x86-64-assembler。它们具有固定的指针大小,因此仅与其中一种编译模型兼容。
  • COM 定义了内存管理的规则。每个 COM 对象都必须实现IUnknown-interface。这个接口定义了三个方法。这些方法AddRefRelease用于内存管理目的。每当客户端访问它需要调用的 COM 对象时AddRef。这将计数器增加一。当客户端不再需要该对象时,它调用Release而不是删除该对象,从而导致计数器递减。如果指针达到 0,则删除对象本身。这与 .NET 管理内存的方式不同。在 .NET 中,垃圾收集器以不确定的方式访问堆上的每个对象(您无法确定删除对象的确切时间点)并在没有对它的引用时释放该对象。
  • COM 定义了身份规则。每当您只想访问对象的基本接口时,都必须调用QueryInterfaceIUnknown. 此方法保证在查询特定接口时始终返回相同的指针。这对于 .NET 也可能是正确的(除了您正在重载一些运算符),但 .NET 确保对象标识的方式是不同的。
  • COM 定义了对象关系的规则。诸如AggregationContainment之类的疯狂东西也存在于 .NET 中,但实现方式不同。
  • COM 定义了不同的多线程规则,例如Single Threaded AppartmentsMulti Threaded Appartments。这些线程模型定义了对象以不同方式共存时如何交互。在 .NET 中,您必须手动执行每个同步过程。

此列表可能不完整,我也不想进一步详细说明,因为这只是您的问题的附带问题,但是您会看到,.NET 和 COM 之间存在一些很大的差异。为了管理这些差异,两个世界之间存在一个层:COM InterOp。

如果您从 .NET 调用 COM 服务器,则 InterOp 只不过是一个.NET 程序集,它可以在后台完成所有艰苦的工作。它是使用tlbimp.exe工具创建的。每当您从 COM 选项卡引用库时,Visual Studio 通常会为您调用它。结果是您要注册的库:InterOp.Libary.dll。该库重新定义了 COM 服务器的所有类型库,实现了 COM 所需的规则,并为您执行实际调用。然而,它是一个托管的 .NET 库,它没有定义前面描述的方法。这就是为什么regsvr32找不到DllRegisterServer入口点的原因。

上面描述的方式只是一种使用非托管 COM 服务器和托管 .NET 客户端的方式。还有另一种方式,对应的tlbexp.exeregasm.

于 2013-04-24T09:56:14.687 回答