none
CoCreateInstance returns E_NOINTERFACE even when server returns the requested interface

    Question

  • I've developed a simple out-of-process COM server. The class factory calls CoRegisterClassObject() with the desired CLSID that I've registered by hand in HKCR\CLSID\{uuid}\LocalServer32. The server implements a custom interface defined as follows in IDL:

    import "oaidl.idl";
    import "ocidl.idl";
    
    [
    	object,
    	uuid(7EB835D6-A196-46cf-BD36-8FE6ED80FAA8),		
    	helpstring("IMyInterface Interface"),
    	pointer_default(unique)
    ]
    	interface IMyInterface : IUnknown
    	{
    		[helpstring("method HandleUrl")] HRESULT HandleUrl([in] BSTR clientName);
    	};
    
    [
    	uuid(03A6E334-AD67-4a3b-B9C6-49D3E1D5CDF7),
    	version(1.0),
    	helpstring("MyInterface 1.0 Type Library")
    ]
    	library MYINTERFACELib
    	{
    		importlib("stdole32.tlb");
    		importlib("stdole2.tlb");
    
    		[
    			uuid(67EA71C8-7F31-4f52-8AC5-D1C8381255C7),
    			helpstring("MyInterface Class")
    		]
    		coclass LbProtocolHandler
    		{
    			[default] interface IMyInterface;
    		};
    	};

    When calling CoCreateInstance() , the class factory's CreateInstance() method is called and it correctly calls QueryInterface() on the implemented interface. The QueryInterface() method looks like this:

    static const QITAB qit[] =
    {
    	QITABENT(MyInterfaceImpl, IMyInterface),
    	{ 0 },
    };
    
    return QISearch(this, qit, riid, ppv);
    I've also tried to manually compare the incoming riid by using InlineIsEqualGUID() and the method does indeed return the this pointer when asked for the IMyInterface interface.

    However, when CoCreateInstance() returns the error code is E_NOINTERFACE . I've tried manually setting the ThreadingModel key under the CLSID registry key to Apartment, but no difference.

    It's worth pointing out that the server code works fine with the IDropTarget . It's only my custom interface that doesn't seem to work.
    Thursday, March 18, 2010 8:03 PM

