![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
CreateThread и GetMessage - error [D5, Win2k]
Призрак © (2006-05-31 18:04:00)Я создал поток с помощью CreateThread и в нём использую GetMessage. Но, как особо указано в хелпе, GetMessage может возвращать ТРИ значения - TRUE, FALSE и -1 ! Поэтому когда я пишу if GetMessage=-1 - компилер говорит что "ошибка преобразования Variant", а если обращаться с ним как с булевым - то программа вылетает, - как я понял, потому что у потока нет очереди мессаджей и возвращается этот самый -1... Что я не так делаю?
кстати, при этом если убрать GetMessage и заставить поток крутиться по кругу - то PostMessage из основного потока завершается с ошибкой 1444 "Неправильный Thread ID", хотя я проверял - он такой же что и при создании thread'а...
И ещё одна штука которая может быть имеет значение... Поток этот создаётся не в основном потоке, а в конструкторе дополнительного. сейчас покажу :)
Основной поток:
thr:=TThr.Create
и потом при нажатии кнопки
if PostThreadMessage(thr.ThirdThreadHandle, WM_USER+1, 1, 1) then messagebox(0, pchar(SysErrorMessage(GetLastError) +' : '+ inttostr(thr.ThirdThreadHandle)), 'Oh Shit', MB_OK);
соответственно, выскакивает мессаджбокс с надписью - "Неверный идентификатор потока команд: 96 ". В хелпе сказано - это бывает, если у потока нет очереди сообщений, и чтобы его создать - достаточно из потока обратиться к GetMessage... но при обращении к нему ошибка выскакивает...
Второй поток (НЕ тот в котором ошибка!)
TThr = class(TThread)
ThirdThreadHandle: THandle;
ThirdThread: DWORD; // Кстати, интересно как это можно использовать...
constructor Create;
function ThirdThreadProc: Longint;
protected
procedure Execute; override;
end;
constructor TThr.Create;
begin
inherited Create(false);
ThirdThreadHandle:=CreateThread(nil, 256, @TPort.ThirdThreadProc, nil, 0, ThirdThread);
messagebox(0, pchar(inttostr(WriteThreadHandle)), 'Thread ID', MB_OK); // Выскакивает "96"
end;
procedure TThr.Execute;
begin
repeat
if not GetExitCodeThread(ThirdThreadHandle, r) then messagebox(0, 'OH SHIT'#$0D#$0A'Error stopping ThirdThread', 'ERROR', MB_OK);
until r<>STILL_ACTIVE;
messagebox(0, pchar(inttostr(r)), 'Result', MB_OK);
CloseHandle(ThirdThreadHandle); // Это уже неважно, потому что ThirdThread не кончится
end;
и вот третий поток:
function TPort.WriteThreadProc: Longint;
var m: TMsg;
begin
result:=10; // Заранее
messagebox(0, 'Started', ThirdThread', MB_OK); // Видно, что поток стартовал
repeat
if not WaitMessage then messagebox(0, 'WaitMessage = false!', 'Error', MB_OK);
GetMessage(m, NULL, 0, 0); // Вот она бяка...
until m.message=WM_USER+1; // Завершится как только поймает то сообщение
messagebox(0, 'Finished', 'ThirdThread', MB_OK); // И я это увижу
result:=m.wParam + m.lParam; // И программа увидит
end;
Ещё немного о "бяке"... Ошибка по-любому случается, хоть обращайся к нему прямо так, хоть пиши if not getmessage, хоть if getmessage=-1 (правда, в этом случае компилер сразу несовместимые типы ловит...)
Может, надо просто очередь сообщений создать?.. но как?!..
MBo (2006-06-01 06:56:00) [1]> да вроде у меня подходящая функция... или нет?..
DWORD WINAPI ThreadProc( LPVOID lpParameter);
это аналогично паскалевскому
function ThreadProc(lpParameter: Pointer): DWord; stdcall;
У тебя же использована не регулярная функция, а метод класса. По счастью, в данном случае звезды так сошлись, что, как ты говоришь, работает, но так будет не всегда...
P.S. А вообще - надо ли смешивать VCL-ные методы работы с потоками (TTHread) и апишные (CreateThread)?
P.P.S. Да и вместо CreateThread обычно стоит использовать BeginThread
Джо (2006-05-31 21:55:00) [2]> [6] Призрак © (31.05.06 21:32)
> *попробовал*
>
> А в хелпе ясно написано что NULL ! :( спасибо!..
Этот хелп подразумевает использование C++.
Призрак (2006-05-31 21:32:00) [3]*попробовал*
УРААААА надо было 0 указать... :) А в хелпе ясно написано что NULL ! :( спасибо!..
begin...end (2006-05-31 21:14:00) [4]> Призрак © (31.05.06 21:02) [3]
> Integer(GetMessage()) ошибку не убрало, - да мне в общем-
> то неважно что оно возвращает...
Странно. По исходному вопросу сложилось иное впечатление...
> и значит надо указывать там NULL
Нет, там надо указывать 0.
> А WaitMessage нужен для того чтобы сначала подождать когда
> мессаг появится...
А GetMessage не ждёт?
> а то кто его знает что будет если на пустую очередь сделать
> GetMessage...
Я уже написал в [1], что будет. При первом вызове GetMessage (или других функций, относящихся к выборке сообщений) очередь создастся.
Призрак (2006-05-31 21:05:00) [5]MBoда вроде у меня подходящая функция... или нет?.. или что-то не так?..
Призрак (2006-05-31 21:02:00) [6]
> Если сообщение послано успешно, выводим сообщение с расшифровкой
> GetLastError. Очень смешно.
простите, опечатка, в программе написано правильно - если НЕ успешно...
> У PostThreadMessage первый параметр -- глобальный идентификатор
> потока, а не его дескриптор.
а-а... та самая DWORD-штука, которую я думал куда девать... понятно... -_-
сейчас попробую...
ага.
1) Заменил дескриптор на идентификатор и ошибка там больше не появляется. 08-)
2) Integer(GetMessage()) ошибку не убрало, - да мне в общем-то неважно что оно возвращает... Отсюда делаю вывод что проблема в том что NULL - "оригинально". :) В хелпе написано, как я понял, что если указать NULL - то "GetMessage возвращает все мессаги которые относятся к любому из окон потока или ко всему потоку, например, отправленные через PostThreadMessage". ...Я чего-то не понимаю?? вроде как я отправляю мессаг PostThreadMessage'ем и значит надо указывать там NULL...
3) А WaitMessage нужен для того чтобы сначала подождать когда мессаг появится... а то кто его знает что будет если на пустую очередь сделать GetMessage...
MBo (2006-05-31 20:54:00) [7]CreateThread нужно передавать поточную функцию определенного типа, а не абы что.
begin...end (2006-05-31 20:35:00) [8]> Призрак © (31.05.06 18:04)
> Поток этот создаётся не в основном потоке, а в конструкторе
> дополнительного.
А конструктор дополнительного работает в том потоке, из которого он вызывается. То есть, скорее всего, в основном. Значит, и третий поток создаётся в основном.
> if PostThreadMessage(thr.ThirdThreadHandle, WM_USER+1, 1,
> 1) then messagebox(0, pchar(SysErrorMessage(GetLastError)
> +' : '+ inttostr(thr.ThirdThreadHandle)), 'Oh Shit', MB_OK)
Если сообщение послано успешно, выводим сообщение с расшифровкой GetLastError. Очень смешно.
У PostThreadMessage первый параметр -- глобальный идентификатор потока, а не его дескриптор.
> if not WaitMessage
Это зачем?
> GetMessage(m, NULL, 0, 0);
NULL? Оригинально...
> if getmessage=-1
var
R: Integer;
begin
R := Integer(GetMessage(...));
case R of
0: ...; // FALSE
-1: ...; // ERROR
else
...; // NONZERO И <> -1
end
end
> Может, надо просто очередь сообщений создать?.. но как?!
Очередь сообщений создаётся автоматически при вызове GUI-функций (в том числе и GetMessage).