msvsmon.exe exceptions when debugging CE applications in VS explained

If you have ever done any application development for Windows Embedded Compact (aka "CE" or "WEC") devices then you no doubt have seen this ugly exception coming out of the serial port of the device:

Exception 'Raised Exception' (0x80010108): Thread-Id=050f001e(pth=ae493688), Proc-Id=044a001e(pprc=ae48a4a0) 'msvsmon.exe', VM-active=044a001e(pprc=ae48a4a0) 'msvsmon.exe'

It has been a long standing issue that so far nobody has really taken the time to investigate or explain, so let's change that!

Today I loaded up a WEC2013 debug kernel, started conmanclient and created a default "ConsoleApplication" targeting my device. I pressed F10 and waited for PB to break because of the exception. The callstack at the time of the exception is:

COREDLL!xxx_RaiseException(unsigned long 0x406d1388, unsigned long 0x00000000, unsigned long 0x00000004, const unsigned long * 0x009ffd48)  line 1347
VSDEBUGENG.IMPL!43e2da82()
KERNEL!APICall + 142 bytes
COREDLL!TlsSetValue(unsigned long 0x00000001, void * 0x00000001)  line 260 + 6 bytes
COREDLL!ThreadBaseFunc(unsigned long (void *) 0x00000000, void * 0x00000000)  line 1269 + 6 bytes

So, msvsmon.exe (VSDEBUGENG.IMPL) is actually raising the exception! But why?

Setting a breakpoint on the call to RaiseException allowed me to step in and see the arguments passed to RaiseException:

    dwExceptionCode     0x406d1388
    dwExceptionFlags    0x00000000
    nNumberOfArguments  0x00000004
-    lpArguments,4      0x009ffd48
    [0]    0x00001000
    [1]    0x43e8794c
    [2]    0x0526001a
    [3]    0x00000000

A quick google search on "Exception 0x406d1388" turned up this little gem of information: "How to: Set a Thread Name in Native Code".

So, what this RaiseException call actually does is simply setting the thread name by sending the VS debugger the event name through this exception. The reason it does this is so it is easier for you (the developer) to identify which thread you are debugging. This could be very useful when debugging multi-threaded applications; open the Threads window (CTRL-ALT-H) to see the thread names.

Knowing what we know now, we can see that the above 4 arguments are indeed matching what is listed on the MSDN page:

-    lpArguments,4      0x009ffd48
    [0]    0x00001000    dwType: Must be 0x1000.
    [1]    0x43e8794c    szName: Pointer to name (in user addr space).
    [2]    0x0526001a    dwThreadID: Thread ID (-1=caller thread).
    [3]    0x00000000    dwFlags: Reserved for future use, must be zero.

Long story short; I don't think there is any way to avoid this exception (even if MS would be interested in 'fixing' this). It's an annoyance, but not more than that. The exception can be safely ignored. It should not have any (or at least not have a big) impact on your debugging experience.

Comments

Michel

Thanks for the explanation. This is yet another example of why you are a true leader in the industry.

Bruce