6
votes

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?

2
The article gives a lot of details, what more do you need? What have you tried? What errors are you getting?Polyfun
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
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
@Rup very good point. Just keep rules.dll binary compatible, and you can just copy the new version, no need to re-register.Polyfun
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

2 Answers

9
votes

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.

2
votes

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.