Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2003.12.16;
Скачать: CL | DM;

Вниз

Создание окна   Найти похожие ветки 

 
rel_   (2003-10-21 08:45) [0]

Мастера, необходимо сгенерить дочернее окно на контроле.

В общем виде делаю так: в конструкторе получаю Parent и затем вызываю след. методы:

type
TWndProc = function(wnd:HWND; Msg : Integer; Wparam:Wparam; Lparam:Lparam):Lresult of object; stdcall;
...

FWndProc : TWndProc;
...

function TGame.InitClass : boolean;
begin

wndClass.style:=cs_hredraw or cs_vredraw;
wndClass.lpfnWndProc:=@FWndProc;
wndClass.cbClsExtra:=0;
wndClass.cbWndExtra:=0;
wndClass.hInstance:=HInstance;
wndClass.hIcon:=LoadIcon(0,idi_application);
wndClass.hCursor:=LoadCursor(0,idc_arrow);
wndClass.hbrBackground:=COLOR_BTNFACE+1;
wndClass.lpszMenuName:=nil;
wndClass.lpszClassName:="TGame";

Result:=Boolean(RegisterClass(wndClass)<>0);
end;

function TAnyClass.MakeWindow(): HWND;
begin
result :=
CreateWindow("TAnyClass","",
WS_VISIBLE or WS_CHILD or WS_CLIPSIBLINGS,
10, 10, 200, 200,
FParent.Handle, 0, HInstance, nil );
end;

Так вот MakeWindow() возвращает "0" - соответственно, ничего не создаётся. Подскажите, что делаю не так (в примере не приведены процедуры сбора сообщении, отображения окна и т.д.).


 
[lamer]Barmaglot ©   (2003-10-21 09:26) [1]

Ну вопервых любимый вопрос Игоря Шевченко - что возвращает GetLastError?
Что за класс окна TAnyClass?


 
rel_   (2003-10-21 10:04) [2]

to [lamer]Barmaglot © !!! спасибо за участие !!!

написал следующее:
if CreateWindow(...) =0
then ShowMessage(IntToStr(GetLastError()));

Вернул 1400


 
Guerrillero ©   (2003-10-21 10:08) [3]

ShowMessage(SysErrorMessage(GetLastError));


 
[lamer]Barmaglot ©   (2003-10-21 10:14) [4]

1400L ERROR_INVALID_WINDOW_HANDLE

Исходя из этого ищи ошибку...


 
rel_   (2003-10-21 10:33) [5]

to Guerrillero ©
Пишет : недопустимый дескриптор окна.


 
Игорь Шевченко ©   (2003-10-21 10:35) [6]

rel_ (21.10.03 10:33)


> Пишет : недопустимый дескриптор окна.


Проверь, чему равен FParent.Handle, сдается мне, что нулю...


 
rel_   (2003-10-21 10:49) [7]

to Игорь Шевченко ©
нет, не равен (там 6 знаков аж).

Может я скину код - там всего 3 процедуры. Что-то я делаю коряво!!!???


 
[lamer]Barmaglot ©   (2003-10-21 10:53) [8]

Скидывай, покрайней мере можно попытаться посмотреть...


 
rel_   (2003-10-21 11:02) [9]

unit GameUn;

interface
uses Windows,Messages,ShellAPI, Controls, Types, SysUtils, Dialogs;

type
TWndProc = function(wnd:HWND; Msg : Integer; Wpar:Wparam; Lpar:Lparam):Lresult of object; stdcall;

TGame = class
private
FParent : TWinControl;
FHandle : HWND;
wndClass : TWndClass;
FWndProc : TWndProc;

procedure Paint(wnd:HWND; Msg : Integer; Wpar:Wparam; Lpar:Lparam);

function InitClass : boolean;
function WndProc(wnd:HWND; Msg : Integer; Wpar:Wparam; Lpar:Lparam):Lresult; stdcall;
function MakeWindow(): HWND;

public
constructor Create(AParent : TWinControl);
end;

implementation

constructor TGame.Create(AParent : TWinControl);
var Msg : TMsg;
begin
FParent := TWinControl(AParent);
FWndProc := WndProc;
if InitClass then begin
FHandle := MakeWindow();
ShowWindow(FHandle, SW_SHOW);
UpdateWindow(FHandle);

while (GetMessage(Msg, 0, 0, 0)) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;

end;
end;

function TGame.WndProc(wnd:HWND; Msg : Integer; Wpar:Wparam; Lpar:Lparam):Lresult; stdcall;
begin
WndProc := 0;
case Msg of
WM_CREATE : ;
WM_ERASEBKGND : ;
WM_PAINT : Paint(wnd, Msg, wPar, lPar);
WM_DESTROY : PostQuitMessage(0);
end;

result := DefWindowProc(wnd, Msg, wPar, lPar);
end;

