【问题标题】:CSharp referencing x64 OCX compiled in Delphi XE2CSharp 引用在 Delphi XE2 中编译的 x64 OCX
【发布时间】:2013-12-06 00:25:56
【问题描述】:

在引用在 Delphi XE2 中编译的 x64 OCX 时,我的 C# 项目出现问题。 OCX 位于并注册在 system32 目录中。但是,当我尝试使用 Visual Studio 2010 引用它时,它不会在浏览引用窗口中列出,除非我将 OCX 移动到另一个目录,例如 c:\test\,然后才会显示它。

当我将 x32 版本的 OCX 复制到 syswow64 目录时,没有在此目录中注册,然后 IDE 在浏览引用窗口中列出它。但是当我尝试实例化该类时,出现以下异常:

System.Runtime.InteropServices.COMException 未处理 消息=由于以下错误,检索具有 CLSID {58465503-4991-4578-8478-FF7A6CBAA8CE} 的组件的 COM 类工厂失败:80040111 ClassFactory 无法提供请求的类(来自 HRESULT 的异常:0x80040111 (CLASS_E_CLASSNOTAVAILABLE))。 源=mscorlib 错误码=-2147221231

当我使用另一个目录,如 c:\test\ 并在那里注册 OCX,并在我的项目中引用并实例化它时,一切正常。

我不知道是什么导致了这个问题,如果它是一个 IDE 错误或 OCX 中的一个问题。 OCX,x32 和 x64,都有不同的 UID。

有人知道会发生什么吗?

谢谢

编辑:IDE 是 x32

【问题讨论】:

  • 这个ocx是32位还是64位?
  • Visual Studio 本身是什么 - 它是 win32 还是 win64 应用程序?您可以在 IDE 运行时打开 Windows 任务管理器或在 ntCore CFF 资源管理器中打开 Visual Studio 的 EXE 来检查它。
  • 第一步:停止将文件放入系统目录。这似乎也与 Delphi 无关。这是一个纯粹的 VS 问题。
  • @DavidHeffernan 如果 VCL TComServer 类在 Win64 机器上的 ActiveX 注册方面变得愚蠢,这可能与 Delphi 相关。不太可能但有可能。
  • @Arioch'XE2 COM 注册工作正常

标签: c# visual-studio-2010 delphi reference ocx


【解决方案1】:

有点不清楚这里到底发生了什么。但这是我的想法:

  1. Visual Studio IDE 是 32 位的。因此,如果您希望它看到您需要注册 32 位版本的组件。
  2. 您说“OCX,x32 和 x64,都有不同的 GUID”。这是一个错误。 COM 注册表使用注册表重定向器来处理位数。您的组件必须对 32 位和 64 位版本使用相同的 GUID。
  3. 请停止将文件放入系统目录。这不是你的。它属于系统。

我的猜测是您正在让 IDE 识别组件的 32 位版本。您正在导入类型库,而 VS 正在为您的组件制作 COM 包装器。这将使用您为 32 位组件定义的 GUID。然后您尝试构建组件的 64 位版本,但编译器使用的是 32 位 GUID。运行此程序时,系统无法找到该组件,因为没有使用 32 位 GUID 注册的 64 位组件。

如果这个假设是准确的,那么您可以通过对组件的所有版本使用相同的 GUID 来解决您的问题。

【讨论】:

  • 感谢您的准确回复,所有版本都使用相同的 GUID,问题得到解决。我们不知道注册表重定向器的工作原理。
  • 我本来打算给你正确答案的,但@arioch 先回答了
  • “我们不知道注册表重定向器的工作原理。” - 将进程监视器保留在您的工具集中。当某些事情没有按预期进行时,它通常会为您节省大量时间。就像它可以为您显示 64 位 OCX 注册和 IDE 查找它的不同注册表路径
  • @dmd_anfini 谢谢。请不要将答案授予第一个答案。将其授予最佳答案。否则,您会鼓励快速蹩脚的答案。请注意,我并不是说您错误地给出了答案。 Arioch 的回答非常好。我的观点是语义之一。更好应该优先于更快。
【解决方案2】:

WOW64(Windows-on-Windows 64-bit)的一个基本规则是简单的硬关系。

  • Win32 EXE可以加载Win32 DLL,不能加载Win64 DLL
  • Win64 EXE可以加载Win64 DLL,不能加载Win32 DLL

这与 1993 年引入 Win32s for Windows 和所有后续的 32 位 Windows 版本不同。特殊系统工具 - thunk - 用于确保跨 16/32 位边界的 EXE 和 DLL 的互操作。但是对于 32/64 边界,微软做出了相反的决定。

