Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "WinAPI";
Текущий архив: 2003.12.16;
Скачать: [xml.tar.bz2];

Вниз

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

 
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 вся ветка

Форум: "WinAPI";
Текущий архив: 2003.12.16;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.55 MB
Время: 0.01 c
1-52267
lipskiy
2003-11-30 20:36
2003.12.16
Приложение загружает ЦП на 100%, как побороть?


1-52148
ThreeDHead
2003-12-03 18:58
2003.12.16
Как отловить смену контрола на форме ?


1-52153
Stalker780
2003-12-03 16:45
2003.12.16
Вывести форму в таскбар


1-52231
knartic
2003-11-27 19:26
2003.12.16
Установка компонент


3-52073
SlavaSH
2003-11-24 14:10
2003.12.16
SQL





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский