WinapiExtension
 All Classes Files Functions Variables Typedefs Pages
WindowModal.h
1 #ifndef WINAPI_EX_WINDOWMODAL_H
2 #define WINAPI_EX_WINDOWMODAL_H
3 
10 class WindowModal : public Window
11 {
12 public:
14  WindowModal();
15 
21  int DoModal(bool blockEntireThread = true);
26  void EndModal(int result);
28  bool IsModal() { return modalLoopRunning; }
29 
31  static const int MODAL_ERROR = -1;
32 private:
34  virtual void ProcessMessage(MSG* msg);
35 
36  static BOOL CALLBACK CountEnabledWindows(HWND hwnd, LPARAM pBuffer);
37  static BOOL CALLBACK ListEnabledWindows(HWND hwnd, LPARAM pBuffer);
38 
39  // helper class if the entire thread should be blocked
40  class HwndBuffer
41  {
42  public:
43  HwndBuffer(HWND pMyWindow) : myWindow(pMyWindow), filled(0) { count = 0; hwnds = NULL; }
44  ~HwndBuffer() { delete [] hwnds; }
45 
46  void EnableWindows(BOOL enable) { for(int i = 0; i < count; ++i) EnableWindow(hwnds[i], enable); }
47 
48  HWND myWindow; // handle of this instance, which should be excluded from enumeration
49  HWND* hwnds;
50  int filled; // counter for the enumeration
51  int count; // size of hwnds
52  };
53 
54  bool modalLoopRunning;
55  int modalResult;
56 };
57 
58 //-----------------------------------------------------------------------------
59 
61 {
62  modalLoopRunning = false;
63  modalResult = MODAL_ERROR;
64 }
65 
66 inline int WindowModal::DoModal(bool blockEntireThread)
67 {
68  // don't start modal loop on the same window twice
69  assert(!modalLoopRunning && GetHandle());
70  if(modalLoopRunning || GetHandle() == NULL)
71  return -1;
72 
73  HWND parent = (HWND)GetWindowLongPtr(GetHandle(), GWLP_HWNDPARENT);
74 
75  // disable some windows
76  HwndBuffer windowsToDisable(GetHandle());
77  if(blockEntireThread)
78  {
79  // make a list of all windows we want to disable during modal message loop
80  EnumThreadWindows(GetCurrentThreadId(), CountEnabledWindows, (LPARAM)&windowsToDisable);
81  windowsToDisable.hwnds = new HWND[windowsToDisable.count];
82  EnumThreadWindows(GetCurrentThreadId(), ListEnabledWindows, (LPARAM)&windowsToDisable);
83  windowsToDisable.EnableWindows(FALSE);
84  }
85  else
86  EnableWindow(parent, FALSE);
87 
88  ShowWindow(GetHandle(), SW_SHOW);
89 
90  // modal message loop
91  modalLoopRunning = true;
92  while(modalLoopRunning)
93  {
94  MSG msg;
95  WaitMessage();
96  while(modalLoopRunning && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
97  {
98  if(msg.message == WM_QUIT)
99  {
100  EndModal(-1);
101  PostQuitMessage((int)msg.wParam); // re-post
102  continue;
103  }
104  // virtual
105  ProcessMessage(&msg);
106  }
107  }
108 
109  // restore everything
110  if(blockEntireThread)
111  windowsToDisable.EnableWindows(TRUE);
112  else
113  EnableWindow(parent, TRUE);
114  // we need this if multiple modal loops are active (creating WindowModal inside another WindowModal)
115  BringWindowToTop(parent);
116  // hide after the parent is restored, otherwise the Z-Order goes wild
117  ShowWindow(GetHandle(), SW_HIDE);
118 
119  return modalResult;
120 }
121 
122 inline void WindowModal::EndModal(int result)
123 {
124  modalLoopRunning = false;
125  modalResult = result;
126 }
127 
128 inline void WindowModal::ProcessMessage(MSG* msg)
129 {
130  // behave like a dialog
131  if(!IsDialogMessage(GetHandle(), msg))
132  {
133  TranslateMessage(msg);
134  DispatchMessage(msg);
135  }
136 }
137 
138 inline BOOL CALLBACK WindowModal::CountEnabledWindows(HWND hwnd, LPARAM pBuffer)
139 {
140  HwndBuffer* buffer = (HwndBuffer*)pBuffer;
141  if(buffer && buffer->myWindow != hwnd && (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD) == 0 && IsWindowEnabled(hwnd))
142  ++buffer->count;
143  return TRUE;
144 }
145 
146 inline BOOL CALLBACK WindowModal::ListEnabledWindows(HWND hwnd, LPARAM pBuffer)
147 {
148  HwndBuffer* buffer = (HwndBuffer*)pBuffer;
149  if(buffer && buffer->myWindow != hwnd && (GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD) == 0 && IsWindowEnabled(hwnd))
150  buffer->hwnds[buffer->filled++] = hwnd;
151  return TRUE;
152 }
153 
154 #endif