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

Вниз

Почему программа создавая окно - вылетает?   Найти похожие ветки 

 
Б   (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;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.022 c
1-1233056631
webpauk
2009-01-27 14:43
2010.01.17
Рисование на ListView.Canvas


2-1259253418
Molchanov
2009-11-26 19:36
2010.01.17
WndProc vs WindowProc


2-1258713886
Andrewtitoff
2009-11-20 13:44
2010.01.17
URL


15-1258147816
Юрий
2009-11-14 00:30
2010.01.17
С днем рождения ! 14 ноября 2009 суббота


15-1258023746
stas
2009-11-12 14:02
2010.01.17
Альтернатива TWebBrowser