office microsoft example c# c++ .net com com-interop

c# - microsoft - ¿La interoperabilidad de.NET copia los datos de la matriz de un lado a otro, o fija la matriz?



interop c# excel (2)

Hagamos un pequeño experimento. Primero, cambiemos su método COM para que se vea así (en C ++):

STDMETHODIMP CComObject::Next(ULONG* pcch, int* addr, OLECHAR* pbuff) { pbuff[0] = L''A''; pbuff[1] = L''/x38F''; *addr = (int)pbuff; *pcch = 1; return S_OK; }

Luego, cambie la firma del método C #:

void Next(ref uint pcch, out IntPtr addr, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] char[] pbuff);

Finalmente, pruébalo así:

uint cch = 10; var buff = new char[cch]; IntPtr addr1; unsafe { fixed (char* p = &buff[0]) { addr1 = (IntPtr)p; } } IntPtr addr2; com.Next(ref cch, out addr2, buff); Console.WriteLine(addr1 == addr2);

Como se esperaba, addr1 == addr2 es true . Por lo tanto, aparentemente la matriz queda inmovilizada en lugar de copiada cuando se pasa a COM.

Dicho esto, no pude encontrar ninguna documentación que presentara esto como un requisito difícil para una implementación de CLR. Por ejemplo, esto puede o no ser cierto para Mono.

Tengo esta firma de método COM, declarada en C #:

void Next(ref int pcch, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] char[] pchText);

Lo llamo así:

int cch = 100; var buff = new char[cch]; com.Next(ref cch, buff);

¿La capa de interconexión .NET primero copia toda la matriz a un búfer de memoria temporal no administrado y luego la copia de nuevo? ¿O la matriz se fija automáticamente y se pasa por referencia?

Por el bien de intentarlo, hice esto en el objeto COM (C ++):

*pcch = 1; pchText[0] = L''A''; pchText[1] = L''/x38F''; // ''Ώ''

''Ώ'' cuando ''Ώ'' buff[1] en C # al volver. Pero no creo que esta sea una prueba fehaciente de que el arreglo se bloquea, en lugar de ser copiado de un lado a otro.


No siempre es fácil de decir, especialmente si usa una declaración de curso inválida. Un char [] no puede clasificarse como LPWStr, tiene que ser LPArray. Ahora el atributo CharSet desempeña un rol, ya que no lo especificó, el char [] se calculará como un char [8] de bits, no como un wchar_t [] de 16 bits. El elemento marshaled del array no tiene el mismo tamaño (no es "blittable"), por lo que el marshaller debe copiar el array.

Bastante indeseable, especialmente dado que su código C ++ espera wchar_t. Una manera muy fácil de contar en este caso específico es no recuperar nada en la matriz. Si la matriz se calcula mediante copia, tendrá que decirle al Marshaller explícitamente que la matriz debe ser copiada nuevamente después de la llamada. Tendría que aplicar el atributo [In, Out] en el argumento. Obtendrás chino.

La forma normal de saber si la matriz se calcula mediante copia es mediante el uso del depurador. Habilite la depuración no administrada en su programa C #. Establezca un punto de interrupción en la llamada, así como un punto de interrupción en la primera declaración en la función nativa. Cuando llegue el primer punto de interrupción, use Depuración + Windows + Memoria + Memoria 1. Coloque buff en el cuadro Dirección y cambie la pantalla a "Entero de 4 bytes". Verá la dirección del objeto de matriz, el manejador de tipo de 4 bytes, la longitud de la matriz de 4 bytes y el contenido de la matriz en sí. Entonces, usted sabe que si la matriz no se copia, la dirección indicada será la dirección mostrada más 8.

Presione F5 para continuar, el punto de interrupción en la función nativa golpea. Mire el argumento pchText , el depurador le dice su dirección. Si coincide, entonces el Marshaller simplemente pasó un puntero. Si no, entonces tienes una copia de la matriz.