Out of process COM object dynamic versioning - c++

I am using out-of-process COM object that is hosted by myexe.exe. There are multiple versions of those exes which host the COM object. Each version can have slightly changed interfaces and methods. Each of myexe.exe files are located in versioned folders(e.g. C:\v2\myexe.exe, c:\v3\myexe.exe)
There is no way to know ahead of time which of the versions will be running. My client application attaches to the running exes using ROT. I need to be able to use that COM object version dynamically, discovering interfaces through IUnknown.QueryInterface.
Unfortunately I am getting crash when using newer methods if older version of COM is registered in Windows Registry. Once I register newer version of out-of-proces COM in windows registry using "myexe.exe -regserver" the crash goes away. So i cannot dynamically use older or newer version of meexe.exe at runtime as each time i need to re-register my com version.
Any ideas on why i get the crash or how to solve the problem?

COM interfaces are never versioned. Each COM interface is as different as any other.
You use IIDs to differentiate and go from one to another using QueryInterface().
See QueryInterface guidelines and the Guide.

COM interfaces are immutable. Once you have defined an interface and start using it in your apps, you CAN'T change it anymore. Its IID and VTABLE are locked in. If you need to make changes to existing methods, or add new methods, you MUST create a new interface with a new IID for that purpose (the new interface can derive from the previous interface, though that is not required). The server must then implement the new interface, and clients can QueryInterface() the server for the new interface when needed. There is no getting around this, it is a fundamental rule of COM, so as not to break existing clients when creating new server versions.

Related

Why is the COM interface contract immutable?

I've googled quite a bit, and found it weird that no one cared to explain why COM interfaces are immutable. I suppose that the reason you're unable to remove any methods from a COM interface, is because a client relying on that interface, would encounter an error, which isn't good. But why would adding new features to the interface change any of that? Has this something to do with the underlying vtable?
COM has a very strong DLL Hell problem. Several basic reasons:
The programmers involved with writing the server and the client code rarely know each other, don't work together and have their own release schedules.
Registering servers is by default machine-wide, affecting every single client program that depends on the server. Isolated COM with a reg-free manifest is a workaround.
Early-bound COM (using a v-table) is very efficient but extremely intolerant to v-table changes. Mismatches are very hard to diagnose when the client code simply calls the completely wrong function or passes the wrong arguments. Late-bound calls through IDispatch is a workaround but slow.
COM programmers are very strongly motivated to cheat, changing the interface {guids} causes pretty grumpy client programmers and awkward support calls. Making an interface backwards compatible is relatively easy to do, making it forward compatible never works. Only changing the interface guid is truly safe.
Deployment of COM servers is often a client duty, they typically don't know enough about the server to troubleshoot and correct problems.
These are otherwise generic versioning problems, many runtime implementations suffer from them with various amounts of pain. A specific advantage in COM is that you can do something about it. Change the {guids} and a lot of the nastiness evaporates.
If you add a method, a newer client that uses that method will fail when working with an older version of the component.
Older versions of the component won't have the new method unless you specifically add code to implement it, rebuild the component, and then reinstall the component on all machines that use the component.
If a newer version of the client attempts to call the new method on an older version of the component that doesn't have the method, undefined behavior will occur (likely a crash but silent data corruption is also possible). The new client will be attempting to call a method through a pointer entry in the vtable that did not exist when the old client was built so the old client will have some unrelated value in this location.
Of course, this wouldn't be an issue for you if you control both client and component and deploy them together but COM is designed for a much broader range of use cases than that.

COM dll without DllRegisterServer, etc

I have a COM dll that exports a custom factory function, CreateX(). Much like D3D11, objects from this dll are not instantiated via CoCreateInstance(), and there are no class factories or CLSIDs - only IIDs. I've removed all mention of the server functions from the ATL project, which builds without problems. I also linked the dll to a test application, and everything works as expected.
Is there a downside to excluding DllRegisterServer() (and the like) in this situation that I am not aware of?
There is no apparent downside. It's a popular misconception that all what is COM related has to be in the Windows registry. On the fundamental level COM is just a convention of binary interoperability. Services available through the registry are not necessary.

Is there a way to manually organize COM marshaling?

