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 request QueryInterface

for the interface IMarshal

. Most objects do not implement the interface IMarshal

and do not work QueryInterface

, indicating that they gladly let COM process all messages through ORPC calls. Objects that implement the Interface IMarshal

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 interface IMarshal

, 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

+3


source to share


2 answers


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 interface IWidget

    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 your IWidget

    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).

+2


source


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.

0


source







All Articles