I have a little problem with CoGetClassObject().
I have an application which must use some DLLs of a specific version,
but they are also present in the system, in a more recent version.
So I start hooking the CoCreateInstance() and loadLibrary(), which I guess are good.
The problem is that the DLLs in the two versions are loaded.
So I think that CoGetClassObject() is the problem/solution because it provides a pointer to an interface of an object associated with a CLSID containing a DLL that the application must use in an older version.
But I don't know what this function "does", so how can I "override" this function ?
thanks.
PS : I'm new in the COM programming.
CoGetClassObject() simply does half the job that CoCreateInstance() does. It returns a class factory. CoCreateInstance() then call IClassFactory::CreateInstance() and releases the IClassFactory. You would only use it if you have a need to create many objects of a certain coclass and want to optimize that. It avoids the cost of creating and releasing the factory over and over again.
You are possibly overlooking a far simpler solution to this problem. You can simply copy the new version of the COM server DLL into the same directory as the client EXE. And create a zero byte file with the name "app.exe.local" where "app" is the name of the EXE. That's enough to force that copied DLL to be loaded instead of the one that the registry points to. The MSDN Library article about DLL redirection is here.
The very simple explanation is CoGetClassObject() opens HKCR\CLSID\{ClassId} and looks at InProcServer32 or LocalServer32 depending on what CLSCTX_* value is passed - that is the COM server path.
Once it find a COM server file path is loads (LoadLibraryEx() with LOAD_WITH_ALTERED_SEARCH_PATH flag in case of in-proc or CreateProcess() in case of out-proc) the COM server. Then it locates and calls DllGetClassObject() for in-proc servers or waits until a class factory is registered for out-proc servers.
This of course ignores stuff like DCOM etc. You can get a better idea of how it traverses the registry using Process Monitor utility.
If you want to load a specific COM DLL regardless of whether there is a newer version installed, and regardless of where the older DLL is located, then simply ignore CoCreateInstance() and CoGetClassObject() altogether. Load the older DLL yourself via LoadLibrary(), then call its exported DllGetClassObject() function directly to get the DLL's IClassFactory interface, then call IClassFactory::CreateInstance() as needed. This is all CoCreateInstance() and CoGetClassObject() do internally anyway, but this bypasses the Registry lookups they perform to determine the DLL path to load.
Related
I have several components (multiple .dlls, one .exe) which I need to use registration free. In my sxs manifest I've listed the dll files as;
<file name="xxx.dll"
<comClass
description="xxx component"
clsid="{xxx-xxx}"
threadingModel="Apartment" />
</file>
I have created and activated an Activation context and can call CoCreateInstance(); on these dll components without issue.
However, I also have a COM server singleton (as an .exe) that I need to run and I believe that you can only put dll files in the sxs manifest. I have its CLSID.
I'm restricted in that using regsvr is not an option for this, so is there an alternative way of being able to achieve this? Ideally having everything done programatically in the same place as where I am creating these other components.
That is a bridge too far...to try and do it through manifests. However, you can do it manually. But, what you have to do is what the OS does. You have to:
Call CreateProcess() with all the correct command line options
Call WaitForInputIdle() on the process
Make your COM calls
You'll probably also have to have entries for the interfaces you use if they are custom. I would probably recommend making them IDispatch compatible if at all possible.
To know what command line options are necessary, you'll have to register the server on your build machine and then look up the LocalServer32 registry key for the CLSID(s) and see what the arguments are. They can be a little different from each other if they are MFC or ATL, but usually ATL arguments are always the same unless you do something custom.
If for some reason the CreateObject() fails, then you probably will have to call TerminateProcess() on the process you created, otherwise you will have a bunch of orphaned processes. If you successfully create the object, the normal COM reference counting should be sufficient to shutdown the server process automatically.
The question below is for educational purposes only and the discussed featured are not meant to alter registered DLLs or develop a malware but for learning and experiencing.
Recently I've been exploring few methods to load my own custom DLLs instead of an application's original DLLs.
One of the methods that came up was the <exe>.local method.
After experiencing with this method a little bit and after I removed the KnownDlls entry from the registry I managed to replace some system DLLs with my patched DLLs successfully.
These are the DLLs:
However, the DLLs are IN the local folder:
However, there are still some DLLs that insist loading from the system32 directory, although they are present in the local folder.
Is there any way I can force the DLL's to load from the local folder instead of the system32 folder?
This is not an answer so much as a rambling, unsourced, brain dump.
It does serve to explain why I am not surprised at your result. This boils down, for me, to the crucial difference between CreateProcess and LoadLibrary, and how Win32 processes work.
Normally, when using LoadLibrary, you are using it from within the process you want the dll to be loaded into. As such, it can take advantage of a whole bunch of in-process context information about activation contexts, dll search paths etc. including knowledge of things like the app.local flag.
All these values are specific to the current process and it is not the job of any other process (or even the Kernel) to track stuff like this.
But, if we look at CreateProcess we can see some problems. When it is initially called, it is called in the context of the launching, not destination, process, so it knows nothing of the destination processes activation context. In fact, the destination process does not exist yet.
The CreateProcess implementation needs to create a NT process, and execute some code in it asap to perform the process load as it doesn't make any sense to instantiate all that per process context stuff in the current process.
But, to do that, there needs to be at least some code in the destination process: The kernel code responsible for parsing the EXE files header, extracting the headers and building the activation contexts that will be used to load the remaining dlls.
This means that, unfortunately for you, kernel32.dll and some dependencies need to be mapped into a process long before that process is capable of building a dll search context, noticing the app.local flag etc.
You should look at how the Windows loader works. This is OS version dependent, but some of those DLLs load before your program and the loader always looks for them on a path provided by the system. Look at the sequence by starting your program with WinDbg.
We have an old C/C++ .dll that a customer accesses via COM.
We have tried to replace our old .dll with a new one written i .NET.
Customer cannot recompile their client so it is important that the old .dll can be replaced simply by COM unregister / register new (using regsvr32 / regasm).
We believe we have built the .NET .dll with the same COM interface as the old; GUID's, names, dispid's etc. all match. We have verified this by writing our own C++ test application and it continues to work when we unregister old .dll / register new one.
The problem is that the customer's client failes to start.
Strangely if we leave the old .dll registered (e.g. both .dll's are registerd) it works; The customer's application starts and calls methods in our new .dll. But as soon as we unregister the old .dll the application fails to start again.
We have tried different ways to register the new .dll; using regasm with /codebase option, /tbl, etc.
If I inspect with OLE/COM Viewer I can see some minor differences between new and old .dll, for example the type library "name" differs. But I suppose since our own C++ test client works with either .dll the COM interfaces are enough similar?
Please, anyone has any idea? How is it possible for one C++ client to load with our new .dll while another fails? Why do both work if we leave the old .dll registered in parallel to the new one? Is there any explanation why the two C++ clients behave differently?
UPDATE:
The error message in the client says:
"failed when running: CLSIDFromProgID. Check if [myDll].dll is registered."
Kind Regards P.T
There are many possibilities. First, ensure you are registering the type library of your new DLL. The old one may be doing it as part of DllRegisterServer, but AFAIK, .Net DLLs do not. Register it with REGTLB.exe.
Also check the threading models are the same in both DLLs.
If neither of those help, I suggest you keep on until OLEVIEW says they are identical - you never know what the client is doing which is different from yours.
One part of some software I have written is a COM dll.
Other software uses this COM dll.
My software has an update function where it will download a newer version of the dll, but the update will fail if the dll is in use because the file cannot be deleted or written to.
The question is, how can I update a COM dll that is in use?
I have considered popping up a message asking the user to close any applications that are using the DLL if it is in use, if this is the best solution how would I go about detecting if the COM dll was in use before popping up the message?
Thanks in advance.
You cannot update it in place for existing applications, but one way to do this would be to save it with a different file name or different folder and call DllRegisterServer on the DLL to register it under the new name. New applications which begin using your object should now use the new version.
If this is just a matter of detecting whether you can replace the file then it is easy. Just try to open it with a share flag that denies reading. That's going to fail if the DLL is loaded in another process. Use _fsopen() or CreateFile(). Beware of the race condition.
Detecting which processes have the file loaded is a harder problem, CreateToolhelp32Snapshot() and Process32First/Next plus Module32First/Next to enumerate processes and the DLLs they have loaded. Still tough to generate a good diagnostic for the user, the process name isn't that helpful.
When you have downloaded the update, you must launch a third program (which you write) that does not have any dependancies on your COM component, or any other piece that is to be updated. This launcher, or bootstrapper, must shut down all your pieces, uninstall them, and install the update. When the update is installed you may then re-launch your application.
If you need also to download updates to the updater itself, your main program can do that.
Here is a simple solution for you. Create a wrapper DLL, which will be used by the other processes. Inside that DLL you explicitly load/unload your DLL, which is subject to updates. Of course you will have to suspend all callers when an update process kicks in.
I really need help...
I have implemented a COM component (i.e A.dll) with IDL, also coded a wrapper DLL (B.dll) for that component. I have implemented required export functions for DLL "A" and registered it with "regsvr32.exe".
Problem is that I have 3 EXE files that uses B.dll to access methods of A.dll. But, I could not manage to create a local server for A.dll, therefore every EXE loads a new A.dll and B.dll. I want to load A.dll only once, and need to realize this functionality in B.dll. Last statement is open for discussion also.
However, I could not manage to find any useful example or resource regarding this problem. Any help will be appreciated, thanks in advance.
A DLL mediated by COM is known as an in-process server. Which suggests your problem: it will always be mapped into the memory space of its clients, just like any other DLL. Similarly any DLLs it loads will be mapped into the original process. It is not clear from your question why you don't want to use a DLL. If it is to save resources then consider that only data will be duplicated; the code will only be loaded once. If it is because you want them to share data, then consider using shared memory. If you really want all three .exe's to be served by an instance then what you need is a COM local server, which will be implemented by an .exe, not a .dll.
There's no such thing as "create a local server". In-proc server has to be loaded into each consumer process, there's no way around that - each consumer is a separate process, so it has its own copy of code and data.
In order to have a single process executing COM server code for all of the consumers you have to create an out-proc server. To do the latter you can either reengineer your COM server or try to use COM+ server application. This way you can have a separate process running the COM server code several consumers can connect to.