Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Here is what I do in my console application (running on Windows 7):</p> <p>i. Create hidden window to wait for close/logoff notification. <strong>Important:</strong> give it own thread for its message loop</p> <pre><code>void interrupt::start() { WNDCLASSEX wc = {}; HINSTANCE hi = GetModuleHandle(NULL); wc.cbSize = sizeof(WNDCLASSEX); wc.lpfnWndProc = WndProc; // . . . etc if(!RegisterClassEx(&amp;wc)) return; hwnd_ = CreateWindowEx(WS_EX_CLIENTEDGE, class_name, "Waiting for user logoff event", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hi , NULL); ShowWindow(hwnd_, SW_HIDE); UpdateWindow(hwnd_); MSG msg = {}; while(GetMessage(&amp;msg, NULL, 0, 0)) { TranslateMessage(&amp;msg); DispatchMessage(&amp;msg); } // call internal function for sending "stop" notification to rest of program ctrl.stop(CTRL_CLOSE_EVENT); } </code></pre> <p>ii. Implement handling of "special events" in your window message handler</p> <pre><code>LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_ENDSESSION: if (lParam) { // call internal function for sending "stop" notification to rest of program ctrl.stop(lParam == ENDSESSION_LOGOFF ? (int) interrupt::logoff : CTRL_CLOSE_EVENT); } break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } </code></pre> <p>iii. Implement internal function for handling "stop" requests. It must handle 2 special conditions:</p> <p>a. when <strong>not</strong> called from window message thread, send WM_CLOSE to window and wait for its thread to exit</p> <p>b. when <strong>not</strong> called from main thread, wait for termination of static variables (at least one).</p> <p>This is because after CtrlHandler exit, Windows will unconditionally terminate your process without giving your code any chance for cleanup. Static variables are destroyed on main thread, so this wait gives you at least guarantee that <code>int main()</code> has exited. You can capture thread id of main thread in the constructor of a static variable (possibly the same which started "shadow" window).</p> <p>Here is how I did it in my code:</p> <pre><code>void interrupt::stop(int signal) { // . . . // Set exit signal InterlockedExchange(&amp;stage_, 2L); // Close shadow window if notification is from elsewhere if (hwnd_ &amp;&amp; GetCurrentThreadId() != thread_.id()) { PostMessage(hwnd_, WM_CLOSE, 0, 0); thread_.wait(); } // Wait for completion of own destructor on main thread if (GetCurrentThreadId() != main_thread_id_) while(stage_ != 3L) Sleep(10); } // My static variable to wait for interrupt ctrl; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload