No puedo evitar publicar esto, aunque no es una respuesta directa a la pregunta.
Hay un brillante artículo de MSKB de las edades doradas de com: Información: descripciones y funcionamiento de los modelos de subprocesos OLE. Todavía allí, y tiene toda la información relevante. El punto es que no debes preocuparte por si hay mariscal o no, si sigues las reglas. Simplemente registre su objeto como ThreadingModel=Both
, agregue el mariscal de hilo libre con CoCreateFreeThreadedMarshaler
, y terminar. Com hará el mariscal si es necesario, de la mejor manera posible. Dependiendo del modelo de apartamento del cliente, el código del cliente puede recibir el puntero directo a su interfaz, si también sigue las reglas.
Cualquier interfaz "alienígena" que pueda recibir cuando se llame a un método de su interfaz será válida en el alcance de la llamada, porque permanece en el mismo hilo. Si no necesita almacenarlo, eso es todo lo que importa.
Sin embargo, si necesita almacenar en caché la interfaz "Alien", la forma correcta de hacerlo sería almacenarla usando CoMarshalInterThreadInterfaceInStream
/CoGetInterfaceAndReleaseStream
:
Para almacenarlo:
- Ingrese la sección crítica;
- llamar
CoMarshalInterThreadInterfaceInStream
y almacenar el IStream
puntero en un campo miembro;
- Dejar la sección crítica;
Para recuperarlo
- Ingrese la sección crítica;
- llamar
CoGetInterfaceAndReleaseStream
Para recuperar la interfaz
- llamar
CoMarshalInterThreadInterfaceInStream
y guárdelo de nuevo como IStream
Para cualquier uso futuro
- Dejar la sección crítica;
- Use la interfaz en el alcance de la llamada actual
Para liberarlo:
- Cuando ya no necesite mantenerlo, simplemente suelte el almacenado
IStream
(Dentro de la sección crítica).
Si el objeto "alienígena" también es libre, y las cosas están sucediendo dentro del mismo proceso, es probable que se ocupe de un puntero de interfaz directa después de CoGetInterfaceAndReleaseStream
. Sin embargo, no debe hacer ninguna suposición, y realmente no necesita saber si el objeto con el que se trata es el objeto original o un proxy de com Marshaller.
Esto puede optimizarse ligeramente usando CoMarshalInterface
w/ MSHLFLAGS_TABLESTRONG
/ CoUnmarshalInterface
/ IStream::Seek(0, 0)
/ CoReleaseMarshalData
en vez de CoGetInterfaceAndReleaseStream
/CoGetInterfaceAndReleaseStream
, para desamar la misma interfaz tantas veces como sea necesario sin liberar la transmisión.
Los escenarios de almacenamiento de almacenamiento más complejos (y posiblemente más eficientes) son posibles, que involucran el almacenamiento local de subprocesos. Sin embargo, creo que sería una exageración. No hice ningún momento, pero creo que la sobrecarga de CoMarshalInterThreadInterfaceInStream
/CoGetInterfaceAndReleaseStream
es realmente bajo.
Dicho esto, si necesita mantener un estado que almacena cualquier recurso u objeto que pueda requerir afinidad de subprocesos, aparte de las interfaces com antes mencionadas, no debe Marque su objeto como ThreadingModel=Both
o agregar el FTM.