What are the rules for CoMarshalInterface and CoUnmarshalInterface?

Raymond Chen

Last time, we looked at the rules for Co­Marshal­Inter­Thread­Interface­In­Stream and Co­Get­Interface­And­Release­Stream, the functions you use for sharing an object with another thread in the sample case where you there is only one other thread you want to share with, and you need to share it only once. Let’s continue with the Q&A.

What if I want to unmarshal more than once?

In this case, you use the more general Co­Marshal­Interface. You can pass the MSHLFLAGS_TABLE­STRONG flag to indicate that you want to be able to unmarshal many times. In that case, you need to tell COM when you are finished unmarshaling so it knows when to clean up, because it cannot assume that you are finished after the first unmarshal. The pattern goes like this:

  • On the originating apartment, create an empty stream.
  • On the originating apartment, call Co­Marshal­Interface with the empty stream and the MSHLFLAGS_TABLE­STRONG flag.
  • Transmit a copy of the stream to each of the threads you want to share the object with. (You need to use a copy so that the multiple threads don’t all try to use the same stream and step on each other’s stream position. Alternatively, you could be clever and use the same stream, but use a mutex or other synchronization object to make sure only one thread uses the stream at a time.)
  • The receiving threads rewind the stream copy to the beginning.
  • The receiving threads call Co­Get­Interface­And­Release­Stream to reconstitute the object from the stream and release the stream.¹
  • The receiving threads happily accesses the object.
  • When the originating apartment decides that it doesn’t want to share the object any more, it calls Co­Release­Marshal­Data to tell COM to clean up all the bookkeeping.
  • The originating apartment destroys the master stream.

What is the relationship between Co­Marshal­Inter­Thread­Interface­In­Stream and Co­Marshal­Interface?

The Co­Marshal­Inter­Thread­Interface­In­Stream function is a helper function that does the following:

  • Create­Stream­On­HGlobal.
  • Co­Marshal­Interface with MSHCTX_INPROC and MSHLFLAGS_NORMAL.
  • Rewinds the stream to the beginning.
  • Returns the stream.

Similarly, Co­Get­Interface­And­Release­Stream is a helper function that does

  • Co­Unmarshal­Interface
  • IStream::Release

Since a one-shot marshal to another thread within the same process is by far the most common case, the helper functions exist to let you get the job done with just one function call on each side.

What if I want to marshal only once, but to another process?

Again, you need to use the more general Co­Marshal­Interface function. This time, you pass the MSHCTX_LOCAL flag if you intend to marshal to another process on the same computer, or the MSHCTX_DIFFERENT­MACHINE flag if you intend to marshal to another computer. For the marshal flags, use MSHLFLAGS_NORMAL to indicate that you want a one-shot marshal. The recipient can unmarshal with Co­Get­Interface­And­Release­Stream as before.

What if I want to marshal to another process and unmarshal more than once?

This is just combining the two axes. On the marshaling side, you do the same as a one-shot cross-process marshal, except you pass the MSHLFLAGS_TABLE­STRONG flag to indicate that you want to be able to unmarshal many times. You then send copies of that stream to all your intended recipients, and each of them calls Co­Get­Interface­And­Release­Stream, just like before.

Can you marshal a proxy? Does it get all Inception-like?

Go ahead and marshal a proxy. COM detects that you’re marshaling a proxy and does the Right Thing. For example, if you marshal a proxy back to the originating thread, then when you unmarshal, you get a direct pointer again!

¹ If the thread wants to unmarshal from the stream than once, it could call Co­Unmarshal­Interface and not release the stream immediately. Then each time it wants to unmarshal from the stream, it calls Co­Unmarshal­Interface again, releasing the stream only when it has decided that it will not do any more unmarshaling. This seems silly because once you unmarshal the first time, you can just Add­Ref the pointer if you want to make another copy. I guess this is for the case where the thread wants to pass the stream off to yet another thread? Definitely a fringe case.

0 comments

Discussion is closed.

Feedback usabilla icon