views:

288

answers:

1

Hello,

I'm after help on how to use complex objects either as return values or passed as parameters to C# class methods exposed to unmanaged C++ as COM components

Here's why:

I'm working on a project where we have half a dozen unmanaged C++ applications that each directly access the same Microsoft SQL Server database. We want to be able to use MS-Sql/Oracle/MySql with minimum changes and we've decided to implement a business logic plus data layer exposed via WCF services to get the required flexibility.

This strategy hinges on being able to get the unmanaged C++ to interop with the WCF service. There are a number of ways to do this, but the strategy I want to follow is to create a C# assembly exposed as a COM component which will act as a bridge between C++ and the WCF layer. This C# assembly will be loaded into unmanaged C++ process as COM component.

The C# bridge assembly will contain a helper class which has a number of methods that describe the operations that were formerly expressed as direct sql or stored proc calls in the C++ code.

I have two problems to solve

1) For an INSERT, I need to pass an object representing the entity to be inserted. On the unmanaged C++ side, the I already know that one of the entities has about 40 properties which have to make it into SQL - I don't want a C# method with 40 parameters, I want to pass an object; I don't know how to marshal a C++ object via COM into C#, so I thought about defining a Stuct on the C# side and then make the Struct COM visible.

2) How to return the result of a "SELECT this, that, other, ... ". I've seen two examples. One returns a struct[] and another returns a single struct containing a string[] for each column field and an int count member describing the length of the other member arrays.

On the C# side, I think it will be a case of defining and exposing a number of request/response structs which will be used to pass data in/out. These structs will need to be decorated with attributes that cause their members not to "change position" as a result of optimization. And the struct members may need to be decorated with the attribute that hints to the marshaller how the member should be exposed in COM.

Then of course I'll have to work out how to instantiate and populate these structs as seen as COM objects from the unmanaged C++, then I'll have to pass them in method calls and process them as return values.

This is the most difficult part for me; I grok C++ and some MFC/ATL but COM under C++ is a whole extra level of complexity. Any recommended books, blogs, tutorials on the subject of parameter passing and return value processing as I've described would be very helpful indeed.

+2  A: 

If possible, I'd avoing bringing COM into the picture. If you control the C++ code (it sounds like you do), it should be easier to add a single C++/CLI cpp file that calls into your C# code. C++/CLI can directly access and create managed and unmanaged types and copy between them.

jdv
Definitely a good idea. You can even create the C++/CLI code in a separate DLL that export unmanaged functions/classes if for some reason you don't want to compile all your C++ code as C++/CLI. You do loose the automatic marshaling that the .NET COM code would give you, but you also side step a lot of potential headaches.
shf301
Yes, I have control of the C++ code. I tried to switch on clr support at the project level, but got an error stating /MTd and /clr switches are incompatible. That's why I went the COM route as I can leave the C++ pretty much unchanged, unless I get some other error calling CoInitialize.If I were to create a C++/CLI DLL, would I not be in the same position? ie having to export it's contents. How would I add a C++/CLI dll to an unmanaged C++ app that doesn't seem to currently use COM?
IanT8
/MTd means static linking of the C++ runtime lib, that is indeed not compatible with C++/CLI. If you link them as DLLs you'll be fine. You don't need to compile all code as C++/CLI. Instead, enable it at the project level, and disable for all files except the new one that will have to talk to .net.
jdv