Форум: "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