Standard COM marshaler does not work with REGDB_E_IIDNOTREG
I am trying to merge an interface with another thread.
Windows provides a handy CoMarshalInterThreadInterfaceInStream
helper function to take care of the boilerplate code associated with use CoMarshalInterface
directly.
const Guid CLSID_Widget = "{F8383852-FCD3-11d1-A6B9-006097DF5BD4}";
const Guid IID_IWidget = "{EBBC7C04-315E-11D2-B62F-006097DF5BD4}";
//Create our widget
HRESULT hr = CoCreateInstance(CLSID_Widget, null,
CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
IID_IWidget, out widget);
OleCheck(hr);
//Marshall the interface into an IStream
IStream stm;
hr = CoMarshalInterThreadInterfaceInStream(IID_IWidget, widget, out stm);
OleCheck(hr);
Except the call CoMarshalThreadInterfaceInStream
fails:
REGDB_E_IIDNOTREG (0x80040155)
Interface not registered
Go directly to CoMarshalInterface
The COM API function CoMarshalInterThreadInterfaceInStream provides a simple wrapper around CreateStreamOnHGlobal
and CoMarshalInterface
, as shown here :
// from OLE32.DLL (approx.)
HRESULT CoMarsha1InterThreadInterfaceInStream(
REFIID riid, IUnknown *pItf, IStream **ppStm)
{
HRESULT hr = CreateStreamOnHGlobal(0, TRUE, ppStm);
if (SUCCEEDED(hr))
hr = CoMarshalInterface(*ppStm, riid, pItf,
MSHCTX_INPROC, 0, MSHLFLAGS_NORMAL);
return hr;
}
So we can try ourselves.
IStream stm = new Stream()
hr = CoMarshallInterface(stm, IID_IWidget, widget,
MSHCTX_INPROC, // destination context is in-process/same host
NULL, // reserved, must be null
MSHLFLAGS_NORMAL // marshal once, unmarshal once
);
OleCheck(hr);
But it fails:
REGDB_E_IIDNOTREG (0x80040155)
Interface not registered
Use standard marshaling
My class is not using an interface IMarhsal
. This is correct and normal.
By default, when
CoMarshalInterface
first called on an object, the object asks if it wants to handle its own internetworking communications. This question comes in the form of a requestQueryInterface
for the interfaceIMarshal
. Most objects do not implement the interfaceIMarshal
and do not workQueryInterface
, indicating that they gladly let COM process all messages through ORPC calls. Objects that implement the InterfaceIMarshal
indicates that the ORPC is irrelevant and that the object developer would prefer to handle all internetworking through a custom proxy. When an object implements an interfaceIMarshal
, all references to the object will be customizable.When an object does not implement an interface
IMarshal
, all object references will be standard marshals. Most objects prefer to use standard marshaling.
So the question is, why does the standard COM marshaler have so many problems? What is the source of the error Interface not registered ?
The interface is essentially not registered
The requirements for COM are undocumented, but I can tell that my interface GUID is not in:
HKEY_CLASSES_ROOT\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4}
The reason for this will be explained at the end.
I know that Windows provides you with a function CoRegisterPSClsid
that allows you to register an interface within your process so that a standard marshaler can marshal it:
Allows the loaded DLL to register its user interfaces within its workflow so that marshaling code can marshal those interfaces.
HRESULT CoRegisterPSClsid( _In_ REFIID riid, _In_ REFCLSID rclsid );
Parameters:
-
riid
[in]: Pointer to the IID of the interface to register. -
rclsid
[in]: Pointer to the CLSID of the DLL that contains the proxy / stub code for the custom interface specified by riid.
Who can I try, but which clsid am I using?
CoRegisterPSClsid(IID_IWidget, ???);
What is the CLSID DLL that contains the proxy / stub code for the custom interface specified in riid? Am I using my own class?
CoRegisterPSClsid(IID_IWidget, CLSID_Widget);
It doesn't match the sound ; but I don't understand the standard COM marshaler well enough. Shouldn't this CLSID be one of the standard COM marsharing classes? implementation IPSFactoryBuffer
?
It won't work anyway. I am still getting the "Interface not registered" error.
Register interface
I can of course register my interface in the registry:
HKEY_CURRENT_USER\Software\Classes\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4}
(default) = "IWidget"
But that doesn't fix it. As I looked through the registry keys Interface
, I noticed that many were pointing to the ProxyStubClsid32 entry .
When a new interface is requested on an entity, the proxy and stub managers must resolve the requested IID on the CLSID of the interface marshaler. In Windows NT 5.0, the class store supports these mappings in NT, and they are cached on each host machine in the local registry. machine mappings IID-to-CLSID are cached in
HKEY_CLASSES_ROOT\Interface
and each user's mappings are cached in
HKEY_CURRENT_USER\Software\Classes\Interface
One or both of these keys will contain a subkey for each known interface. If the interface has an interface marshaler installed, an additional subkey (ProxyStubClsid32) will be added that specifies the CLSID of the interface packer.
Except which class implements marshaling? I don't have a marshal.
Can COM automatically marshal based on TypeLibrary
Is it possible that if I register a type library with my interface, this standard COM marshaler can load the proxy class on the fly?
I have registered my interface above. Now I manually enable TypeLibrary:
HKEY_CURRENT_USER\Software\Classes\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4}\TypeLib
(default) = "{38D528BD-4948-4F28-8E5E-141A51090580}"
And if I watch the registry during the call CoMarshalInterface
, I can see that it tries and finds my IID interface:
- Operation:
RegOpenKey
- Way:
HKCR\WOW6432Node\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4}
- Result:
SUCCESS
Then it tries to find ProxyStubClsid32 and fails:
- Operation:
RegOpenKey
- Way:
HKCR\WOW6432Node\Interface\{668790E3-83CC-47E0-907F-A44BA9A99C8D}\ProxyStubClsid32
- Result:
NAME NOT FOUND
My hope is that the standard COM marshaler will try to find:
- Operation:
RegOpenKey
- Way:
HKCR\WOW6432Node\Interface\{668790E3-83CC-47E0-907F-A44BA9A99C8D}\TypeLib
But this is not the case.
OLE Automation Router
According to Don Box, the Ole Automation marshaler (PSOAInterface - {00020424-0000-0000-C000-000000000046}) can create a stub / proxy from a type library:
Type library router
When these specially annotated interfaces meet RegisterTypeLib (or LoadTypeLib in legacy mode), COM adds
ProxyStubClsid32
entries for the value interface{00020424-0000-0000-C0000-000000000046}
. This GUID corresponds to the PSOAInterface class , which is registered as living in OLEAUT32.DLL, an OLE automation DLL. Because of the DLL it lives in, this marshaler is sometimes called a marshaller[oleautomation]
, although it is also called a library type marshaler or generic marshaler. I'll refer to it as the type library marshaller as it really has very little to do with IDispatch. (In fact, the attribute is commonly used[oleautomation]
on interfaces that are not directly or indirectly derived from IDispatch.)The factory class for the type library marshaler does something very complicated in its CreateProxy and CreateStub routines . Instead of returning a statically compiled vtable (which is not possible given the fact that the requested interface did not exist when OLEAUT32.DLL was built in as part of the OS), the type library marshaler actually creates an OICF style proxy and is based on a stub in type library for the interface. Since there is no efficient way to find
ITypeInfo
for an arbitrary interface, the LIBID and version of the interface type library must be stored in the folder:
HKCR\Interface\{XXX}\TypeLib
registry key.
I tried to set PSOAInterface
as my class the ProxyStub class:
-
Register the standard COM class PSOAInterface as our proxy clsid
HKEY_CURRENT_USER\Software\Classes\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4}\ProxyStubClsid32 (default) = "{00020424-0000-0000-C0000-000000000046}"
-
Register our type library for our interface
HKEY_CURRENT_USER\Software\Classes\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4}\TypeLib (default) = "{38D528BD-4948-4F28-8E5E-141A51090580}" Version = "1.0"
-
The type library itself is already registered:
HKEY_CURRENT_USER\Software\TypeLib\{38D528BD-4948-4F28-8E5E-141A51090580}\1.0\0\win32 (default) = "D:\Junk\ComLibraryProxyTest\Win32\Project1.dll"
But it still doesn't work.
- he reads
HKCR\Interface\[IID_IWidget]
- he reads
HKCR\Interface\[IID_IWidget]\ProxyStubClsid32
But this:
- never reads:
HKCR\Interface\[IID_IWidget]\TypeLib
Thus, it cannot proxy the object.
Questions
- Is it possible to for the standard COM "Ole Automation" marshaler to create a proxy class from a type library at runtime?
- Is it possible for me to create a proxy class from a type library at runtime?
Background
CoMarshalInterface
takes a pointer to input and writes a serialized representation of the pointer to the byte stream provided by the caller. This stream of bytes can then be transferred to another apartment where the
CoUnmarshalInterface
API function uses the stream of bytes to return an interface a pointer that is semantically equivalent to the original object can be legally available in the apartment that makes the CoUnmarshalInterface
call. When called, the CoMarshalInterface
caller should indicate how far the importer flat is expected to be. COM defines an enumeration for expressing this distance:
enum MSHCTX {
MSHCTX_INPROC = 4, // in-process/same host
MSHCTX_LOCAL = 0, // out-of-process/same host
MSHCTX_NOSHAREDMEM = 1, //16/32 bit/same host
MSHCTX_DIFFERENTMACHINE = 2, // off-host
};
It is legal to specify more distance than required, but it is more efficient to use the correct MSHCTX if possible. CoMarshalInterface
also allows the caller to specify marshaling semantics using the following marshal flags:
enum MSHLFLAGS {
MSHLFLAGS_NORMAL, // marshal once, unmarshal once
MSHLFLAGS_TABLESTRONG, // marshal once, unmarshal many
MSHLFLAGS_TABLEWEAK, // marshal once, unmarshal many
MSHLFlAGS_NOPING = 4 // suppress dist. garbage collection
Normal marshaling (sometimes called call marshaling) specifies that the reference to the marshaled object should only be unbound once, and if additional proxies are needed, additional calls are needed CoMarshalInterface
. The marshaling table indicates that a reference to a marshaled object can be unmarshaled zero or more times without requiring additional calls to CoMarshalInterface.
I think all COM object type libraries compiled with MIDL can create proxy / wub factory automatically. But in my case:
if the standard COM marshaler cannot find the proxy / stub factory for the interface, it returns a REGDB_E_IIDNOTREG error.
Perhaps I should either:
- use CreateProxyFromTypeInfo and CreateStubFromTypeInfo to create my own proxy.
- let the standard COM marshaler automatically create a proxy / stub if there is a typeinfo block associated with an interface GUID.
Reading bonuses
- Old New Thing: What are the rules for CoMarshalInterThreadInterfaceInStream and CoGetInterfaceAndReleaseStream?
- Old New Thing: Why am I getting a REGDB_E_IIDNOTREG error when I call a method that returns an interface?
- Old New Thing: Why am I getting E_NOINTERFACE when creating an object that supports this interface?
- Don Box - MSJ: Standard COM Sort ( archive )
- Mysterious Disappearing Activities with Samples from Microsoft's SDK
source to share
It CoMarshalInterface
requires an IMarshal
implementation (pointer) for the given interface, so the API can request marshall magic from it, and in particular, request IMarshal::GetUnmarshalClass
it to get information that is about to do the reverse magic later:
This method is called indirectly , when CoMarshalInterface is called by any code in the server process, it is responsible for marshaling the interface pointer on the object. This marshaling code is usually a stub generated by COM for one of several interfaces that can marshal a pointer to an interface implemented on a completely different object.
You don't have IMarshal
one implemented in your widget, so you can get it from somewhere.
As you start your question by noting that you want to "bind the interface to another thread" and the code comment "Create our widget", you can use IMarhsal
the free streaming marshaler implementation . The question does not provide information to determine if this is a possible and / or acceptable solution.
Going back to the task of getting a marshal, you try to solve this problem by using a "standard" marshaler by "registering an interface":
why the standard COM marshaler has so many problems
[...]
I can of course register my interface in the registry
Well, that's not how things work.
Registering an interface is not just a registry key that "well, this IID has its own key in the registry." The purpose of this registration is to indicate where to find the proxy / stub for that interface. Your guide to creating registry entries cannot help here unless you have a proxy / stub DLL for the interface in question. If you had this, you would just regsvr32 is the usual way to create registry keys.
A so called standard marshaler, your next attempt is not meant to marshal any interface and yours IWidget
in particular. OLE provides a so-called "PSOAInterface" marshaler that is capable of supplying proxy / stub pairs for OLE Automation-compliant interfaces. Just for them! The Marshal doesn't have many problems, in fact he only has one: yours is IWidget
unlikely to be compatible, or you won't have a problem in the first place.
If yours IWidget
was compatible, it had an associated type library where it was marked as [oleautomation]
, the type library registration process automatically generated registry keys that reference PSOAInterface and supply ProxyStubClsid32
. Then the marshaling API would pick a PSOAInterface for your widget, it would take a registered type library, load the interface details, then provide a standard proxy / stub pair for it and that's it. The standard marshaler only works within these contraindications, not just for whatever interface it points to.
That is, your options are:
- implement
IMarshal
widgets on the server - make
IWidget
OLE Automation is type library compatible, so the registration process for the type library activates the "standard marshaler" PSOAInterface for your interface. - build, if possible and applicable, a proxy / stub implementation for your interface auto-generated with MIDL-complier (you can check out the standard ATL DLL project generated from the Visual Studio template for how this can be done - it creates an additional project with using "PS", for an additional proxy DLL / stub)
- implement separately
IMarshal
in a standalone DLL and register it in the registry and your interfaceIWidget
so that the marshaling API picks it up when it tries to marshal the interface pointer (I suppose that's the only option here if yourIWidget
OLE is incompatible and you have reasons not to change the original implementation ) - use a free streaming marshaler on the widget server if its limitations are acceptable
Oh wait, hold on - there's another strange one. If you donโt want or cannot afford it, or you donโt want to change the COM server (widget that is), but you can change the client-side code as you see fit, you can create a thin wrapper that implements two interfaces IWidget
(all methods call forwarding to the real server) and IMarshal
on the client side, and pass it IWidget
to the APICoMarshalInterThreadInterfaceInStream
... This will force COM to use marshaling without changing the source server. You have to do the actual marshaling by yourself, of course. It is unlikely to fit your actual need, and this is just an abstract discussion note (which basically consists of trying to make it impossible without details about the interface itself and the options available when modifying the server implementation).
source to share
TL; DR: Current issues:
- Is it possible to for the standard COM "Ole Automation" marshaler to create a proxy class from a type library at runtime?
The short answer is yes.
- Is it possible for me to create a proxy class from a type library at runtime?
The short answer is yes, with the type library marshaller and IPSFactoryBuffer
. Or if you want to use undocumented CreateProxyFromTypeInfo
and CreateStubFromTypeInfo
.
I wonder why you need this.
This question is riddled with red herrings.
I am trying to merge an interface with another thread.
(...) call
CoMarshalThreadInterfaceInStream
fails:
REGDB_E_IIDNOTREG (0x80040155) Interface not registered
Helpful error code in this case.
Go directly to
CoMarshalInterface
(...) which fails:
REGDB_E_IIDNOTREG (0x80040155) Interface not registered
It's not by toggling API calls, which are essentially the same thing that you might solve your problem.
Use standard marshaling
My class doesn't implement the interface
IMarhsal
.
Can you confirm that he does not implement INoMarshal
, IStdMarshalInfo
and IAgileObject
to be exhaustive?
The interface is essentially not registered
Expected.
I know Windows provides you
CoRegisterPSClsid
(...)
I can try to call, but what can I use clsid ?
CoRegisterPSClsid(IID_IWidget, ???);
If you don't have a proxy / stub, why would you want to?
But to answer that question, the CLSID of standard marshalls usually matches the GUID as the first IDN found in the IDL file .
Register interface
I can of course register my interface in the registry:
HKEY_CURRENT_USER\Software\Classes\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4} (default) = "IWidget"
But that doesn't fix it. As I browse through the interface registry keys, I notice that many are pointing to the ProxyStubClsid32 entry .
You should read the documentation and not rely on what other registry entries contain.
(...) I don't have a marshal.
This must be a real problem. If this object is yours, how are you going to marshal it? Please see the bottom of my answer.
Can COM automatically marshal based on TypeLibrary
This is clearly rhetoric. Why are you thinking about a type library now and not to start with? The rest of your question confirms.
Now I manually enable TypeLibrary:
HKEY_CURRENT_USER\Software\Classes\Interface\{EBBC7C04-315E-11D2-B62F-006097DF5BD4}\TypeLib (default) = "{38D528BD-4948-4F28-8E5E-141A51090580}"
You mentioned it twice.
But this:
- never reads: HKCR \ Interface [IID_IWidget] \ TypeLib
The type library router has its own interface-> type library cache. To clear the cache, try re-creating the registry entries, logging out and logging back in, or eventually rebooting.
The object can implement IProvideClassInfo
, I don't know if the type library marshaler is actually referring to QueryInterface
for this, select a workspace ITypeInfo
to work with.
These are the main types of marshals:
-
Standard marshalers, which are usually compiled into DLLs from the C / C ++ source code generated by the MIDL (which consists mainly of declarations on how to sort the types)
-
A type library router that can marshal types at runtime based on automation-compatible type information
-
Free stream router combined with
CoCreateFreeThreadedMarshaler
that avoids marshaling between streams within the same process -
Custom marshalls that do whatever the developer wants will most often implement marshall by value or arbitrary marshaler back when
CoCreateFreeThreadedMarshaler
doesn't exist
The standard marshalers created by the MIDL consist mainly of declarations on how to marshal types to and from, so the way they work is in the same vein as the type library marshaler. According to Don Box, the result is very similar.
However, the actual declarations are very different. The type library marshaler works with type information that is designed to work in VB6 and (excluding certain types such as custom types) scripting languages โโ(mainly VBScript and JScript) and is intended for use by IDEs (such as VB6, VBA, Delphi, OleView) and interoperability code generators (eg VC ++ #import
, tlbimp.exe, Delphi "Import Type Library", Lisp 1 2 ), etc.
source to share