6

In one of my Project, I have c# application which is using C++ DLL. Currently at client PC we are registering C++ DLLS at COM components in the registry so that we will use them in C#.

I learn on NET that there is a Reg Free solution available from microsoft at link http://msdn.microsoft.com/en-us/library/ms973913.aspx

But after reading I didn't get much clue because my application architecture is different as following

  1. I am having 2 C++ dlls LET SAY CPForms.dll and Rules.dll.
  2. Rule.dll is include inside CPForms.dll
  3. I have 1 C# dll let say ConsumeForm.dll which is using CPForms.DLL
  4. I have another C# Exe which is using ConsumeForm.dll

My client is only opening C# Exe which in turn is calling ConsumeForm.dll which is further calling CPForms.dll which shows C++ form (UI), there is button validate, when user click that button it internally using C++ Rules.dll. Currently I am registering both C++ dlls in registry.

Now client only want Rule.dll to be referenced as RegFree installation, because Rule.dll changes frequently and the client don't want to unregister and register again and again using Admin account.

Other then that client is OK with registration of CPForms.dll.

My question is how we can generate manifest file? And how it will work in my scenario?

Rup
  • 33,765
  • 9
  • 83
  • 112
Hemant Kothiyal
  • 4,092
  • 19
  • 61
  • 80
  • The article gives a lot of details, what more do you need? What have you tried? What errors are you getting? – Polyfun Feb 09 '12 at 11:30
  • I'd guess you need to know whether the manifest is attached to the .exe or one of the DLLs - I'd guess the .exe because it sets up the process. Apart from that, isn't the XML syntax clear? – Rup Feb 09 '12 at 11:43
  • 1
    Actually, does it need to be registration free? As long as rules.dll is installed in the same place (which would require admin rights anyway, correct?) and implements the same objects and interfaces that CPForms.dll is built against, why does it need to be unregistered and re-registered every time? (The registration-free question is interesting in itself, though.) – Rup Feb 09 '12 at 11:46
  • 1
    @Rup very good point. Just keep rules.dll binary compatible, and you can just copy the new version, no need to re-register. – Polyfun Feb 09 '12 at 12:10
  • Actually the reason for Registration free is that Rules.dll is frequently changing and if we can refer that winthin CPForms.dll using Reg Free then it will be great. But again as you said Reg Free manifest only attached with exe not dll then i am not sure whetehr if i will create manifest for rules.dll and attched in c# EXe, it will work or not? – Hemant Kothiyal Feb 09 '12 at 12:24
  • "Rules.dll is frequently changing" - OK, but are the COM object definitions and interfaces (i.e. the TLB data) frequently changing? If so, you'll need to rebuild CPForms.dll every time too. If not, then as long as you put the new version in the same place as the last one then it'll continue to work with the old registration. Where to put the manifest: don't know, sorry. Write them all and get it working then figure out which ones are actually used? – Rup Feb 09 '12 at 13:25
  • 2
    This is not a workable solution. The manifest needs to be embedded in *your* program. If the owner of Rules.dll keeps changing the interface then *you* need to keep rebuilding your program. Not just to update the embedded manifest but also to tweak your own code to deal with the changes. If the only intent is isolation then just copy the DLLs into your own EXE folder and create an empty directory with the name "yourapp.exe.local". – Hans Passant Feb 09 '12 at 13:34
  • I again recheck same issue with client, and now they said that they want all COM dlls Reg Free, Now how should i approach? I tried today but not suceed. Now i am able to generate manifest of ConsumeForm.dll and manifest of Exe, but i am not able to refer dll maifest inside exe manifest. Second problem is Inside ConsumeForm.dll.manifest i am only getting information of CPForms.dll not Rules.dll – Hemant Kothiyal Feb 10 '12 at 14:02
  • See also this walkthrough if it helps: http://msdn.microsoft.com/en-us/library/ms973913.aspx#rfacomwalk_topic2 – Ben Feb 10 '12 at 17:26
  • Also see this question: http://stackoverflow.com/questions/465882/generate-manifest-files-for-registration-free-com – Ben Feb 10 '12 at 17:27
  • Also see this lot: http://social.msdn.microsoft.com/search/en-us?query=registration+free+com&x=0&y=0 – Ben Feb 10 '12 at 17:28

2 Answers2

10

Note: Consider using a manifest as in the answer here for a better solution:

How to do it without a manifest

The COM registry is a service which is optional for an inproc server.

Again: You do not have to register an object in order to create it. If it is not registered, (and not in a manifest) you cannot create it with CoCreateInstance, because the registry (or manifest) is what tells CoCreateInstance which DLL to load.

However you can create it with LoadLibrary, GetProcAddress, DllGetClassObject and IClassFactory::CreateInstance.

(Note you will not get any COM+ services, and you cannot create out-of-process objects in this way, or objects whose threading model isn't compatible with the creating thread. If you don't ask COM to do it for you these things become your problem).

The service which CoCreateInstance provides is to locate the correct DLL for the call to LoadLibrary, and just call the other functions for you. (And checking the threading models are compatible, creating on the appropriate thread, and using CoMarshalInterthreadInterfaceInStream/CoUnmarshalInterfaceAndReleaseStream to marshal the interface if they are not. That sounds like a lot of work but if you just have one STA therad you can pretty much ignore all the issues.)

