Microsoft KB Archive/172314

= INFO: Explanation of RPC_E_WRONG_THREAD Error =

Article ID: 172314

Article Last Modified on 7/11/2005

-

APPLIES TO


 * Microsoft OLE 4.0, when used with:
 * Microsoft Platform Software Development Kit-January 2000 Edition

-



This article was previously published under Q172314



SUMMARY
A RPC_E_WRONG_THREAD error occurs when a thread calls via an interface pointer which is for a proxy object that does not belong to the thread's apartment.



MORE INFORMATION
See the REFERENCES section at the bottom of this article for more information on the workings of the COM threading models. Briefly, an interface pointer held by a client thread can be of one of the following types:


 * A direct pointer to the object. In this case, the object is in the same apartment as the client thread. Also, no system (COM) provided code is in between the caller and the callee. -or-


 * A pointer to a proxy. In this case, the object is in a different apartment from the client thread. Also, system (COM) provided code sits in between the caller and the callee.

Whether the client has one type of pointer or the other is dependent on such factors as whether the object is in-process or out-of-process, and if the object is in-process, whether the threading model of the object is compatible with the apartment model of the calling thread. See the article in the REFERENCES section below for more information.

When a proxy object is created, it is associated with the apartment that creates it. If a pointer to a proxy object is somehow passed to a thread which does not belong to the apartment (e.g., via a shared global variable), and if this thread then calls through this pointer, the call returns a RPC_E_WRONG_THREAD error. COM returns this error because the proxy object is invalid for a thread that does not belong to the apartment that created the proxy object. The following is also an error. One apartment holds a direct pointer to the object. It then transfers the pointer to another apartment via a global variable (without marshaling). The second apartment calls through this pointer. This call is indeed in error. However, COM has no way of detecting this unlike the proxy case.

The correct way of transferring an interface pointer (either a direct pointer or a proxy pointer) from one apartment to another is via COM's marshaling mechanism. The source apartment can call CoMarshalInterThreadInterfaceInStream to marshal the interface pointer to a shared (global) stream. The destination apartment can unmarshal this interface pointer by calling CoGetInterfaceAndReleaseStream. This action creates a proxy that is valid for the destination apartment. Note that COM's proxy objects are "smart" enough to avoid the problem of "proxy chaining." That is, if apartment A marshals an interface pointer to apartment B, and if B marshals the same to C, the proxy object that is created in C is directly connected to the stub in A. Therefore, when C calls through the proxy pointer it is calling A directly and B is not in the picture. COM also prevents the "circular" interface-passing problem. That is, if A marshals to B and B marshals to C, and C then marshals to A, then the resultant pointer in A is a direct pointer, not a proxy pointer.

NOTE: The RPC_E_WRONG_THREAD error can occur even when all the COM rules are followed and no interfaces are explicitly passed between apartments without marshaling. This happens when an in-process object aggregates with the system provided Free Threaded Marshaler (FTM) by calling CoCreateFreeThreadMarshaler and also holds pointers to COM proxies. Typically in-process objects that can be marked as Threading Model "Both" use the FTM. When an interface pointer to such an object is marshaled from one apartment to another, a direct pointer to the object is passed (no proxy/stub is created). This is the benefit of using the FTM, however this also results in an RPC_E_WRONG_THREAD error if the object's implementation tries to call through the proxy pointer on a non-original-apartment thread. There is no good workaround to this problem, in general, objects that use the FTM should not themselves be clients of out-of-apartment COM servers. If they need to do this infrequently, then they should pass the call to a forwarding object that does not use the FTM. If they do this frequently, they should just mark themselves "free" or "both" and not use the FTM. When an interface pointer to such an object is marshaled to another apartment, the system creates the proxys/stub code needed as the object no longer aggregates with the FTM.