你的描述在我看来是这样的:

  1. 看起来 Visual Studio IDE 本身就是 Win32 应用程序,而不是 Win64 应用程序。 您可以通过在 Windows 任务管理器中查看 IDE 进程来检查它(启动 IDe 并按 Ctrl+Shift+Esc,然后 r-单击 IDe 并选择“查找进程”),或者通过在ntCore CFF 资源管理器。或者通过 Total Commander,或者通过任何其他方式。 因此,它无法加载您为它制作的 64 位 OCX。它只是行不通。但它确实成功加载了 32 位 DLL(OCX)。

  2. 您写道“OCX,x32 和 x64,都有不同的 GUID。” - 实际上这是一个相当奇怪的决定。如果它们实现相同的 COM 接口,为什么它应该有不同的 GUID?在我看来,这违反了基本的 COM 原则。相同的界面意味着相同的 GUID,反之亦然。我相信您应该使它们具有相同的 GUID,因为它们通过相同的接口提供相同的服务。

  3. 我相信您必须在 Windows 中注册 32 位和 64 位 OCX(具有相同的 GUID!)。这样应用程序就会根据自己的位数加载正确的应用程序。

  4. 您将了解 Vista Win64 中引入的文件系统和注册表虚拟化。简而言之,对于注册表和磁盘中的某些选定路径,Win32 和 Win64 应用程序被重定向到两个单独的数据容器。其中包括 System32 和 SysWOW64 文件夹,其中包括一些注册密钥,用于注册/查找/加载 OCX DLL。

    System32 文件夹运行RegEdit.exe 并查看HKLM\Software\Classes,然后运行RegEdit.exe 来自 SysWOW64 并且在同一个键下你会看到不同的内容!

  5. 您可以运行 Microsoft Process Monitor(从 http://www.SysInternals.com 下载)来查看不同应用程序实际访问的文件和注册密钥。例如 - 您可以了解您的 Win32 和 Win64 OCX 的注册有多么不同,尽管它们是从相同的来源编译的。同样的方式,您会看到 Visual Studio IDE 和您的应用程序使用了哪些实际路径来查找您的 OCX。

  6. 当您将 OCX 放入 c:\test 时 - 您将其置于 FS 可视化范围之外。所以 Win64 和 Win32 应用程序都加载了相同的真实文件路径。您绕过 Windows 内置的特殊 hack,以实现 Win64/Win32 旧版兼容性。

所以总而言之,我向您提出以下建议:

  1. 确保 Win32 和 Win64 OCX 都提供相同的 API,并通过使所有使用的 GUID 相同来明确指定。

  2. 将两个 OCX 放在机器上,或者作为 c:\test 中的不同文件或 c:\test\32c:\test\64 或任何其他文件夹中的同名文件,您的程序将安装到其中。使用System32 文件夹虽然在技术上可能是一个有争议的“快速而丑陋”的决定。

    传统的(阅读:遗留)方法是将 64 位 OCX 放入 c:\Windows\System32,将 32 位 OCX 放入 c:\Windows\SysWOW64。然而,这种做法被认为已弃用,并可能导致 DLL-Hell。相反,在这个新千年中,微软建议使用 WinSxS 多版本存储库来放置系统范围的 DLL。 OTOH,由于您在注册的 ActiveX 组件的注册表列表中没有版本,我不确定这些参数是否适用于 OCX,而不是传统的未注册 DLL。但是,某些第三方程序可能(不幸的是)将其 DLL 命名为与您的 OCX 命名相同的方式,并将其覆盖在 Windows 全局文件夹(如 System32)中。因此,将 OCX 放在 Program Files 自己的文件夹中可能比使用 SxS 更容易,并且比 [mis] 使用 System32 更可靠。`

  3. 同时注册 Win32 和 Win64 OCX。除非您采取特殊措施来抑制虚拟化,否则使用相同的源,OCX 将在不同的真实注册表存储中注册,在 Win32one 和 Win64 中。因为 COM/OCX 目录是注册表的一部分,它被系统包含在 32/64 虚拟化中。因此它们不会相互干扰,而是为 Win32 EXE 注册一个,为 Win64 EXE 注册另一个。

  4. 您是否决定让您的 OCX 保持现代化并使用 WinSxS?那么您似乎甚至不必注册它们。见Registration-Free Activation of COM Components

  5. 在调试时使用 Process Explorer 检查库的注册以及 IDE 和您的应用程序的搜索/加载是否按预期进行。

【讨论】:

  • 请不要劝人把文件放到系统目录下! FWIW,您甚至不需要将 DLL 放在不同的文件夹中。它们可以有不同的名称。因为注册表重定向器完成了所有繁重的工作。
  • @DavidHeffernan 是否有微软的官方立场反对这一点?例如,我可以看到 `c:\Windows\System32\Macromed\Flash`,这是一种传统方式。
  • 是的,Adobe 也使用 3DES 加密他们的密码。所以我不认为我们可以将他们视为一个好的榜样。它可能是传统的,但只要我记得它是错误的。没有必要弃用从未被允许的东西。如果你的 DLL 和我的 DLL 同名会怎样?
  • msdn.microsoft.com/en-us/library/windows/desktop/ms724373.aspx 应用程序不应在系统目录中创建文件。我个人认为安装程序是一个应用程序。
  • @DavidHeffernan 感谢您的链接,添加了它。好吧,如果我们在 Program Files 或 Common Files 中选择相同的 fokder 名称,或者在注册表 Uninstall 键中为分支选择相同的名称,所发生的情况是一样的。或者即使我们的 GUID 相同 - 在 1990 年代就有先例。
猜你喜欢
  • 2011-12-19
  • 1970-01-01
  • 1970-01-01
  • 2012-08-06
  • 1970-01-01
  • 1970-01-01
  • 2011-11-22
  • 1970-01-01
  • 2014-01-14
相关资源
最近更新 更多