function TGame.InitClass : boolean;
begin
wndClass.style:=cs_hredraw or cs_vredraw;
wndClass.lpfnWndProc:=@FWndProc;
wndClass.cbClsExtra:=0;
wndClass.cbWndExtra:=0;
wndClass.hInstance:=GetModuleHandle (NIL);
wndClass.hIcon:=LoadIcon(0,idi_application);
wndClass.hCursor:=LoadCursor(0,idc_arrow);
wndClass.hbrBackground:=COLOR_BTNFACE+1;
wndClass.lpszMenuName:=nil;
wndClass.lpszClassName:="TGame";

Result:=Boolean(RegisterClass(wndClass)<>0);

//здеся вроде всё проходит
end;

function TGame.MakeWindow(): HWND;
begin
result :=

CreateWindow( "TGame", "",
WS_CHILD,
0, 0, 200, 200, FParent.Handle, 0, HInstance, nil);

//вот здесь я проверял, что вы писали
if result =0 then ShowMessage(SysErrorMessage(GetLastError)+" "+IntToStr(FParent.Handle));
end;

// отрисовка - можно вообще не смотреть - рисую rectangle ради проверки и всё.
procedure TGame.Paint(wnd:HWND; Msg : Integer; Wpar:Wparam; Lpar:Lparam);
var
_paint : PAINTSTRUCT;
_dc, _mdc : HDC;
_tmpBm, _saveBm : HBITMAP;
_tmpBrush, _saveBrush : HBRUSH;
_savePen : HPEN;

begin
_dc := BeginPaint(wnd,_paint);
_mdc := CreateCompatibleDC(_dc);
_tmpBm := CreateDiscardableBitmap(_dc, 200,200);
_tmpBrush := CreateSolidBrush(RGB(255,255,255));

_saveBm := SelectObject(_mdc, _tmpBm);
_saveBrush := SelectObject(_mdc, _tmpBrush);
_savePen := SelectObject(_mdc, CreatePen(PS_SOLID,1,RGB(0,0,0)));

//---

FillRect(_mdc, Rect(0,0,100,100),_tmpBrush);

BitBlt(_dc,0,0,200,200,_mdc,0,0,SRCCOPY);
//---

DeleteObject(SelectObject(_mdc, _saveBm));
DeleteObject(SelectObject(_mdc, _saveBrush));
DeleteObject(SelectObject(_mdc, _savePen));

DeleteDC(_mdc);
EndPaint(Wnd,_paint);
end;

end.


 
Digitman ©   (2003-10-21 11:11) [10]

вот сей момент прелюбопытен :

constructor TGame.Create(AParent : TWinControl);
var Msg : TMsg;
begin
...
while (GetMessage(Msg, 0, 0, 0)) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;
...
end;

и когда ж ты ожидаешь завершение работы конструирующего метода, если в нем крутится по сути бесконечный цикл ?
при каких условиях ты ожидаешь здесь получить WM_QUIT , дабы прервать этот цикл ?


 
Игорь Шевченко ©   (2003-10-21 11:16) [11]

Оконная процедура в твоем случае не может быть методом объекта

RTFM MakeobjectInstance, твоя ошибка в этом


 
rel_   (2003-10-21 11:37) [12]

to Игорь Шевченко © если не трудно, проясни пожалуйста.
Instance я вообще использую вслепую не зная его предназначения.

>>Оконная процедура в твоем случае не может быть методом объекта

Почему??? Неужели не корректно такое объявление

TWndProc = function(wnd:HWND; Msg : Integer; Wpar:Wparam; Lpar:Lparam):Lresult of object; stdcall;
...
FWndProc : TWndProc
...
FWndProc := WndProc;
...

и потом использовнаие адреса FWndProc при описании класса окна???

А как же мне тогда быть, если я хочу создать класс, создающий дочернее окно на заданной Parent???
Причём весь механизм создания окна должен быть скрыт внутри класса.

Если не трудно, просвети меня.


 
Digitman ©   (2003-10-21 11:57) [13]


> Неужели не корректно


некорректно.

непонятно вообще, зачем ты это делаешь непосредственно на WinAPI

на то есть готовый класс TWinControl, св-во ParentWindow которого позволяет легко и просто создать дочерний контрол-наследник данного VCL-класса на указанном родительском non-VCL-окне (либо св-во Parent, если род.окно создано VCL-контролом)


 
rel_   (2003-10-21 12:01) [14]

to Digitman © Конечно знаю, что есть готовый класс TWinControl - в итоге, если не получится навоять руками, то унаследую именно от него.

Но есть задумка : создать класс, создающий дочернее окно на заданной Parent??? Причём весь механизм создания окна должен быть скрыт внутри класса. (сделать хочу руками : на API)

