Форум: "Начинающим";
Текущий архив: 2010.01.17;
Скачать: [xml.tar.bz2];
ВнизПочему программа создавая окно - вылетает? Найти похожие ветки
← →
Б (2009-11-21 12:09) [0]Здрасти!
Создаю окно под рендер 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;
← →
DVM © (2009-11-21 12:11) [1]
> lpfnWndProc := @WndProc;
вот тут ошибка
← →
Б (2009-11-21 12:21) [2]
>
> > lpfnWndProc := @WndProc;
>
> вот тут ошибка
> <Цитата>
C калбэков всё нормально.
Если FFull поставить в False, то окно нормально создаёться и функционирует.
← →
DVM © (2009-11-21 12:25) [3]
> Б (21.11.09 12:21) [2]
> C калбэков всё нормально.
Может и нормально, но мне непонятно, эта WndProc - метод класса или нет? Если метод класса то так неправильно делать.
← →
Б (2009-11-21 12:25) [4]И ещё.
Если убрать флаг WS_POPUP, то окно создаётся.
Не пойму в чём дело.
← →
Б (2009-11-21 12:27) [5]> Может и нормально, но мне непонятно, эта WndProc - метод класса или > нет? Если метод класса то так неправильно делать.
Это, естесственно, не метод класса.
А обычная оконная процедура.
Function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
← →
DVM © (2009-11-21 12:37) [6]
> Б (21.11.09 12:27) [5]
> Это, естесственно, не метод класса.
Ааа. Тогда у тебя будут проблемы потом при обращении из этой процедуры к членам класса. Ведь наверняка придется. Иначе зачем класс создавать. Советую продумать вопрос этот.
Вот так должно заработать:
if(fullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
ShowCursor(FALSE);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
← →
DVM © (2009-11-21 12:39) [7]
> Вот так должно заработать:
хотя у тебя тоже самое
← →
Б (2009-11-21 12:43) [8]
> Вот так должно заработать:
Не-а, всё равно вылетает с флагом WS_POPUP, как никрути.
> Тогда у тебя будут проблемы потом при обращении из этой процедуры к членам класса.
Я специально написал вот такую строчку:
SetWindowLong(FWnd, GWL_USERDATA, INTEGER(Self));
Чтобы спокой в WndProc работать с полями и методами своего класса.
← →
DVM © (2009-11-21 12:50) [9]
> Не-а, всё равно вылетает с флагом WS_POPUP, как никрути.
Странно. Мне кажется у меня раньше с этим стилем проблем не было. Ну и выкинь его, он же необязателен.
← →
Б (2009-11-21 12:58) [10]
> Ну и выкинь его, он же необязателен.
Нет. Без него не как.
В полноэкранном режиме окно должно быть без рамки. (OpenGL)
Хотя раньше с этим флагом проблем тоже не было.
← →
DVM © (2009-11-21 13:09) [11]
> Б
попробуй вот такое сочетание стилей
Style = WS_POPUP or
WS_VISIBLE or WS_MAXIMIZE or
WS_CLIPSIBLINGS or
WS_CLIPCHILDREN or
WS_OVERLAPPED;
ExtStyle = WS_EX_LEFT or
WS_EX_RTLREADING or
WS_EX_TOOLWINDOW or
WS_EX_RIGHTSCROLLBAR;
← →
DVM © (2009-11-21 13:10) [12]
> Б
еще обычно после создания окна делают
ShowWindow(Wnd, SW_SHOWNORMAL);
UpdateWindow(Wnd);
← →
Б (2009-11-21 13:19) [13]> попробуй вот такое сочетание стилей
Хм. Вылетает с теми же ошибками.
> ShowWindow(Wnd, SW_SHOWNORMAL);
> UpdateWindow(Wnd);
Этот код у меня находиться прямо перед циклом сообщений окна.
Чтобы при неудавшейся инициализации не лицезреть несколько секунд окно.
← →
DVM © (2009-11-21 13:26) [14]вот набросал на скорую руку - ничего не вылетает
program winmin;
uses
windows, messages;
var
wc: TWndClassEx;
MainWnd: HWND;
Mesg: TMsg;
//------------------------------------------------------------------------------
function WindowProc(Wnd: HWND; Msg: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
begin
case msg of
wm_destroy :
begin
PostQuitMessage(0);
Result := 0;
exit;
end;
else
Result := DefWindowProc(Wnd, Msg, wParam, lParam);
end;
end;
//------------------------------------------------------------------------------
var
xPos, yPos, nWidth, nHeight: integer;
const
Style = WS_POPUP;
ExtStyle =0;
begin
wc.cbSize:=sizeof(wc);
wc.style:=cs_hredraw or cs_vredraw;
wc.lpfnWndProc:=@WindowProc;
wc.cbClsExtra:=0;
wc.cbWndExtra:=0;
wc.hInstance:=HInstance;
wc.hIcon:=LoadIcon(0,idi_application);
wc.hCursor:=LoadCursor(0,idc_arrow);
wc.hbrBackground:=COLOR_BTNFACE+1;
wc.lpszMenuName:=nil;
wc.lpszClassName:="WndClass1";
RegisterClassEx(wc);
xPos := 0;
yPos := 0;
nWidth := 1366;
nHeight := 768;
MainWnd := CreateWindowEx(ExtStyle, "WndClass1", "Caption", Style,
xPos, yPos, nWidth, nHeight, 0, 0, Hinstance, nil);
ShowWindow(MainWnd,CmdShow);
while GetMessage(Mesg,0,0,0) do
begin
TranslateMessage(Mesg);
DispatchMessage(Mesg);
end;
end.
← →
Б (2009-11-21 13:33) [15]Хм. У меня тоже работает.
Что-то я ничего не понимаю.
Мой пример без WS_POPUP работает.
← →
DVM © (2009-11-21 13:43) [16]попробуй сделать глобальной переменной Info: TWndClassEx;
← →
Б (2009-11-21 13:52) [17]Результат не радует.
← →
DVM © (2009-11-21 14:01) [18]
> Б (21.11.09 13:52) [17]
Тогда даже не знаю что еще предположить, давай больше кода, но желательно минимально необходимый кусок.
← →
DVM © (2009-11-21 14:02) [19]Title у тебя задан?
← →
Б (2009-11-21 14:06) [20]> Тогда даже не знаю что еще предположить, давай больше кода
А больше и нечего добавить.
> Title у тебя задан?
Как бы нет.
Но от этого разве что-нибудь зависит?
If not WndInit(HInstance, 0, 0, 870, 640, "") then
begin
Log.MsgBox(" - Window - No create!");
Exit;
end;
← →
DVM © (2009-11-21 14:44) [21]
> А больше и нечего добавить.
а в оконной функции чего?
> Но от этого разве что-нибудь зависит?
ну в таком виде как у тебя не должно
← →
Б (2009-11-21 15:18) [22]
> а в оконной функции чего?
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;
← →
Б (2009-11-21 15:25) [23]Кстати, я долго бился над тем, чтобы можно в каллбэке менять поля.
http://delphimaster.net/view/9-1248277133/
← →
Игорь Шевченко © (2009-11-21 17:50) [24]
> 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 передается)
← →
DVM © (2009-11-21 22:25) [25]
> Б
Точно, Игорь прав.
← →
Б (2009-11-26 10:08) [26]> твоя оконная процедура вызовется с десяток раз
Действительно! ;)
Как руки дошли - сделал.
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);
Всё правильно?
← →
Б (2009-11-26 20:11) [27]Вот ещё как вариант:
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 20:16) [28]
> Всё правильно?
здесь да.
в оконной процедуре проверяешь, что GetWindowLong возвращает не 0 (при создании окна его структура должна нулями заполняться)
← →
Б (2009-11-27 06:39) [29]
> в оконной процедуре проверяешь, что GetWindowLong возвращает
> не 0 (при создании окна его структура должна нулями заполняться)
В справке написано, что, если до этого SetWindowLong не вызывался, то GetWindowLong возвратит 0. Поэтому проверку считаю лишней.
← →
Leonid Troyanovsky © (2009-11-27 09:02) [30]
> Б (26.11.09 10:08) [26]
> Всё правильно?
Если есть нужда в использовании собс-ручно изготовленного окна
в своем объекте, то самым правильным будет подход,
основанный на MakeObjectInstance.
Пример реализации можно найти в исходниках TTimer.
--
Regards, LVT.
← →
Б (2009-11-27 14:18) [31]
> то самым правильным будет подход,
> основанный на MakeObjectInstance.
А чем мой вариант плох?
P.S. Данный класс не будет иметь наследников (1 экземпляр), не является компонентом.
← →
Leonid Troyanovsky © (2009-11-27 14:29) [32]
> Б (27.11.09 14:18) [31]
> P.S. Данный класс не будет иметь наследников (1 экземпляр),
> не является компонентом.
Сегодня нет, а завтра есть.
Когда оконная функция есть метод класса,
намного удобней, чем приведение типа.
А объект или компонент здесь без разницы.
--
Regards, LVT.
← →
Б (2009-11-28 12:21) [33]> Сегодня нет, а завтра есть.
Окно будет точно - одно.
> Когда оконная функция есть метод класса,
намного удобней
У меня в общем так и сделано. (См. выше)
Конечно, можно было бы сделать через MakeObjectInstance, но меня беспокоит размер Classes.pas. (VCL)
Движок не должен быть "больших" размеров.
← →
Leonid Troyanovsky © (2009-11-28 14:01) [34]
> Б (28.11.09 12:21) [33]
> У меня в общем так и сделано. (См. выше)
Чего-то не нашел, видел только через приведение.
> но меня беспокоит размер Classes.pas. (VCL)
Скопируй себе, там 100 строк всего.
Заодно и баг подправишь, с утечкой блока после VirtualAlloc.
--
Regards, LVT.
← →
Б (2009-11-28 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;
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 19:30) [36]
> Б (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 20:00) [37]
> Тебе ж раньше обяснили, что SetWindowLong д.б. в WM_CREATE,
>
> или проверка должна быть <> 0.
А я так и сделал. (См. Б (26.11.09 10:08) [26])
> А DefWindowProc нужно вызывать не из метода класса, а
из оконной функции.
А как же её там вызывать, в не case?
> У метода класса параметры д.б. var, включая Result.
hWnd передавать не надо, у объекта д.б. такое поле.
Менял, конечно. Но программа почему-то сразу же вылетает.
> Если уж планируется мертвая связь один к одному,
> то заведи себе глобальную переменную, хранящую
> указатель на объект и пользуй ее в оконной процедуре.
Хотя в будущем, может быть подадобятся и несколько экземпляров.
Завести глобальную переменную это "слишком" просто. Плохой стиль.
Это я так в самом начале делал. ;)
← →
Leonid Troyanovsky © (2009-11-28 20:19) [38]
> Б (28.11.09 20:00) [37]
> > А DefWindowProc нужно вызывать не из метода класса, а
> А как же её там вызывать, в не case?
Посмотри, например, тип TMessageEvent (TApplication.OnMessage).
Т.е., если Handled := True, то DefWindowProc вызывать не надо.
> Менял, конечно. Но программа почему-то сразу же вылетает.
Там не менять надо, а сначала передать методу TMsg or TMessage,
а после возврата - менять на возвращенные значения.
> Это я так в самом начале делал. ;)
Значит, сейчас созрел для MakeObjectInstance ;)
--
Regards, LVT.
--
Regards, LVT.
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.01.17;
Скачать: [xml.tar.bz2];
Память: 0.57 MB
Время: 0.006 c