Não é possível empacotar a matriz de estruturas de C ++ para C # no Unity
Estou tentando passar uma matriz destruct
s de C ++ para um script do Unity em C #. Quando estou usando o código na produção, o tamanho da matriz varia bastante, portanto, preciso efetivamente passar uma matriz de comprimento desconhecido.
Minha idéia inteligente foi armazenar a matriz na pilha e passar uma referência a essa matriz para o Unity. Encontrei posts do StackOverflow sobre como fazer isso. Mas então o Unity reclama que uma referência é nula.
Aqui está parte do meu código C ++:
extern "C" struct S; // Not currently used.
struct S {
int i;
float f;
};
extern "C" bool helloWorld(S ** a, int * i);
S * s;
bool helloWorld(S ** a, int * i) {
s = new S[4];
for (int j = 0; j < 4; j++) {
s[j].i = j; // Fill in placeholder
s[j].f = (float) j; // data for now.
}
*a = s; // I don't know if this works.
*i = 4; // Works.
return true;
}
Eu tentei isso comint
s em vez destruct
se funcionou.
Agora, meu código C # é:
[StructLayout(LayoutKind.Sequential),Serializable]
public struct S {
int i;
float f;
};
void Start() {
IntPtr ptrNativeData = IntPtr.Zero;
int itemsLength = 0;
bool success = helloWorld(ref ptrNativeData, ref itemsLength);
if (!success) {
return;
}
S[] SArray = new S[itemsLength]; // Where the final data will be stored.
IntPtr[] SPointers = new IntPtr[itemsLength];
Debug.Log("Length: " + itemsLength); // Works!
Marshal.Copy(ptrNativeData, SPointers, 0, itemsLength); // Seems not to work.
for (int i = 0; i < itemsLength; i++) {
Debug.Log("Pointer: " + SPointers[i]); // SPointers[0] prints 0.
Marshal.PtrToStructure(SPointers[i], SArray[i]); // Crashes here. Boom.
}
}
[DllImport("TestUnity")]
private static extern bool helloWorld(ref IntPtr ptrResultVerts,
ref int resultVertLength);
oMarshal.PtrToStructure
A instrução diz que o argumento SPointers [i] é nulo. Eu verifiquei com o comando Debug.Log e, de fato, parece nulo: ele é impresso como 0.
Mas tentei algo semelhante com uma variedade deint
s mais cedo e que funcionou. O que não tenho certeza é: meu problema está no C ++ ou no C #? Não estou transmitindo as informações corretas ou estou processando as informações corretas da maneira errada?
Essa foi a primeira solução que eu encontrei principalmente por conta própria. A segunda solução é melhor.
Totalmente graças a Alex Skalozub, eu descobri. Um nível de indireção do ponteiro é abstraído durante o empacotamento. Então, agora, meu código C ++ contém:
S ** s; // Not a pointer to Ss, but a pointer to pointers to Ss.
bool helloWorld(S *** a, int * i) { // Pass a triple pointer.
s = new S * [4]; // Create array of pointers.
for (int j = 0; j < 4; j++) {
s[j] = new S; // Actually create each object.
s[j]->i = j;
s[j]->f = (float) j;
}
*a = s;
*i = 4;
return true;
}
E meu código C # contém:
for (int i = 0; i < itemsLength; i++) {
Debug.Log("Pointer: " + SPointers[i]);
SArray[i] = (S) Marshal.PtrToStructure(SPointers[i], typeof(S));
}
E é isso! Todos os dados são transferidos.
Agora, isso me deixa com um problema de gerenciamento de memória:todo objeto criado no código C ++ precisará ser liberado. Estou ciente disso e vou cuidar disso a seguir.
Solução 2Veja a resposta verificada. A resposta de Alex é muito melhor, pois faz muito menos uso de indicadores desnecessários. Usei mais ponteiros porque acabei de descobrir como usá-los em C #.