Marshal classe C ++ “string” em C # P / Invoke
-
03-07-2019 - |
Pergunta
Eu tenho uma função em uma DLL nativa definida da seguinte forma:
#include <string>
void SetPath(string path);
Eu tentei colocar isso em Assistente de P / Invoke Interop da Microsoft, mas engasga com a classe "string" (que eu acho que é do MFC?).
Eu tentei empacotamento-lo como uma variedade de diferentes tipos (C # String, char [], byte []) mas cada vez que quer pegar um NotSupportedException ou uma Exceção Assembléia Native (dependendo do que o empacotamento eu tentei).
Como alguém já fez nativo / geridos Interop onde a classe string nativa é usado? Existe alguma maneira de Marshal isso? Am I vai ter que escrever a minha própria Marshaler?
Solução
Parece que você está tentando usar o C ++ classe string biblioteca padrão. Duvido que vai ser fácil de Marshal. Melhor ficar com um char * e Marshal como StringBuilder. Isso é o que eu costumo fazer. Você vai ter que adicionar um wrapper que gera a string C ++ para você.
Outras dicas
O PInvoke interoperabilidade assistente só suporta C não C ++. Infelizmente a classe MFC String (CString eu acredito?) É C ++ e não funcionará através do assistente. Em vez disso tente usar a seguinte
void SetPath(__in const WCHAR* path);
Sim. Você pode. Na verdade, não apenas std::string
, std::wstring
, qualquer classe padrão C ++ ou suas próprias classes pode ser empacotado ou instanciado e chamado de C # /. NET.
A idéia básica de instanciar um objeto C ++ a partir de .NET mundo é alocar tamanho exato do objeto C ++ da NET, em seguida, chamar o construtor que é exportado a partir do ++ DLL C para inicializar o objeto, então você será capaz de chamar qualquer das funções para acessar esse objeto C ++, se qualquer do método envolve outras classes C ++, você precisará envolvê-los em uma classe C #, bem como, para os métodos de tipos primitivos, você pode simplesmente P / Invoke-los. Se você tem apenas alguns métodos para chamar, seria simples, codificação manual não vai demorar muito. Quando você é feito com o objeto C ++, você chamar o método de destruição do objecto C ++, que é uma função de exportação também. se ele não tiver um, então você só precisa de libertar a sua memória de NET.
Aqui está um exemplo.
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);
}
}
Para os detalhes, consulte o link abaixo,
C # /. NET PInvoke Interop SDK
(Eu sou o autor da ferramenta SDK)
Depois de ter a classe wrapper # C para sua classe C ++ pronto, é fácil de implementar ICustomMarshaler
para que você possa organizar o objeto C ++ a partir de .NET.
http://msdn.microsoft.com/ en-us / library / system.runtime.interopservices.icustommarshaler.aspx