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

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.

Related

How to hide C# class from custom IL Inspector?

I am currently working with a piece of software known as Kofax TotalAgility or KTA for short.
This is Business Process Automation Software, which I have the "pleasure" of expanding with custom .net libraries.
I have been creating a MS Graph library to perform actions with the MS Graph API. The API works great and I am quite pleased with how it turned out.
However due to the way KTA is accessing methods in classes I have used "Data classes" (dont know if that is the right word) to use as input parameters for my methods. To be clear these methods have no functionality other than to store data for methods to use, the reason I am doing this, is because of the way it is structured in the KTA class inspector (I am assuming that KTA uses the IL Code from my library to create a list of classes and methods).
This is what I am expecting the user is shown when they are using my methods. As you can see by using classes as input parameters I get this nice hierarchical structure.
By using classes as input parameters another issue occurs which is that my "Data Classes" are show in the list of classes, which produces alot of unnecessary clutter.
Is there a way to hide these classes from the inspector? I get that it might be an internal KTA issue, which of course would mean I am not asking in the right place, and it is an internal Kofax issue.
However if there is some C# or .NET way of doing this, that would be preferable.
There are a number of different terms for the data/parameter classes that you mention, such as DTO (data transfer objects), POCO (plain old C# objects), or the one that you can see in the KTA product dlls: model classes.
There is not a direct way to hide public classes from KTA. However, when you use the KTA API via the TotalAgility.Sdk.dll, you notice that you don’t see all of the parameter classes mixed in with the list of the classes that hold the SDK functions. The reason is just that these objects are in a separate referenced assembly: Agility.Sdk.Model.dll. When you are configuring a .NET activity/action in KTA, it will only list the classes directly in the assembly that you specify, not referenced assemblies.
If you are using local assembly references in KTA, then this should work because you can just have your referenced assembly in the same folder as your main dll. However if you are ILMerging into a single dll to can add it to the .NET assembly store, then this approach won’t work.
When ILMerged together, the best you can do is to have your parameter classes grouped in a namespace that helps make it clear. What I do is have a main project with just one class that acts as a wrapper for any functions I want to expose. Then use ILMerge with the internalize option, which changes visibility to internal for any types not in the primary assembly. To allow the model classes to still be public, I keep them in a specific namespace and add that namespace to the exclude list for the internalize command. See Internalizing Assemblies with ILMerge for more detail.
Keep in mind that anyone seeing this list is configuring a function call with your dll. Even if they are not a skilled developer, they should at least have some competence for this type of task (hopefully). So even if the list shows a bunch of model classes, it shouldn’t be too hard to follow instructions if you tell them which class is to be used.

How to dynamically create wrapper classes for 3rd party library classes?

I am writing a library that depends on another library and utilizes some of it's design.
There are about 10 or so container classes that just hold data. I need an exact wrapper for these 10 classes so the client code of my library does not have to declare the 3rd party library as a dependency in their project.
I'm curious if there is a way to easily create wrappers for these classes without manually creating a file and definition of the classes / fields.
My initial solution was to just extend from the 3rd party library class like this.
using LibFooOne = SomeLibrary.SomeNamespace.FooOne;
using LibFooTwo = SomeLibrary.SomeNamespace.FooTwo;
// ...
public class FooOne : LibFooOne { }
public class FooTwo : LibFooTwo { }
// ... And so on for the 10+ other classes
But once I tested my library in a example project, there was a compile error complaining that the 3rd party was not referenced in the project assembly.
So far the only working solution I have figured out was to manually create an exact copy of the 3rd party library classes, and write type cast methods for each of them.
Any possible way I can dynamically create these copies so does not force the client code to install the 3rd party library? Is there a library to handle this type of task?
Edit: My question wasn't asking if I could some how make my initial solution work. I was simply using it as an example for my end goal. I'm asking if there are libraries or way in c# to wrap classes. I can create a class with the same fields, and create a casting method. This works and solves my issues. However it's a lot of manual work.
No: You are subclassing classes stored in third-party assemblies. You will need those assemblies on the target machine when your program runs.
If you have the source code to the third-party assemblies in question and you have the licensing rights, you could subclass and compile your own version of the third-party assembly. But it doesn't sound like you have the source code to those third-party assemblies.

Reusing a COM interface

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?

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.

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?

Categories