none
CreateInstance failing with Error 2147221164 in COM Interop RRS feed

  • Question

  • Hi

    I am trying to write a COM Interface to a C# managed code.

    Here is the C# code.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Runtime.InteropServices;
    using OZS.Wizard.Util;
    
    namespace OZSInteropUtils
    {
      public struct inputSigningParam
      {
        public int i;
      };
      public struct inputKSKParam
      {
        public int i;
      };
      public struct inputZSKParam
      {
        public int i;
      };
    
      [ComVisible(true)]
      [Guid("9F2B4F45-35A2-43C3-882B-6D166A75CFFA")]
      public interface OZSComInterface
      {
        bool SimpleSigningTestCallerInterop(inputSigningParam inpsigning, inputKSKParam inpksk, inputZSKParam inpzsk);
      }
      [ComVisible(true)]
      [ClassInterface(ClassInterfaceType.None)]
      [Guid("0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F")]
      public class OZSInteropUtilClass : OZSComInterface
      {
        public OZSInteropUtilClass()
        {
          System.Console.WriteLine("Constructor Called");
        }
        public bool SimpleSigningTestCallerInterop(inputSigningParam inpsigning, inputKSKParam inpksk, inputZSKParam inpzsk)
        {
          System.Console.WriteLine(inpsigning.i);
          System.Console.WriteLine(inpksk.i);
          System.Console.WriteLine(inpzsk.i);
          System.Console.WriteLine("Call Success");
          return true;
        }  
      }
    }
    

    I created a DLL out of the above code. Then used REGASM.EXE to create a TLB file.

    Then I am using the following code on the client side.

    #include "stdafx.h"
    #include <iostream>
    #import "OZSInteropUtils.tlb" named_guids raw_interfaces_only
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	CoInitialize(NULL);
    	OZSInteropUtils::inputKSKParam inpksk;
    	OZSInteropUtils::inputSigningParam inpsigning;
    	OZSInteropUtils::inputZSKParam inpzsk;
    	OZSInteropUtils::OZSComInterfacePtr pOZSComInterfacePtr;
    	inpksk.i = 1;
    	inpzsk.i = 2;
    	inpsigning.i = 3;
    	VARIANT_BOOL result = 0;
    	HRESULT hRes = pOZSComInterfacePtr.CreateInstance(OZSInteropUtils::CLSID_OZSInteropUtilClass);
    	if (hRes == S_OK)
    	{
    		pOZSComInterfacePtr->SimpleSigningTestCallerInterop(inpsigning,inpksk,inpzsk, &result);
    		std::cout << "Success" << std::endl;
    	}
    	else
    	{
    		std::cout << hRes << std::endl;
    		std::cout << "Fail" << std::endl;
    	}
    	CoUninitialize ();  
    	return 0;
    }
    

    Now, when I compile and run this program, I get the following error:

    -2147221164

    Fail

     

    On searching the forums, I noticed that this error corresponds to CLASS NOT REGISTERED. However, I am unable to figure out how to get rid of it.

    Any help / pointers are appreciated.

     

    Thanks

    Sameer


    Thanks Sameer
    Friday, June 10, 2011 4:57 PM

Answers

  • Hello Sameer,


    1. 64-bit Target Platform.

    1.1 From the description of your last post, it looks likely that you are using a 64-bit OS (likely Windows 7), hence the presence of "Wow6432Node" registry sub-paths.

    1.2 In this case, the project settings for your Class Library may have been set to target the 64-bit platform.

    1.3 If 64-bit is indeed your target platform then you must ensure that the C++ client is also targetted for 64-bits.

    1.4 If you are still targetting the 32-bit platform, then see section 2 below.


    2. 32-bit Target Platform.

    2.1 This section applies only if you are targetting the 32-bit subsystem inside a 64-bit OS.

    2.2 First manually unregister the current type library. Do this by using the command prompt, navigating to the relevant folder where OZSInteropUtils.dll resides and then executing the following command :

    regasm OZSInteropUtils.dll /unregister

    2.3 Next, go to the class library's Project Settings, "Build" Section.

    2.4 At the combo box labelled "Platform target", make sure you select the "x86" option. Do not select "Any CPU" because this means : target the 64-bit platform.

    2.5 Run regasm.exe again at the command prompt. This time, you may need to ensure that the 32-bit version of REGASM.EXE is used. The 32-bit REGASM.EXE should be found in the following path :

    C:\windows\microsoft.net\Framework\v2.0.50727\regasm.exe

    Hence run this version of REGASM.EXE :

    C:\windows\microsoft.net\Framework\v2.0.50727\regasm.exe OZSInteropUtils.dll /tlb /codebase

    If the compiler does not make any complaints, you may also use the "Register for COM interop" checkbox (it will perform the same thing as REGASM.EXE with the /tlb and /codebase flags).

    2.6 This time, the registry setting which is relevant will be :

    [HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocServer32]
    @="mscoree.dll"
    "ThreadingModel"="Both"
    "Class"="OZSInteropUtils.OZSInteropUtilClass"
    "Assembly"="OZSInteropUtils, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    "RuntimeVersion"="v2.0.50727"
    "CodeBase"="<path>/OZSInteropUtils.DLL"

    Note the additional "Wow6432Node" registry sub-path.

    2.7 Your C++ client should run properly as long as it is targetted for 32-bits.


    - Bio.

     

    • Marked as answer by Sameer_ Monday, June 13, 2011 12:05 PM
    Sunday, June 12, 2011 2:26 PM

