I'm trying to instantiate a COM object, defined in a x86 dll written in Borland C++, in a testing program i write in C# (.net 4.7.2). The COM dll (server) is working, I have a windows service also written in C++ Borland that can use it and instantiate a COM object from the class (using CoCreateInstance). The dll is registered and the InprocServer32 entry has the correct path to the dll. There is no coclass existing in a typelib, only interfaces (those exist in the typelib). I have used the TlbImp to create dll:s which i reference in the c# project. In the project the target platform is set to x86. The way i try to instantiate an object is:
var comType = Type.GetTypeFromProgID("ins.MyComType");
object comObj = Activator.CreateInstance(comType);
however the second line gives me
"Exception thrown: 'System.IO.FileNotFoundException' in mscorlib.dll"
with the message 'Retrieving the COM class factory for component with
CLSID {C4363C5E-3831-46DF-8701-60C8D1B612BA} failed due to the
following error: 8007007e The specified module could not be found.
(Exception from HRESULT: 0x8007007E).".
It does not matter if i try to run the app as administrator. I have a vague memory of trying out a similar thing a couple of years ago and that it at that time worked. It was probably on a Win 7 machine (might even have been a 32-bit system). I have tried to open the project in DependencyWalker but i'm not sure what i'm looking at. I get a couple of errors:
*Error: At least one required implicit or forwarded dependency was not found.
*Error: Modules with different CPU types were found.
*Error: A circular dependency was detected.
*Warning: At least one delay-load dependency module was not found.
*Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.
Does any one have any idea on what it could be causing the exception? Or if i could get some hints as of how to dig deeper into dependencywalker? I get a gigantic tree of systemassembly stuff but i cannot see any obvious assembly standing out, though DW refers to many of them as being 64 bit. My guess is some dependent dll(s) somewhere should be x86 but which one(s). Is there a redist similar thingi i should have installed for this to work?
best regards
/Erik
You should write a simple VBScript that contains these lines:
set obj = CreateObject("ins.MyComType")
MsgBox TypeName(obj)
Name the file test.vbs
Execute the command:
c:\windows\syswow64\wscript.exe test.vbs
Using the version from syswow64 ensures that it uses the 32-bit version of wscript.exe which can instantiate 32-bit COM objects. The version in c:\windows\system32 can only instantiate 64-bit In-process COM objects in DLLs...you said your object is a 32-bit COM DLL server.
If the vbscript fails, it could be that the object is not automation compatible--implements IDispatch. Otherwise you will get an error message why it fails.
If it succeeds, you will know there is probably nothing on the C++ side causing problems. You THINK this is the case...but where is the runtime for Borland C++? Is everything statically linked, or is some of it dynamically linked? If it is dynamically linked, where is it in the path? It could be that the C++ service you have has the library in its path so that when it loads your COM object, the library is available. But, when you try to load from a 3rd party, like .NET or VBScript then the path to the library manifests itself. Who knows? I'm just making suggestions.
If you use ProcMon, it can see where the problems are. It will show you what registry entries are being read and which files are trying to be loaded.
Related
Using COM interop, I have following exception in my C# client code when trying to instantiate a COM object coded in C++ compiled and running in a COM executable server: System.InvalidCastException: Unable to cast object of type 'System.__ComObject' to type "XXX". (Where XXX was the class type used in my C# code for the COM object)
The executable containing the COM object runs on the same machine as the client code. I have verified that the COM object is registered properly in the windows registry.
The instantiation fails not systematically in my project. I need to execute at least 3 times to see the failure. I have the same issue during the tests running in our CI system.
The problem is solved: 2 assemblies were used by my project that had references to the Interop dll used to instantiate the COM object. One of these 2 assemblies had “EmbedInteropTypes” set to true and the other one had the same property set to false. Putting “EmbedInteropTypes” to false for both fixed the problem.
I am still looking for good explanations on why this did not work. I have found other projects where similar issues happened it seems:
https://github.com/yck1509/ConfuserEx/issues/302
I'm hitting a wall that I understand. I have a simple COM server that I want to instantiate. I can do so with simple VBS or PS commands outside of my EXE:
$sms_client = New-Object -COM 'CPApplet.CPAppletMgr'
Set controlPanelAppletManager = CreateObject("CPApplet.CPAppletMgr")
In my C# code I tried early binding, late binding, a PS runspace/pipeline and lastly Process.Start( cscript myVBS ). In all of those scenarios it comes back with class not registered and fails.
//throws exception
CPAPPLETLib.CPAppletMgr cpAppletMgr= new CPAPPLETLib.CPAppletMgr();
// myType does not come back null
Type myType = Type.GetTypeFromProgID("CPApplet.CPAppletMgr");
// throws exception
object myObject = Activator.CreateInstance(myType);
Update: I can create the Scripting.FileSystemObject without issue. I don't need that... it was just a test.
I've tried compiling 32bit, 64bit. Running as standard user and elevated. I've tried registering the DLL again but something about my C# .NET EXE is doing something that it just can't see the COM. I even tried creating a brand new console app project and it does it there also.
Am I missing something that is a .NET 101 COM-Interop fundamental?
Retrieving the COM class factory for component with CLSID {096C5BA8-044B-4BAC-9914-144723BA4F2A} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
Update:
Setting the platform to x64 made the error go away. AnyCPU and x86 fail. Does this mean I have to create 2 versions of the EXE for my 32bit and 64bit workstations?
It doesn't necessarily mean you have to create two instances. You should be able to create just one as long as you make it AnyCPU. The thing is, you have to register it with the correct runtime. By default, Visual Studio registers AnyCPU with the 32-bit runtime on a 64-bit machine. If you make sure to run the regasm.exe with the 64-bit runtime and correct version of the runtime, then you should be able to call it from a 64-bit process.
However, in my shop we've generally compiled one for x86 and one for x64 and deploy the right one for the right platform.
I am writing a C# assembly that is called from an x64 process (SS Reporting Services) and needs to use an x86 3rd party COM assembly.
When I compile my assembly as x64, I get a "Class not registered" COM exception as soon as the first call to the COM assembly is made.
Following the advice here (sorry if my terminology is incorrect) I created a new COM+ application and added components found in the COM assembly I am referencing. When I run my assembly as x64 it does make some successful calls to the COM assembly until I get this error:
Unable to cast COM object of type 'TRIMSDK.RecordTypesClass' to interface type 'TRIMSDK.IBaseObjects'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{8A354545-6BCB-11D3-B273-00A0C9FC3DC0}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
'TRIMSDK.RecordTypesClass' does implement 'TRIMSDK.IBaseObjects' according to the class definition.
If I search the registry for the interface GUID from the error message or for 'IBaseObjects', no matches are found. Since creating the COM+ application I get the same error in x86 mode (which I guess makes sense), though it worked fine in x86 before that.
So, I assume the 'TRIMSDK.IBaseObjects' interface I'm trying to use isn't being registered as a COM+ thingy and I don't know why or how to fix it.
Any ideas? Thanks in advance.
Update: I think I am getting the E_NOINTERFACE exception for TRIMSDK.IBaseObjects because the TypeLibType attribute on the interface is set to 'FNonExtensible' only, whereas other interfaces I use successfully in the assembly also have 'FDispatchable'. Is it possible to get around this error (either altering the type library or manually registering the 'IBaseObjects' interface somehow)?
This is quite an old question, but I've just sorted this out in our environment after having been struggling with this issue for a while. I have very little experience with COM and/or Interop so excuse me if my terminology is a little off.
The error message I was getting was;
Unable to cast COM object of type 'TYSTransfer.TransferClass' to
interface type 'TYSTransfer._Transfer'. This operation failed because
the QueryInterface call on the COM component for the interface with
IID '{E825C39B-1EF3-4319-89FC-AEF62C8117B9}' failed due to the
following error: No such interface supported (Exception from HRESULT:
0x80004002 (E_NOINTERFACE)).
I was also struggling to find the interface GUID specified in the message. I looked in Component Services for the GUID assigned to our COM component and could see;
Then when I used DotPeek to look at the generated Interop class that I was using to access this COM component, I noticed that the associated GUID for the same interface was the one as was reported in my error;
So DotPeek showed me that the Guid being referenced was from my Interop class. It turned out that regenerating the Interop class against the target COM object generated a class with the correct Guids (at least they matched so I assumed they were correct), and utilising this fixed the issue for us.
The generated Interop class we were using during runtime was simply replaced with the regenerated one. Once the program was restarted with the new generated Interop class in place, it started working again.
The reason this issue simply appeared all of a sudden was due moving the code to a new server. I think something got mixed up during the move.
I have developed a sample c# COM-Visible DLL.
Built in x86 and registered via 32-bit Regasm, it executes well by COM Client.
Built in x64 and registered via 64-bit Regasm, the COM Client call drops the following error :
Retrieving the COM class factory for component with CLSID {A0F2F58F-7B98-3605-BEC9-84724FF1E824} failed due to the following error: 80040154.
I checked and made sure that CLSID is present indeed in the registry under HKCR\CLSID.
Below is an example of simulating a COM Access via c# :
var type = Type.GetTypeFromProgID("ProgID.Interop.5683");
var obj = Activator.CreateInstance(type); // <-- blows here
I also checked via procmon that there is a successful access to the type via progId
The question is, where is the Activator looking exactly ? and how to make it "see" my x64 registered assembly ? is there something I need to add somewhere ?
I have found many "solutions" advising an x86 re-build. But Come'on ! I am not going to do that and lose all x64 benefits just for COM's sake. Is there a "REAL" solution to that ?
After a night of sleep and a little hindsight, I figured out that the Activator needed to be called from an x64 App, to find the x64 CLSID by looking in the x64 locations in the Registry.
i.e, when called from an x86 App, Activaor looks in the x86 locations in the Registry for CLSID and subsequent key including codebase.
var type = Type.GetTypeFromProgID("ProgID.Interop.5683");
var obj = Activator.CreateInstance(type);
Hello
I created COM visible class MyClass on C#
registered by regasm command - registration passed OK
And I can see in registry progid corresponding to MyClass
In the client C++ code :
1) call of CLSIDFromProgID passed OK
2) call of CoCreateInstance fail with error "Class not registered" (80040154)
What can be possible reasons of such behavior - your help will be very valuable
Thanks in advance
I just want to add that the "class not registered" problem may happen because one uses the incorrect bit-depth version of regasm. The .NET framework comes with 2 versions of regasm.exe. One version in the “Framework” path, and the other in “Framework64″ path.
On my 64 bit machine i got the error when using the 32-bit regasm to register the dll and tried to get an instance from a 64-bit C++ exe.
I had the same issue, solved executing these commands from the console:
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\regasm dllname.dll /tlb:dllname.tlb
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\regasm dllname.dll /regfile
then doing a double click on the reg file generated.
to test if everything is ok you can have a very small vb script file which created the object, just put a command like this in a .vbs file:
SET testObj = CreateObject("Namespace.ClassName")
your COM visible assembly should be strongly named.