当来自另一个线程的消息时,Winapi控件不适当地访问内存

时间:2011-05-29 23:53:34

标签: c multithreading winapi exception controls

我知道我不应该从没有创建它的线程访问控件,但我还是尝试了它并且得到了一个非常特殊的错误。我在汇编中做过,每个人都讨厌阅读,所以这里是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;
    };
}

信不信由你,这可以完美地从一个没有创建hListbox的线程直到最后一个项目,此时列表框通过读取字符串[size + 1]导致访问冲突。它在UI线程(创建列表框的线程)中抛出异常,忽略工作线程的异常处理程序。 SendMessage()不恰当地返回0而不是列表框错误代码。

我通过从工作线程向UI线程的窗口发送用户定义的消息来完成这项工作,该窗口又将具有相同参数的LB_ADDSTRING消息发送到完全相同的列表框,并且它完美地工作。当从UI线程发送消息时,异常还没有发生,但这是一个随机的差异,我对正确的工作代码感到紧张。任何人都知道列表框首先在字符串的空终止结束之外访问内存,以及我可以做些什么来阻止它这样做?

1 个答案:

答案 0 :(得分:0)

由于SendMessage()将调用序列化到接收线程,因此我希望在UI线程上发生异常,因为那是添加字符串的那个。

MSDN SendMessage: '返回值指定消息处理的结果;这取决于发送的消息。这不是列表框中的错误代码,除非消息处理程序将其放在那里,否则不会将异常放入消息字段中。

如果你用一个1号的字符串打电话,最后'size'会发生什么?将'size'设置为-1,即。不是假的?

RGDS, 马丁