Sync with trunk.
[reactos.git] / lib / atl / atlwin.h
1 /*
2 * ReactOS ATL
3 *
4 * Copyright 2009 Andrew Hill <ash77@reactos.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #pragma once
22
23 #ifdef __GNUC__
24 #define GCCU(x) x __attribute__((unused))
25 #define Unused(x)
26 #else
27 #define GCCU(x) (x)
28 #define Unused(x) (x);
29 #endif // __GNUC__
30
31 #ifdef SetWindowLongPtr
32 #undef SetWindowLongPtr
33 inline LONG_PTR SetWindowLongPtr(HWND hWnd, int nIndex, LONG_PTR dwNewLong)
34 {
35 return SetWindowLong(hWnd, nIndex, (LONG)dwNewLong);
36 }
37 #endif
38
39 #ifdef GetWindowLongPtr
40 #undef GetWindowLongPtr
41 inline LONG_PTR GetWindowLongPtr(HWND hWnd, int nIndex)
42 {
43 return (LONG_PTR)GetWindowLong(hWnd, nIndex);
44 }
45 #endif
46
47 namespace ATL
48 {
49
50 struct _ATL_WNDCLASSINFOW;
51 typedef _ATL_WNDCLASSINFOW CWndClassInfo;
52
53 template <DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0>
54 class CWinTraits
55 {
56 public:
57 static DWORD GetWndStyle(DWORD dwStyle)
58 {
59 if (dwStyle == 0)
60 return t_dwStyle;
61 return dwStyle;
62 }
63
64 static DWORD GetWndExStyle(DWORD dwExStyle)
65 {
66 if (dwExStyle == 0)
67 return t_dwExStyle;
68 return dwExStyle;
69 }
70 };
71
72 typedef CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0> CControlWinTraits;
73 typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE> CFrameWinTraits;
74 typedef CWinTraits<WS_OVERLAPPEDWINDOW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_MDICHILD> CMDIChildWinTraits;
75
76 template <DWORD t_dwStyle = 0, DWORD t_dwExStyle = 0, class TWinTraits = CControlWinTraits>
77 class CWinTraitsOR
78 {
79 public:
80 static DWORD GetWndStyle(DWORD dwStyle)
81 {
82 return dwStyle | t_dwStyle | TWinTraits::GetWndStyle(dwStyle);
83 }
84
85 static DWORD GetWndExStyle(DWORD dwExStyle)
86 {
87 return dwExStyle | t_dwExStyle | TWinTraits::GetWndExStyle(dwExStyle);
88 }
89 };
90
91 class _U_MENUorID
92 {
93 public:
94 HMENU m_hMenu;
95 public:
96 _U_MENUorID(HMENU hMenu)
97 {
98 m_hMenu = hMenu;
99 }
100
101 _U_MENUorID(UINT nID)
102 {
103 m_hMenu = (HMENU)(UINT_PTR)nID;
104 }
105 };
106
107 class _U_RECT
108 {
109 public:
110 LPRECT m_lpRect;
111 public:
112 _U_RECT(LPRECT lpRect)
113 {
114 m_lpRect = lpRect;
115 }
116
117 _U_RECT(RECT &rc)
118 {
119 m_lpRect = &rc;
120 }
121 };
122
123 struct _ATL_MSG : public MSG
124 {
125 public:
126 BOOL bHandled;
127 public:
128 _ATL_MSG(HWND hWnd, UINT uMsg, WPARAM wParamIn, LPARAM lParamIn, BOOL bHandledIn = TRUE)
129 {
130 hwnd = hWnd;
131 message = uMsg;
132 wParam = wParamIn;
133 lParam = lParamIn;
134 time = 0;
135 pt.x = 0;
136 pt.y = 0;
137 bHandled = bHandledIn;
138 }
139 };
140
141 #if defined(_M_IX86)
142
143 #pragma pack(push,1)
144 struct thunkCode
145 {
146 DWORD m_mov;
147 DWORD m_this;
148 BYTE m_jmp;
149 DWORD m_relproc;
150 };
151 #pragma pack(pop)
152
153 class CWndProcThunk
154 {
155 public:
156 thunkCode m_thunk;
157 _AtlCreateWndData cd;
158 public:
159 BOOL Init(WNDPROC proc, void *pThis)
160 {
161 m_thunk.m_mov = 0x042444C7;
162 m_thunk.m_this = PtrToUlong(pThis);
163 m_thunk.m_jmp = 0xe9;
164 m_thunk.m_relproc = DWORD(reinterpret_cast<char *>(proc) - (reinterpret_cast<char *>(this) + sizeof(thunkCode)));
165 return TRUE;
166 }
167
168 WNDPROC GetWNDPROC()
169 {
170 return reinterpret_cast<WNDPROC>(&m_thunk);
171 }
172 };
173
174 #elif _AMD64_ //WARNING: NOT VERIFIED
175 #pragma pack(push,1)
176 struct thunkCode
177 {
178 DWORD_PTR m_mov;
179 DWORD_PTR m_this;
180 BYTE m_jmp;
181 DWORD_PTR m_relproc;
182 };
183 #pragma pack(pop)
184
185 class CWndProcThunk
186 {
187 public:
188 thunkCode m_thunk;
189 _AtlCreateWndData cd;
190 public:
191 BOOL Init(WNDPROC proc, void *pThis)
192 {
193 m_thunk.m_mov = 0xffff8000042444C7LL;
194 m_thunk.m_this = (DWORD_PTR)pThis;
195 m_thunk.m_jmp = 0xe9;
196 m_thunk.m_relproc = DWORD_PTR(reinterpret_cast<char *>(proc) - (reinterpret_cast<char *>(this) + sizeof(thunkCode)));
197 return TRUE;
198 }
199
200 WNDPROC GetWNDPROC()
201 {
202 return reinterpret_cast<WNDPROC>(&m_thunk);
203 }
204 };
205 #else
206 #error ARCH not supported
207 #endif
208
209 class CMessageMap
210 {
211 public:
212 virtual BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult, DWORD dwMsgMapID) = 0;
213 };
214
215 class CWindow
216 {
217 public:
218 HWND m_hWnd;
219 static RECT rcDefault;
220 public:
221 CWindow(HWND hWnd = NULL)
222 {
223 m_hWnd = hWnd;
224 }
225
226 operator HWND() const
227 {
228 return m_hWnd;
229 }
230
231 static LPCTSTR GetWndClassName()
232 {
233 return NULL;
234 }
235
236 HDC BeginPaint(LPPAINTSTRUCT lpPaint)
237 {
238 ATLASSERT(::IsWindow(m_hWnd));
239 return ::BeginPaint(m_hWnd, lpPaint);
240 }
241
242 BOOL DestroyWindow()
243 {
244 ATLASSERT(::IsWindow(m_hWnd));
245
246 if (!::DestroyWindow(m_hWnd))
247 return FALSE;
248
249 m_hWnd = NULL;
250 return TRUE;
251 }
252
253 void EndPaint(LPPAINTSTRUCT lpPaint)
254 {
255 ATLASSERT(::IsWindow(m_hWnd));
256 ::EndPaint(m_hWnd, lpPaint);
257 }
258
259 BOOL GetClientRect(LPRECT lpRect) const
260 {
261 ATLASSERT(::IsWindow(m_hWnd));
262 return ::GetClientRect(m_hWnd, lpRect);
263 }
264
265 CWindow GetParent() const
266 {
267 ATLASSERT(::IsWindow(m_hWnd));
268 return CWindow(::GetParent(m_hWnd));
269 }
270
271 BOOL Invalidate(BOOL bErase = TRUE)
272 {
273 ATLASSERT(::IsWindow(m_hWnd));
274 return ::InvalidateRect(m_hWnd, NULL, bErase);
275 }
276
277 BOOL InvalidateRect(LPCRECT lpRect, BOOL bErase = TRUE)
278 {
279 ATLASSERT(::IsWindow(m_hWnd));
280 return ::InvalidateRect(m_hWnd, lpRect, bErase);
281 }
282
283 BOOL IsWindow() const
284 {
285 return ::IsWindow(m_hWnd);
286 }
287
288 BOOL KillTimer(UINT_PTR nIDEvent)
289 {
290 ATLASSERT(::IsWindow(m_hWnd));
291 return ::KillTimer(m_hWnd, nIDEvent);
292 }
293
294 BOOL LockWindowUpdate(BOOL bLock = TRUE)
295 {
296 ATLASSERT(::IsWindow(m_hWnd));
297 if (bLock)
298 return ::LockWindowUpdate(m_hWnd);
299 return ::LockWindowUpdate(NULL);
300 }
301
302 BOOL ScreenToClient(LPPOINT lpPoint) const
303 {
304 ATLASSERT(::IsWindow(m_hWnd));
305 return ::ScreenToClient(m_hWnd, lpPoint);
306 }
307
308 LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
309 {
310 ATLASSERT(::IsWindow(m_hWnd));
311 return ::SendMessage(m_hWnd, message, wParam, lParam);
312 }
313
314 static LRESULT SendMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
315 {
316 ATLASSERT(::IsWindow(hWnd));
317 return ::SendMessage(hWnd, message, wParam, lParam);
318 }
319
320 HWND SetCapture()
321 {
322 ATLASSERT(::IsWindow(m_hWnd));
323 return ::SetCapture(m_hWnd);
324 }
325
326 HWND SetFocus()
327 {
328 ATLASSERT(::IsWindow(m_hWnd));
329 return ::SetFocus(m_hWnd);
330 }
331
332 UINT_PTR SetTimer(UINT_PTR nIDEvent, UINT nElapse, void (CALLBACK *lpfnTimer)(HWND, UINT, UINT_PTR, DWORD) = NULL)
333 {
334 ATLASSERT(::IsWindow(m_hWnd));
335 return ::SetTimer(m_hWnd, nIDEvent, nElapse, reinterpret_cast<TIMERPROC>(lpfnTimer));
336 }
337
338 BOOL SetWindowPos(HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags)
339 {
340 ATLASSERT(::IsWindow(m_hWnd));
341 return ::SetWindowPos(m_hWnd, hWndInsertAfter, x, y, cx, cy, nFlags);
342 }
343
344 BOOL SetWindowText(LPCTSTR lpszString)
345 {
346 ATLASSERT(::IsWindow(m_hWnd));
347 return ::SetWindowText(m_hWnd, lpszString);
348 }
349
350 BOOL ShowWindow(int nCmdShow)
351 {
352 ATLASSERT(::IsWindow(m_hWnd));
353 return ::ShowWindow(m_hWnd, nCmdShow);
354 }
355
356 BOOL UpdateWindow()
357 {
358 ATLASSERT(::IsWindow(m_hWnd));
359 return ::UpdateWindow(m_hWnd);
360 }
361 };
362
363 __declspec(selectany) RECT CWindow::rcDefault = { CW_USEDEFAULT, CW_USEDEFAULT, 0, 0 };
364
365 template <class TBase = CWindow, class TWinTraits = CControlWinTraits>
366 class CWindowImplBaseT : public TBase, public CMessageMap
367 {
368 public:
369 enum { WINSTATE_DESTROYED = 0x00000001 };
370 DWORD m_dwState;
371 const _ATL_MSG *m_pCurrentMsg;
372 CWndProcThunk m_thunk;
373 WNDPROC m_pfnSuperWindowProc;
374 public:
375 CWindowImplBaseT()
376 {
377 m_dwState = 0;
378 m_pCurrentMsg = NULL;
379 m_pfnSuperWindowProc = ::DefWindowProc;
380 }
381
382 virtual void OnFinalMessage(HWND /* hWnd */)
383 {
384 }
385
386 BOOL SubclassWindow(HWND hWnd)
387 {
388 CWindowImplBaseT<TBase, TWinTraits> *pThis;
389 WNDPROC newWindowProc;
390 WNDPROC oldWindowProc;
391 BOOL result;
392
393 ATLASSERT(m_hWnd == NULL);
394 ATLASSERT(::IsWindow(hWnd));
395
396 pThis = reinterpret_cast<CWindowImplBaseT<TBase, TWinTraits>*>(this);
397
398 result = m_thunk.Init(GetWindowProc(), this);
399 if (result == FALSE)
400 return FALSE;
401 newWindowProc = m_thunk.GetWNDPROC();
402 oldWindowProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(newWindowProc)));
403 if (oldWindowProc == NULL)
404 return FALSE;
405 m_pfnSuperWindowProc = oldWindowProc;
406 pThis->m_hWnd = hWnd;
407 return TRUE;
408 }
409
410 virtual WNDPROC GetWindowProc()
411 {
412 return WindowProc;
413 }
414
415 static DWORD GetWndStyle(DWORD dwStyle)
416 {
417 return TWinTraits::GetWndStyle(dwStyle);
418 }
419
420 static DWORD GetWndExStyle(DWORD dwExStyle)
421 {
422 return TWinTraits::GetWndExStyle(dwExStyle);
423 }
424
425 LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
426 {
427 CWindowImplBaseT<TBase, TWinTraits> *pThis;
428
429 pThis = reinterpret_cast<CWindowImplBaseT<TBase, TWinTraits> *>(this);
430 return ::CallWindowProc(m_pfnSuperWindowProc, pThis->m_hWnd, uMsg, wParam, lParam);
431 }
432
433 static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
434 {
435 CWindowImplBaseT<TBase, TWinTraits> *pThis;
436 WNDPROC newWindowProc;
437 WNDPROC GCCU(pOldProc);
438
439 pThis = reinterpret_cast<CWindowImplBaseT<TBase, TWinTraits> *>(_AtlWinModule.ExtractCreateWndData());
440 ATLASSERT(pThis != NULL);
441 if (pThis == NULL)
442 return 0;
443 pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);
444 newWindowProc = pThis->m_thunk.GetWNDPROC();
445 pOldProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(newWindowProc)));
446 Unused(pOldProc); // TODO: should generate trace message if overwriting another subclass
447 pThis->m_hWnd = hWnd;
448 return newWindowProc(hWnd, uMsg, wParam, lParam);
449 }
450
451 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
452 {
453 CWindowImplBaseT<TBase, TWinTraits> *pThis = reinterpret_cast<CWindowImplBaseT< TBase, TWinTraits> *>(hWnd);
454 _ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
455 LRESULT lResult;
456 const _ATL_MSG *previousMessage;
457 BOOL handled;
458 LONG_PTR saveWindowProc;
459
460 ATLASSERT(pThis != NULL && (pThis->m_dwState & WINSTATE_DESTROYED) == 0 && pThis->m_hWnd != NULL);
461 if (pThis == NULL || (pThis->m_dwState & WINSTATE_DESTROYED) != 0 || pThis->m_hWnd == NULL)
462 return 0;
463
464 hWnd = pThis->m_hWnd;
465 previousMessage = pThis->m_pCurrentMsg;
466 pThis->m_pCurrentMsg = &msg;
467
468 handled = pThis->ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, 0);
469 ATLASSERT(pThis->m_pCurrentMsg == &msg);
470
471 if (handled == FALSE)
472 {
473 if (uMsg == WM_NCDESTROY)
474 {
475 saveWindowProc = ::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
476 lResult = pThis->DefWindowProc(uMsg, wParam, lParam);
477 if (pThis->m_pfnSuperWindowProc != ::DefWindowProc && saveWindowProc == ::GetWindowLongPtr(hWnd, GWLP_WNDPROC))
478 ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(pThis->m_pfnSuperWindowProc));
479 pThis->m_dwState |= WINSTATE_DESTROYED;
480 }
481 else
482 lResult = pThis->DefWindowProc(uMsg, wParam, lParam);
483 }
484 ATLASSERT(pThis->m_pCurrentMsg == &msg);
485 pThis->m_pCurrentMsg = previousMessage;
486 if (previousMessage == NULL && (pThis->m_dwState & WINSTATE_DESTROYED) != 0)
487 {
488 pThis->m_dwState &= ~WINSTATE_DESTROYED;
489 pThis->m_hWnd = NULL;
490 pThis->OnFinalMessage(hWnd);
491 }
492 return lResult;
493 }
494
495 HWND Create(HWND hWndParent, _U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle,
496 _U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam)
497 {
498 HWND hWnd;
499
500 ATLASSERT(m_hWnd == NULL);
501 ATLASSERT(atom != 0);
502 if (atom == 0)
503 return NULL;
504 if (m_thunk.Init(NULL, NULL) == FALSE)
505 {
506 SetLastError(ERROR_OUTOFMEMORY);
507 return NULL;
508 }
509
510 _AtlWinModule.AddCreateWndData(&m_thunk.cd, this);
511 if (MenuOrID.m_hMenu == NULL && (dwStyle & WS_CHILD) != 0)
512 MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this;
513 if (rect.m_lpRect == NULL)
514 rect.m_lpRect = &TBase::rcDefault;
515 hWnd = ::CreateWindowEx(dwExStyle, reinterpret_cast<LPCWSTR>(MAKEINTATOM(atom)), szWindowName, dwStyle, rect.m_lpRect->left,
516 rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left, rect.m_lpRect->bottom - rect.m_lpRect->top,
517 hWndParent, MenuOrID.m_hMenu, _AtlBaseModule.GetModuleInstance(), lpCreateParam);
518
519 ATLASSERT(m_hWnd == hWnd);
520
521 return hWnd;
522 }
523 };
524
525 template <class T, class TBase = CWindow, class TWinTraits = CControlWinTraits>
526 class CWindowImpl : public CWindowImplBaseT<TBase, TWinTraits>
527 {
528 public:
529 static LPCTSTR GetWndCaption()
530 {
531 return NULL;
532 }
533
534 HWND Create(HWND hWndParent, _U_RECT rect = NULL, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0,
535 DWORD dwExStyle = 0, _U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
536 {
537 CWindowImplBaseT<TBase, TWinTraits> *pThis;
538 ATOM atom;
539
540 ATLASSERT(m_hWnd == NULL);
541 pThis = reinterpret_cast<CWindowImplBaseT<TBase, TWinTraits>*>(this);
542
543 if (T::GetWndClassInfo().m_lpszOrigName == NULL)
544 T::GetWndClassInfo().m_lpszOrigName = pThis->GetWndClassName();
545 atom = T::GetWndClassInfo().Register(&pThis->m_pfnSuperWindowProc);
546
547 if (szWindowName == NULL)
548 szWindowName = T::GetWndCaption();
549 dwStyle = T::GetWndStyle(dwStyle);
550 dwExStyle = T::GetWndExStyle(dwExStyle);
551
552 return CWindowImplBaseT<TBase, TWinTraits>::Create(hWndParent, rect, szWindowName, dwStyle,
553 dwExStyle, MenuOrID, atom, lpCreateParam);
554 }
555 };
556
557 template <class TBase = CWindow, class TWinTraits = CControlWinTraits>
558 class CContainedWindowT : public TBase
559 {
560 public:
561 CWndProcThunk m_thunk;
562 LPCTSTR m_lpszClassName;
563 WNDPROC m_pfnSuperWindowProc;
564 CMessageMap *m_pObject;
565 DWORD m_dwMsgMapID;
566 const _ATL_MSG *m_pCurrentMsg;
567 public:
568 CContainedWindowT(CMessageMap *pObject, DWORD dwMsgMapID = 0)
569 {
570 m_lpszClassName = TBase::GetWndClassName();
571 m_pfnSuperWindowProc = ::DefWindowProc;
572 m_pObject = pObject;
573 m_dwMsgMapID = dwMsgMapID;
574 m_pCurrentMsg = NULL;
575 }
576
577 CContainedWindowT(LPTSTR lpszClassName, CMessageMap *pObject, DWORD dwMsgMapID = 0)
578 {
579 m_lpszClassName = lpszClassName;
580 m_pfnSuperWindowProc = ::DefWindowProc;
581 m_pObject = pObject;
582 m_dwMsgMapID = dwMsgMapID;
583 m_pCurrentMsg = NULL;
584 }
585
586 LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
587 {
588 return ::CallWindowProc(m_pfnSuperWindowProc, this->m_hWnd, uMsg, wParam, lParam);
589 }
590
591 BOOL SubclassWindow(HWND hWnd)
592 {
593 CContainedWindowT<TBase> *pThis;
594 WNDPROC newWindowProc;
595 WNDPROC oldWindowProc;
596 BOOL result;
597
598 ATLASSERT(m_hWnd == NULL);
599 ATLASSERT(::IsWindow(hWnd));
600
601 pThis = reinterpret_cast<CContainedWindowT<TBase> *>(this);
602
603 result = m_thunk.Init(WindowProc, pThis);
604 if (result == FALSE)
605 return FALSE;
606 newWindowProc = m_thunk.GetWNDPROC();
607 oldWindowProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(newWindowProc)));
608 if (oldWindowProc == NULL)
609 return FALSE;
610 m_pfnSuperWindowProc = oldWindowProc;
611 pThis->m_hWnd = hWnd;
612 return TRUE;
613 }
614
615 static LRESULT CALLBACK StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
616 {
617 CContainedWindowT<TBase> *pThis;
618 WNDPROC newWindowProc;
619 WNDPROC GCCU(pOldProc);
620
621 pThis = reinterpret_cast<CContainedWindowT<TBase> *>(_AtlWinModule.ExtractCreateWndData());
622 ATLASSERT(pThis != NULL);
623 if (pThis == NULL)
624 return 0;
625 pThis->m_thunk.Init(WindowProc, pThis);
626 newWindowProc = pThis->m_thunk.GetWNDPROC();
627 pOldProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(newWindowProc)));
628 Unused(pOldProc); // TODO: should generate trace message if overwriting another subclass
629 pThis->m_hWnd = hWnd;
630 return newWindowProc(hWnd, uMsg, wParam, lParam);
631 }
632
633 static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
634 {
635 CContainedWindowT<TBase> *pThis = reinterpret_cast<CContainedWindowT<TBase> *>(hWnd);
636 _ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
637 LRESULT lResult;
638 const _ATL_MSG *previousMessage;
639 BOOL handled;
640 LONG_PTR saveWindowProc;
641
642 ATLASSERT(pThis != NULL && pThis->m_hWnd != NULL && pThis->m_pObject != NULL);
643 if (pThis == NULL || pThis->m_hWnd == NULL || pThis->m_pObject == NULL)
644 return 0;
645
646 hWnd = pThis->m_hWnd;
647 previousMessage = pThis->m_pCurrentMsg;
648 pThis->m_pCurrentMsg = &msg;
649
650 handled = pThis->m_pObject->ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, pThis->m_dwMsgMapID);
651 ATLASSERT(pThis->m_pCurrentMsg == &msg);
652
653 pThis->m_pCurrentMsg = previousMessage;
654 if (handled == FALSE)
655 {
656 if (uMsg == WM_NCDESTROY)
657 {
658 saveWindowProc = ::GetWindowLongPtr(hWnd, GWLP_WNDPROC);
659 lResult = pThis->DefWindowProc(uMsg, wParam, lParam);
660 if (pThis->m_pfnSuperWindowProc != ::DefWindowProc && saveWindowProc == ::GetWindowLongPtr(hWnd, GWLP_WNDPROC))
661 ::SetWindowLongPtr(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(pThis->m_pfnSuperWindowProc));
662 pThis->m_hWnd = NULL;
663 }
664 else
665 lResult = pThis->DefWindowProc(uMsg, wParam, lParam);
666 }
667 return lResult;
668 }
669
670 };
671 typedef CContainedWindowT<CWindow> CContainedWindow;
672
673 #define BEGIN_MSG_MAP(theClass) \
674 public: \
675 BOOL ProcessWindowMessage(HWND GCCU(hWnd), UINT GCCU(uMsg), WPARAM GCCU(wParam), LPARAM GCCU(lParam), LRESULT &GCCU(lResult), DWORD dwMsgMapID = 0) \
676 { \
677 BOOL GCCU(bHandled) = TRUE; \
678 Unused(hWnd); \
679 Unused(uMsg); \
680 Unused(wParam); \
681 Unused(lParam); \
682 Unused(lResult); \
683 Unused(bHandled); \
684 switch(dwMsgMapID) \
685 { \
686 case 0:
687
688 #define END_MSG_MAP() \
689 break; \
690 default: \
691 ATLASSERT(FALSE); \
692 break; \
693 } \
694 return FALSE; \
695 }
696
697 #define MESSAGE_HANDLER(msg, func) \
698 if (uMsg == msg) \
699 { \
700 bHandled = TRUE; \
701 lResult = func(uMsg, wParam, lParam, bHandled); \
702 if (bHandled) \
703 return TRUE; \
704 }
705
706 #define MESSAGE_RANGE_HANDLER(msgFirst, msgLast, func) \
707 if (uMsg >= msgFirst && uMsg <= msgLast) \
708 { \
709 bHandled = TRUE; \
710 lResult = func(uMsg, wParam, lParam, bHandled); \
711 if (bHandled) \
712 return TRUE; \
713 }
714
715 #define COMMAND_ID_HANDLER(id, func) \
716 if (uMsg == WM_COMMAND && id == LOWORD(wParam)) \
717 { \
718 bHandled = TRUE; \
719 lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
720 if (bHandled) \
721 return TRUE; \
722 }
723
724 #define COMMAND_RANGE_HANDLER(idFirst, idLast, func) \
725 if (uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) \
726 { \
727 bHandled = TRUE; \
728 lResult = func(HIWORD(wParam), LOWORD(wParam), (HWND)lParam, bHandled); \
729 if (bHandled) \
730 return TRUE; \
731 }
732
733 #define NOTIFY_CODE_HANDLER(cd, func) \
734 if(uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) \
735 { \
736 bHandled = TRUE; \
737 lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
738 if (bHandled) \
739 return TRUE; \
740 }
741
742 #define NOTIFY_HANDLER(id, cd, func) \
743 if(uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom && cd == ((LPNMHDR)lParam)->code) \
744 { \
745 bHandled = TRUE; \
746 lResult = func((int)wParam, (LPNMHDR)lParam, bHandled); \
747 if (bHandled) \
748 return TRUE; \
749 }
750
751 #define DECLARE_WND_CLASS_EX(WndClassName, style, bkgnd) \
752 static ATL::CWndClassInfo& GetWndClassInfo() \
753 { \
754 static ATL::CWndClassInfo wc = \
755 { \
756 { sizeof(WNDCLASSEX), style, StartWindowProc, \
757 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
758 NULL, NULL, IDC_ARROW, TRUE, 0, _T("") \
759 }; \
760 return wc; \
761 }
762
763 struct _ATL_WNDCLASSINFOW
764 {
765 WNDCLASSEXW m_wc;
766 LPCWSTR m_lpszOrigName;
767 WNDPROC pWndProc;
768 LPCWSTR m_lpszCursorID;
769 BOOL m_bSystemCursor;
770 ATOM m_atom;
771 WCHAR m_szAutoName[5 + sizeof(void *)];
772
773 ATOM Register(WNDPROC *p)
774 {
775 if (m_wc.hInstance == NULL)
776 m_wc.hInstance = _AtlBaseModule.GetModuleInstance();
777 if (m_atom == 0)
778 m_atom = RegisterClassEx(&m_wc);
779 return m_atom;
780 }
781 };
782
783 }; // namespace ATL