CSharp引用在Delphi XE2中编译的x64 OCX

时间:2013-11-21 13:41:43

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

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

当我将OCX的x32版本复制到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

2 个答案:

答案 0 :(得分:3)

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

  1. Visual Studio IDE为32位。因此,如果您希望它看到您想要注册32位版本的组件。
  2. 你说“两个OCX,x32和x64都有不同的GUID”。那是个错误。 COM注册表使用注册表重定向器来处理位数。您的组件必须对32位和64位版本使用相同的GUID。
  3. 请停止将文件放入系统目录。这不是你的。它属于该系统。
  4. 我的猜测是你让IDE识别该组件的32位版本。您正在导入类型库,VS正在为您的组件创建一个COM包装器。这使用您为32位组件定义的GUID。然后,您尝试构建64位版本的组件,但编译器正在使用32位GUID。运行此命令时,系统无法找到组件,因为没有向32位GUID注册64位组件。

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

答案 1 :(得分:2)

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

  • Win32 EXE可以加载Win32 DLL并且无法加载Win64 DLL
  • Win64 EXE可以加载Win64 DLL并且无法加载Win32 DLL

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

您所描述的内容通过以下方式向我看:

  1. 看起来Visual Studio IDE本身就是Win32应用程序,而不是Win64应用程序。 您可以通过在Windows任务管理器中查看IDE进程来检查它(启动IDe并按Ctrl + Shift + Esc,然后单击IDe并选择"查找进程")或打开IDE的exe文件在ntCore CFF Explorer中。或者通过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 ,然后运行<来自 SysWOW64 的em> RegEdit.exe ,在相同的密钥下,您会看到不同的内容!

  5. 您可以运行Microsoft Process Monitor(从http://www.SysInternals.com下载)以查看不同应用程序实际访问的文件和注册密钥。例如 - 您可以了解尽管从相同的源代码编译,但Win32和Win64 OCX的注册有何不同。您可以通过Visual Studio IDE和应用程序查看找到OCX的实际路径。

  6. 当您将OCX放入c:\ test时 - 将其置于FS Vistualization范围之外。因此,Win64和Win32应用程序都会加载相同的真实文件路径。您绕过Windows内置的特殊攻击,以获得Win64 / Win32旧版兼容性。

  7. 总而言之,我建议你:

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

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

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

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

    4. 您是否决定保留您的OCX并使用WinSxS-然后看起来您甚至不必注册它们。请参阅Registration-Free Activation of COM Components

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