Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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
15-1258112660
TUser
2009-11-13 14:44
2010.01.17
Скончался Виталий Лазаревич Гинзбург


15-1258448018
KilkennyCat
2009-11-17 11:53
2010.01.17
Из Магадана в Москву или Петербург


2-1259313490
Molchanov
2009-11-27 12:18
2010.01.17
Application.Title := Const


15-1258019493
Виталий
2009-11-12 12:51
2010.01.17
Задачка на размышление


1-1233656448
Heady
2009-02-03 13:20
2010.01.17
вывести на печать линию в реальном масштабе





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский