Без дополнительной информации вам будет сложно помочь вам отладить это, особенно, почему он работает в одной службе, но не в другой. Однако:
Вместо того, чтобы исправить проблему в вашем коде, вы можете вообще удалить все окна и использовать PostThreadMessage() вместо PostMessage(). Для правильной работы сообщений вам нужен цикл сообщений, но не обязательно получение окон.
Редактировать: Я пытаюсь ответить на все ваши ответы за один раз.
Во-первых - если вы хотите сделать вашу жизнь легкой, вы должны действительно проверить OmniThreadLibrary на gabr. Я не знаю, работает ли он в приложении Windows, я даже не знаю, было ли это еще попыток. Вы можете спросить на форуме. Тем не менее, он имеет множество отличных функций и заслуживает внимания, хотя бы для эффекта обучения.
Но, конечно, вы также можете запрограммировать это для себя, и вам придется иметь дело с версиями Delphi до Delphi 2007. Я просто добавлю некоторые фрагменты из нашей внутренней библиотеки, которая развивалась на протяжении многих лет и работает в нескольких десятках программы. Однако я не утверждаю, что это ошибка. Вы можете сравнить его с вашим кодом, и, если что-нибудь выйдет, не стесняйтесь спрашивать, и я попытаюсь уточнить.
Это упрощенная Execute() метода рабочего потока базового класса:
procedure TCustomTestThread.Execute;
var
Msg: TMsg;
begin
try
while not Terminated do begin
if (integer(GetMessage(Msg, HWND(0), 0, 0)) = -1) or Terminated then
break;
TranslateMessage(Msg);
DispatchMessage(Msg);
if Msg.Message = WM_USER then begin
// handle differently according to wParam and lParam
// ...
end;
end;
except
on E: Exception do begin
...
end;
end;
end;
Важно, чтобы не допустить исключения получить необработанные, так что есть обработчик исключений верхнего уровня вокруг все. Что вы делаете с исключением, это ваш выбор и зависит от приложения, но все исключения должны быть пойманы, иначе приложение будет прекращено. В службе ваш единственный вариант, вероятно, для их регистрации.
Существует специальный метод, чтобы инициировать отключение нити, потому что поток должен быть разбужен, когда он находится внутри GetMessage():
procedure TCustomTestThread.Shutdown;
begin
Terminate;
Cancel; // internal method dealing with worker objects used in thread
DoSendMessage(WM_QUIT);
end;
procedure TCustomTestThread.DoSendMessage(AMessage: Cardinal;
AWParam: integer = 0; ALParam: integer = 0);
begin
PostThreadMessage(ThreadID, AMessage, AWParam, ALParam);
end;
Проводка WM _ QUIT вызовет сообщение чтобы выйти. Однако существует проблема, заключающаяся в том, что код в классах потомков может полагаться на правильные обращения к сообщениям Windows во время остановки потока, особенно когда используются интерфейсы COM. Вот почему вместо простого WaitFor() следующий код используется для освобождения всех запущенных потоков:
procedure TCustomTestController.BeforeDestruction;
var
i: integer;
ThreadHandle: THandle;
WaitRes: LongWord;
Msg: TMsg;
begin
inherited;
for i := Low(fPositionThreads) to High(fPositionThreads) do begin
if fPositionThreads[i] <> nil then try
ThreadHandle := fPositionThreads[i].Handle;
fPositionThreads[i].Shutdown;
while TRUE do begin
WaitRes := MsgWaitForMultipleObjects(1, ThreadHandle, FALSE, 30000,
QS_POSTMESSAGE or QS_SENDMESSAGE);
if WaitRes = WAIT_OBJECT_0 then begin
FreeAndNil(fPositionThreads[i]);
break;
end;
if WaitRes = WAIT_TIMEOUT then
break;
while PeekMessage(Msg, 0, 0, 0, PM_REMOVE) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
end;
except
on E: Exception do
// ...
end;
fPositionThreads[i] := nil;
end;
end;
Это в переопределен BeforeDestruction() метода, потому что все нити должны быть освобождены до деструктора класса контроллера потомков начинает освобождать любые объекты, которые могут использовать потоки.
getMessage() зависает нить, без исключения, просто зависает. Любая идея почему? – Codebeat
@Erwinus: 'GetMessage()' является блокирующим вызовом, поэтому он будет возвращаться только в том случае, если он может вернуть сообщение, или цикл сообщения больше не работает. Вы уверены, что вы вызвали 'PostThreadMessage()', и для правильного потока? – mghie