All replies

  • SysInternals' ProcMon tool works pretty well in tracing inproc COM creation. Just set a breakpoint on CreateInstance, start the program in debugger, start procmon, pause logging, clear logs, then resume logging, switch to your debugger and execute the CreateInstance statement, switch to procmon, pause logging, then look at file and registray access made by the program during the creation of the COM project.



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP
    Friday, June 10, 2011 5:16 PM
  • Hello Sameer,

     

    1. Concerning the CLASS NOT REGISTERED Error.

    >> On searching the forums, I noticed that this error corresponds to CLASS NOT REGISTERED. However, I am unable to figure out how to get rid of it.

    1.1 This error occurs when the CLR is not able to locate the assembly that contains the managed class to be instantiated as a COM object.

    1.2 Note that using REGASM.EXE to register your assembly to the COM subsystem is necessary but may not be completely sufficient.

    1.3 REGASM.EXE will write the following information to the registry :

    [HKEY_CLASSES_ROOT\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocServer32]
    @="mscoree.dll"
    "ThreadingModel"="Both"
    "Class"="OZSInteropUtils.OZSInteropUtilClass"
    "Assembly"="OZSInteropUtils, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    "RuntimeVersion"="v2.0.50727"

    Note that I have asseumed that your assembly is compiled into OZSInteropUtils.dll and with the version, culture and PublicKeyToken values as indicated above.

    1.4 With the registry information as set above, the in-proc server that is loaded for the COM coclass 0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F is actually mscoree.dll - the .NET runtime.

    1.5 The runtime will then search for and load the assembly that contains the managed class as indicated in the "Class" string value : "OZSInteropUtils.OZSInteropUtilClass". The location of this assembly is indicated in the "Assembly" string value : "OZSInteropUtils, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null".

    1.6 Note that with just the name of the assembly provided : "OZSInteropUtils", the runtime uses the usual assembly search process to locate the required assembly (see section 2 below).

    1.7 In your case, it is obvious that the CLR is not able to locate the required assembly, i.e. OZSInteropUtils.dll. Hence the rather misleading CLASS NOT REGISTERED error.

     

    2. Solutions.

    2.1 You need to be familiar with this assembly search process. Refer to "How the Runtime Locates Assemblies" (http://msdn.microsoft.com/en-us/library/yx7xezcf(v=vs.71).aspx).

    2.2 The way an assembly is registered, whether it is strong named, whether it is registered to the GAC, and many other factors, all affect how assemblies are loaded.

    2.3 For a quick solution, and to make things quickly clear to you, you may perform the following :

    2.3.1 If you have manually performed the REGASM.EXE call, add the /codebase flag to your call, e.g. :

    regasm .\bin\debug\OZSInteropUtils.dll /tlb /codebase

    This will add a "CodeBase" string value to the registry information for the 0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F coclass :

    [HKEY_CLASSES_ROOT\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocServer32]
    @="mscoree.dll"
    "ThreadingModel"="Both"
    "Class"="OZSInteropUtils.OZSInteropUtilClass"
    "Assembly"="OZSInteropUtils, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    "RuntimeVersion"="v2.0.50727"
    "CodeBase"="<path>/OZSInteropUtils.DLL"

    This is useful information for the CLR. It will indicate the exact path to the required assembly.

    2.3.2 You may also achieve the same effect by selecting the "Register for COM interop" checkbox in the "Build" section of the project properties of the Class Library.

    However, note that adding the "CodeBase" registry string is considered a temporary solution used as part of development. This should not be part of long term deployment.

    2.4 Another quick solution is to copy the assembly to the same folder as the C++ client exe.

    2.5 For longer term deployment purposes, you may want to strong name the assembly and register it into the GAC.

     

    - Bio.

     


    Saturday, June 11, 2011 12:05 PM
  • Hi Sheng & Lim

    Thanks a lot for the tips. I tried what you suggested.

    I saw NAME NOT FOUND errors for the keys below from the Procmon logs.

    HKCU\Software\Classes\Wow6432Node\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}
    HKCR\Wow6432Node\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\TreatAs
    HKCR\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\TreatAs
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\Progid
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\ProgId
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\Progid
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\ProgId
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocHandler32
    HKCR\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocHandler32
    HKCU\Software\Classes\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocHandler
    HKCR\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocHandler
    HKCU\Software\Classes\Wow6432Node\Interface\{00000134-0000-0000-C000-000000000046}\ProxyStubClsid32
    HKCU\Software\Classes\Wow6432Node\Interface\{00000134-0000-0000-C000-000000000046}\ProxyStubClsid32
    

    There were other registry access under HKCR\CLSID\<GUID> which all went fine. All the keys that Lim mentioned were present here. I also tried using REGASM with the /codebase option and putting the assembly in the same folder. Also tried gacutil /i OZSInterop.dll to put it in the global assembly cache.

    When I tried to look @ HKCU\Software\Classes\CLSID\, there was nothing there. Am I missing something which I should have done?

     

    Thanks

    Sameer


    Thanks Sameer
    Sunday, June 12, 2011 1:17 PM
  • Hello Sameer,


    1. 64-bit Target Platform.

    1.1 From the description of your last post, it looks likely that you are using a 64-bit OS (likely Windows 7), hence the presence of "Wow6432Node" registry sub-paths.

    1.2 In this case, the project settings for your Class Library may have been set to target the 64-bit platform.

    1.3 If 64-bit is indeed your target platform then you must ensure that the C++ client is also targetted for 64-bits.

    1.4 If you are still targetting the 32-bit platform, then see section 2 below.


    2. 32-bit Target Platform.

    2.1 This section applies only if you are targetting the 32-bit subsystem inside a 64-bit OS.

    2.2 First manually unregister the current type library. Do this by using the command prompt, navigating to the relevant folder where OZSInteropUtils.dll resides and then executing the following command :

    regasm OZSInteropUtils.dll /unregister

    2.3 Next, go to the class library's Project Settings, "Build" Section.

    2.4 At the combo box labelled "Platform target", make sure you select the "x86" option. Do not select "Any CPU" because this means : target the 64-bit platform.

    2.5 Run regasm.exe again at the command prompt. This time, you may need to ensure that the 32-bit version of REGASM.EXE is used. The 32-bit REGASM.EXE should be found in the following path :

    C:\windows\microsoft.net\Framework\v2.0.50727\regasm.exe

    Hence run this version of REGASM.EXE :

    C:\windows\microsoft.net\Framework\v2.0.50727\regasm.exe OZSInteropUtils.dll /tlb /codebase

    If the compiler does not make any complaints, you may also use the "Register for COM interop" checkbox (it will perform the same thing as REGASM.EXE with the /tlb and /codebase flags).

    2.6 This time, the registry setting which is relevant will be :

    [HKEY_CLASSES_ROOT\Wow6432Node\CLSID\{0B9EA7E9-E6A3-49E8-8BCD-D542BB4E393F}\InprocServer32]
    @="mscoree.dll"
    "ThreadingModel"="Both"
    "Class"="OZSInteropUtils.OZSInteropUtilClass"
    "Assembly"="OZSInteropUtils, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
    "RuntimeVersion"="v2.0.50727"
    "CodeBase"="<path>/OZSInteropUtils.DLL"

    Note the additional "Wow6432Node" registry sub-path.

    2.7 Your C++ client should run properly as long as it is targetted for 32-bits.


    - Bio.

     

    • Marked as answer by Sameer_ Monday, June 13, 2011 12:05 PM
    Sunday, June 12, 2011 2:26 PM
  • Hi Bio

    Thanks a lot.

    The client side I was trying to write was 32 bit application. The managed code was 64 bit.

    I changed the client architecture to 64 bit and it started working after that.

    Thanks a lot again.

     - Sameer


    Thanks Sameer
    Monday, June 13, 2011 12:07 PM