views:

1164

answers:

4

I am trying to create an instance of a COM object. I have the class name that implements the interface and I get a CLSID by using CLSIDFromProgID(). So since I am getting a CLSID I thought everything should be fine from now on. However when I do a call to CreateInstance and pass in the CLSID, I get an error saying "Class not registered". Also I get this error only in some computers. It runs error free on several computers. I don't understand where the problem could be. Is my registry dirty? Does anyone know what is going on here? Thanks for your help!

I just want to add that this is a .NET COM class. The appropriate entries are in the registry and the DLL is in the GAC.

+1  A: 

It's a two step process in the registry. You used the ProgID to get the CLSID. Then, when you call CreateInstance, COM then uses the CLSID to find the path to the dll. You can used regedit yourself to lookup the CLSID and see what that entry looks like.

Corey Trager
Lets say it is a .net COM class. Then where does it look when I call CreateInstance()?
Shao
I believe, no difference. COM is COM. The registry maps CLSID's to the paths to the dlls.
Corey Trager
+1  A: 

CLSIDFromProgId is simply looking up the ProgId's name in the registry and translating it to a CLSID, it doesn't have to look at anything beyond the registry or even check that something is actually implementing that CLSID.

When you call CreateInstance on the CLSID, Windows will look up in the registry to find out how the object should be instantiated (usually a exe or dll). It will then try to load the dll (or start up the exe) and create the object from it.

There is a lot of documentation in MSDN on the processes involved, for example see "COM Class Objects and CLSIDs", and if you do a lot of COM work it is worthwhile learning the process from first principals since it can save a lot of time and hassle when debugging this type of issue.

Rob Walker
Lets say it is a .net COM class. Then where does it look when I call CreateInstance()?
Shao
Look under HKEY_CLASSES_ROOT\CLSID\{..your clsid..}\ You should see a Server32 or InprocServer23 subkey which will tell you which executable is registered to handle the object.The oleview tool is useful for diagnosing these issues ... open a Visual Studio command prompt and type: oleview
Rob Walker
+1  A: 

Thanks for your answers. The .Net assemblies were registered properly and were present in the GAC. One application that absolutely confirmed this was Process Explorer. You can view the dlls that are loaded by each application. So from here I was able to see if the application that was instantiating the COM objects was actually able to load the DLLs or not. I found out that this was indeed happening. The problem was due to different Regional settings. We found that the application threw an exception when the region was not set to US. This issue was fixed. The error message "Class not registered" was not very helpful. Thankfully it was a quick fix.

Shao
"Not very helpful" was actually the working name for COM.
bzlm
A: 

Using shell32 as an example, you can create a new instance like so;

var shl = (Shell) Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));

This will aquire a refernce to an existing component;

var shl2 = (Shell) Marshal.GetActiveObject("Shell.Application");

Here's a reference to how to do the same in IronPython.

** Note, this used the progid, clsid would be nearly identical, just use Type.GetTypeFromCLSID({GUID}).

RandomNickName42