I have two .exe application. Each of them contains interfaces compatible with Automation and described in projects IDLs. So, I have tlb for both applications. Need to organize the call methods of the class that implements one of the interfaces from code running in another/different application. Just how it works in COM Server and COM client throw out-of-process boundary. But intrefaces is privacy and not registered in Registry, so standard CoMarshalInterface/CoUnmarshalInterface is not working.
How I can do it, manualy organize marshaling (all requred data are exist: tlb, automation compatible interfaces) ?
P.S. Looks like this but without registry registration.
Having type library available and registered you might expect COM to create proxy/stub pairs automatically using type library information. This is however not the only way, COM will first query the object if it is capable to marshhal itself into stream, via IMarshal interface, IMarshal::MarshalInterface method.
Marshaling Details on MSDN writes:
Custom marshaling is inherently unique to the object that implements
it. It uses proxies implemented by the object and provided to the
system on request at run time. Objects that implement custom
marshaling must implement the IMarshal interface, whereas objects that
support standard marshaling do not.
By implementing custom marhshaling this way you have your COM object saving its essential information into stream, and it provides CLSID of unmarshaler to re-create the interface on the other side. The data will be passed over process boundary and your object will be instantiated and provided this stream data in order for you to re-create the interface in question.
Hence, implement IMarshal and friends and you will be able to integrate into COM processing without having your type library registered or even available.
To communicate two process containing COM objects, you can use ROT (Running object table), here's a sample showing how to do it.

What is the ($Foo)PS project in my $Foo ATL solution for?

Creating an ATL project in MSVC seems to create not one but two projects; the latter named the same as the former but with PS appended to its name. What is the purpose of this second project and how can I tell whether I need it?
COM supports making interface method calls across two different threads, two different processes or two different machines. This is called marshaling. Two different threads is the most common case, a COM server is often not thread-safe. COM implements thread-safety for such single-threaded coclasses by marshaling the call from the 'wrong' thread to the thread that created the server. Marshaling between processes occurs when you write an out-of-process server. Between different machines across a network is called DCOM.
This is implemented by creating an instance of the interface that looks exactly like the original. But all the methods of the interface are actually substitutes that do the job of the marshaling the call. This is the proxy. On the other end of the wire there's a substitute that looks exactly like the interface but does the opposite job. This is the stub. The proxy and stub work together to create the illusion that you're making a simple method call in your program.
The primary job of the proxy is to serialize the arguments of the method call into a memory buffer or network packet. This can be pretty untrivial, especially when you use pointers to variable-sized structures. COM needs help to get that right and that's the job of your FooPS project. When you run midl.exe on your .idl file, midl auto-generates code from the interface definitions to implement the proxy and the stub. This is quite often good enough but you may need to implement your own if the built-in keywords in IDL are not sufficient to describe your data.
Last but not least, Windows provides a standard marshaller that can marshal simple interfaces. Designed to support the sub-set of COM that's defined by COM Automation. In other words, interfaces that derive from IDispatch and only use Automation compatible types. You only need to get the registry entries right to enable it and don't otherwise need the proxy/stub generated by midl. And of course, if you only make simple in-process calls on one thread then you won't need it either. This is pretty common.
As #ebutusov said, *PS project contains implementations for Proxy and Stub. They are not standard, instead they are generated by MIDL for interfaces exported from your ATL server. These interfaces are declared in the *.IDL file. The ouput of the project is DLL. You may read this article to get more details.
You may remove PS project from the solution in case if you do not define any custom interfaces in you *.IDL file or if you define only interfaces which have dual and oleautomation modifiers. In that case a standard typelib marshaller will be used.
In order to be able to make use of the standard typelib marshaller, one has to register a typelibrary (which is done automatically since you are using ATL)
It's proxy/stub code, which contains non-standard data marshallers needed to transfer data between different apartments (threading related). It's used when application, which calls your COM object, uses different COM threading model. There was an option in ATL/COM wizard to merge this code into main library. In many common scenarios you don't have to worry about it (i.e. when your COM dll runs in the client context), unless you want to write a custom marshaller.

How to load COM DLL at runtime

I have a VB6 COM DLL. I want to use it from C++. I know how to register it, generate a tlb file from the DLL, and #import it in C++.
I'd like however, to load and use DLLs like this dynamically, at runtime, without knowing them in advance. Is this possible?
Thanks,
Yes, but you need to get the question clearer.
Sometimes, you do know the COM interface upfront, just not the implementation. In that case, you can create a dummy implementation of the interface and #import that. At runtime, you'd still register the real component, get an object from it (via CoCreateInstance probably) and store that in an appropriate smart pointer.
With VB6, it's a bit less direct. This adds a level of indirection. Read up on IDispatch. You need to get that known interface to describe an unknown interface. That way, the unknown interface can be obtained at runtime.
IMHO, You need at least some common interface (so you known what to call in the C++ side).
I'd do something like:
Define a common interface (in its own DLL/TLB)
Implement this interface in one or more COM servers
Import this interface in the C++ side (let's call it client)
Define a way to pass the progid of the COM server you want to work with (load dynamically) in the client.
Hope this helps
Take a look at these two MSDN articles about Registration-Free Activation of COM Components:
Registration-Free Activation of COM Components: A Walkthrough
Escape DLL Hell: Simplify App Deployment with ClickOnce and Registration-Free COM
There also have been some similar question here on StackOverflow:
Generate manifest files for registration-free COM
Windows/C++: how to use a COM dll which is not registered