How do I call C++/CLI from C#?
I have a开发者_Python百科 class implemented in C++ that's responsible for the arithmetic computation of the program, and an interface using WPF. I process the input with C# but then how can I use my C++ class?
I've seen some comments about making a managed C++ wrapper class to interact with it, but I don't know where to start. Nor do I know how I'd go to compile it along with all the other code. I can't really find a tutorial on this, and the stuff google shows on managed C++ doesn't really seem helpful.
Anything out there to help me out? This doesn't seem unreasonable to me.
EDIT Tried m3rLinEz solution but it's giving me a BadImageFormatException, I think it's because the DLL isn't generated. I did everything as told, I don't know what happened. Any ideas?
Have you take a look at C++/CLI?
Let me give a very short example. Here is the source file from a Visual C++ -> CLR -> Class Library project. It basically get Windows username and return it.
Please note that, in order to get this compiled, you have to go into project settings and mark "Additional Dependencies" as "Inherit from parent" because we are using those Windows libs (kernel32.lib, user32.lib, ..)
// CSCPP.h
#pragma once
#include "windows.h"
using namespace System;
namespace CSCPP {
public ref class Class1
{
// TODO: Add your methods for this class here.
public:
String^ GetText(){
WCHAR acUserName[100];
DWORD nUserName = sizeof(acUserName);
if (GetUserName(acUserName, &nUserName)) {
String^ name = gcnew String(acUserName);
return String::Format("Hello {0} !", name);
}else{
return gcnew String("Error!");
}
}
};
}
Now created a new C# project and add reference to our first C++/CLI Class Library project. And then call the instance method.
namespace CSTester
{
class Program
{
static void Main(string[] args)
{
CSCPP.Class1 instance = new CSCPP.Class1();
Console.WriteLine(instance.GetText());
}
}
}
This gave the following result on my machine:
Hello m3rlinez !
C++/CLI is basically a managed extension over C++ standard. It allows you to utilize CLR classes and data types in your C++/CLI project and also expose this to managed language. You can created a managed wrapper for your old C++ library using this. There are some weird syntaxes such as String^
to define reference type to CLR String. I find "Quick C++/CLI - Learn C++/CLI in less than 10 minutes" to be useful here.
There are at least three ways to call unmanaged code from managed in the same process:
- C++/CLI
- Platform Invoke
- Wrap your C++ in a COM object
At work we use C++/CLI for this, it seems to work.
I would create a standard (non COM/Managed) Dynamic Link Library as described here and then use the DllImport attribute (platform invoke) in the c# code to access the exported functions.
The key point from that article:
Note the __declspec(dllexport) modifier in the method declarations in this code. These modifiers enable the method to be exported by the DLL so that it can be used by other applications. For more information, see dllexport, dllimport.
This is a lighter weight alternative to an actual COM interop wrapper and avoids issues such as registration etc (the DLL can simply be placed in the application directory) .
Another alternative is It Just Works (IJW). This is probably a better choice if you have managed C++ code and need to access this from other .NET languages. But this is only an option if you are able/happy to convert your unmanaged C++ to managed C++ though.
I would stay away from P/Invoke as it's pretty slow compared to IJW (It Just Works). The latter allows you to seamlessly interweave managed and and unmanaged c++. All you have to do is to create a managed c++ assembly, write a managed class that is visible from c# and call the unmanaged code out of that.
Uhm... OK. I was under the impression that P/Invoke calls were slower which they are inherintly not. However, by having explicit control over marshalling, you can make your C++/CLI version to perform better in a lot of the cases.
Here is Microsoft's article about both mechanisms:
http://msdn.microsoft.com/en-us/library/ms235282.aspx
Advantages of IJW
- There is no need to write DLLImport attribute declarations for the unmanaged APIs the program uses. Just include the header file and link with the import library.
- The IJW mechanism is slightly faster (for example, the IJW stubs do not need to check for the need to pin or copy data items because that is done explicitly by the developer).
- It clearly illustrates performance issues. In this case, the fact that you are translating from a Unicode string to an ANSI string and that you have an attendant memory allocation and deallocation. In this case, a developer writing the code using IJW would realize that calling _putws and using PtrToStringChars would be better for performance.
- If you call many unmanaged APIs using the same data, marshaling it once and passing the marshaled copy is much more efficient than re-marshaling every time.
There are aesthetic advantages as well:
- C# code looks like C# code without any interop'y weirdness.
You don't have to define
DLLImport
attribute, you don't have to define any of the data structures (also with p/invoke specific attributes) which could look like this:[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DevMode { [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string dmDeviceName; }
- You don't have to convert all parameter primitive types into their .NET counterparts (there is table on this page that lists how managed types map to unmanaged types).
- You get to work with C++/CLI which is really fun to learn and is really polished. It's come a long way since VS 2003 and is now a fully featured .NET language. Microsoft documentation for it is pretty good, as is all the IJW information.
- Doing C++ interop in C++/CLI feels very natural as opposed to C#. This is completely subjective, but I would much rather prefer to do string marshalling in C++ that do
Marshal.PtrToString(ptr)
. - If exposing an API you would probably want to wrap up all P/Invoke stuff in another layer, so you don't have to deal with P/Invoke ugliness. This way you have the overhead of all the marshalling AND the C# layer around it. With C++/CLI the marshalling and the interop abstraction are in one place, and you can choose how much marshalling you need.
IMHO if you are calling an odd function in Windows SDK, go with P/Invoke. If you are exposing a moderately complex C++ API to the managed world, definitely C++/CLI.
精彩评论