0

I have some libraries in x32 that I need to call from x64 process. Googling around, I found the best way to do this is using COM components. I created 3 projects in c#:

  • WinForms project that is X64
  • BaseDll project that is AnyCPU (has single interface BaseInter and method someMethod)
  • Dll32 project that is x32 and has "Register for COM interop" (references BaseDll and implements BaseInter and implements it's method someMethod; Only here I have ComVisible and Guid annotations).

I also registered this COM component (Dll32) in registry (manually adding Wow6432Node paths, and added DllSurrogate props in order to be able to call this x32 from x64 process)

I call this from WinForms project using following code:

Type ComType = Type.GetTypeFromCLSID(new Guid("85840403-68F7-4B39-B015-7ED3506FD06B"));
dynamic c2 = Activator.CreateInstance(ComType);
string dd = c2.someMethod("asd");
MessageBox.Show(dd);

Now this thing is working, but what i wanted to do is to be able to reference BaseDll inside WinForms project and have the following line working:

BaseInter c2 = (BaseInter) Activator.CreateInstance(ComType);

The exception that I get here is:

System.InvalidCastException: 'Unable to cast COM object of type 'System.__ComObject'
to interface type 'BaseDll.BaseInter'. This operation failed because the 
QueryInterface call on the COM component for the interface with IID 
'{40E88E31-DFEA-357E-8A97-E5F0077666C2}' failed due to the following error:
 No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).'

Is the problem here the fact that interface included in WinForms app is compiled for x64 and is not the same as the one in x32 Dll32 project? If I compile WinForms as x32, then this casting code also works without the problem.

UPDATE

BaseInter

public interface BaseInter
{
    string someMethod(String ime);
}

Dll32

[ComVisible(true)]
[Guid("85840403-68F7-4B39-B015-7ED3506FD06B")]
public class JaviSe : BaseInter
{
    public string someMethod(string ime)
    {
        return "Hi from 32 " + ime;
    }
}

Reigstry entries (beside the ones that VS already inserted):

REGEDIT4

[HKEY_CLASSES_ROOT\Wow6432Node\Dll32.JaviSe]
@="Dll32.JaviSe"

[HKEY_CLASSES_ROOT\Wow6432Node\Dll32.JaviSe\CLSID]
@="{85840403-68F7-4B39-B015-7ED3506FD06B}"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}]
@="Dll32.JaviSe"
"AppID"="{85840403-68F7-4B39-B015-7ED3506FD06B}"

[HKEY_CLASSES_ROOT\Wow6432Node\AppID\{85840403-68F7-4B39-B015-7ED3506FD06B}]
"DllSurrogate"=""

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\InprocServer32]
@="mscoree.dll"
"ThreadingModel"="Both"
"Class"="Dll32.JaviSe"
"Assembly"="Dll32, Version=1.0.0.0, Culture=neutral, PublicKeyToken=143740cba1c5c559"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///C:/Users/default.DESKTOP-VNP7D7O/source/repos/SurogateTests/Dll32/bin/Debug/Dll32.dll"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\InprocServer32\1.0.0.0]
"Class"="Dll32.JaviSe"
"Assembly"="Dll32, Version=1.0.0.0, Culture=neutral, PublicKeyToken=143740cba1c5c559"
"RuntimeVersion"="v4.0.30319"
"CodeBase"="file:///C:/Users/default.DESKTOP-VNP7D7O/source/repos/SurogateTests/Dll32/bin/Debug/Dll32.dll"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\ProgId]
@="Dll32.JaviSe"

[HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{85840403-68F7-4B39-B015-7ED3506FD06B}\Implemented Categories\{62C8FE65-4EBB-45E7-B440-6E39B2CDBF29}]
Bojan Vukasovic
  • 2,054
  • 22
  • 43
  • Hard to imagine anybody would still recommend using COM surrogates to do this in this day and age. WCF or gRPC are the more sensible choices. Make it diagnosable first, use SysInternals' Process Monitor. Some odds you'll see it searching for the `Interface` registry key to marshal the interface and not finding it. – Hans Passant Apr 27 '23 at 19:42
  • @HansPassant any tutorial how to use WCF here (and is it also as simple as this one - just few annotations and reg. values)? Also, unmarshalling should happen even though there is difference in bitness? – Bojan Vukasovic Apr 27 '23 at 19:54
  • @HansPassant just checked with ProcessMonitor. Cannot see any search for this GUID or any failure to find Interface key (there were 3 occurences of Interface but all success). Do I also need to annotate and register BaseDll for COM? – Bojan Vukasovic Apr 27 '23 at 20:57
  • Are you using multiple threads? Is this .NET Framework or .NET Core? Have you created a TLB? Have you registered it? PS: IMHO it's much easier to use Component Services than manual surrogates, eg: https://stackoverflow.com/questions/42569377/tlbinf32-dll-in-a-64bits-net-application – Simon Mourier Apr 28 '23 at 05:52
  • @SimonMourier I guess it is only single thread by default (Have not changed anything here aside what VisualStudio created initially). It is .NET Framework 4.8. TLB was created automatically by VS (but only for Dll32 project, not for interface). I can find tlb definitions in registry, so guess Visual studio did this? I will try to update the problem. desc. now. – Bojan Vukasovic Apr 28 '23 at 06:40
  • The interface is not [ComVisible(true)] so the cast will always fail. And you need registry entries for the interface as well so the marshalling plumbing can find it, [ComVisible(true)] on the interface should provide them. And both for 32-bit code and 64-bit code (without Wow6432Node). – Hans Passant Apr 28 '23 at 06:56
  • @HansPassant That was it - just adding [ComVisible(true)] works OK! – Bojan Vukasovic Apr 28 '23 at 09:31

0 Answers0