CSharp referencing x64 OCX compiled in Delphi XE2

1

Im having a problem in my C# project when referencing a x64 OCX compiled in Delphi XE2. The OCX is located and registered in the system32 directory. However when I try to reference it using Visual Studio 2010 it isn't listed in the browse references window, except when I move the OCX to another directory like for instance c:\test\, then it is shown.

When I copy the x32 version of the OCX to the syswow64 directory, without registering in this directory, then the IDE lists it in the browse references window. But when I try to instantiate the class I ge the following exception:

System.Runtime.InteropServices.COMException was unhandled Message=Retrieving the COM class factory for component with CLSID {58465503-4991-4578-8478-FF7A6CBAA8CE} failed due to the following error: 80040111 ClassFactory cannot supply requested class (Exception from HRESULT: 0x80040111 (CLASS_E_CLASSNOTAVAILABLE)). Source=mscorlib ErrorCode=-2147221231

When I use another directory like c:\test\ and register the OCX there, and reference in my project and instantiate it, everything works fine.

I have no idea what could be causing this problem, if it is an IDE bug or a problem in the OCX. Bothe OCXs, x32 and x64, have different UIDs.

Anyone knows what could be happening?

thanks

EDIT: The IDE is x32

c#
visual-studio-2010
delphi
reference
ocx
asked on Stack Overflow Nov 21, 2013 by dmd_anfini • edited Nov 21, 2013 by dmd_anfini

2 Answers

3

A little bit unclear exactly what's going on here. But here are my thoughts:

  1. Visual Studio IDE is 32 bit. So if you want it to see the component you'll want to register the 32 bit version.
  2. You say that "both OCXs, x32 and x64, have different GUIDs". That's a mistake. The COM registry uses the registry redirector to handle bitness. Your components must use the same GUIDs for both 32 and 64 bit versions.
  3. Please stop putting files in the system directory. It's not yours. It belongs to the system.

My guess is that you are getting the IDE to recognise the 32 bit version of the component. You are importing the type library and VS is making a COM wrapper for your component. This uses the GUIDs that you defined for the 32 bit component. Then you try to build a 64 bit version of the component but the compiler is using the 32 bit GUIDs. When you run this, the system cannot locate the component since there is no 64 bit component registered with the 32 bit GUIDs.

If this hypothesis is accurate then you can resolve your problems by using the same GUIDs for all versions of the component.

answered on Stack Overflow Nov 21, 2013 by David Heffernan
2

One base rule of WOW64 (Windows-on-Windows 64-bit) is the simple hard relation.

  • Win32 EXE can load Win32 DLL and can not load Win64 DLL
  • Win64 EXE can load Win64 DLL and can not load Win32 DLL

It was different with introducing Win32s for Windows in 1993 and in all subsequent 32-bit Windows releases. Special system tooling - thunks - were used to ensure interop of EXEs and DLLs across 16/32 bitness boundary. But for 32/64 boundary Microsoft made the opposite decision.

What you describe looks to me the following way:

  1. It looks like Visual Studio IDE is by itself Win32 application, not Win64 one. You can check it by seeing the IDE process in Windows Task Manager (launch IDe and press Ctrl+Shift+Esc, then r-click the IDe and choose "Find Process"), or by opening the IDE's exe-file in ntCore CFF Explorer. Or by Total Commander, or by any other means. Thus it can not load 64-bit OCX that you made for it. It just does not work. But it does succesfully load 32-bit DLL(OCX).

  2. You wrote that "Both OCXs, x32 and x64, have different GUIDs." - actually that is a rather weird decision. Why should it have different GUIDs, if they implement the same COM Interface ? It looks like violating the basic COM principle to me. The same interface means the same GUID and vice versa. I believe you should make them the same GUID, because they provide the same service by the same interface.

  3. I believe you have to have both 32-bit and 64-bit OCXs (with the same GUID!) registered in your Windows. So that the application would load the correct one, depending on its own bitness.

  4. You are to learn about filesystem and registry virtualization introduced in Vista Win64. In short, for some selected paths in registry and on disk, Win32 and Win64 applications are redirected to two separate data containers. That includes System32 and SysWOW64 folders and that includes some register keys, used to register/find/load OCX DLLs.

    It may be insightful to you to run RegEdit.exe from System32 folder and looking into HKLM\Software\Classes, then running RegEdit.exe from SysWOW64 and under the same key you would see different content!

  5. You can run Microsoft Process Monitor (download from http://www.SysInternals.com) to see which files and register keys are actually accessed by different applications. For example - you can learn how different is registration of your Win32 and Win64 OCXes despite being compiled from the same sources. Same way you would see which actual paths to find your OCXs are used by Visual Studio IDE and by your application.

  6. When you put your OCX in c:\test - you put it outside of FS Vistualization scope. So both Win64 and Win32 application loads them the same real file path. You bypass the Windows built-in special hack for Win64/Win32 legacy compatibility.

So all in all i suggest to you the following:

  1. Ensure that both Win32 and Win64 OCX do provide the same APIs and explicitly specify that by making all the used GUIDs the same.

  2. Put both OCXs on the machine, either as different files in c:\test or same-named files in c:\test\32 and c:\test\64 or any other folders, that your program would be installed into. Using of System32 folder for it is while technicalyl possible a controversial "fast and ugly" decision.

    The traditional (read: legacy) way would be to put 64-bit OCX into c:\Windows\System32 and 32-bit OCX into c:\Windows\SysWOW64. However this practice is considered deprecated and potentially leading to DLL-Hell. Instead, in this new millenium, Microsoft suggests using WinSxS multi-version repository for placing system-wide DLLs. OTOH, since you don't have versions in the registry list of registered ActiveX components, I ain't sure those arguments apply well to OCXs, rather than traditional non-registered DLLs. However, some third-party program may - by sheer misfortune - name its DLL the same way as your OCX is named and overwrite it in Windows-global folders like System32. So, placing OCXs in their own folder in Program Files would probably be easier than using SxS and more reliable than [mis]using System32 for it.`

  3. Register both Win32 and Win64 OCXs. Unless you took special measures to inhibit the virtualization, using the same sources, the OCXs would register in different real registry storages, in Win32one and Win64 one. Because COM/OCX directory is that part of Registry that is included into 32/64 virtualization by system. So they would not interfere with each another, but rather one would be registered for Win32 EXEs and another for Win64 EXEs.

  4. Would you decide to keep your OCXs moder nand use WinSxS- then it appears you don't have to even register them. See Registration-Free Activation of COM Components

  5. Use Process Explorer while debugging to check that both registration of libraries and their search/load by IDE and your application proceeded as expected.

answered on Stack Overflow Nov 21, 2013 by Arioch 'The • edited May 23, 2014 by BenMorel

User contributions licensed under CC BY-SA 3.0