Marshal C++ “string” class in C# P/Invoke

2020-02-28 07:28发布

I have a function in a native DLL defined as follows:

#include <string>
void SetPath(string path);

I tried to put this in Microsoft's P/Invoke Interop Assistant, but it chokes on the "string" class (which I think is from MFC?).

I have tried marshaling it as a variety of different types (C# String, char[], byte[]) but every time I either get a NotSupportedException or a Native Assembly Exception (depending on what marshaling I tried).

As anyone ever done Native/Managed Interop where the native string class is used? Is there any way to Marshal this? Am I going to have to write my own Marshaler?

3条回答
Viruses.
2楼-- · 2020-02-28 08:10

The PInvoke interop assistant only supports C not C++. Unfortunately the MFC String class (CString I believe?) is C++ and won't work through the assistant. Instead try using the following

void SetPath(__in const WCHAR* path);
查看更多
Bombasti
3楼-- · 2020-02-28 08:18

Looks like you're trying to use the C++ standard library string class. I doubt that will be easy to Marshal. Better to stick with a char * and Marshal as StringBuilder. That's what I usually do. You'll have to add a wrapper that generates the C++ string for you.

查看更多
家丑人穷心不美
4楼-- · 2020-02-28 08:33

Yes. You can. Actually, not just std::string, std::wstring, any standard C++ class or your own classes can be marshaled or instantiated and called from C#/.NET.

The basic idea of instantiating a C++ object from .NET world is to allocate exact size of the C++ object from .NET, then call the constructor which is exported from the C++ DLL to initialize the object, then you will be able to call any of the functions to access that C++ object, if any of the method involves other C++ classes, you will need to wrap them in a C# class as well, for methods with primitive types, you can simply P/Invoke them. If you have only a few methods to call, it would be simple, manual coding won't take long. When you are done with the C++ object, you call the destructor method of the C++ object, which is a export function as well. if it does not have one, then you just need to free your memory from .NET.

Here is an example.

public class SampleClass : IDisposable
{    
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,          CallingConvention=CallingConvention.ThisCall)]
    public extern static void SampleClassConstructor(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject);

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,      CallingConvention=CallingConvention.ThisCall)]
    public extern static void DoSomething(IntPtr thisObject, int x);

    IntPtr ptr;

    public SampleClass(int sizeOfYourCppClass)
    {
        this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
        SampleClassConstructor(this.ptr);  
    }

    public void DoSomething()
    {
        DoSomething(this.ptr);
    }

    public void DoSomethingElse(int x)
    {
        DoSomethingElse(this.ptr, x);
    }

    public void Dispose()
    {
        Marshal.FreeHGlobal(this.ptr);
    }
}

For the detail, please see the below link,

C#/.NET PInvoke Interop SDK

(I am the author of the SDK tool)

Once you have the C# wrapper class for your C++ class ready, it is easy to implement ICustomMarshaler so that you can marshal the C++ object from .NET.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx

查看更多
登录 后发表回答