The application called an interface that was marshalled for a different thread.

Another one from someone sending a comment:

I came across your blog and was wondering if what to do when encountering above error message in an application program.

The error occurs once in a while when printing out from a Windows application.

Is there some setting missing in computer administration or in the Registry or can it only be solved in the code?

Appreciate your help!

Yech.  This one's ugly.  It's time for Raymond's Psychic Powers(tm) of detection.

If you take the error message text and look inside winerror.h, you'll see that the error message mentioned is exactly the text for the RPC_E_WRONG_THREAD error.

If you then do an MSDN search for RPC_E_WRONG_THREAD, the first hit is: "INFO: Explanation of RPC_E_WRONG_THREAD Error".  Essentially, the error's a side effect of messing up threading models.  I wrote about them about 18 months ago in "What are these threading models, and why do I care?". 

So, knowing that the app's dutifully reporting RPC_E_WRONG_THREAD to the user, what had to have happened to cause this error?

It means that the application did a CoCreateInstance of an Single Threaded Apartment COM object in one thread, but used it in another thread.

Given the comment that it only happens once in a while, we can further deduce that the application called CoCreateInstance from a thread in a pool of worker threads, and attempted to use it in a function queued to that pool of threads (otherwise it would fail all the time and the author of the app would have found the problem).  Given that it only happens when printing (an operation that's usually handled in a background thread), this makes sense.

Unfortunately for the person who asked the question, they don't really have any choice but to contact the vendor that created the app and hope that they have an update that fixes the problem, because there's no workaround you can do outside the app :(

Comments

  • Anonymous
    August 25, 2005
    I was going to suggest - for the vendor - CoMarshalInterThreadInterfaceInStream, but remembered that the reverse process, calling CoGetInterfaceAndReleaseStream, uh, releases the stream object. Can you pair CoUnmarshalInterface with CMITIIS?

    If not, using the Global Interface Table - available in all versions of Windows that are commonly in use - would seem to be the right option. Actually it's probably simpler than using CMITIIS/CGIARS anyway. Look up IGlobalInterfaceTable.
  • Anonymous
    August 25, 2005
    Mike, of course you can. Here is the function does (probably badly mangled by this blog software):

    HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(
    REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm)
    {
    ULARGE_INTEGER xpos;
    LARGE_INTEGER seekto;
    HRESULT hres;

    hres = CreateStreamOnHGlobal(0, TRUE, ppStm);
    if (FAILED(hres)) return hres;
    hres = CoMarshalInterface(*ppStm, riid, pUnk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);

    memset(&seekto,0,sizeof(seekto));
    IStream_Seek(*ppStm,seekto,SEEK_SET,&xpos);

    return hres;
    }

    So you can see that you can simply call CoUnmarshalInterface to match up with the CoMarshalInterface.
  • Anonymous
    August 25, 2005
    I knew I should have checked the disassembly first. On Windows XP SP2, at least, all CoGetInterfaceAndReleaseStream does is call CoUnmarshalInterface, then call Release() on the stream interface pointer. How obvious.
  • Anonymous
    August 25, 2005
    The real solution for the vendor would be to use the Global Interface Table. Publishing the interface to the GIT gives you back a context agnostic cookie that can be used to retrieve the interface from a different context; COM's plumbing decides whether you get back a raw pointer or a proxy to the object depending on which context your calling “GetInterfaceFromGlobal” from (This only works inproc BTW).

    Interestingly this error will (normally) only happen when you get a proxy to the object either from the original activation request or an interface marshalled back from an existing interface method call. This is because proxies are notorious for enforcing access from the correct context. User code (on the whole) isn't so vigilant.

    This probably means the original activation request got a pointer to a proxy rather than a raw pointer and subsequently tried to use it from another context without marshalling it first (either by using the GIT or any other means).

    Just a quick question Larry:

    The activation request surely doesn't have to be from the STA? Isn't it quite feasible the client activated the object from an MTA and it was subsequently used from an STA. The proxy should still stipulate the call came from the context for which the proxy was created?

    Graham
  • Anonymous
    August 26, 2005
    Graham, you're right - both on the "right" solution and the fact that all that had to happen was a mismatch of threading models.

    In fact, under the covers, I believe that the GIT uses CoMarshalInterfaceInStream etc.


    I didn't want to include mitigations to the problem, they've been covered elsewhere (including in my linked threading models article).