Something like this should do the trick:

// Really you should break this up int GetClassFactoryFromDLL, then reuse the class factory.
// But this is all from memory...
// Load CLSID_MyID, from DLL pszMyDllPath
typedef HRESULT __stdcall (*_PFNDLLGETCLASSOBJECT)(
  __in   REFCLSID rclsid,
  __in   REFIID riid,
  __out  LPVOID *ppv
) PFNDLLGETCLASSOBJECT;

HRESULT CreateInstanceFromDll(LPCTSTR pszMyDllPath, CLSID clsidMyClass, IUknown** ppunkRet)
{
    // Handle bad callers
    *ppunkRet = NULL;
    HANDLE hDLL = LoadLibrary(pszMyDllPath);
    if(hDLL == NULL)
    {
        // Failed to load
        return HRESULT_FROM_NTSTATUS(GetLastError());
    }
    PFNDLLGETCLASSOBJECT pfnDllGetClassObject = GetProcAddress(hDLL);
    if(pfnDllGetClassObject == NULL)
    {
        // Not a COM dll
        HRESULT hrRet = HRESULT_FROM_NTSTATUS(GetLastError());
        FreeLibrary(hDLL);hDLL = NULL;
        return hrRet;
    }
    IClassFactory* pClassFactory = NULL;
    HRESULT hr = pfnDllGetClassObject(clsidMyClass, IID_IClassFactory, &pClassFactory);
    if(FAILED(hr)){
        FreeLibrary(hDLL);hDLL = NULL;
        return hr;
    }
    hr = pClassFactory->CreateInstance(NULL, IID_IUnknown, &ppunkRet);
    pClassFactory->Release();
    if(FAILED(hr))
    {
        *ppunkRet = NULL;
        FreeLibrary(hDLL);
        return hr;
    }
    return hr;
}

Note: This will allow you to create the object. However if the object you call is itself reliant onbeing registered, it will not function correctly.

In particular, many IDispatch implementations rely on the type library. If that's the case for a particular object, then GetIDsOfNames and GetTypeInfo will fail, and you will not be able to use late-bound methods with the object. This includes using dynamic in C#, and dynamic languages such as Python.

Other methods such as dual interface methods and interfaces not inheriting from IDispatch may well work however even if the IDispatch methods do not.

Bottom line: For registration-free COM to work, the object being instantiated must not rely on its own registration.

Community
  • 1
  • 1
Ben
  • 34,935
  • 6
  • 74
  • 113
  • I followed this for my case (AutoItX.dll). Object indeed was created. But I cannot invoke it not via interop lib not via reflection. When I register C++ lib all starts to work. – Dzmitry Lahoda Nov 20 '13 at 16:46
  • @DzmitryLahoda, you cannot register a C++ *.lib file. I assume you mean you registered the COM dll? How did you register it? – Ben Nov 20 '13 at 21:48
  • Sorry for misleading lib. I talk about dll. When I do `regsvr32 AutoItX3.dll /u' then I cannot invoke any method on created object. It is unusable. When I do 'regsvr32 AutoItX3.dll' all works. But in this case I do not need code provided in sense that code is not answer "How to use Registration free COM dll in dot net" for fully valid COM object. – Dzmitry Lahoda Nov 21 '13 at 09:35
  • @DzmitryLahoda what happens when you invoke methods? – Ben Nov 21 '13 at 09:50
  • I found. Doing reflection invocation fails when AutoIt not registered. `System.Runtime.InteropServices.COMException (0x8002801D): Library not registered. (Exception from HRESULT: 0x8002801D (T YPE_E_LIBNOTREGISTERED)) at System.RuntimeType.InvokeDispMethod(...) `. I tried to invoke methods from C# or from IronPython. When using interop dll things work fine in C#. But IronPython still fails. So in my case answer is correct until calling via interop dlls, not via reflection. – Dzmitry Lahoda Nov 21 '13 at 11:44
  • 1
    @DzmitryLahoda, on unregistered objects you may find that methods such as IDispatch::GetIDsOfNames or GetTypeInfo fail (for late binding, e.g. Dynamic objects or dynamic languages) if the implementation uses the type library. However where you have performed early binding, GetIDsOfNames should not be called. In particular if the interface concerned is not IDispatch (for example you are calling dual interface methods directly rather than via Invoke) then this should work. Bottom line: The object you call must not itself rely on its own registration! – Ben Nov 21 '13 at 12:16
  • @DzmitryLahoda, what you have discovered is very interesting. I have expanded the answer to include information on the cause of the failure you observed. – Ben Nov 21 '13 at 12:22
  • This looks my case. Additionally validated it calling IDipatch::GetIDsOfNames method directly in C#. No reg - fails. – Dzmitry Lahoda Nov 21 '13 at 15:40
2

For those who will jump to this question in search for Registration free COM dll in dot net, I was able to use AutoItX COM object in Reg Free manner from C# in this answer https://stackoverflow.com/a/19996424/173073. Creating and using other Reg Free objects would be similar.

Community
  • 1
  • 1
Dzmitry Lahoda
  • 939
  • 1
  • 13
  • 34