Win API control accesses memory inappropriately when messaged from another thread
I know I'm not supposed to access a control from a thread that didn't create it, but I tried it anyway and got a really peculiar error. I did it in assembly, which everybody hates reading, so here's the equivalent code in C:
/* Function that returns the number of characters after startOfItem
that are not some delimeter. startOfItem[maxSize] is guaranteed to
be at a valid address and to be a delimiter. The function is defined
elsewhere and works perfectly. */
unsigned int getSizeOfItem(char* startOfItem, unsigned int maxSize);
/* This function runs in a worker thread. It has an exception handler that is
omitted here for clarity, and because it is never run anyway. */
void itemizeAndAddToListbox (HWND hListbox, char* strings, unsigned int size) {
while (size) {
unsigned int sizeOfItem = getSizeOfItem(strings, size);
strings[sizeOfItem] = 0; //overwrite the delimiting character with null
SendMessage( hListbox, LB_ADDSTRING, (WPARAM) 0, (LPARAM) strings );
/* passing a pointer to a different thread is a no-no, but SendMessage
does not return until the message is processed, so no disposal issues
are possible. And I happen to know that all addresses from *strings
to strings[sizeOfItem] remain valid. */
strings += sizeOfItem+1;
size -= sizeOfItem+1;
};
}
Believe it or not, this works perfectly from a thread that did not create hListbox until the very last item, at which point the listbox causes an access violation by reading strings[size+1]. It throws the exception in the UI thread (the one that created the listbox), ignoring the worker thread's exception handler. SendMessage() inappropriately returns 0 instead of the listbox error code.
I made this work by sen开发者_JAVA技巧ding user-defined messages from the worker thread to the UI thread's window, which in turn sends the LB_ADDSTRING message with the very same parameters to the very same listbox, and it works perfectly. The exception hasn't happened yet when the message is sent from the UI thread, but that's such a random difference that I'm nervous about the proper working code as well. Anybody know what the listbox is doing accessing memory beyond the null-terminated end of the string in the first place, and what I can do to prevent it from doing so?
Since the SendMessage() serializes the call onto the receiving thread, then I would expect the exception to happen on the UI thread because that's the one adding the string.
MSDN SendMessage: 'The return value specifies the result of the message processing; it depends on the message sent.' This is not the listbox error code from teh exception will not be put into the message field unless the message-hander puts it there.
What happens to 'size' at the end if you call in with one string of size 1? Will 'size' not be set to -1, ie. not false?
Rgds, Martin
精彩评论