Encontrei um problema em que a alocação de memória para uma estrutura com new na função C++ não transfere corretamente a instância de volta para C#.
Parece que a abordagem correta é evitar usar new
na função C++ e definir diretamente os valores do parâmetro out. No entanto, não consegui encontrar documentação que descreva explicitamente esse comportamento ou explique como os parâmetros out manipulam automaticamente a criação de instâncias. Você tem essa informação em algum lugar no Microsoft Document? Gostaria de saber se você sabe disso.
Código C++:
struct MyStruct {
int value1;
float value2;
};
extern "C" __declspec(dllexport) void GetValues(MyStruct* outStruct) {
// outStruct = new MyStruct(); // NG
outStruct->value1 = 42;
outStruct->value2 = 3.14f;
}
Código C#:
[StructLayout(LayoutKind.Sequential)]
public struct MyStruct {
public int value1;
public float value2;
}
[DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void GetValues(out MyStruct result);
public static void TestInterop() {
MyStruct result;
GetValues(out result);
}
A resposta é: não.
Não tenho conhecimento de documentação específica que especifique isso, é simplesmente uma questão básica de como o C++ funciona, independentemente de P/Invoke.
Eles não.
A criação da instância é feita no seu caso no lado C# com:
Note que, como
MyStruct
é uma struct e, portanto, um tipo de valor , não requernew
ing (embora seja opcional).A instância é criada na pilha.
Um ponteiro para essa instância (
outStruct
) é então passado para C++, e é preenchido por meio desse ponteiro pela função C++.Uma observação lateral:
O motivo pelo qual usar
outStruct = new MyStruct();
insideGetValues
não teve o efeito esperado é que em C++ (assim como em C) os parâmetros são geralmente passados por valor (em C++ também temos pass-by-ref, mas este não é o caso aqui).Neste caso, o ponteiro (que contém um endereço) é passado por valor. Alterar o ponteiro em si na função não afetará o chamador.
Para afetar o chamador, você precisa passar um ponteiro-para-um-ponteiro.
Veja esta postagem para mais informações: C++ por que ponteiro duplo para parâmetro de função out/return? .