Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Почему программа создавая окно - вылетает? [D7, XP]


Страницы:   1 2

Б ©   (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 у тебя задан?


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо