Элемент управления Win API неправильно обращается к памяти при передаче сообщений из другого потока - PullRequest
0 голосов
/ 30 мая 2011

Я знаю, что не должен обращаться к элементу управления из потока, который его не создавал, но я все равно попробовал и получил действительно странную ошибку.Я сделал это в сборке, которую все ненавидят читать, поэтому вот эквивалентный код на 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 до самого последнего элемента,в этот момент список вызывает нарушение прав доступа при чтении строк [размер + 1].Он генерирует исключение в потоке пользовательского интерфейса (который создал список), игнорируя обработчик исключений рабочего потока.SendMessage () неправильно возвращает 0 вместо кода ошибки списка.

Я сделал эту работу, отправив пользовательские сообщения из рабочего потока в окно потока пользовательского интерфейса, которое, в свою очередь, отправляет сообщение LB_ADDSTRING с тем же самымПараметры к тому же списку, и он работает отлично.Исключение еще не произошло, когда сообщение отправлено из потока пользовательского интерфейса, но это такая случайная разница, что я также нервничаю по поводу правильного рабочего кода.Кто-нибудь знает, что список делает, обращаясь к памяти за концом строки с нулевым символом в конце, и что я могу сделать, чтобы предотвратить это?

1 Ответ

0 голосов
/ 30 мая 2011

Поскольку SendMessage () сериализует вызов в принимающем потоке, я ожидаю, что исключение произойдет в потоке пользовательского интерфейса, потому что это тот, который добавляет строку.

MSDN SendMessage: 'Возвращаемое значение указывает результат обработки сообщения; это зависит от отправленного сообщения. Это не код ошибки списка из исключения, который не будет помещен в поле сообщения, если обработчик сообщений не поместит его туда.

Что произойдет с 'size' в конце, если вы позвоните с одной строкой размера 1? Будет «размер» не будет установлен в -1, т.е. не ложь?

Rgds, Martin

...