This article was previously published under Q172314
A RPC_E_WRONG_THREAD error occurs when a thread calls via an interfacepointer which is for a proxy object that does not belong to the thread'sapartment.
See the REFERENCES section at the bottom of this article for moreinformation on the workings of the COM threading models. Briefly, aninterface pointer held by a client thread can be of one of the followingtypes:
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 onsuch factors as whether the object is in-process or out-of-process, and ifthe object is in-process, whether the threading model of the object iscompatible with the apartment model of the calling thread. See the articlein the REFERENCES section below for more information.
When a proxy object is created, it is associated with the apartment thatcreates it. If a pointer to a proxy object is somehow passed to a threadwhich does not belong to the apartment (e.g., via a shared globalvariable), and if this thread then calls through this pointer, the callreturns a RPC_E_WRONG_THREAD error. COM returns this error because theproxy object is invalid for a thread that does not belong to the apartmentthat created the proxy object. The following is also an error. Oneapartment holds a direct pointer to the object. It then transfers thepointer to another apartment via a global variable (without marshaling).The second apartment calls through this pointer. This call is indeed inerror. However, COM has no way of detecting this unlike the proxy case.
The correct way of transferring an interface pointer (either a directpointer or a proxy pointer) from one apartment to another is via COM'smarshaling mechanism. The source apartment can callCoMarshalInterThreadInterfaceInStream() to marshal the interface pointer toa shared (global) stream. The destination apartment can unmarshal thisinterface pointer by calling CoGetInterfaceAndReleaseStream(). This actioncreates a proxy that is valid for the destination apartment. Note thatCOM's proxy objects are "smart" enough to avoid the problem of "proxychaining." That is, if apartment A marshals an interface pointer toapartment B, and if B marshals the same to C, the proxy object that iscreated in C is directly connected to the stub in A. Therefore, when Ccalls through the proxy pointer it is calling A directly and B is not inthe 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 rulesare followed and no interfaces are explicitly passed between apartmentswithout marshaling. This happens when an in-process object aggregates withthe system provided Free Threaded Marshaler (FTM) by callingCoCreateFreeThreadMarshaler 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 fromone apartment to another, a direct pointer to the object is passed (noproxy/stub is created). This is the benefit of using the FTM, however thisalso results in an RPC_E_WRONG_THREAD error if the object's implementationtries to call through the proxy pointer on a non-original-apartment thread.There is no good workaround to this problem, in general, objects that usethe 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 aforwarding 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. Whenan interface pointer to such an object is marshaled to another apartment,the system creates the proxys/stub code needed as the object no longeraggregates with the FTM.
For additional information, please see the following article in theMicrosoft Knowledge Base:
150777 INFO: Descriptions and Workings of OLE Threading Models