![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Почему программа создавая окно - вылетает? [D7, XP]
Б © (2009-11-21 12:09:00)Здрасти!
Создаю окно под рендер OpenGL след. самописной функцией.
Но если создать его в полноэкранном режиме (FFlag = True), то выскакивает "AV".
GetLastError пишет: "Не все окна, принадлежащие данному классу, закрыты (1412)".
В итоге в лог не попадает НЕ ОДНО сообщение.
Как быть?
Function TWindow.WndInit(Inst: HINST; x, y, W, H: integer; Title: PChar): boolean;
Var
Info: TWndClassEx;
Clss: PChar;
begin
Clss:= 'eXAAAXe';
ZeroMemory(@Info, SizeOf(Info));
With Info do
begin
cbSize := SizeOf(TWndClassEx);
Style := CS_OWNDC or CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS;
lpfnWndProc := @WndProc;
hInstance := Inst;
hIcon := LoadIcon(0, IDI_APPLICATION);
hCursor := LoadCursor(0, IDC_ARROW);
hbrBackground:= HBRUSH(GetStockObject(BLACK_BRUSH));
lpszClassName:= Clss;
hIconSm := LoadIcon(0, IDI_APPLICATION);
end;
If (RegisterClassEx(Info) = 0) then
begin
Log.Print('No register!'); (* Всё записываем в лог *)
Result:= False;
Exit;
end;
If FFull then (* Полноэкранный режим *)
begin
// Mode(640, 480, 16, 60); (* Меняем разрешение экрана *)
FWnd:= CreateWindowEx(WS_EX_APPWINDOW, Clss, Title, WS_POPUP or WS_CLIPCHILDREN or WS_CLIPSIBLINGS, x, y, W, H, 0, 0, Inst, nil);
Log.Print('FullScreen mode');
end else (* Оконный режим *)
begin
FWnd:= CreateWindowEx(WS_EX_APPWINDOW or WS_EX_WINDOWEDGE, Clss, Title, WS_OVERLAPPEDWINDOW or WS_CLIPCHILDREN or WS_CLIPSIBLINGS, x, y, W, H, 0, 0, Inst, nil);
Log.Print('Windowed mode');
end;
SetWindowLong(FWnd, GWL_USERDATA, INTEGER(Self));
Log.Print('УРА!!!');
Result:= (FWnd <> 0);
End;
Leonid Troyanovsky (2009-11-28 20:19:00) [1]
> Б (28.11.09 20:00) [37]
> > А DefWindowProc нужно вызывать не из метода класса, а
> А как же её там вызывать, в не case?
Посмотри, например, тип TMessageEvent (TApplication.OnMessage).
Т.е., если Handled := True, то DefWindowProc вызывать не надо.
> Менял, конечно. Но программа почему-то сразу же вылетает.
Там не менять надо, а сначала передать методу TMsg or TMessage,
а после возврата - менять на возвращенные значения.
> Это я так в самом начале делал. ;)
Значит, сейчас созрел для MakeObjectInstance ;)
--
Regards, LVT.
--
Regards, LVT.
Б (2009-11-28 20:00:00) [2]
> Тебе ж раньше обяснили, что SetWindowLong д.б. в WM_CREATE,
>
> или проверка должна быть <> 0.
А я так и сделал. (См. Б (26.11.09 10:08) [26])
> А DefWindowProc нужно вызывать не из метода класса, а
из оконной функции.
А как же её там вызывать, в не case?
> У метода класса параметры д.б. var, включая Result.
hWnd передавать не надо, у объекта д.б. такое поле.
Менял, конечно. Но программа почему-то сразу же вылетает.
> Если уж планируется мертвая связь один к одному,
> то заведи себе глобальную переменную, хранящую
> указатель на объект и пользуй ее в оконной процедуре.
Хотя в будущем, может быть подадобятся и несколько экземпляров.
Завести глобальную переменную это "слишком" просто. Плохой стиль.
Это я так в самом начале делал. ;)
Leonid Troyanovsky (2009-11-28 19:30:00) [3]
> Б (28.11.09 14:06) [35]
> Если скажете, чем этот вариант хуже, то испавлю.
> Function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM;
> lParam: LPARAM): LRESULT; stdcall;
> begin
> Result:= TWindow(GetWindowLong(hWnd, GWL_USERDATA)).CallBack(hWnd,
> Msg, wParam,lParam);
> End;
Этот, во-ще, неправильный.
Тебе ж раньше обяснили, что SetWindowLong д.б. в WM_CREATE,
или проверка должна быть <> 0.
А DefWindowProc нужно вызывать не из метода класса, а
из оконной функции.
У метода класса параметры д.б. var, включая Result.
hWnd передавать не надо, у объекта д.б. такое поле.
Если уж планируется мертвая связь один к одному,
то заведи себе глобальную переменную, хранящую
указатель на объект и пользуй ее в оконной процедуре.
--
Regards, LVT.
Б (2009-11-28 14:06:00) [4]
> Чего-то не нашел, видел только через приведение.
А чем приведение плохо?
> Скопируй себе
Если скажете, чем этот вариант хуже, то испавлю.
Function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
Result:= TWindow(GetWindowLong(hWnd, GWL_USERDATA)).CallBack(hWnd, Msg, wParam,lParam);
End;
Function TWindow.CallBack(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
Result:= 0;
Case Msg of
WM_USERMSG: FFiled:= LParam + 100;
else
Result:= DefWindowProc(hWnd, Msg, wParam, lParam);
end
End;
Leonid Troyanovsky (2009-11-28 14:01:00) [5]
> Б (28.11.09 12:21) [33]
> У меня в общем так и сделано. (См. выше)
Чего-то не нашел, видел только через приведение.
> но меня беспокоит размер Classes.pas. (VCL)
Скопируй себе, там 100 строк всего.
Заодно и баг подправишь, с утечкой блока после VirtualAlloc.
--
Regards, LVT.
Б (2009-11-28 12:21:00) [6]> Сегодня нет, а завтра есть.
Окно будет точно - одно.
> Когда оконная функция есть метод класса,
намного удобней
У меня в общем так и сделано. (См. выше)
Конечно, можно было бы сделать через MakeObjectInstance, но меня беспокоит размер Classes.pas. (VCL)
Движок не должен быть "больших" размеров.
Leonid Troyanovsky (2009-11-27 14:29:00) [7]
> Б (27.11.09 14:18) [31]
> P.S. Данный класс не будет иметь наследников (1 экземпляр),
> не является компонентом.
Сегодня нет, а завтра есть.
Когда оконная функция есть метод класса,
намного удобней, чем приведение типа.
А объект или компонент здесь без разницы.
--
Regards, LVT.
Б (2009-11-27 14:18:00) [8]
> то самым правильным будет подход,
> основанный на MakeObjectInstance.
А чем мой вариант плох?
P.S. Данный класс не будет иметь наследников (1 экземпляр), не является компонентом.
Leonid Troyanovsky (2009-11-27 09:02:00) [9]
> Б (26.11.09 10:08) [26]
> Всё правильно?
Если есть нужда в использовании собс-ручно изготовленного окна
в своем объекте, то самым правильным будет подход,
основанный на MakeObjectInstance.
Пример реализации можно найти в исходниках TTimer.
--
Regards, LVT.
Б (2009-11-27 06:39:00) [10]
> в оконной процедуре проверяешь, что GetWindowLong возвращает
> не 0 (при создании окна его структура должна нулями заполняться)
В справке написано, что, если до этого SetWindowLong не вызывался, то GetWindowLong возвратит 0. Поэтому проверку считаю лишней.
Игорь Шевченко (2009-11-26 20:16:00) [11]
> Всё правильно?
здесь да.
в оконной процедуре проверяешь, что GetWindowLong возвращает не 0 (при создании окна его структура должна нулями заполняться)
Б (2009-11-26 20:11:00) [12]Вот ещё как вариант:
Function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
Var
Wnd: TWindow;
begin
Result:= 0;
Wnd:= Pointer(GetWindowLong(hWnd, GWL_USERDATA));
Case Msg of
WM_USERMSG: Wnd.FField:= LParam + 100;
. . . . . . . .
else
Result:= DefWindowProc(hWnd, Msg, wParam, lParam);
end
End;
Б (2009-11-26 10:08:00) [13]> твоя оконная процедура вызовется с десяток раз
Действительно! ;)
Как руки дошли - сделал.
WM_CREATE: SetWindowLong(hWnd, GWL_USERDATA, INTEGER(PCreateStruct(LParam).lpCreateParams)); // Передаём через указатель себя же.
. . . . .
FWnd:= CreateWindowEx(WS_EX_APPWINDOW, 'X_Window', FTitle, WS_POPUP or WS_CLIPCHILDREN or WS_CLIPSIBLINGS, x, y, W, H, 0, 0, HInstance, Self);
Всё правильно?
DVM (2009-11-21 22:25:00) [14]
> Б
Точно, Игорь прав.
Игорь Шевченко (2009-11-21 17:50:00) [15]
> Function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM;
> lParam: LPARAM): LRESULT; stdcall;
> begin
> Result:= TWindow(GetWindowLong(hWnd, GWL_USERDATA)).CallBack(hWnd,
> Msg, wParam,lParam);
> End;
Чудо.
До того, как ты установишь SetWindowLong после CreateWindow(Ex), твоя оконная процедура вызовется с десяток раз - и с каким коллбэком она будет работать ?
Читать про передачу параметров обработчикам сообщений WM_CREATE, WM_NCCREATE через задание параметра LPCREATESTRUCT в вызовах CreateWindow(Ex)
(Это там, где у тебя тупо nil передается)
Б (2009-11-21 15:25:00) [16]Кстати, я долго бился над тем, чтобы можно в каллбэке менять поля.
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1248277133&n=9
Б (2009-11-21 15:18:00) [17]
> а в оконной функции чего?
Function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
Result:= TWindow(GetWindowLong(hWnd, GWL_USERDATA)).CallBack(hWnd, Msg, wParam,lParam);
End;
Function TWindow.CallBack(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
Result:= 0;
Case Msg of
WM_DESTROY: PostQuitMessage(0);
(* Тут ещё много обработок *)
else
Result:= DefWindowProc(hWnd, Msg, wParam, lParam);
end
End;
DVM (2009-11-21 14:44:00) [18]
> А больше и нечего добавить.
а в оконной функции чего?
> Но от этого разве что-нибудь зависит?
ну в таком виде как у тебя не должно
Б (2009-11-21 14:06:00) [19]> Тогда даже не знаю что еще предположить, давай больше кода
А больше и нечего добавить.
> Title у тебя задан?
Как бы нет.
Но от этого разве что-нибудь зависит?
If not WndInit(HInstance, 0, 0, 870, 640, '') then
begin
Log.MsgBox(' - Window - No create!');
Exit;
end;
DVM (2009-11-21 14:02:00) [20]Title у тебя задан?