Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

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).


Наверх

Титульная страница Поиск, карта сайта Написать письмо