All replies

  • Hello Soren Dreijer,

    1. Have you created and registered a Proxy/Stub DLL for your IMyInterface interface ?

    2. You can check this quickly by using regedit.exe to look up the following registry entry :

    HKEY_CLASSES_ROOT\Interface\{7EB835D6-A196-46cf-BD36-8FE6ED80FAA8}

    Notice that I used the same IID for IMyInterface as specified in your IDL specification above.

    3. If this registry entry does not exist, it is likely that either the proxy/stub dll has not been registered or that it has not been created yet.

    4. A proxy/stub DLL may be necessary when an interface is a custom interface (usually derived from IUnknown viz IDispatch). A custom interface requires custom marshaling in order for a client application to access the object behind an interface (e.g. the IMyInterface object). Custom marshaling will require the presence of a custom proxy/stub DLL.

    - Bio.

     

    • Edited by Lim Bio Liong Friday, March 19, 2010 6:23 AM Simplified point 4.
    Friday, March 19, 2010 6:09 AM
  • Oh,I see. No, I have not registered a proxy or stub DLL. I was going through this blog post which talks about embedding the TLB in the exe and then registering it at startup, and I sort of thought that would have the same effect as registering a stub DLL.

    What kind of "custom marshaling" are we talking about here? Why is my interface so special compared to, say, the IDropTarget interface?

    Thanks!

    Friday, March 19, 2010 2:00 PM
  • Hello Soren Dreijer,

    1. The TLB file will be of no help when it comes to custom interfaces.

    2. To put things simply, where a COM object is accessed across threads (be it threads of a single process or threads across processes), marshalling may be involved.

    3. Since your COM object resides in an EXE Server, marshalling will be required because your client (a separate EXE by itself) is actually accessing your COM object which resides in a separate process.

    3.1 It is only a question of whether custom or standard COM marshaling will be used.

    4. Why is custom marshaling involved in your case ? Because of the following :

    4.1 IMyInterface is declared as being derived from IUnknown. The IDropTarget is also derived from IUnknown but its registry entry indicates that it uses the proxy/stub provided by ole32.dll.

    4.2 IMyInterface is not declared as being ole-automation-compatible (this requires the "oleautomation" attribute for your interface).

    5. The alternative to custom marshaling would be standard COM (or Type Library) marshaling.

    5.1 This is provided that your interface has been assigned the [dual] or the [oleautomation] attribute.

    5.2 The standard COM marshaler is oleaut32.dll (the standard Proxy/Stub DLL for Ole Automation).

    5.3 In this case, you do not have to build any Proxy/Stub DLL in order for your clients to use your interface.

    6. I have written some notes on proxy/stubs "Concerning Proxy/Stub DLLs" in my code project member site. Please have a look :

    http://www.codeproject.com/Members/Lim-Bio-Liong?msg=1413206#xx1413206xx


    7. Actually, before going into how to build a proxy/stub DLL for IMyInterface, you can perform the following experiment :

    7.1 In the declaration for IMyInterface, add the "oleautomation" atttibute, e.g. :

    [
    object,
    uuid(7EB835D6-A196-46cf-BD36-8FE6ED80FAA8),

    oleautomation,

     helpstring("IMyInterface Interface"),
    pointer_default(unique)
    ]
    interface IMyInterface : IUnknown
    {
    [helpstring("method HandleUrl")] HRESULT HandleUrl([in] BSTR clientName);
    };

    7.2 This is possible because the methods of IMyInterface uses only ole-automation compatible types : BSTR. If IMyInterface uses some other types (e.g. custom structures), then v likely the IDL will not compile (the "oleautomation" attribute would present a problem).

    7.3 Please give this a try. Thereafter, re-register your COM EXE server and recompile your client and see if you are able to instantiate a IMyInterface object.

    - Bio.

     

    Friday, March 19, 2010 3:37 PM
  • Hi Bio,

    Thanks for the very elaborate description. After your first reply, I went spelunking and read up on proxy/stub DLLs and succeeded in instantiating my custom COM object and calling a method on it.

    However, seeing as I'm only using very basic types here, I'm still very interested in using the standard COM marshaler. I therefore went ahead and added the "oleautomation" attribute to the IDL file and recompiled the binaries. Unfortunately, I still get an E_NOINTERFACE error when attempting to instantiate my custom object. Do I need to specify something in the registry for my COM object to indicate that it uses the standard COM marshaler?

    Thanks!

    Friday, March 19, 2010 11:33 PM
  • Hello Soren,

    1. Let's confirm that the addition of the "oleautomation" attribute has made the required difference. Please perform the folllowing :

    1.1 In the registry, look up the following entry :

    HKEY_CLASSES_ROOT\Interface\{7EB835D6-A196-46cf-BD36-8FE6ED80FAA8}

    {7EB835D6-A196-46cf-BD36-8FE6ED80FAA8} being the IID of IMyInterface.

    1.2 Confirm that there is a subfolder named "ProxyStubClsid32" :

    HKEY_CLASSES_ROOT\Interface\{7EB835D6-A196-46cf-BD36-8FE6ED80FAA8}\ProxyStubClsid32

    1.3 Confirm that the string value for this subfolder is : {00020424-0000-0000-C000-000000000046}.

    This is the CLSID for the standard COM marshaler is oleaut32.dll (the standard Proxy/Stub DLL for Ole Automation).

    1.4 Confirm also that there is a subfolder named "TypeLib" :

    HKEY_CLASSES_ROOT\Interface\{7EB835D6-A196-46cf-BD36-8FE6ED80FAA8}\TypeLib

    and the string value for this is : {03A6E334-AD67-4a3b-B9C6-49D3E1D5CDF7}.

    This is the LIBID of your Type Library which is indicated in your IDL File. The standard COM Marshaling will require the Type Library.

    2. The above registry entries will indicate that standard COM marshaling is to be used for IMyInterface.

    - Bio.

     

    Saturday, March 20, 2010 1:21 AM
  • Bio,

    No registry key with the value {7EB835D6-A196-46cf-BD36-8FE6ED80FAA8} exists. Should this have been created automatically when my server registers itself with the 'oleautomation' interface? If not, do I need to do this manually?

    Thanks,

    Soren

    Saturday, March 20, 2010 1:29 AM
  • Hello Soren,

    1. >> Should this have been created automatically when my server registers itself with the 'oleautomation' interface?

    1.1 Yes, it should have been written automatically during the registration process.

    1.2 Are you using Visual Studio ? If so, which version are you using ?

    2. Please perform the following :

    2.1 Register the EXE COM Server. Then check to see if the registry entries discussed previously have indeed been created.

    2.2 If all went well with the registry, re-compile the client application. Then run the client again to see if the CoCreateInstance() succeeds.

    - Bio.

     

     

     

    Saturday, March 20, 2010 1:44 AM
  • I've already tried running the COM server and it does indeed register itself but no registry keys show up.

    Previously, I created the CLSID key for the server manually, which seems to work fine (it's the same code I've used in the past). Maybe that's the problem? I call CoRegisterClassObject() with CLSCTX_LOCAL_SERVER and REGCLS_MULTIPLEUSE .

    If I call CoCreateInstance() from the client, I do see the server getting called, but it obviously fails because marshaling hasn't been set up.

    I'm using Visual Studio 2008 SP1 with Administrator privileges on a Windows 7 box.

    Saturday, March 20, 2010 1:49 AM
  • Hello Soren

    1. >> I've already tried running the COM server and it does indeed register itself but no registry keys show up.

    1.1 Ah, I think there is a misunderstanding of the term "registration" here.

    1.2 What needs to be done now is the registration of the COM Server EXE to the registry. This is done in a command prompt with the following command :

    <COM Server exe filename> /RegServer

    e.g. :

    MyInterface.exe /RegServer

    1.3 The CoRegisterClassObject() API is required at runtime to register a COM class with the COM runtime subsystem so that clients will be able to instantiate it.

    1.4 Please perform the registry registration and try again.

    - Bio.

     

    Saturday, March 20, 2010 2:00 AM
  • So, this is my own exe (obviously), and therefore the /RegServer flag won't have any effect unless I implement it :) Can I leverage any of the code in the auto-generated MIDL files, or do I have to write to the registry manually?
    Saturday, March 20, 2010 2:13 AM
  • Hello Soren,

    1. >> So, this is my own exe (obviously), and therefore the /RegServer flag won't have any effect unless I implement it :)

    1.1 Did you write the entire server code manually without the help of ATL ?

    1.2 If so, you will have to also manually write the code to perform the registry writing.

    1.3 This is a very tedious task.

    2. I'll do some digging in my hard disk and see if I have any old code that performs this.

    3. If you are interested, I can email these to you (source codes) [if I can find them :-)]. My email address is : bio_lim_2004@yahoo.com

    - Bio.

     

    Saturday, March 20, 2010 2:20 AM
  • Yes, the server code is done without ATL at all. I'll send you an e-mail.
    Saturday, March 20, 2010 2:23 AM
  • Oh, and by the way, I added the HKEY_CLASSES_ROOT\Interface\{7EB835D6-A196-46cf-BD36-8FE6ED80FAA8 }keys you mentioned above by hand for testing purposes, and now CoCreateInstance() returns E_FAIL .
    Saturday, March 20, 2010 2:52 AM
  • Hi Bio,

    I am also stuck in an exactly similar scenario. Would it be possible for you to also email the code that you referred to above.

    The only difference in my problem is that I am writing a DLL, which will host a COM server in a specific process. And all the clients will communicate through it via out-of-proc communication.

    I have explored a lot on the web, but could not get any relevant pointers.

    It would be great if you could help me with this.

    Thanks


    Parul Gupta


    It would be great if you could help me with this.
    It would be great if you could help me with this.
    It would be great if you could help me with this.
    • Edited by Ninja8 Monday, April 21, 2014 5:15 PM
    Monday, April 21, 2014 4:33 PM
  • Hello Parul,

    >> The only difference in my problem is that I am writing a DLL, which will host a COM server in a specific process. And all the clients will communicate through it via out-of-proc communication.

    Pls describe this out-of-proc communication.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Tuesday, April 22, 2014 5:05 AM
  • Hi Bio,

    I am writing an ATL COM DLL, where I am writing a COM out-of-proc server. The problem is that I am getting a "Class not registered" error when doing a CoCreateInstance for this object from my win32 application. 

    The problem seems to be because I am not able to register my Proxy/Stub DLL. I am pasting the code in my IDL file below: 

    import "oaidl.idl";
    import "ocidl.idl";
    
    [
    	uuid(731023BB-1EED-450E-B359-C67720BB144B),
    	version(1.0),
    	helpstring("LocalServer 1.0 Type Library")
    ]
    library LocalServerLib
    
    {
    	importlib("stdole32.tlb");
    	importlib("stdole2.tlb");
    
    	//
    	// Interfaces
    	//
    
    	// ILocalServer interface
    	[
    		object,
    		uuid(ECF0CAC2-897D-4DCF-97EA-916BF045AE63),
    		helpstring("ILocalServer Interface"),
    		pointer_default(unique),
    		oleautomation
    	]
    	interface ILocalServer : IUnknown
    	{
    		[id (1)]
    		HRESULT InvokeLocalServerMessageBox();
    	};
    	
    	[
    		uuid(96FF78C5-1AF0-47C9-9D14-A6D5973B17B7),
    		helpstring("LocalServer Class")
    	]
    	coclass LocalServer
    	{
    		[default] interface ILocalServer;
    	};
    
    };
    

    In VS 2010 Project properties, I have set the following paths:

    Configuration Properties->  MIDL -> Output ->Header File  to LocalServer_i.h

    Configuration Properties->  MIDL -> Output ->DLLData File to dlldata.c

    Configuration Properties->  MIDL -> Output ->IID File to LocalServer_i.c

    Configuration Properties->  MIDL -> Output ->Proxy File to LocalServer_p.c

    Also I have set the setting

    Configuration Properties->  MIDL -> General -> Generate Stubless Proxies to Yes (/Oicf).

    But even then compiling the ILD file is not creating dlldata.c and LocalServer_p.c file. 

    Please suggest.


    Parul Gupta

    Tuesday, April 22, 2014 6:15 AM
  • Hello Parul,

    >> I am writing an ATL COM DLL, where I am writing a COM out-of-proc server...

    * A COM DLL and a COM out-of-proc server (an EXE) are 2 different things.

    * Which one are you building ?

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Tuesday, April 22, 2014 7:00 AM
  • Hi Bio,

    I have created a Win32 DLL Project which uses ATL. In this DLL, I have a COM class which extends as:

    class ATL_NO_VTABLE CLocalServer :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CLocalServer, &CLSID_LocalServer>,
    public IDispatchImpl<ILocalServer, &IID_ILocalServer, &LIBID_LocalServerLib, /*wMajor =*/ 1, /*wMinor =*/ 0>

    {

    }

    >> Which one are you building ?

    I am currently building this DLL.

    The code flow I need is stated below:

    This DLL will be loaded in a process, say ServerProcess.exe. From my client process, say ClientProcess.exe, I would create an instance of this COM component using CLSCTX_LOCAL_SERVER in CoCreateInstance and then call methods exposed by this COM component with this instance from ClientProcess.exe.

    For the time being, I will be adding the DllSurrogate key for this COM class, which will host this COM server component in dllhost.exe.




    Parul Gupta

    Tuesday, April 22, 2014 7:54 AM
  • My registration script for this is :

    HKCR
    {
        COMLocServerDLL.LocalServer = s 'LocalServer Class'
        {
            CLSID = s '{96FF78C5-1AF0-47C9-9D14-A6D5973B17B7}'
        }
    
    	NoRemove CLSID
        {
            ForceRemove {96FF78C5-1AF0-47C9-9D14-A6D5973B17B7} = s 'LocalServer Class'
            {
    			val AppID = s '{96FF78C5-1AF0-47C9-9D14-A6D5973B17B7}'
    			ProgID = s 'COMLocServerDLL.LocalServer'
    			VersionIndependentProgID = s 'COMLocServerDLL.LocalServer'
                InProcServer32 = s '%MODULE%'
                {
                    val ThreadingModel = s 'Apartment'
                }
                TypeLib = s '{731023BB-1EED-450E-B359-C67720BB144B}'
            }
        }
    
    		
    	NoRemove AppID
    	{
    		val AppID = s '{96FF78C5-1AF0-47C9-9D14-A6D5973B17B7}'
    		ForceRemove {}
    		{
    			val DLLSurrogate = s ''
    		}
    	}
    
    }


    Parul Gupta

    Tuesday, April 22, 2014 8:14 AM
  • Hi Bio

    I have figured this out. I need to write the interface definition outside the library definition in order to get the compiled proxy and stub files.

    Thanks.


    Parul Gupta

    Tuesday, April 22, 2014 9:19 AM
  • Hello Parul,

    1. Congratulations and thanks for explaining about your use of dllhost.exe as a surrogate process for your COM DLL.

    2.>> I have figured this out. I need to write the interface definition outside the library definition in order to get the compiled proxy and stub files.

    2.1 Yes, if you want to create the proxy/stub source codes, you need to declare the interface (e.g. ILocalServer) outside the "library" definition in the IDL file.

    2.2 But actually, in the case of ILocalServer, it is still possible to do without any proxy/stub DLL. This is because it has been declared with the "oleautomation" attribute.

    2.3 At runtime, the standard marshaler is still able to perform parameter marshaling as long as all parameter types are automation-compatible.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/


    • Edited by Lim Bio Liong Tuesday, April 22, 2014 5:02 PM Corrected point 2.3 : I realized that if ILocalServer is defined outside of the "library" block then no type lib information will be generated for it.
    Tuesday, April 22, 2014 10:44 AM
  • Hi Bio, 

    Thanks for the information. 

    This landed me to this new problem. Earlier, my DllRegisterServer was working absolutely fine. But now regsvr32 is throwing error "The module was found but the entry point DllRegisterServer was not found." 

    I am pasting below the code for my DllRegisterServer:

    STDAPI DllRegisterServer(void)
    {
    	MessageBox(0, L"LocalCOMServerDLL", L"DllRegisterServer", 1);
    
    	// registers object, typelib and all interfaces in typelib
        HRESULT hr = _Module.DllRegisterServer();
    #ifdef _MERGE_PROXYSTUB
        if (FAILED(hr))
            return hr;
        hr = PrxDllRegisterServer();
    #endif
    	return hr;
    }
    

    And the class dlldatax.h has the following:

    #pragma once
    
    #ifdef _MERGE_PROXYSTUB
    
    extern "C" 
    {
    BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, 
    	LPVOID lpReserved);
    STDAPI PrxDllCanUnloadNow(void);
    STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
    STDAPI PrxDllRegisterServer(void);
    STDAPI PrxDllUnregisterServer(void);
    }
    
    #endif

    In dlldatax.c, I have

    #define REGISTER_PROXY_DLL //DllRegisterServer, etc.
    
    #define _WIN32_WINNT 0x0500	//for WinNT 4.0 or Win95 with DCOM
    #define USE_STUBLESS_PROXY	//defined only with MIDL switch /Oicf
    
    #pragma comment(lib, "rpcns4.lib")
    #pragma comment(lib, "rpcrt4.lib")
    
    #define ENTRY_PREFIX	Prx
    
    // Theses files are generated differently and at different locations for different configurations, 
    // so including them here instead of directly in the project.
    #include "dlldata.c"
    #include "LocalServer_i.c"
    #include "LocalServer_p.c"
    

    Would you be able to help with this?


    Parul Gupta

    Tuesday, April 22, 2014 5:39 PM
  • Hello Parul,

    Did the message box (as coded at the beginning of DllRegisterServer()) appear ?

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Wednesday, April 23, 2014 4:05 AM
  • No, it is not able to find the entry point to DllRegisterServer. I opened my DLL with depends and even it is not showing any functions in the exported functions list.


    Parul Gupta

    Wednesday, April 23, 2014 4:07 AM
  • Hello Parul,

    1. Pls check your .DEF file (there should be one in your project).

    2. It should contain the following :

    	DllCanUnloadNow		PRIVATE
    	DllGetClassObject	PRIVATE
    	DllRegisterServer	PRIVATE
    	DllUnregisterServer	PRIVATE
    	DllInstall		PRIVATE
    
    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Wednesday, April 23, 2014 4:23 AM
  • Yes, the DEF file also has these entries. I never removed these.

    Parul Gupta

    Wednesday, April 23, 2014 4:55 AM
  • Hello Parul,

    >> Yes, the DEF file also has these entries. I never removed these.

    This is strange. You would have encountered a linker error indicating that these exported functions could not be found if they are not defined or they have been obscured by various #if conditionals.

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Wednesday, April 23, 2014 5:41 AM
  • Hello Parul,

    1. Have you tried to re-compile your project ?

    2. As you know, the VS environment would automatically register your output DLL at the end of a re-build. How did this go ? Any errors ?

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Wednesday, April 23, 2014 5:56 AM
  • Yes, I have tried that too.

    Parul Gupta

    Wednesday, April 23, 2014 10:38 AM
  • Hello Parul,

    >> Yes, I have tried that too.

    And was the re-build successful ?

    - Bio.


    Please visit my blog : http://limbioliong.wordpress.com/

    Wednesday, April 23, 2014 11:31 AM