Reusing a COM interface - c#

Let me elaborate, before someone is thundering down on me with "Never reuse a COM interface!!!"
We implemented an COM interface on a program which is discontinued. We now actually buy a similar piece of software from a third party (so I can't change that!)
The COM interface is still used by many (third party) programs. Now I have to integrate the new piece of software with these programs (which I can't change because they are third party).
So I think I need a proxy: This proxy will reuse the COM interface so none of the third party programs will be able to tell they're not talking to the discontinued software. Inside the COM object, I'll 'translate' the commands and forward them to the new piece of software.
I'm using C# to build my proxy and I've used the tlbimp.exe to generate a DLL from the type library of the old program.
I'm referencing this generated DLL in my COM project where I provide a implementation for the given interface.
Next, I register the output DLL from my project and use a old client to call the proxy.
It returns the error: Unable to cast object of type 'Lib.ApiClass' to type 'Lib.ApiClass'.
Why is that?
Should I use a different approach?

Related

How to interact with another programs with OLE Automation in C#?

I create an application with C# that can read item data from SQL Server and push it to the scale system named "SLP-V Ishida Retail Scales". They have an interface "SLP-V Automation Interface" that allows user programs to interact with their systems. This is the note from help page in SLP-V :
The automation interface (also known as the "COM (common object model) interface") provides a method for user programs to access SLP-V functions. The most common application for this is the use of VB Script to automate SLP-V operations such as importing host files. However, the automation interface can be used from any programming environment that supports automation (COM), and this is the preferred method for incorporating SLP-V functions into end-user applications.
This topic provides a reference for the methods and properties of the SLP-V automation object and includes some sample programs.
SLP-V Automation Object
The SLP-V automation object name is "Ishida.Slp.Scripting.CommonApi" and the type library file is "SlpScripting.tlb".
My question is, does the C# language allow us to interact other programs using OLE Automation? And if the answer is yes, how do I interact with my program?
I mean like calling their method. Because I can't add SlpScripting.tlb as a reference. It says
A reference to 'SLP Scripting Interface ' could not be added
The ActiveX type library 'SlpScripting.tlb' was exported from a .NET assembly and cannot be added as reference. Add a reference to the .NET assembly instead
And I have searched Google about this, but I didn't find the answer.
Finally found a solution
I don't have to add reference in c#, instead of just using :
System.Type objType = System.Type.GetTypeFromProgID("The name of progID that you want to call");
dynamic comObject = System.Activator.CreateInstance(objType);
Example ProgID = "Ishida.Slp.Scripting.CommonApi".
And then just call the function / method that exist in that object, for example :
comObject.LoginToHost("localhost", 8085, username, pass);
OLE automation is old wording for what we now call COM. And yes, .NET can access COM very easily (starting with .NET 1.0).
You have these options:
Method 1
First "register" the COM library on your development system. Look in the documentation of the SLP system, probably this was done already during setup. If not, normally a COM DLL can be registered manually with regsvr32 XXX.DLL. Be aware of 32/64 Bit issues (if you want to register a 32 bit COM DLL in 64 bit Windows, use C:\Windows\SysWOW64\regsvr32.exe).
Then your COM DLL should be listed in Visual Studio if you go to
Add Reference ==> COM
as "SlpScripting Type Library 1.0" or similar.
Then, add a "using SLPxxxx" or similar (Intellisense should show the real name).
After this, you should be able to create a new instance of your COM object.
For additional help, search for "C# COM interop", you will find lots of informations.
Method 2
Open a Visual Studio command prompt, and enter:
tlbimp SlpScripting.tlb
A DLL will be created, which you can add as a reference.

Force .NET type to instantiate as COM

Is it possible to force a COM Visible .NET assembly to instantiate as System.__ComObject, rather than it's .NET type? The reason I ask is, part of my app uses 3rd party COM objects, but some of those, when written in .NET, get instantiated as their .NET types and break the object handlers I've created. I have no control over methods used to create the COM objects. Currently I'm using the following to create the objects.
Type comType = Type.GetTypeFromCLSID(objectGUID);
comObject = Activator.CreateInstance(comType);
Thanks!
Actually, no.
The COM activation of managed objects is done in the same AppDomain as the caller. IMHO, This is a nasty issue with COM interop in .NET. There are several questions here on SO with all sorts of attempts at making this work. I can attest that I've tried most of these to no avail. Your COM API provider SHOULD be producing a PIA (Primary Interop Assembly) to ensure forward type compatibility. If they are not, you are going to have some nasty issues.
The only workaround I'm aware of as a client is to only use the 'object' type. Everything would need to go through reflection. Some things you still can't do. For example, you would not be able to implement an interface.
I havn't a clue why this works this way. It's caused me no end of problems producing a viable api for both unmanaged and managed code.

Adding an in-proc COM Server object to a C# application

I am new to COM and need to add a Server COM object to my c# application so I can call its methods and implement events. The documentation I have says this requires a COM-aware language such as Visual C++. My app is written in C# so I'm not sure how this is going to work. Any direction would be appreciated.
I am writing an app that communicates with a serial hypercom terminal. The device came with a DLL (the com server interface) that I will need to figure out how to use in my c# application.
I added a reference to the DLL to my project, which shows up as a type library. In object explorer I get interfaces, and some classes etc.
Thanks,
Matt
You can add the COM object as a reference. .NET will create an interop assembly to work with the COM object, just like it was a .NET type.
CComObjectRoot can be used as a base class for all COM objects implemented with ATL. As such you don't have to worry to implement something similar in C#, the required methods (AddRef, Release, QueryInterface) will be generated by tlbexp for classes that are tagged with ClassInterface.
STDMETHODIMP is a define which serves to declare the most common methods that can be called from COM (#define STDMETHODIMP HRESULT STDMETHODCALLTYPE). Again if your class is tagged with ClassInterface you will not have to worry about.
Such construction is required in C++ when your class implements several interfaces. I think this is not required if you tell C# compiler that your C# object implement IDispatch, IFPESOlementationEvents. The appropriate code will be written automatically by the compiler.
Probably everything will not make much sense if you are new to COM and C#, I'll suggest to take a look at the various introduction that you may find on the web, like this.

Replacing a C++ ActiveX component with a .NET implementation?

I have existing managed and unmanaged software using an ActiveX component supplied by a third party to perform some communications, but it is now required that this communication be routed through my application.
Ideally I'd be able to install a .NET component which will expose exactly the same interface, and will be usable as a drop-in replacement.
However, I am running into the limits of my understanding of COM, which admittedly is quite minimal.
How best to ensure that my implementation of the interface is 100% binary compatible with the existing object?
How do I ensure that applications use my implementation of the interface instead of the legacy implementation? Is it simply a matter of registering my implementation, and unregistering the legacy one?
How do I ensure it's a "drop-in" replacement, and requires no changes to existing software?
How do I ensure unmanaged code can use it without issue?
Note: I am able to require that .NET 4.0 be used, if that will make things simpler.
Edit: Bounty will be moved here How to debug why a VB6 application using my .NET ActiveX control does not register for events? after 2 days.
Use the type library of the ActiveX component. Import it with Tlbimp.exe to get the interop library, you probably already have it if you use this component yourself. Implement your own code by inheriting the interfaces in that type library.
Your implementation must use the exact same GUIDs and ProgIDs as the ActiveX component. Use OleView.exe, File + View Typelib and select the ActiveX DLL to see the GUIDs. The ProgIDs are more difficult, best thing to do is to watch how the registry is modified with the SysInternals' ProcMon utility when you register the ActiveX DLL with Regsvr32.exe. Ultimately, the exact same changes need to be made by Regasm.exe when you register your replacement.
As point 2.
Same, the registration gets unmanaged code to use yours instead.
To make this work out well, you really have to know what the interfaces do. You cannot make this work if the ActiveX component is actually an out-of-process server (an EXE).
Well, I've gotten a lot further along with this, but I seem to have encountered an intractable problem.
The object I am replacing uses COM events. When one of the client applications (VB6 I believe, as depends.exe tells me it uses msvbvm60.dll) instantiates and uses my replacement, it does not register for any of the events, and unfortunately, the way it works is that after a particular method call has completed, the client application does nothing until an event fires.
Note: My replacement ActiveX control inherits from System.Windows.Forms.Control, and sets MiscOptions of 131457 on the coclass registry entries as suggested by http://ondotnet.com/pub/a/dotnet/2003/01/20/winformshosting.html, the reason being that the thing I am replacing was an honest to goodness ActiveX control, and I could not get these existing clients to instantiate my object successfully without any code changes at all until I inherited from WinForms control.
I have tried the approach where my coclass declares public events with the same name as the interface specified by ComSourceInterfaces, this works 100% from a C# app that uses AxHost, events are triggered.
I have also tried instead to implement IConnectionPointContainer and all supporting interfaces on my replacement control, and this works 100% from a C# app, but in the VB app, it never actually attempts to Advise() the connection point of the client sink interface to call, it only calls Unadvise() with an invalid cookie value of 0.
One issue with the typelib that I have noticed is that I cannot get tlbexp.exe to export one of the properties on the coclass interface as OLE_HANDLE, it just ends up being a long in the TLB generated from the assembly (this TLB is referenced by the TypeLib entry in the registry). Could this cause issues with eventing?
Any ideas how to debug this?

How to marshal an object and its content (also objects)

I have a question for which I suspect the answer is a bit complex. At this moment I am programming a DLL (class library) in C#. This DLL uses a 3rd party library and therefore deals with 3rd party objects of which I do not have the source code. Now I am planning to create another DLL, which is going to be used in a later stadium in my application. This second DLL should use the 3rd party objects (with corresponding object states) created by the first DLL.
Luckily the 3rd party objects extend the MarshalByRefObject class. I can marshal the objects using System.Runtime.Remoting.Marshal(...). I then serialize the objects using a BinaryFormatter and store the objects as a byte[] array. All goes well. I can deserialize and unmarshal in a the opposite way and end up with my original 3rd party objects...so it appears...
Nevertheless, when calling methods on my 3rd party deserialized objects I get object internal exceptions. Normally these methods return other 3rd party objects, but (obviously - I guess) now these objects are missing because they weren't serialized.
Now my global question: how would I go about marshalling/serializing all the objects which my 3rd party objects reference...and cascade down the "reference tree" to obtain a full and complete serialized object? Right now my guess is to preprocess: obtain all the objects and build my own custom object and serialize it. But I'm hoping there is some other way...
It's a bit unclear to me why you need two C# assemblies to deal with the third party DLL, isn't the first class library you created already interfacing your third party DLL? Here are some general answers when dealing with native libraries. It would help if the third party library is publicly available, to see what interfaces it uses.
If the native DLL exposes its functions you can use P/Invoke calls and in most cases the marshaling will be done for you;
If the native DLL exposes its methods as COM interfaces, you can create COM wrappers;
If you must do everything by hand, you might need to use the LayoutKind and FieldOffsetAttribute or the StructLayoutAttribute, these attribute help you tell the compiler how the internal memory layout of the object is;
Have a look at MarshalAsAttribute and UnmanagedType, it may be just what you need.

Categories