| 2132 | |
| 2133 | |
| 2134 | void GuiType::Destroy() |
| 2135 | // Destroys the window and performs related cleanup which is only necessary for |
| 2136 | // a successfully constructed Gui, then calls Dispose() for the remaining cleanup. |
| 2137 | { |
| 2138 | if (!mHwnd) |
| 2139 | return; // We have already been destroyed. |
| 2140 | |
| 2141 | // First destroy any windows owned by this window, since they will be auto-destroyed |
| 2142 | // anyway due to their being owned. By destroying them explicitly, the Destroy() |
| 2143 | // function is called recursively which keeps everything relatively neat. |
| 2144 | // Lexikos: I'm not really sure what Chris meant by "neat", since Destroy() is called |
| 2145 | // recursively via WM_DESTROY anyway. It's currently left to WM_DESTROY because the |
| 2146 | // code below is actually broken in two ways (unique to the new object-oriented API): |
| 2147 | // 1) If there are no external references to gui, it will be deleted and gui->mNextGui |
| 2148 | // will likely crash the program. |
| 2149 | // 2) Destroy() removes the gui from the list, which causes the loop to break at the |
| 2150 | // first owned/child window. Saving the next/previous link before-hand may not |
| 2151 | // solve the problem since Destroy() could recursively destroy other windows. |
| 2152 | //for (GuiType* gui = g_firstGui; gui; gui = gui->mNextGui) |
| 2153 | // if (gui->mOwner == mHwnd) |
| 2154 | // gui->Destroy(); |
| 2155 | |
| 2156 | // Testing shows that this must be done prior to calling DestroyWindow() later below, presumably |
| 2157 | // because the destruction immediately destroys the status bar, or prevents it from answering messages. |
| 2158 | // MSDN says "During the processing of [WM_DESTROY], it can be assumed that all child windows still exist". |
| 2159 | // However, for DestroyWindow() to have returned means that WM_DESTROY was already fully processed. |
| 2160 | if (mStatusBarHwnd) // IsWindow(gui.mStatusBarHwnd) isn't called because even if possible for it to have been destroyed, SendMessage below should return 0. |
| 2161 | { |
| 2162 | // This is done because the vast majority of people wouldn't want to have to worry about it. |
| 2163 | // They can always use DllCall() if they want to share the same HICON among multiple parts of |
| 2164 | // the same bar, or among different windows (fairly rare). |
| 2165 | HICON hicon; |
| 2166 | int part_count = (int)SendMessage(mStatusBarHwnd, SB_GETPARTS, 0, NULL); // MSDN: "This message always returns the number of parts in the status bar [regardless of how it is called]". |
| 2167 | for (int i = 0; i < part_count; ++i) |
| 2168 | if (hicon = (HICON)SendMessage(mStatusBarHwnd, SB_GETICON, i, 0)) |
| 2169 | DestroyIcon(hicon); |
| 2170 | } |
| 2171 | |
| 2172 | if (IsWindow(mHwnd)) // If WM_DESTROY called us, the window might already be partially destroyed. |
| 2173 | { |
| 2174 | // If this window is using a menu bar but that menu is also used by some other window, first |
| 2175 | // detach the menu so that it doesn't get auto-destroyed with the window. This is done |
| 2176 | // unconditionally since such a menu will be automatically destroyed when the script exits |
| 2177 | // or when the menu is destroyed explicitly via the Menu command. It also prevents any |
| 2178 | // submenus attached to the menu bar from being destroyed, since those submenus might be |
| 2179 | // also used by other menus (however, this is not really an issue since menus destroyed |
| 2180 | // would be automatically re-created upon next use). But in the case of a window that |
| 2181 | // is currently using a menu bar, destroying that bar in conjunction with the destruction |
| 2182 | // of some other window might cause bad side effects on some/all OSes. |
| 2183 | ShowWindow(mHwnd, SW_HIDE); // Hide it to prevent re-drawing due to menu removal. |
| 2184 | ::SetMenu(mHwnd, NULL); |
| 2185 | if (!mDestroyWindowHasBeenCalled) |
| 2186 | { |
| 2187 | mDestroyWindowHasBeenCalled = true; // Signal the WM_DESTROY routine not to call us. |
| 2188 | DestroyWindow(mHwnd); // The WindowProc is immediately called and it now destroys the window. |
| 2189 | } |
| 2190 | // else WM_DESTROY was called by a function other than this one (possibly auto-destruct due to |
| 2191 | // being owned by script's main window), so it would be bad to call DestroyWindow() again since |
no test coverage detected