PostMessage возвращает «неверный дескриптор окна» в потоке - PullRequest
6 голосов
/ 13 августа 2010

Фон: Я использую OmniThreadLibrary для загрузки хранимых процедур ADO в пакетном режиме в фоновом режиме. Я делаю немного хитроумные вещи, меняя соединение после открытия SP, но это кажется довольно надежным. Я использую PostMessage для отправки сообщений обратно в форму вызова, и это работает в моих тестовых приложениях. Каналы связи Primoz работают для меня, я использую их для связи между потоками, но для нашего основного приложения я пытаюсь избежать этой зависимости, используя стандартные вызовы PostMessage, как мы делаем в других местах приложения.

Проблема: К сожалению, когда я помещаю это в наше основное приложение, вызовы PostMessage в потоке начинают давать сбой с 1400: недопустимый дескриптор окна.

Я добавил дополнительные вызовы PostMessage и код для регистрации, чтобы попытаться найти проблему, но сейчас у меня нет идей. Код является стандартным:

const WM_PW_ADLQUEUEEMPTY = WM_USER + 11;
...
if PostMessage (OwnerHandle, WM_PW_ADLPROGRESS, QueueID, 10) then
    pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to  ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+')     OK for Queue ' + IntToStr (QueueID))
else
    pwDebugLog ('TADLQueue.Run WM_PW_ADLPROGRESS send to  ' + IntToHex (OwnerHandle, 8) + ' (IsWindow '+BoolToStr(IsWindow(OwnerHandle),true)+') failed for Queue ' + IntToStr (QueueID));

Но журнал для серии звонков мне не очень показателен. обратите внимание, что четыре шестнадцатеричные цифры после времени - это идентификатор потока из GetCurrentThreadID.

15:41:53.221 1614  TpwAsyncDataLoader.RunQueue WM_PW_ADLPROGRESS send to  00A5110C (IsWindow True)    OK for Queue -6
15:41:53.265 13B4  TADLQueue.Run WM_PW_ADLPROGRESS send to  00A5110C (IsWindow True)     OK for Queue -6
15:41:53.554 13B4  TADLQueueManager.WriteSysErrorMessageToDatabase Postmessage   00A5110C (IsWindow False)  failed with 1400  Invalid window handle

Может кто-нибудь пролить свет на это? Я смущен тем, как дескриптор окна может стать недействительным, когда я смотрю на него, но вот как он выглядит для меня.

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

Ответы [ 2 ]

4 голосов
/ 13 августа 2010

В некоторых случаях дескриптор воссоздается, особенно когда вы меняете флажки окна.Это может быть то, что происходит в вашем приложении.

Все, что я нашел до сих пор о воссоздании дескриптора окна, это этот пост от Аллена Бауэра, но я уверен, что читаю более подробный, написанный Питером Боуом.К сожалению, я не могу найти это.

Наконец, вам нужно знать о случаях, когда ваш дескриптор может нуждаться в воссоздании.Это может произойти, если окружающая форма или дескриптор родительского компонента проходит процесс воссоздания.Вплоть до более поздних выпусков Windows единственным способом изменения некоторых флагов окна было уничтожение дескриптора и воссоздание с новыми флагами в вызове CreateWindowEx ().Есть много компонентов, которые все еще делают это.Вы знаете, если вы находитесь в воссозданной ситуации, проверив (csRecreating в ControlState).

Редактировать

На самом деле не посты Петра I, которые я имел в виду, но они могут дать вам некоторыесвежие идеи.

Форма не будет иметь дескриптора, пока вы не покажете ее в первый раз (если что-то в последовательности загрузки формы не запрашивает дескриптор), но дескриптор не уничтожается при скрытии формы иесли вы не сделаете что-то, что заставит форму воссоздать дескриптор, например, изменить стиль границы или значки границ, или вызвать RecreateWnd самостоятельно, дескриптор останется прежним.

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

и

Существует также тот факт, что дескриптор окна формыуничтожается и воссоздается при назначении его родительскому свойству.Это также уничтожает и воссоздает маркеры для всех элементов управления в форме.

0 голосов
/ 15 апреля 2016

У меня была похожая проблема (но в VC ++ 2010), и я не нашел решения ни на одном форуме, поэтому выкладываю его здесь, надеюсь, это поможет:

Выпуск:

  • Создание темы,
  • Передача ручки HWnd
  • В теме, PostMessage выдает ошибку 1400 (неверный дескриптор), хотя указатель был равен с дескриптором, как видно из потока пользовательского интерфейса (с GetSafeHWnd ()).

Решение:

  1. Не передавать дескриптор, но родительский класс CDialog (Ex)
  2. В этом классе есть член m_hWnd, который будет выполнять эту работу

Вот пример (Cpp), извините за беспорядок приведения.

// In the worker thread
ThreadParam *threadParam = (ThreadParam*)param

// This is ugly because my pointer is a void *, to avoid one more forward declaration
CCoreGenDlg *dlg = static_cast<CCoreGenDlg *>(threadParam->ptr);

// Post
bool b = PostMessage(dlg->m_hWnd ,1221,0,(LPARAM)message);

Приветствия

...