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

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

Messages & TThread [D6, Win2k]


Страницы:   1 2 3

Dynamit ©   (2002-07-25 14:01:00) 

Уважаемые Мастера, помогите: не обрабатываются сообщения, посланные потоку (ThreadID) командой PostThreadMessage.
Вот как тут не плакать :(


Digitman   (2002-07-31 09:52:00) [1]

Упс !

А ведь ты прав !!!!
Я ведь тоже - вот тундра то !) - не обратил внимания на with QueryForm )))))

Ну молодец ! Что ж сказать еще ) ...


Dynamit   (2002-07-31 09:37:00) [2]

Эх, далеко мы забрались, а проблема оказалась сверху!!

Шел я вчера с работы и думал, ну и понял вдруг, что QueryForm у меня тоже является объектом, а значит имеет метод TObject.Dispatch() !!! Так что пришел сегодня на работу, поставил
self.Dispatch() и все заработало как надо!!!!

Интересно, додумался бы я, если бы вчера не просматривал выполнение процедур в ассемблерном виде в дебаггере? Да еще реализацию Application.Run...

Ну вот вроде бы и все! Спасибо за помощь и науку - мне все, что здесь было сказано сильно пригодится!

Dynamit


Digitman   (2002-07-30 16:21:00) [3]

Ну да) ... в момент брейкпойнта - когда ж еще ? Нужно ж выяснить, что реально происходит ... открывай system.pas на реализации TObject.Dispatch() - там всего-то дюжина строчек - шагай инструкция за инструкцией и контролируй, что ожидается и что есть на самом деле ... только так истина выясняется в таких смутных моментах !


Dynamit   (2002-07-30 15:54:00) [4]

У меня все константы определяются в DataModule и более нигде!

Насчет сокрытия чего-либо - это не ко мне - мне скрывать нечего.
Я же говорил, что модуль привел полностью, только процедуры создания временных таблиц и копирования из одной таблицы в другую не стал приводить, да и не этот модуль самый большой в программе ;)

Вот только трудновато сейчас с AS/400 - жара, виснут паразитки.

А окно CPU можнопопробовать. Его когда дергать - прямо в момент брекпойнта на Dispatch()?


Digitman   (2002-07-30 15:05:00) [5]

Dispatch() должен работать ! Просто обязан ! Иначе вся VCL и ее производные - коту, извините, под хвост ...

Эх, заглянуть бы в окно CPU у тебя при брейкпойнте на Dispatch() ! Все бы встало на свои места и "глюк" твой сразу бы вычислили в 2 счета .. А так - упаришься вычислять лажу ... Весь проект целиком нужно видеть ... и модуль с TQueryThread - в первую очередь ... чего-то ты недоговариваешь ..

Кстати, а не переопределил ли ты иным образом константу PM_THREADCMD в модуле, где декларирован класс TQueryThread ?

Ну , если ты настолько ленив, чтобы не копать до истины, бросай Dispatch() и делай case...of




Dynamit   (2002-07-30 14:42:00) [6]

Все отработало на ОК!!

Так может быть сделать нечто похожее с Dispatch()???


Digitman   (2002-07-30 14:26:00) [7]

Вот проблема-то !(

Ну так тогда :

var
pMsg: PMessage;
...

While (Not Terminated) and GetMessage(lpmsg,0,0,0) Do
begin
pMsg := @lpmsg.Message
case lpmsg.Message of
PM_THREADCMD: PMThreadCmd(pMsg^);
PM_ENDTHREAD: Terminate;
end;
end;

PM_THREADCMD: PMThreadCmd(pMsg^);

>>не понимаю я как это

Ну ты сравни две структуры : TMsg и TMessage ! Они очень похожи !
а Dispatch() требует в кач-ве параметра просто адрес . Некий адрес, по которому находится некий UINT. Тот же некий адрес может быть интарпретирован тобой и как адрес структуры TMessage, ппо смещению +0 которой лежит тот же самый UINT


Dynamit   (2002-07-30 14:13:00) [8]


> PM_THREADCMD: PMThreadCmd(@lpmsg.Message);

Да я бы довел, но ведь и на эту строку та же ошибка!
Да и потом не понимаю я как это
message: UINT
будет одного типа с TMessage, а тем более адрес...
ну трудно мне это понять - вот и спрашиваю не боясь сойти за тупого !


Digitman   (2002-07-30 14:02:00) [9]

Мда .....


PM_THREADCMD: PMThreadCmd( @lpmsg.Message);

Мне каждую очепятку свою исправлять ? Или таки доведешь до ума своими силами ? Взялся за API, а в типах - плаваешь ...


Dynamit   (2002-07-30 13:50:00) [10]

Вот на эту строку
PM_THREADCMD: PMThreadCmd(lpmsg.Message);
Компилятор дает такую ошибку:
[Error] UQThread.pas(114): Types of actual and formal var parameters must be identical

Т.е. получается, что lpmsg.Message имеет разный тип с TMessage?

А насчет

> Synchronize(SetSQLReady);

я думал убрать, да руки не доходят... как нибудь... или сейчас!
Спасибо за напоминание!


Lmatveev   (2002-07-30 13:49:00) [11]

Прошу прощения, если мой совет не в кассу, но я бы на вашем месте воспользовался пакетом GALA Library ( http://gurin.tomsknet.ru/gala.html). Там все, что касается работы с потоками уже реализовано, и вместо того, чтобы отлаживать системные функции, можно заняться программированием непосредственно функционала приложения


Digitman   (2002-07-30 13:37:00) [12]

>>Synchronize(SetSQLReady);

Зачем Synchronize ? С каким неразделяемым ресурсом ты работаешь в SetSQLReady() ? Не вижу ничего, кроме PostMessage()

Ну, это так , к слову ...

Вообще же - ну не вижу я никаких явных плюх ... Если дело до Dispatch() действительно доходит и в момент вызова код сообщения действительно равер константе PM_THREADCMD или PM_ENDTHREAD, то все должно работать !

Хорошо, пробуй на время вот такой (полноэквивалентный) заменитель Dispatch() :


While (Not Terminated) and GetMessage(lpmsg,0,0,0) Do
case lpmsg.Message of
PM_THREADCMD: PMThreadCmd(lpmsg.Message);
PM_ENDTHREAD: Terminate;


Dynamit   (2002-07-30 12:59:00) [13]


> А на Dispatch(), говоришь, точно отрабатывает брейкпойнт
> при посылке сообщения ?


Точно обрабатывает (из кода видно - там еще сообщенице выводится)
Вот наиболее полный код (убрано только совсем лишнее)
--------------
unit UQThread;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, DBTables, BDE;

type
TFQThread = class(TForm)
QInd: TQuery;
SThr: TSession;
DB1: TDatabase;
Table1: TTable;
private
{ Private declarations }
UCnt, UCmd: LongInt;
UNum: Integer;
UHndl: THandle;
USQL: String;
Function BathMv: LongInt;
procedure CrtRcv;
public
{ Public declarations }
end;

Var
UniqueNumber: Integer;

Function CreateQuery(const Number: Integer; const ASQL: String; AHndl: THandle): THandle;

implementation

Uses UData, UMain;

{$R *.DFM}

Type TQueryThread = class(TThread)
private
QueryForm: TFQThread;
MessageText: string;
procedure DisplayMessage;
procedure SetThreadId;
procedure Term(Sender: TObject);
Procedure SetSQLReady;
Procedure PMEndThread(var Msg: TMessage); message PM_ENDTHREAD;
Procedure PMThreadCmd(var Msg: TMessage); message PM_THREADCMD;
protected
procedure Execute; override;
public
constructor Create(AQueryForm: TFQThread);
end;

constructor TQueryThread.Create(AQueryForm: TFQThread);
begin
QueryForm := AQueryForm;
FreeOnTerminate := True;
inherited Create(True);
end;

procedure TQueryThread.Execute;
Var
lpmsg: MSG;
i: LongBool;
lpMsgBuf: PChar;
begin
SetThreadId;
Try
try
with QueryForm do
begin
SThr.SessionName := Format("A%s%x", [SThr.Name,UNum]);
DB1.SessionName := SThr.SessionName;
DB1.DatabaseName := Format("A%s%x", [DB1.Name,UNum]);
QInd.SessionName := DB1.SessionName;
QInd.DatabaseName := DB1.DatabaseName;

While (Not Terminated) Do
Begin

If UCmd=1 Then
Begin
QInd.SQL.Text:=USQL;
MessageText := USQL;
Synchronize(DisplayMessage);
Table1.TableName:=Format("Tmp\Rcv%x",[UNum]);
Table1.SessionName:=SThr.SessionName;
CrtRcv; // Создание таблицы-приемника
UCnt:=BathMv; // Получение данных
Synchronize(SetSQLReady); //Данные готовы
UCmd:=0;
End Else
Begin
i:=GetMessage(lpmsg,0,0,0);
If Integer(i)<0 Then
Begin
GetMem(lpMsgBuf,1000);
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER Or FORMAT_MESSAGE_FROM_SYSTEM,
Nil,GetLastError(), 0,
lpMsgBuf,0,Nil);
MessageText:=String(lpMsgBuf);
Synchronize(DisplayMessage);
FreeMem(lpMsgBuf);
End Else
If Integer(i)>0 Then
Begin
Dispatch(lpmsg.Message);
MessageText:="Message - OK "+#13+IntToStr(Integer(i))+" CMDMSG="+IntToStr(PM_THREADCMD);
Synchronize(DisplayMessage);
End;

End;
End;
End;
except
on E: Exception do
begin
{ Display any error we receive on the status line }
MessageText := Format("Хмм "+QueryForm.QInd.SQL.Text+#13+" %s: %s.", [E.ClassName, E.Message]);
Synchronize(DisplayMessage);
end;
End;
Finally
QueryForm.QInd.Close;
QueryForm.SThr.Active:=False;
QueryForm.DB1.Connected:=False;

End;
end;

procedure TQueryThread.DisplayMessage;
begin
ShowMessage(MessageText);
end;

Procedure TQueryThread.SetSQLReady;
Begin
PostMessage(QueryForm.UHndl,PM_DATAREADY,QueryForm.UNum,QueryForm.UCnt);
End;

procedure TQueryThread.Term(Sender: TObject);
Begin
PostMessage(QueryForm.UHndl,PM_THREADDEAD,QueryForm.UNum,0);
End;

procedure TQueryThread.PMEndThread(var Msg: TMessage);
begin
self.Terminate;
end;

Procedure TQueryThread.PMThreadCmd(var Msg: TMessage);
Begin
MessageText := "Cmd = 1";
Synchronize(DisplayMessage);
QueryForm.QInd.SQL.Text:=DMData.TmpSQL;
QueryForm.UCmd:=1;
End;

Function TFQThread.BathMv: LongInt;
{...}
end;

procedure TFQThread.CrtRcv;
{...}
end;


Function CreateQuery(const Number: Integer; const ASQL: String; AHndl: THandle): THandle;
var
QueryForm: TFQThread;
begin
QueryForm := TFQThread.Create(Application);
QueryForm.Visible:=False;
With TQueryThread.Create(QueryForm) Do
Begin
Result:=ThreadId;
QueryForm.UNum:=Number;
QueryForm.UCmd:=1;
QueryForm.USQL:=ASQL;
QueryForm.UHndl:=AHndl;
OnTerminate:=Term;
Resume;
End;
end;

procedure TQueryThread.SetThreadId; //Это для проверки ThreadId = GetCurrentThreadId
begin
DMData.AThr[QueryForm.UNum]:=GetCurrentThreadId;
end;

end.


Digitman   (2002-07-30 12:22:00) [14]

А на Dispatch(), говоришь, точно отрабатывает брейкпойнт при посылке сообщения ?


Приведи еще раз декларацию и реализацию класса TQueryThread c учетом всех проделанных тобой изменений на последний момент. Бизнес-логику, разумеется, можешь не указывать, заменяя на {...}


Dynamit   (2002-07-30 11:30:00) [15]

Структура MSG - не менял, взял как есть.
Ставлю точку останова внутрь PMThreadCmd(), мало того, внутри этой процедуры еще и вывод на экран сообщения (естествено через Synchronize).


> >>"Вывел на экран константу PM_THREADCMD - тоже 1135 "
> А чего ее выводить-то ? Ты ж ее сам и определил ! Или не
> так ?

Я ее определил как
PM_ENDTHREAD=WM_USER+110;
PM_THREADCMD=WM_USER+111;

А т.к. не знаю чему равен WM_USER, пришлось вывести на экран.


Digitman   (2002-07-30 11:03:00) [16]

Структура MSG у тебя взята из Windows.pas ? Тогда - ну хоть убей - это должно работать !
Ты точку останова действительно не "ловишь" в теле процедуры PMThreadCmd() ? Или даже не думал поставить ее туда, ограничившись попыткой пошагово пройти Dispatch() ?

>>"Вывел на экран константу PM_THREADCMD - тоже 1135 "
А чего ее выводить-то ? Ты ж ее сам и определил ! Или не так ?


Dynamit   (2002-07-30 09:38:00) [17]

Я действительно не понимаю здесь что и как объявлять :(
У меня объявлено так:
Var
lpmsg: MSG;

Далее
GetMessage(lpmsg,0,0,0)
и наконец
Dispatch(lpmsg.Message)


Digitman   (2002-07-30 09:23:00) [18]

tagMSG = packed record
hwnd: HWND;
message: UINT;
wParam: WPARAM;
lParam: LPARAM;
time: DWORD;
pt: TPoint;
end;
TMsg = tagMSG;
{$EXTERNALSYM MSG}
MSG = tagMSG;

TMessage = packed record
Msg: Cardinal;
case Integer of
0: (
WParam: Longint;
LParam: Longint;
Result: Longint);
1: (
WParamLo: Word;
WParamHi: Word;
LParamLo: Word;
LParamHi: Word;
ResultLo: Word;
ResultHi: Word);
end;

About TObject.Dispath :

...
The Message parameter is untyped. The only assumption Dispatch makes about the data in Message is that the first two bytes contain a message ID, that is an integer-that determines which message handler Dispatch calls to handle the message. Although any kind of data can be passed to Dispatch, most TObject descendants expect a message record such as TMessage or a specific message-record type.
...


Digitman   (2002-07-30 09:15:00) [19]

Слушай, а как это у тебя поле lpmsg.Message стало кардинального типа ? Это поле д.б. типа запись TMessage, у которой, в свою очередь, есть поле msg - вот оно-то и является кардинальным значением кода сообщения . Давай-ка проверяй все объявления : метод TObject.Dispatch() принимает нетипизированный параметр по ссылке, возможно, ты передаешь ему далеко не структуру TMessage, а что-то другое ... а компилятор "промолчит" - ему по-барабану ..


Dynamit   (2002-07-30 09:08:00) [20]

Да !!!


Страницы:   1 2 3

Наверх

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