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.
Related
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.
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.
I am pretty new to managed/unmanaged interoperability and COM concepts.
I received a suggestion of using COM Interop, for using my existing MFC code in C#. But the problem for me is, i have a MFC Dll which is not a valid COM component. How can I make this MFC DLLs to have COM-accessible interfaces ready for use in .NET?
From thread Loading MFC DLL in C# Windows Application
To access native code from C# you have a few choices.
Most directly, you can use DllImportAttribute to describe your DLL's entry points in C# terms so that they can be called via P/Invoke. They'll look like static methods to your C# program.
Less directly, you can create a Managed C++ assembly that wraps your DLL in one or more managed objects. The Managed C++ DLL can be accessed from C# via Add Reference (because it is a managed assembly with a .dll extension) and should also be able to access your MFC dll by using #include to include the MFC dll's header file.
A third option would be to turn your dll into a COM object so that your C# program can access it that way.
There is no simple way to make MFC Dll COM accessible. It is necessary to write a lot of COM code manually, making COM wrapper. If you don't have previous COM experience, this may be difficult. The second option from Jacob Seleznev's post looks less painful. C++/CLI wrapper which is internally linked to existing MFC dll, and exposes pure .NET interface to C# client, looks like optimal solution.
If MFC Dll exports C-style interface (API), and not classes, use PInvoke.
From my experience, I concur with #Jacob Seleznev and will add that if your MFC DLL interface contains mainly "simple" parameter and return types, using the DLLImportAttribute is most likely going to be your path of least resistance.
A great reference for marshaling types is to see how it's done against the unmanaged Win32 API. That can be found here:
pinvoke.net
What I've done is find an API call with like types and see how that call is setup on pinvoke.net. I don't use it often anymore, but it was extremely helpful a few years ago.
Hope this helps.
Of the three ways to call native code from managed code (COM Interop, P/Invoke, and IJW or C++/CLI interop), COM Interop is the slowest. And if your existing native code is not in the form of a COM component, then it's also the hardest because that will be step 1.
To use P/Invoke you will need some C-style functions (extern C) that go on and call your existing code. To use IJW or C++/CLI interop you will implement a public ref class (in a file compiled /clr) with methods that go on and call your existing code. It is up to you which you find easier. Once you have the wrapper, from C# you can do the PInvoke with a DllImport attribute on the declaration of the functions, and you then call them as usual. To do the IJW you add a reference to the assembly with the public ref class in it and call the methods on that class as usual.
My recommendation is to ask whether you want some sort of Facade pattern where you're putting some logic in front of the interop - if so, go IJW. Also if you want to control the marshaling, go IJW. If not then go P/Invoke. But either way works.
I was wondering if I can use a library -written in C++- in C#
The problem is that library has its own structures and classes..
Will I be able to use it in C#?
Thanks
EDIT This library is open source..
so if my requirements needs something special in C++ code, I will be able do it...
You cannot directly use C++ classes in managed code. The chief problems are not being able to use the same memory allocator as used by the C++ code and not being able to invoke the constructor and destructor easily. A Microsoft employee posted a blog post to show that it is not impossible. I would not recommend doing this.
COM is a solution but that invariably requires a fairly big rewrite and good COM programming skillz. A managed class wrapper in the C++/CLI language is usually the best solution. You could take a peek at the SWIG tool to consider auto-generating those wrapper classes. Beware however that this tool can easily create more problems than it solves.
There are two ways, both using an Adapter (which maps C++ classes to .NET classes):
C++/CLI
COM
The former avoids going via COM, and much of the C++ code might be able to be just compiled with the correct switches.
Additional: In theory P/Invoke might be possible, but all the C++ semantics would be lost, you would need to handle C++ object lifetime manually (and instance references as IntPtr). Plus of course you would need to call the mangled names...
Another option is to write a managed wrapper in C++/CLI. I prefer that instead of using P/Invoke.
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.