I have a development which requires the passing of objects between a VB6 application and a C# class library. The objects are defined in the C# class library and are used as parameters for methods exposed by other classes in the same library. The objects all contain simple string/numeric properties and so marshaling has been relatively painless.
We now have a requirement to pass an object which contains a list of other objects. If I was coding this in VB6 I might have a class containing a collection as a member variable. In C# I might have a class with a List member variable.
Is it possible to construct a C# class in such a way that the VB6 application could populate this inner list and marshal it successfully? I don't have a lot of experience here but I would guess Id have to use an array of Object types.
Options are more limited through COM than what you have in C#:
You can't use generics (COM does not have support for this, and TLBEXP will leave them out)
There is the olden ArrayList class. Or an array.
The COM interop layer will automatically generate a COM enumerator for a C# class that implements IEnumerable (the non-generic version), you can iterate it on the VB6 side with For Each.
Similarly, it generates an IEnumerable for a COM class that implements an COM enumerator. You can use foreach in C# code to enumerate a VB6 Collection. Choose between them depending on who creates the collection.
Related
I'm doing some prototyping, plugging into a big legacy C++ application. I'm using C# to do this as a proof of concept (eventually I will write the library in C++). I've setup a COM interface between my C++ application and a .net class library and am able to pass strings and ints between. They get automatically marshalled as appropriate (e.g. a managed string goes to BSTR*).
I now have added a new method to my COM interface which returns a List<String>. I figured the method type generated would return an array of BSTR* (BSTR**) and a count a SAFEARRAY, however when I look at the IDL (using oleview), this interface method doesn't even appear. I'm guessing the COM framework isn't sure what a List<String> looks like, so what are my options here? Just using string[]?
I'm not using C++/CX, and I cannot.
Thanks
This is the first time I am implementing C# COM Interface with Perl. I would appreciate if somebody could help me to understand how a data of key value pairs be passed over the COM interface:
Is it possible to pass Hash?
or alternatively an array or array.
Another related doubt, Is it possible to pass object over COM interface?
If so, what about array of objects?
Hashes aren't supported over COM, but SAFEARRAYs are. Safearrays can be nested, so you could pass an array of 2-element arrays.
While Objects per se can't be passed across COM, interfaces can be. (COM is language neutral; passing a C++ object to a C# or Perl runtime isn't going to work. COM interfaces have a common implementation across languages, and so can be passed around.) Safearrays support arrays of interfaces, as well.
I have made a C# COM Visible class that I can access via the
dynamic com = AutomationFactory.CreateObject("MyCom");
function in Silverlight and I am able to return basic datatypes (ie string, int..). So far so good :).
But now I would like to return an object over the COM connection and that proved to be quite difficult. I can return an object and place it into a dynamic variable and from there access the object members, but I can't cast the data to my desired object type.
Questions:
1. Is there a way to cast a dynamic variable to my desired class.
2. Is there a way to make the COM object return an object of my desired class?
The answer to both your questions is: No.
There is no interop between the full version of .NET installed on a client and the Silverlight version of .NET.
The best you can do is create wrapper class that accepts the dynamic and delegates its members into the dynamic.
If you want to re-use code that consumes this .NET object in both full .NET and Silverlight then define the object using an interface. Have the original class implement the interface and have the wrapping class also implement the interface.
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.
I am using Delphi 2010 to access objects stored in a C# Assembly written in Visual Studio 2008 using the techniques described in the Hosting CLR in Delphi. These techniques do work and I am able to obtain an instance of a .NET class - via an interface - and call its methods and read it properties. Calling the methods works fine as long as long as the parameters are simple parameters, such as strings, integers, chars, and booleans. But if I try to pass a parameter that is an IDispatch reference, the C#/.NET code only sees the parameter as a null value.
The one difference from the Hosting CLR in Delphi example is that I do not define the interfaces in both Delphi and C# by hand. Instead, I write the interface type library as a RIDL file in Delphi 2010. Then I compile that RIDL file into a TLB file, then use Microsoft's TLBIMP.EXE to build a COM/Interop DLL from the DLL, and then I add a reference to that DLL in the C# project. I use this approach for defining the interfaces of the COM objects that I use for both the interface usage (as described in Hosting CLR in Delphi) and as for defining the interface of the IDispatch interface that I pass as a parameter.
Here is the interface that I use from Delphi and the one that the C# classes that I use implement (.NET Metadata):
[TypeLibType(4160)]
[Guid("C4D342E4-62A0-4049-BF1E-9F2A6EE19E5E")]
public interface ITestInterface
{
[DispId(203)]
int Run(object Test);
}
Delphi can startup the CLR, then instantiate a C# object that implements ITestInterface. Delphi can call Run and I can verify that Run executes properly. Return values are as expected and if I pass parameters other than "object Test" (rewrite the interface), then those parameters are properly seen. But when I pass a reference to an IDispatch object for the Test interface, the C# code sees it only as NULL. Trying to cast the parameter using "as" to the right interface doesn't fail - but it results in a NULL because the initial value seems to be NULL.
I have double checked and the value is not NULL when it leaves Delphi.
I'm guessing that there is some sort of extra marshalling step that I have to perform on the C# side to properly obtain an interface supported by the IDispatch object.
Any thoughts, suggestion would be greatly appreciated.
The CLR won't know what to do with a raw interface pointer and no type info. You'll need to pass a VARIANT of type VT_DISPATCH. That will map to a __ComObject on the C# side, late binding is required to make calls on that reference.