Pregunta

Tenemos un componente COM que la implementación y definición de interfaz de existir en el código administrado, pero es impulsado por un componente nativo.El componente administrado es la devolución de un SafeArray de vuelta al código nativo a través de la siguiente declaración del método.

interface IExample {
  <return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UNKNOWN)>
  object[] DoSomeOperation()
}

El generado firma nativa correctamente, se pasa esta de vuelta como un SafeArray.

Durante una revisión de código pesar de que vino para arriba con algunas preguntas acerca de las llamadas a la matriz resultante con SafeArrayGetElement.La cuestión es si o no SafeArrayGetElement devuelve un IUnknown instancia que es AddRef gustaría o no.Esencialmente se reduce a cuál de las siguientes opciones es la correcta

Ejemplo 1:

CComPtr<IUnknown> spUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&spUnk));

Ejemplo 2:

IUnknown* pUnk;
hr = SafeArrayGetElement(pArray, &bounds, reinterpret_cast<void**>(&pUnk));

La documentación es muy delgada sobre este tema.Sólo se incluye la siguiente línea.

Si el elemento de datos es una cadena, un objeto o una variante, la función copia el elemento en la forma correcta.

La definición de una correcta es un poco ambiguo.

¿Fue útil?

Solución

El primer método debe ser correcto, y estaría en línea con el manejo de objetos en COM, presumiblemente la definición que encontró supone que el consumidor conoce la forma correcta.

Los otros elementos mencionados lo requieren. Copiar un VARIANT o un SAFEARRAY conlleva un AddRef () implícito cuando contienen objetos. Sin embargo, VARIANT no lo requiere cuando VT_BYREF está presente.

VariantCopy @ MSDN
SafeArrayCopy @ MSDN

Este comportamiento no es intrínseco a SAFEARRAYs o VARIANTs ya que es parte de las reglas de manejo de parámetros en COM. Sin embargo, no hay nada que impida que alguien intente eludir las reglas.

Para los parámetros de entrada, no es responsabilidad del destinatario de AddRef () a menos que tengan la intención de mantener el puntero de la interfaz para su uso posterior. Sin embargo, otros casos de uso de parámetros lo requieren.

Por ejemplo, las interfaces colocadas en VARIANT u otros contenedores deben tener al menos una llamada AddRef () aplicada, de lo contrario, esto crearía problemas al usar VARIANT como parámetros de salida de métodos COM, ya que la transferencia de datos / referencias es unidireccional. El objeto original podría caducar para cuando la llamada llegue a su destino. Del mismo modo, organizar una interfaz en un Stream requiere también un AddRef ().

Del mismo modo, llamar por referencia requiere al menos una llamada AddRef también. Si este no fuera el caso, cualquier llamada de larga duración adecuada (por ejemplo, a través de DCOM) podría no llegar a su destino con la garantía de que el objeto referenciado aún está vivo. Sin embargo, las llamadas adicionales AddRef () / Release () se omiten con frecuencia aquí, ya que el objeto ya debería estar en 1+ debido a la creación en o antes del alcance de la llamada.

Si es posible modificar el componente y sus llamadas están en proceso, entonces puede ser conveniente utilizar el GIT en su lugar. Esto le permite pasar un token en su lugar, y será más fácil reunir la interfaz entre los apartamentos COM. La vida útil de los objetos involucrados se convierte en responsabilidad de la persona que llama a lo largo de la duración de la llamada, y podrá atrapar casos en los que un objeto no se pudo ordenar.

Creación de la tabla de interfaz global @ MSDN

También es interesante la nota a pie de página para BSTR.

  

Si la implementación de una función que toma un parámetro de referencia BSTR asigna un nuevo BSTR al parámetro, debe liberar el BSTR previamente referenciado.

Funciones de manipulación de cadenas (COM)

Otros consejos

Debe ser AddRef:ed, pero no tengo de primera mano la información que ese es el caso (por ejemplo,No he leído la fuente).

Creo que la documentación es bastante claro, sin embargo-la copia de un puntero de interfaz "correctamente" es AddRef:ing.

Si quieres estar realmente seguro, construir un super-simple objeto COM de ATL, que implementa el IUnknown, cosas que un número de ellos en un SAFEARRAY y poner un punto de interrupción en CComObjectBase<>::InternalAddRef (si mi memoria no sirve).A continuación, depurar una llamada a SafeArrayGetElement y ver si su punto de interrupción.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top