-
Доброго времени суток! Столкнулся с проблемой перехвата сообщений или событий окном созданным средствами WinAPI.<br> В общем я создаю класс окна в одном модуле(wnd.pas) и дочерний класс в другом(main.pas), при этом у меня одна локальная процедура WndProc для всех окон. Я пробовал прописывать в дочернем классе процедуру для перехвата сообщений как делал это раньше на VCL procedure WMPaint(var Msg : TWMPaint); message wm_paint; Ничего не получилось, наверное я неправильно понимаю как работает такой способ перехвата, может быть надо присваивать каждому классу свой хэндл, ведь сообщения посылаются владельцу хэндла, но я не знаю как такое реализовать. <br> Теперь пробую сделать события как на VCL (onPaint), но тоже пока безуспешно. Заранее спасибо!
-
У Вас должен после CreateWindowEx запускацца цикл обработки сообщений...до Application.Terminate. Советую глянуть примеры на masm32
-
Показывай код
-
Цикл обработки сообщений у меня для всех окон один - это
function WndProc(wnd: HWND; msg: integer; wParam: wParam; lParam: lParam): lResult; stdCall;
begin
result:=0;
case msg of
wm_Destroy:
begin
PostQuitMessage(0);
Exit
end;
else Result:=DefWindowProc(wnd,msg,wparam,lparam)
end; end;
Прописывать обработку сообщений здесь не получиться т.к. окон может быть много, да и доступа к модулю main.pas из модуля wnd.pas нет и быть не должно(пишу с расчетом на то, что в будующем буду пользоваться этим модулем и в других программах). Единственный вариант - это прописать там события класса tApp, который создается в модуле wnd.pas и тот в свою очередь будет обрабатывать события главного окна, а оно обрабатывать события дочернего окна и т.д.
tFormClass = class of tFrm;
tApp = class
private
MainForm: tFrm;
public
constructor Create;
destructor Destroy; override;
procedure CreateForm(FormClass: tFormClass; var FormName);
procedure Run;
end;
И по этому я хотел прописать перехват только нужных сообщений в дочернем классе формы который описывается в main.pas
tMainForm = class(tFrm)
procedure FormCreate;
private
procedure Load;
procedure Draw;
protected
procedure WMPaint(var Msg : TWMPaint); message wm_paint;
end;
Но процедура WMPaint не выполняется даже если в WndProc отсылать сообщение о перересовке. Так же покажу процедуру для создания формы в классе tApp, потому, что этот код мне не полностью понятен, я его переписывал из forms.pas, может быть я тут допустил ошибку, но он работает, форма создается.
procedure tApp.CreateForm(FormClass: tFormClass; var FormName);
var
Form: tFrm;
begin
Form:=tFrm(FormClass.NewInstance);
tFrm(FormName):=Form;
try
Form.Create;
except
tFrm(FormName) := nil;
raise;
end;
if MainForm = nil then begin
MainForm := TFrm(Form);
end;
end;
-
> Цикл обработки сообщений у меня для всех окон один - это
Это не цикл, не выдумывай.
-
ну да, не цикл - обработка сообщений. Цикл здесь и однин для всей программы
procedure tApp.Run;
var
Msg: tMsg;
begin
if not MainForm.CreateWnd then exit;
while GetMessage(Msg, 0, 0, 0) do
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end
end;
или его для каждой формы свой нужно создавать??? создание формы выглядит так
function tFrm.CreateWnd: boolean;
var
wc: tWndClassEx;
begin
result:=true;
zeromemory(@wc,sizeof(wc));
with wc do begin
cbSize:=sizeof(wc);
style:=cs_hredraw or cs_vredraw;
wc.cbClsExtra:=0;
wc.cbWndExtra:=0;
lpfnWndProc:=@WndProc;
wc.hInstance:=HInstance;
wc.hIcon:=LoadIcon(0,idi_application);
hCursor:=LoadCursor(0, idc_Arrow);
wc.hbrBackground:=COLOR_BTNFACE+1;
wc.lpszMenuName:=nil;
lpszClassName:=cName;
end;
if RegisterClassEx(wc)=0 then
result:=false
else
handle:=CreateWindowEx(WS_EX_TOPMOST or WS_EX_TOOLWINDOW, cName, capt, WS_POPUP, left, top, width, height, 0, 0, HInstance, nil);
if handle=0 then begin
result:=false;
exit
end;
show
end;
-
> Цикл здесь и однин для всей программы
Не для "всей программы", а для для окон, созданных в тек.треде.
> function tFrm.CreateWnd: boolean;
Сравни с
procedure TApplication.CreateHandle;
и сделай выводы.
-
Сравню, когда окажусь за компьютером, а пока могу только предполагать или ждать прямого ответа на вопрос.
-
А ради чего вся эта жуткая каша из окон и форм тобой заварена ?
-
Пишу на чистом WinAPI, получаю мелкий размер программы, больший контроль над программой, учусь, получаю удовольствия от программирования больше чем на VCL...
-
> учусь, получаю удовольствия
Похвально)
-
> Galiaf (18.02.08 13:45) [9]
> Пишу на чистом WinAPI, получаю мелкий размер программы,
Понятно. Мазохист. Лучше получи удовольствие от книги. Например, Чарльз Калверт. Дельфи Х: Энциклопедия пользовавателя.
-- Regards, LVT.
-
О чем книга? Сколько весит?
-
> Galiaf (18.02.08 14:15) [12]
> О чем книга? Сколько весит?
Про дельфи, вестимо. Кг 1.5 бумаги.
-- Regards, LVT.
-
А по-подробнее можно?
-
> Galiaf (18.02.08 14:38) [14]
> А по-подробнее можно?
Подробнее можно в библиотеке.
-- Regards, LVT.
-
Вернемся к теме: ближайшие 8-9 часов компьютера я не увижу, а по этому прошу написать мне код процедуры TApplication.CreateHandle; для дальнейшего изучения. Спасибо.
-
procedure TApplication.CreateHandle;
var
TempClass: TWndClass;
SysMenu: HMenu;
begin
if not FHandleCreated
and not IsConsole then
then
begin
FObjectInstance := WinUtils.MakeObjectInstance(WndProc);
FObjectInstance := Classes.MakeObjectInstance(WndProc);
WindowClass.lpfnWndProc := @DefWindowProc;
if not GetClassInfo(HInstance, WindowClass.lpszClassName, TempClass) then
begin
WindowClass.hInstance := HInstance;
if Windows.RegisterClass(WindowClass) = 0 then
raise EOutOfResources.Create(SWindowClass);
end;
FHandle := CreateWindow(WindowClass.lpszClassName, PChar(FTitle),
WS_POPUP or WS_CAPTION or WS_CLIPSIBLINGS or WS_SYSMENU
or WS_MINIMIZEBOX,
GetSystemMetrics(SM_CXSCREEN) div 2,
GetSystemMetrics(SM_CYSCREEN) div 2,
0, 0, 0, 0, HInstance, nil);
FTitle := '';
FHandleCreated := True;
SetWindowLong(FHandle, GWL_WNDPROC, Longint(FObjectInstance));
if NewStyleControls then
begin
SendMessage(FHandle, WM_SETICON, 1, GetIconHandle);
SetClassLong(FHandle, GCL_HICON, GetIconHandle);
end;
SysMenu := GetSystemMenu(FHandle, False);
DeleteMenu(SysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
DeleteMenu(SysMenu, SC_SIZE, MF_BYCOMMAND);
if NewStyleControls then DeleteMenu(SysMenu, SC_MOVE, MF_BYCOMMAND);
end;
end;
-
Это мазохизм? Зачем пытаться повторять VCl, в API принято писать несколько по другому.
-
С этого места по-подробнее
-
> Galiaf (19.02.08 01:26) [19]
Ключевой момент во всей этой бодяге, что ты затеял, - ф-ция MakeObjectInstance().
-
> Сергей М. © (19.02.08 10:01) [20]
Щас копну в этом направлении, хотя как приспособить его у меня пока не знаю
-
function MakeObjectInstance(Method: TWndMethod): Pointer; - кучка непонятного кода, буду разбираться...
-
Полностью переписал процедуру CreateHandle, все равно не форма не хочет перехватывать сообщения. Не исключаю тот вариант, что я сделал это неправильно.
-
> Не исключаю тот вариант, что я сделал это неправильно
Как ни странно, я тоже не исключаю)
-
без посторонней помощи не разберусь, тупо переписывая CreateHandle, только больше запутываюсь, нужно теперь все удалять и попытаться вставить только нужное в свой код, потому что переписывание результатов не дало. Кто-нибудь сталкивался с такой задачей или вместе со мной на догадках строите свои предложения?
-
Скопируй этот код к себе в проект:
const
InstanceCount = 313;
type
PObjectInstance = ^TObjectInstance;
TObjectInstance = packed record
Code: Byte;
Offset: Integer;
case Integer of
0: (Next: PObjectInstance);
1: (Method: TWndMethod);
end;
type
PInstanceBlock = ^TInstanceBlock;
TInstanceBlock = packed record
Next: PInstanceBlock;
Code: array[1..2] of Byte;
WndProcPtr: Pointer;
Instances: array[0..InstanceCount] of TObjectInstance;
end;
var
InstBlockList: PInstanceBlock;
InstFreeList: PObjectInstance;
function StdWndProc(Window: HWND; Message, WParam: Longint;
LParam: Longint): Longint; stdcall; assembler;
asm
XOR EAX,EAX
PUSH EAX
PUSH LParam
PUSH WParam
PUSH Message
MOV EDX,ESP
MOV EAX,[ECX].Longint[4]
CALL [ECX].Pointer
ADD ESP,12
POP EAX
end;
function CalcJmpOffset(Src, Dest: Pointer): Longint;
begin
Result := Longint(Dest) - (Longint(Src) + 5);
end;
function MakeObjectInstance(Method: TWndMethod): Pointer;
const
BlockCode: array[1..2] of Byte = (
$59,
$E9);
PageSize = 4096;
var
Block: PInstanceBlock;
Instance: PObjectInstance;
begin
if InstFreeList = nil then
begin
Block := VirtualAlloc(nil, PageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Block^.Next := InstBlockList;
Move(BlockCode, Block^.Code, SizeOf(BlockCode));
Block^.WndProcPtr := Pointer(CalcJmpOffset(@Block^.Code[2], @StdWndProc));
Instance := @Block^.Instances;
repeat
Instance^.Code := $E8;
Instance^.Offset := CalcJmpOffset(Instance, @Block^.Code);
Instance^.Next := InstFreeList;
InstFreeList := Instance;
Inc(Longint(Instance), SizeOf(TObjectInstance));
until Longint(Instance) - Longint(Block) >= SizeOf(TInstanceBlock);
InstBlockList := Block;
end;
Result := InstFreeList;
Instance := InstFreeList;
InstFreeList := Instance^.Next;
Instance^.Method := Method;
end;
procedure FreeObjectInstance(ObjectInstance: Pointer);
begin
if ObjectInstance <> nil then
begin
PObjectInstance(ObjectInstance)^.Next := InstFreeList;
InstFreeList := ObjectInstance;
end;
end;
.. Теперь смотри внимательно, как этот код используется:
TFrm = class(..)
..
hWnd: THandle;
FDefWndProc: Pointer;
..
procedure DefaultHandler(var Message); override; ..
procedure WndProc(var Message: TMessage);
..
function CreateWnd: boolean;
function DestroyWnd: boolean;
..
end;
function TFrm.CreateWnd: boolean;
begin
..
hWnd:=CreateWindowEx(..);
..
SetWindowLong(Result, GWL_WNDPROC, Longint(MakeObjectInstance(WndProc)));
..
end;
function TFrm.DestroyWnd: boolean;
var
Instance: Pointer;
begin
..
Instance := Pointer(GetWindowLong(Wnd, GWL_WNDPROC));
DestroyWindow(Wnd);
if Instance <> @DefWindowProc then FreeObjectInstance(Instance);
..
end;
procedure TFrm.WndProc(var Message: TMessage);
begin
with Message do
case Msg of
...
else
Dispatch(Msg);
end
end;
procedure TFrm.DefaultHandler(var Message);
begin
with TMessage(Message) do begin
..
Result := CallWindowProc(@WndProc, FHandle, Msg, WParam, LParam);
..
end;
end;
-
Благодарю. До завтра компьютера мне не видеть, а по этому буду изучать вышеизложенный код на экране мобильного телефона. А откуда этот код взят? Личные наработки, взятый откуда-то или только что собранный?
-
> откуда этот код взят?
Тот что до "смотри внимательно" - из classes.pas, один в один.
Тот что ниже - "только что собранный", считай что это "экстракт" из кучи VCL-кода, который ты не понимаешь, но от которой ты желаешь избавиться.
-
> Galiaf (19.02.08 01:26) [19] > С этого места по-подробнее
Ну объясни, на кой этот огород. Что из этого должно получится? Пытаешься создать свой велосипед (VCL)? Ну для начала посмотри хотя бы не исходники, которые тебе предлагают мазохисты, а "С"-шные. Перевести их на Pascal небольшой труд, но зато поймешь стратегию написания программ на API. Но если же упрямо будешь городить то, что здесь предлагаешь, то очень скоро твои программы перестанут быть "маленькими".
-
И чем же исходники "мазахистов" хуже исходников на сях? Если я пишу на API в первую очередь для того, чтобы столкнуться со сложностями и преодалив их положить что-либо в свою копилку опыта, то почему бы не перелопатить тот же VCL?
-
А про стратегию написания программ на API хотелось бы почитать по-подробнее
-
А какой смысл городить всю эту конструкция классов? Можно и проще и быстрее.
-
Ну уж, если так сильно прижало, воспользуйтесь библиотекой KOL.
-
Пользовался - не интересно. Как можно сделать проще и быстрее?
-
> Сергей М. © (19.02.08 12:57) [26]
Огромное спасибо! Все работает, теперь моя форма умеет рисовать кружок, при этом весит 17 920 kb, понял не все по этому мне еще предстоит по сидеть, по изучать вышеприведенный код. Есть там пару ошибок но незначительные (путанница с именами переменных). Буду рад если мне объяснят что такое и для чего используется Instance и что за hInstance, читал про это в книгах, хэлпах но от человека нормального объяснения не слышал, по этому могу только думать о нем только как о каком-то описателе приложения, который зачем-то нужен.
-
> что такое и для чего используется Instance и что за hInstance
Instance - в общем случае экземпляр чего-либо.
Префикс h обычно означает handle.
Означает и используется по-разному, в зависимости от тек.контекста.
-
Разницу между регулярной функцией/процедурой и функциональным/процедурным методом Делфи-объекта понимаешь ?
Как представлен метод любого объекта в памяти Делфи-приложения понимаешь ?
-
нет
-
Вот с этого и начни.
-
регулярная функция/процедура, имеется в виду цикл?
-
> имеется в виду цикл?
Причем здесь цикл ?
Я говорю о Pascal и Object Pascal.
-
Короче, ты взялся за непосильную (пока) для тебя задачу.
И вот этим вот
> получаю мелкий размер программы, больший контроль над программой, > учусь, получаю удовольствия от программирования больше > чем на VCL
свое откровенное дилетантство в этих вопросах прикрывать не надо)
Так что тебе прямая дорога в "Начинающие")
-
я не отрицаю свое дилетантство, но то чем я якобы прикрываюсь - правда.
-
> Galiaf © (23.02.08 01:48) [43] > > я не отрицаю свое дилетантство, но то чем я якобы прикрываюсь > - правда. >
Ну так купи и читай книжки. Если не знаешь какие, то именно это и спроси. P.S. Я удивляюсь "долготерпению" Сергей М. © .
-
Не понимаю, зачем столько критики??? Не знаю как сделать, спросил на форуме, получил ответ, все работает. А дилетант я или нет, какая собственно разница? Или спрашивать на форумах и учиться на форумах можно только профи, а дилетантам можно только спрашивать из какой книги это вычитать?
-
> Galiaf © (24.02.08 03:14) [45] > > Не понимаю, зачем столько критики???
Тебе "ответ" нужен или "готовый код"? За "готовый код" нужно платить! Уж извини. Сей "готовый" код, как правило, добыт "плотом и кровью". Ну или за него уже кто-то заплатил. И теперь хочет получить свои денежки обратно, да ещё и с прибылью! Шпаргалки забудь. Это было до реальной жиэни.
-
>>Galiaf Для начала не обязательно лезти в дебри VCL и вникать в MakeObjectInstance Можно при создании окна сохранять соответствие handle и адреса объекта "обертки" например вмассиве, затем в общей WndProc по wnd:HWND восстонавливать адрес объекта и вызывать уже WndProc объекта обертки
-
> просто так (26.02.08 00:35) [47]
Что-то похожее хотел сделать до того как задал вопрос но сомнения по поводу правильности заставили обратиться на форум.
-
> Galiaf © (27.02.08 23:42) [48] > > > > просто так (26.02.08 00:35) [47] > > Что-то похожее хотел сделать до того как задал вопрос но > сомнения по поводу правильности заставили обратиться на > форум. >
Лучше бы те сомнения заставили читать учебники.
-
> Что-то похожее хотел сделать до того как задал вопрос но > сомнения по поводу правильности заставили обратиться на > форум.
откуда сомнения в правильности?
-
> Германн © (28.02.08 02:54) [49]
Не стоит делать из хорошего форума помойку! Просьба проследовать в конференцию "Прочее".
> откуда сомнения в правильности?
Я "самоучка" и свой код воспринимаю как догадки, каждые новые решения для меня сомнительны, даже если работают я ищу информацию о том как это делают опытные люди. То, что я хотел сделать - это создать массив хэндлов для доступа к каждой форме и просто по массиву проверять, где что нужно рисовать. По-моему глупое и в корне неправильное решение проблемы. Но это способ работал бы 100%. P.S. ну 99% ну или 99%.
-
Жаль, что автор такой упрямый. Я ведь предлагал реальную помощь при написании подобных программ, причем без оплаты, как некоторые предлагают. У меня достаточный опыт при написании не самых навороченных программ, но надеюсь автор на такое пока не замахивается. Но вот все равно никак не могу понять, ну зачем сразу же, без достаточного опыта, пытаться перелопатить под себя VCL? Для начала попробуй писать как я показывал, а потом по мере накопления опыта можно создавать и свои классы, наподобии того же VCL.
-
> dsoft © (01.03.08 23:20) [52]
Не могу согласитться.
> зачем сразу же, без достаточного опыта, пытаться перелопатить > под себя VCL
Для того, чтобы получить тот самый опыт.
-
> Galiaf © (29.02.08 03:13) [51] > > > > Германн © (28.02.08 02:54) [49] > > Не стоит делать из хорошего форума помойку! > Просьба проследовать в конференцию "Прочее". >
Согласен. Сделай, пожалуйста, соответствующие выводы для себя.
-
К сожалению автор вряд ли чему научится. Не имея соответствующих навыков пытаться построить "ракету"...
-
> К сожалению автор вряд ли чему научится. Не имея соответствующих > навыков пытаться построить "ракету"...
эт почему? винапи освоит маленько, поймет как не надо делать кстати Galiaf, юзай object, зачем тебе class
-
> кстати Galiaf, юзай object, зачем тебе class
Для начала пусть узнает разницу между этими понятиями.
-
> кстати Galiaf, юзай object, зачем тебе class
До того как задать вопрос на форуме спрашивал у друга в чем разница между ними, пришли к выводу что object - это базовай класс... до того разговора использовал именно object но после начал использовать class, т.к. подумал, что object - это лишнее. В чем моя/наша ошибка?
> Согласен. Сделай, пожалуйста, соответствующие выводы для > себя.
И я согласен с вами. Уже давно считаю ветку закрытой, но отвечаю на коментарии.
-
> просто так (02.03.08 10:05) [56]
Если class (и все что с ним связано) автору дан в "бесплатную нагрузку", почему бы этим не воспользоваться ? Минусов от этого никаких - одни плюсы)
-
> пришли к выводу что object - это базовай класс...
Не совсем так. Лучше почитать литературу.
|