Может кто отсоветует что-нибудь???


 
Digitman ©   (2003-10-21 12:07) [15]

поля класса TMyClass :
hWnd: THandle;
FOldCallback : Pointer;
FNewCallback : Pointer;

метод-обработчик ок.сообщений в классе TMyClass

function TMyClass.WndProc(Wnd: HWND; Msg: UINT; mywParam: WPARAM;
mylParam: LPARAM): LRESULT; stdcall;
begin
case Msg of
...
else
Result:=CallWindowProc(FOldCallback,wnd, msg, mywparam, mylparam);
end;
end;

в конструкторе (или любом другом методе) класса TMyClass

hWnd:=CreateWindowEx(.., ParentHwnd,..,hInstance,..);

FNewCallback := VirtualAlloc(nil, 12, MEM_RESERVE OR MEM_COMMIT, PAGE_EXECUTE_READWRITE);
asm
mov EAX, Self
mov ECX, [EAX].FNewCallback
mov word ptr [ECX+0], $6858 // pop EAX
mov dword ptr [ECX+2], EAX // push _Self_
mov word ptr [ECX+6], $E950 // push EAX
mov EAX, OFFSET(WndProc)
sub EAX, ECX
sub EAX, 12
mov dword ptr [ECX+8], EAX // jmp
end;

FOldCallback := Pointer(GetWindowLong(hWnd,GWL_WNDPROC));
SetWindowLong(hWnd,GWL_WNDPROC,DWORD(FNewCallback));


 
Игорь Шевченко ©   (2003-10-21 12:10) [16]


> Если не трудно, просвети меня.


Вообще-то для просвещения служит волшебная кнопка F1 или исходники VCL...


 
rel_   (2003-10-21 12:21) [17]

to Digitman ©

Вроде понятно:
ф-ей SetWindowLong(hWnd,GWL_WNDPROC,DWORD(FNewCallback)); я переопределю обработчик сообщений, но перед строкой

hWnd:=CreateWindowEx(.., ParentHwnd,..,hInstance,..);

в описание класса в wndClass.lpfnWndProc:=??? что изначально передавать???


 
Digitman ©   (2003-10-21 12:28) [18]

в данной реализации - что угодно, указатель на любую stdcall-callback-ф-цию, все равно колбек будет изменен


 
rel_   (2003-10-21 12:50) [19]

to Digitman ©
Огромное спасибо - сейчас ухожу - о результатах сообщу позже.


 
rel_   (2003-10-21 14:36) [20]

Всё просто OK за одним исключением:

Где мне повесить цикл обработки сообщений ?
while (GetMessage(Msg, 0, 0, 0)) do begin
TranslateMessage(Msg);
DispatchMessage(Msg);
end;

Он должен запускаться сразу после создания окна
Если вешаю его в конструкторе - то, сам понимаешь, объект не созадаётся, т.к. курсор из конструктора не выходит до закрытия окна.


 
Digitman ©   (2003-10-21 14:42) [21]

цикл помести в коде, который выполняется при старте приложения
перевым делом приложение создает объект TGame (в конструкторе которого создается окно) и где-то следом помести цикл


 
rel_   (2003-10-21 14:58) [22]

Понятно. Помещу, например в процедуре SetParent (как в VCL).

A есть возможность сменить Parent, не убивая при этом окно???


 
Digitman ©   (2003-10-21 15:19) [23]


> Помещу, например в процедуре SetParent


что поместишь ? цикл ? нельзя туда его !


> есть возможность сменить Parent, не убивая при этом окно


см.реализацию метода TWinControl.SetParentWindow


 
rel_   (2003-10-21 15:35) [24]

В какой момент я должен вызывать деструктор класса???

У меня возникает непонятный эффект - окно Parent закрывается лишь при втором нажатии на Close в системном меню. Может это из-за неправильного вызова деструктора моего класса?


 
rel_   (2003-10-21 15:40) [25]

to Digitman © (21.10.03 14:42) [21]
>>цикл помести в коде, который выполняется при старте приложения
>>перевым делом приложение создает объект TGame (в конструкторе которого создается окно) и где-то следом помести цикл

У меня цикл должен быть в классе зашит, а не во приложении его использующем.


 
Digitman ©   (2003-10-21 15:56) [26]


> В какой момент я должен вызывать деструктор класса


в твоем случае - практически в любой


> У меня возникает непонятный эффект - окно Parent закрывается
> лишь при втором нажатии на Close


мы здесь вроде бы не о родителе говорим ... о доч.окне


> У меня цикл должен быть в классе зашит


зачем ?? ты посмотри на реализацию класса TApplication и его метода Run() !


 
rel_   (2003-10-21 16:03) [27]

to Digitman © Я тебя наверное уже совсем замучал. Пока поковыряюсь сам. Рез-т обязательно скажу.

Огромное спасибо!!!


 
rel_   (2003-10-22 09:54) [28]

to Digitman © Если не трудно, давай вернёмся ко вчерашней теме. Посмотрел на реализацию класса TApplication и его метода Run - мало, что понял.

Как мне поместить цикл сбора сообщений вне класса, если я хочу, чтобы он был инкапсулирован внутри класса и обрабатывал сообщения именyо от окна созданного текущим объектом класса?


 
Digitman ©   (2003-10-22 10:04) [29]

я не понял, кем и какими средствами у тебя создается гл.окно приложения

в случае использования станд.класса TApplication оно создается автоматически, и цикл обработки сообщений запускается автоматически (в теле Application.Run), но ты же говоришь, что делаешь все непосредственно на WinAPI ... поясни вот это ... приведи текст dpr-файла своего проекта


 
rel_   (2003-10-22 10:38) [30]

Digitman © Мне кажется, что говорим немного о разных вещах:

Идея проста - некая имитация класса TControl. Я хочу, чтобы мой класс создавал окно и отлавливал его сообщения. В dpr файле ничего нет. Весь механизм регистрации класса окна, создания его и обработки сообщений должен быть внутри моего класса.

Пример:
мой класс: TMyWindow.

1) Создаю проект, в классе TForm1 объявляю переменную MyNewWindow : TMyWindow.

2) Где нибудь (например при нажатии некой кнопки) создаю экземпляр моего класса MyNewWindow := TMyWindow.Create(Selef) (Self в данном случае Form1). И больше не делаю ничего.

3) Результат - окно (некий контрол) на фомре Form1. И я не забочусь об отработке сообщений окна, созданного классом TMyWindow, всё зашито внутри класса TMyWindow. Т.е. объект MyNewWindow полностью поддерживает окно, им созданное.

Нечто, например, в вроде класса TButton - контрол(окно), а внутри него весь механизм.


 
Digitman ©   (2003-10-22 11:51) [31]


> В dpr файле ничего нет


здрааасть ! как же "ничего нет" ? ты хоть посмотрел бы, что там творится у тебя, прежде чем утверждать такую несуразицу)

а там (в dpr-файле) у тебя следующее :

programm Такая_то
uses .. Такие_то_модули
....
begin
//здесь начинается выполнение кода приложения !
Application.Initialize; // объект TApplication автоматически создан, здесь он явно инициализируется
Application.CreateForm(TКлассМоейГлавнойФормы, переменная);
Application.Run; // этот метод стартует цикл обработки сообщений для всех окон (существующих и потенциально создаваемых тобой в будущем) осн.код.потока процесса приложения
end;

т.о., создавая в осн.код.потоке новые верхнеуровневые или дочерние окна, нет необходимости заботиться о создании цикла обработки сообщений для них - цикл уже запущен и работает.

в цикле этом есть вызов ф-ции DispatchMessage(), которая как раз и предназначена для вызова соответствующих оконных процедур тех окон, которые были когда либо созданы данным код.потоком (автоматически сгенерированным компилятором кодом или впоследствии тобой явно) и которым адресованы сообщения, выбираемые из очереди сообщений данному код.потоку предшествующим вызовом GetMessage()


 
rel_   (2003-10-22 12:20) [32]

to Digitman ©

>>здрааасть ! как же "ничего нет" ? ты хоть посмотрел бы, что там творится у тебя, прежде чем утверждать такую несуразицу)

Я наверное не так выразился. я имею в виду, что нетничего, что бы касалось моего класса. А то, что ты привёл, конечно есть.

Ура!!! всё абсолютно понятно, всё получилось.
НУ СПАСИБО!!!
Маленький вопросик: я в деструкторе класса пишу:
postMessage(FHandle, WM_DESTROY, 0,0);

данное сообщение обрабатываю так:
WM_DESTROY: PostQuitMessage (0);

Результат: удаляется класс и закрывается всё приложение. Причина не совсем понятна. Как корректно удалить мой класс(удалив окно класса)???


 
Digitman ©   (2003-10-22 12:43) [33]

для разрушения окна в WinAPI имеется ф-ция DestroyWindow()


 
rel_   (2003-10-22 13:28) [34]

to Digitman © Просто огромное спасибо. Не представляешь, как ты мне помог.



Страницы: 1 вся ветка

Текущий архив: 2003.12.16;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.019 c
8-52296
Ник
2003-08-20 12:15
2003.12.16
TImage-jpeg


1-52266
lipskiy
2003-11-29 14:52
2003.12.16
Запуск html странички с указанием внутренней ссылки?


1-52169
Alibaba
2003-12-03 15:36
2003.12.16
TNotebook


6-52312
mktl
2003-10-16 17:33
2003.12.16
Сеть в консоле


6-52314
ak
2003-10-20 11:09
2003.12.16
idSmtp