1 //--- K.I.LIB ---
2 // kl_wnd.cpp : window information manager
3
4 #include "stdafx.h"
5 #include "kilib.h"
6
7
8 //-------- Windowを作成時に HWND に kiWindow* をセットするための処理 -------//
9
10
11 kiWindow* kiWindow::st_pCurInit = NULL;
12 HHOOK kiWindow::st_hHook = NULL;
13
14 void kiWindow::init()
15 {
16 // CreateWindow 用フック設置
17 st_hHook = ::SetWindowsHookEx( WH_CBT, &CBTProc, NULL, ::GetCurrentThreadId() );
18 }
19
20 void kiWindow::finish()
21 {
22 // CreateWindow 用フック解除
23 ::UnhookWindowsHookEx( st_hHook );
24 }
25
26 LRESULT CALLBACK kiWindow::CBTProc( int code, WPARAM wp, LPARAM lp )
27 {
28 if( code == HCBT_CREATEWND )
29 {
30 if( st_pCurInit )
31 {
32 // k.i.lib のウインドウが CreateWindow された場合
33 st_pCurInit->setHwnd( (HWND)wp );
34 ::SetWindowLong( (HWND)wp, GWL_USERDATA, (LONG)st_pCurInit );
35 st_pCurInit = NULL;
36 }
37 else
38 ::SetWindowLong( (HWND)wp, GWL_USERDATA, 0 );
39 }
40
41 return ::CallNextHookEx( st_hHook, code, wp, lp );
42 }
43
44 void kiWindow::detachHwnd()
45 {
46 ::SetWindowLong( hwnd(), GWL_USERDATA, 0 );
47 if( this == app()->mainwnd() )
48 app()->setMainWnd( NULL );
49 setHwnd( NULL );
50 }
51
52
53 //------------ Window にまつわるエトセトラな処理 (static) ---------------//
54
55
56 bool kiWindow::loopbreaker = false;
57
58 void kiWindow::msg()
59 {
60 for( MSG msg; ::PeekMessage( &msg,NULL,0,0,PM_REMOVE ); )
61 ::TranslateMessage( &msg ), ::DispatchMessage( &msg );
62 }
63
64 void kiWindow::msgLoop( msglooptype type )
65 {
66 kiWindow* wnd;
67 MSG msg;
68 while( !loopbreaker &&
69 type==GET ? ::GetMessage( &msg,NULL,0,0 )
70 : ::PeekMessage( &msg,NULL,0,0,PM_REMOVE ) )
71 {
72 if( wnd = app()->mainwnd() )
73 {
74 if( wnd->m_hAccel )
75 if( ::TranslateAccelerator( wnd->hwnd(), wnd->m_hAccel, &msg ) )
76 continue;
77 if( msg.message!=WM_CHAR && wnd->isDlgMsg( &msg ) )
78 continue;
79 }
80 ::TranslateMessage( &msg ), ::DispatchMessage( &msg );
81 }
82 loopbreaker = false;
83 }
84
85 void kiWindow::setFront( HWND wnd )
86 {
87 const OSVERSIONINFO& v = app()->osver();
88
89 // Win2000 以上 or Win98 以上
90 if( ( v.dwPlatformId==VER_PLATFORM_WIN32_NT && v.dwMajorVersion>=5 )
91 || ( v.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS &&
92 v.dwMajorVersion*100+v.dwMinorVersion>=410 ) )
93 {
94 DWORD pid;
95 DWORD th1 = ::GetWindowThreadProcessId( ::GetForegroundWindow(), &pid );
96 DWORD th2 = ::GetCurrentThreadId();
97 ::AttachThreadInput( th2, th1, TRUE );
98 ::SetForegroundWindow( wnd );
99 ::AttachThreadInput( th2, th1, FALSE );
100 ::BringWindowToTop( wnd );
101 }
102 else // 古いWin
103 ::SetForegroundWindow( wnd );
104
105 // Special Thanks To kazubon !! ( the author of TClock )
106 }
107
108 void kiWindow::setCenter( HWND wnd, HWND rel )
109 {
110 RECT rc,pr;
111 ::GetWindowRect( wnd, &rc );
112
113 if( rel )
114 ::GetWindowRect( rel, &pr );
115 else
116 ::SystemParametersInfo( SPI_GETWORKAREA, 0, &pr, 0 );
117
118 ::SetWindowPos( wnd, 0,
119 pr.left + ( (pr.right-pr.left)-(rc.right-rc.left) )/2,
120 pr.top + ( (pr.bottom-pr.top)-(rc.bottom-rc.top) )/2,
121 0, 0, SWP_NOSIZE|SWP_NOZORDER );
122 }
123
124
125 //------------------ Windowベースクラスとしての処理 ----------------------//
126
127
128 kiWindow::kiWindow()
129 {
130 m_hWnd = NULL;
131 m_hAccel = NULL;
132 app()->shellInit();
133 }
134
135 kiWindow::~kiWindow()
136 {
137 if( m_hWnd && ::IsWindow( m_hWnd ) )
138 {
139 ::SetWindowLong( m_hWnd, GWL_USERDATA, 0 );
140 ::DestroyWindow( m_hWnd );
141 }
142 }
143
144 void kiWindow::loadAccel( UINT id )
145 {
146 m_hAccel = ::LoadAccelerators( app()->inst(), MAKEINTRESOURCE(id) );
147 }
148
149
150 //---------------- スタンドアロンのWindowの処理 ---------------------//
151
152 // …未完成…
153
154 //---------------------------- Dialog -----------------------------//
155
156
157 kiDialog::kiDialog( UINT id )
158 {
159 m_Rsrc = id;
160 }
161
162 void kiDialog::doModal( HWND parent )
163 {
164 setState( true );
165 preCreate( this );
166
167 ::DialogBoxParam( app()->inst(), MAKEINTRESOURCE(m_Rsrc),
168 parent, commonDlg, (LPARAM)this );
169 }
170
171 void kiDialog::createModeless( HWND parent )
172 {
173 setState( false );
174 preCreate( this );
175
176 ::CreateDialogParam( app()->inst(), MAKEINTRESOURCE(m_Rsrc),
177 parent, commonDlg, (LPARAM)this );
178
179 ::ShowWindow( hwnd(), SW_SHOW );
180 ::UpdateWindow( hwnd() );
181 }
182
183 void kiDialog::end( UINT endcode )
184 {
185 setEndCode( endcode );
186
187 if( isModal() )
188 ::EndDialog( hwnd(), getEndCode() );
189 else
190 ::DestroyWindow( hwnd() );
191 }
192
193 BOOL kiDialog::commonDlg( HWND dlg, UINT msg, WPARAM wp, LPARAM lp )
194 {
195 // kiDialog インターフェイスへのポインタを取得
196 kiDialog* ptr = (kiDialog*)::GetWindowLong( dlg, GWL_USERDATA );
197 if( !ptr ) return FALSE;
198
199 // WM_INITDIALOG なら onInit を呼ぶ
200 if( msg == WM_INITDIALOG )
201 return ptr->onInit();
202
203 // OK / Cancel 処理
204 else if( msg == WM_COMMAND )
205 {
206 switch( LOWORD(wp) )
207 {
208 case IDOK:
209 if( ptr->onOK() )
210 ptr->end( IDOK );
211 return TRUE;
212 case IDCANCEL:
213 if( ptr->onCancel() )
214 ptr->end( IDCANCEL );
215 return TRUE;
216 }
217 }
218
219 // 普通のメッセージ
220 BOOL ans = ptr->proc( msg, wp, lp );
221
222 // WM_DESTORY ならウインドウハンドル切り離し
223 if( msg == WM_DESTROY )
224 ptr->detachHwnd();
225
226 return ans;
227 }
228
229
230 //------------------------ PropertySheet -------------------------//
231
232
233 kiPropSheet* kiPropSheet::st_CurInitPS = NULL;
234
235 kiPropSheet::kiPropSheet() : kiDialog( 0 )
236 {
237 ki_memzero( &m_Header, sizeof(m_Header) );
238 m_Header.dwSize = sizeof(m_Header);
239 m_Header.dwFlags |=PSH_USECALLBACK | PSH_PROPSHEETPAGE;
240 m_Header.pfnCallback = main_initProc;
241 m_Header.hInstance = app()->inst();
242 m_Header.nStartPage = 0;
243 }
244
245 void kiPropSheet::begin()
246 {
247 int l = m_Pages.len();
248 PROPSHEETPAGE* ppsp = new PROPSHEETPAGE[ l ];
249 ki_memzero( ppsp, sizeof(PROPSHEETPAGE)*l );
250
251 for( int i=0; i<l; i++ )
252 {
253 ppsp[i].dwSize = sizeof( PROPSHEETPAGE );
254 ppsp[i].hInstance = app()->inst();
255 ppsp[i].pfnCallback = page_initProc;
256 ppsp[i].pfnDlgProc = page_cmmnProc;
257 ppsp[i].dwFlags = PSP_USECALLBACK | PSP_HASHELP;
258 m_Pages[i]->setInfo( ppsp+i );
259 }
260
261 m_Header.ppsp = ppsp;
262 m_Header.nPages = l;
263
264 st_CurInitPS = this;
265 PropertySheet( &m_Header );
266 delete [] ppsp;
267 }
268
269 void kiPropSheet::doModal( HWND parent )
270 {
271 m_Header.dwFlags &= (~PSH_MODELESS);
272 setState( true );
273 begin();
274 }
275
276 void kiPropSheet::createModeless( HWND parent )
277 {
278 m_Header.dwFlags |= PSH_MODELESS;
279 setState( false );
280 begin();
281 }
282
283 void kiPropSheet::end( UINT endcode )
284 {
285 // 終了コードセット
286 setEndCode( endcode );
287
288 // サブクラス化解除
289 ::SetWindowLong( hwnd(), GWL_WNDPROC, (LONG)m_DefProc );
290
291 // 終了
292 if( isModal() ) // サブクラス化解除してるので、再度 end が呼ばれることはないはず。
293 ::PostMessage( hwnd(), WM_COMMAND, IDCANCEL, 0 );
294 else
295 ::DestroyWindow( hwnd() );
296
297 // WM_DESTROY時相当の動作
298 detachHwnd();
299 }
300
301 LRESULT CALLBACK kiPropSheet::main_cmmnProc( HWND dlg, UINT msg, WPARAM wp, LPARAM lp )
302 {
303 kiPropSheet* ptr = (kiPropSheet*)::GetWindowLong( dlg, GWL_USERDATA );
304 if( !ptr )
305 return 0;
306
307 // まずデフォルトの処理
308 LRESULT result = ::CallWindowProc( ptr->m_DefProc, dlg, msg, wp, lp );
309
310 // ×ボタンはキャンセル扱い
311 if( msg==WM_SYSCOMMAND && wp==SC_CLOSE )
312 ::PostMessage( dlg, WM_COMMAND, IDCANCEL, 0 );
313
314 // コマンド処理
315 else if( msg==WM_COMMAND )
316 {
317 switch( LOWORD(wp) )
318 {
319 case IDOK:
320 if( ptr->onOK() )
321 ptr->end( IDOK );
322 return TRUE;
323 case IDCANCEL:
324 if( ptr->onCancel() )
325 ptr->end( IDCANCEL );
326 return TRUE;
327 case IDAPPLY:
328 ptr->onApply();
329 break;
330 case ID_KIPS_HELP:
331 ptr->onHelp();
332 break;
333 default:
334 ptr->onCommand( LOWORD(wp) );
335 break;
336 }
337 }
338
339 // ドラッグ&ドロップ
340 else if( msg==WM_DROPFILES )
341 ptr->onDrop( (HDROP)wp );
342
343 return result;
344 }
345
346 struct DLGTEMPLATEEX
347 {
348 WORD dlgVer;
349 WORD signature;
350 DWORD helpID;
351 DWORD exStyle;
352 DWORD style;
353 WORD cDlgItems;
354 short x;
355 short y;
356 short cx;
357 short cy;
358 };
359
360 int CALLBACK kiPropSheet::main_initProc( HWND dlg, UINT msg, LPARAM lp )
361 {
362 if( msg == PSCB_PRECREATE )
363 {
364 // スタイルを指すDWORDのアドレスを取得
365 DWORD* pst = ( 0xffff==((DLGTEMPLATEEX*)lp)->signature ) ?
366 &(((DLGTEMPLATEEX*)lp)->style) : &(((DLGTEMPLATE*)lp)->style);
367 // ヘルプボタンを消して最小化ボタンを付ける
368 (*pst) &= ~DS_CONTEXTHELP;
369 (*pst) |= WS_MINIMIZEBOX;
370
371 preCreate( st_CurInitPS );
372 }
373 else if( msg == PSCB_INITIALIZED )
374 {
375 // 何故か出来てしまう余計なメニューを削除
376 HMENU sysm = ::GetSystemMenu( dlg, FALSE );
377 ::DeleteMenu( sysm, SC_SIZE, MF_BYCOMMAND );
378 ::DeleteMenu( sysm, SC_MAXIMIZE, MF_BYCOMMAND );
379
380 // 起動時はウインドウを必ず前面へ
381 setFront( dlg );
382
383 //サブクラス化する
384 st_CurInitPS->m_DefProc = (WNDPROC)::SetWindowLong( dlg, GWL_WNDPROC, (LONG)main_cmmnProc );
385 st_CurInitPS->onInit();
386 }
387 return 0;
388 }
389
390 BOOL kiPropSheet::page_cmmnProc( HWND dlg, UINT msg, WPARAM wp, LPARAM lp )
391 {
392 kiPropSheetPage* ptr = (kiPropSheetPage*)::GetWindowLong( dlg, GWL_USERDATA );
393 if( !ptr )
394 return FALSE;
395
396 // ここで、共通処理
397 switch( msg )
398 {
399 case WM_INITDIALOG:
400 return ptr->onInit();
401
402 case WM_NOTIFY:
403 switch( ((NMHDR*)lp)->code )
404 {
405 case PSN_APPLY:
406 ptr->onOK();
407 return TRUE;
408 }
409 break;
410
411 case WM_COMMAND:
412 if( lp )
413 switch( HIWORD(wp) )
414 {
415 case BN_CLICKED:
416 if((HWND)lp==::GetFocus())
417 case EN_CHANGE:
418 case CBN_SELCHANGE:
419 PropSheet_Changed( ptr->parent()->hwnd(), dlg );
420 }
421 break;
422
423 case WM_DESTROY:
424 BOOL ans=ptr->proc( msg, wp, lp );
425 ptr->detachHwnd();
426 return ans;
427 }
428
429 return ptr->proc( msg, wp, lp );
430 }
431
432 UINT CALLBACK kiPropSheet::page_initProc( HWND dlg, UINT msg, LPPROPSHEETPAGE ppsp )
433 {
434 if( msg == PSPCB_CREATE )
435 preCreate( (kiWindow*)(ppsp->lParam) );
436 return TRUE;
437 }
438
439 void kiPropSheetPage::setInfo( PROPSHEETPAGE* p )
440 {
441 p->pszTemplate = MAKEINTRESOURCE( getRsrcID() );
442 p->lParam = (LPARAM)this;
443
444 if( m_hIcon )
445 {
446 p->dwFlags|= PSP_USEHICON;
447 p->hIcon = m_hIcon;
448 }
449 }
450