We have a COM interface declared and implemented in unmanaged C++. We no longer wish to maintain this assembly, but do need to make some changes, and still be backward compatible.
What I want to do, is to write all the new code in C#, and make it ComVisible. From this thread I see a reference to TreatAs to replace the old interface.
I was thinking along the same path as Jonathan Peppers regarding ProgId, Guid, etc. I will implement the exact interface as the old version as a wrapper to the new implementation. I am also thinking about adding MarshalAs attributes exactly as in the generated interop wrapper to be sure the data types will be the same, if possible.
Are there anything else I should consider while working with this? Anyone with experience doing this conversion?
EDIT: I do have the IDL file for the server. I am not sure if there is a way I can auto generate the code based on this. COM is not something I'm very familiar with.
EDIT Q: How should I deal with HRESULT used by existing clients?
ADDED: Figured I should point other readers to a different fix, which is not available for my scenario as I can't recompile all the .NET applications using the existing com:
Bjørnar Sundsbø
One quick way to get started:
Import your existing COM object into C# with tlbimp (or Visual Studio)
Load up .Net Reflector and get the generated interface to put in your new project
Implement the generated interface in C#
Switch any import declarations to export instead
This should get all your types and method signatures correct from the start. It is a great starting point for porting an existing COM interface to C#.
It seems to be by design to prevent managed COM object from being used from a managed client.
Here are some links to the same problem, as well as this thread, providing some solutions. Also take a look at the answer Jonathan Peppers provided to see how to start out if you only need to use it from unmanaged applications.
The only way I figure I could work around this, is a messy solution where I create the new code in C#, add a COM layer on top of that. Then create an additional COM layer as unmanaged C++ which accesses the first layer so, that my .NET applications can access it.
{Unmanaged COM exposing the original interface} => {Managed COM with rewrite of the original logic of the COM}. All existing applications will then access the "{Unmanaged COM...}". If I get desperate enough, that might be a way. For now I'm abandoning this approach and looking for other solutions.
If you can, recompile your managed application to use the new assembly, do so. You can still use that managed COM from VB6, unmanaged C++, etc. If you still need to reference as a COM from managed, you might be able to create new instances using the approach specified in one of the referenced posts, as long as you don't need to create an interop wrapper.
Related
I am trying to use 7zip from within my application code. On 7zip's website, they say I can use 7z.dll. So, I tried to reference it from C#, but that didn't work. So, I decided to write a C++ library that references 7z.dll, and then I can reference that library from C#.
I was able to load the library (I think) in my C++ library, and I am able to reference that library from C# and successfully call a method.
However, I don't know how to figure out the method names inside the 7z.dll library so that I can call them.
Please help
Hmm, Hans Passant pointed out SevenZipSharp which makes my answer rather useless ;-) I'll leave it for purely educational purposes. No need to write your own COM interop wrappers if somebody else has already done it for you...
I had a look at their C++ example (under CPP/7zip/UI/Client7z). Everything is done using COM interfaces and various types of callbacks.
While C# has excellent COM interop support, it would require redeclaring the relevant COM interfaces in C#, or perhaps using late-bound dynamic magic instead. However, both of these options are rather non-trivial for a project the size of 7z, so on second thought it's likely best to stick with your C++/CLI wrapper approach.
Within that example, you can see exactly how main does it: It loads the DLL (using a wrapper class NDLL::CLibrary around the LoadLibrary call), then obtains a pointer to the COM CreateObject function (via the same wrapper that does a GetProcAddress internally).
Once you have the address of the CreateObject function, you can call it with the appropriate application and interface GUIDs to obtain instances of objects that implement them, after which you can use those objects to do the actual work. The interfaces themselves are declared in header files such as IArchive.h.
We're integrating a communications company's software into our own for doing things like answering calls, transfering calls, matching numbers with clients etc.
They have given us the API documentation, which includes a TLB file. We've used the tlbimp tool to create an assembly which we now want to use in our implementation.
Some of the classes created by tlbimp have been given internal constructors, rendering them uninstantiable. I think it should be ok in this instance as another class should return an instance of these classes.
This made me think though: are there any other pitfalls I should be aware of when using tlbimp.exe, and TLB's as a whole? Would it be better to create the DllImport/ComImport/PInvoke code by hand?
In general if you have a TLB I would at least start my work by consuming the assembly produced by tlbimp.
The tool itself is widely used and produces correct code based on the definitions provided in the TLB. I have seen some circumstances where the resulting code was incorrect but it almost always came back to either a very complex marshalling situation with arrays or a place where the TLB author had simply added the wrong COM annotations.
If you do find any issues down the road then you should consider beginning to hand code the fixes. But I certainly wouldn't start that way.
You cannot pinvoke the kind of COM interface methods that are declared in a type library. The DLL that implements the COM server doesn't export the methods. You can use late binding with reflection or the dynamic keyword but that's painful and error prone. Use the import library, that's why it is there.
Thus far I've figured out out I needed to recompile the library as a .dll instead of a .lib, enable /clr and /EHa instead of /EHsc. Now I've got a managed dll which I've added as a reference in my C# project.
Now how do I use it?
I'm prepared to write some wrappers, but I don't know where to begin or how to "see" what functions I've gained access to. I've read a little bit about how the class names and functions might be mangled by the compiler... do I need to go back and add __declspec exports everywhere (if so, how?), or is there an option in VS2010 that says "don't mangle it!"?
The C++ library in question is still under active development, so I'm hoping I can modify the C++ library as little as possible and just recompile it periodically with a few switches, and then expose the new functionality as I need it.
If you are going to compile your C++ (if originally was unmanaged C++) you will need to do much more than just add the /clr switch. In order for C# to use the DLL you will need to create managed classes and other types based on CTS which are compatible with C# (.NET).
See and ref classes.
A good book to read about the subject (IMHO) is this one
You can either expose the functions as C style functions (i.e., no mangling) from your dll or you can expose them as COM objects.
I'd suggest writing a COM wrapper, and using that instead. Have a look at http://msdn.microsoft.com/en-us/library/035x3kbh%28v=VS.80%29.aspx for intro instructions. You'll want to make your object interfaces derived from IDispatch and be automation compatible, which should enable the runtime to consume them without any custom marshaling.
A nice benefit of this approach is you can continue to build your native code as a library, and just make your COM project use it. Also, it's still native code inside the COM object, so there's much less potential for unknown problems (once you get the interface layer working).
That's my suggestion, anyway.
Yes, wrap it in à COM object. I believe ATL is what you meed to do this with the least effort.
Is it possible to share references to C# objects between C# and C++ code without massive complexity? Or is this generally considered a bad idea?
The best solution for sharing a C# object between native and managed code is to use COM interop. This allows you to essentially share an interface of an object between managed code and it's equivalent signature in C++.
As for the complexity side of things. The majority of COM interop scenarios are straight forward and really are no more complex than good old COM programming. On the managed side it looks really no different than a normal interface.
Once you introduce multiple threads or start playing around between COM apartments though, things can get a bit tricky.
In my experience, the easiest way to get this working is the following.
Define an interface in C# that you wish to use in C++
Mark the interface with the ComVisible(true) attrbute
Run tlbexp on the assembly which generates a TLB file
Import the TLB into your native project
This will get the interface definition into both of your projects. How to pass that between the projects requires a bit more detail into your architecture.
Another solution I can recommend, from personal experience, is to use a managed C++ interface between the two if the C++ code you want to access is too large or too complex.
For example, I am using the RakNet C++ network library in a C# project. The solutions are to either create a massive wrapper class in C# to access the required C++ functions, create a C++ wrapper around those functions which can than be used as a COM interop or use Managed C++ (Visual C++/CLI).
I chose the latter which allows me to use C++ to access the RakNet library, but the classes created can be used directly in another .NET project as if. So the main logic has been created in those Managed C++ classes, which also allow me to use the .NET framework and some of its wonderful features. In my C# project I simply need to call the Managed C++ library which provides me with all in all 20 functions I need to perform everything.
I just got handed an SDK made of C++ dll, lib, exe, and various .h files. I presume it is meant for C++ developers. The sample projects they provide with their documentation are all written in C++. I am able to spin them up with Visual Studio 8 (2005) and run them. They do control the device as advertised. However the project this needs to be used by is in C# .Net 2.0 and that is unchangeable.
My boss was a C++ developer and says all I need to do is to compile it as a COM object and then import the COM object into my C# solution. My boss says it should take less than an hour to "wrap" there SDK up as a COM object, even for me with no knowledge of C++ compiling.
I've used COM objects in C# solutions before so once this is made, I can continue on from there without a problem.
However, I don't know what to do to make the COM object from the 2 .dll files, 1 .exe, 1 .lib file, 1 .xml file, and the 12 .h files. Is there a resource available to tell me what to do to make this happen?
My boss was a C++ developer and says all I need to do is to compile it as a COM object and then import the COM object into my C# solution.
That's true, however compiling it as a COM object is "difficult" (by which, I mean that you can't do it) unless it already implements the COM APIs (if it doesn't then you need to implement the COM APIs before you can build it as a COM object).
There are books (for example, Essential COM) which explain how to to create COM objects using C++, but it's non-trivial (for building COM objects there may be better books than Essential COM, and better/easier tools than C++).
I think you and/or your boss have 3 options:
Ask the vendor to give them to you as COM objects
Design a COM API that would wrap the SDK's API. Create a COM project (in the language of your choice) which exports this API. Implement these APIs by invoking the underlying SDK methods. To do this you may need someone who knows C++, or be willing to spend much, much longer than "an hour" on this project.
Forget about using COM; instead, build the SDK as a DLL, and use PInvoke to invoke it from .NET code.
My boss says it should take less than an hour to "wrap" there SDK up as a COM object, even for me with no knowledge of C++ compiling.
Based on what you've said I don't know of any way to make that happen.
Tell your boss if it would take him less than an hour to wrap it up, he should certainly do it: it would be a more efficient use of both your time.
I would also suggest ATL (not using attributes), but this is something which can take some time to get right if you're not experienced.
My boss says it should take less than
an hour to "wrap" there SDK up as a
COM object, even for me with no
knowledge of C++ compiling.
That may be true for an experienced C++/COM developer, but not for a beginner. I think your best bet is to use ATL. Take a look at the MSDN tutorial.
And do not use attributes.
This doesn't quite answer your question, but...
One option instead of trying to make a COM object is to use P/Invoke and just call the methods in the DLL.
This thread on the MSDN Forums documents how to make a DLL to call using P/Invoke.
Of course if you need access to a whole class (and make an instance of said object), this isn't going to be helpful.
It's good that the code compiles and runs for you. That said it's totally unfair to assume you can do this in an hour.
Have you checked to see what is actually being built by Visual Studio. There could be a chance that it is already building a COM object.
Investigate how the code is being called. I assume you have a .exe that you can run to test the code. Step through this in the VC++ debugger (it's similar enough to debugging C# code) and try to identify any API calls that match with your docs/expectations. This knowledge will be helpful if you try to go the P/Invoke route.
Something else to consider is SWIG. This is typically used by Python developers to wrap C/C++ code and provides some support for C#.
The managed C++ route is probably more advisable for experienced C++ devs because you need to understand a lot about memory allocation, for all but the simplest code.
I (well, really my lead and I) will first try using p/Invoke (via the DllImport feature of System.Runtime.InteropServices) against the SDK's dll the company provided. I'll let you know how it goes.
I think what you really want/need is C++/CLI, that way you can just build them directly into a managed assembly. The idea is that you write a pretty plain wrapper that looks like kind of a cross between C# and C++ and then it does the rest.