Advertisement
Guest User

console exit handling research

a guest
Feb 1st, 2014
575
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.01 KB | None | 0 0
  1. http://www.mischel.com/pubs/consoledotnetconsoledotnet.zip
  2.  
  3. Far Manager can still prompt for saving when I'm in the editor when I close-click the console window. Its code is open-source, so someone who knows C++ better than me might be able to
  4.  
  5. glean how they do it. svn co http://farmanager.googlecode.com/svn/trunk fardev
  6.  
  7. case CTRL_CLOSE_EVENT:
  8. Global->CloseFAR=TRUE;
  9. Global->AllowCancelExit=FALSE;
  10.  
  11. // trick to let wmain() finish correctly
  12. ExitThread(1);
  13.  
  14.  
  15.  
  16. There is a tool named Restart Manager (rmtool.exe) in the Microsoft's Logo Testing Tools for Windows, which can be used to send shutdown and restart messages to a process. Logo testing
  17.  
  18. tools can be downloaded here: http://download.microsoft.com/download/d/2/5/d2522ce4-a441-459d-8302-be8f3321823c/LogoToolsv1.0.msi
  19.  
  20. Then you can simulate shutdown for your process:
  21.  
  22. rmtool.exe -p [PID] -S
  23. where [PID] is the process ID. According to the Vista Logo Certification Test Cases document,
  24.  
  25. Restart Manager shutdown messages are:
  26.  
  27. a. WM_QUERYENDSESSION with LPARAM = ENDSESSION_CLOSEAPP(0x1): GUI applications must respond (TRUE) immediately to prepare for a restart.
  28.  
  29. b. WM_ENDSESSION with LPARAM = ENDSESSION_CLOSEAPP(0x1): The application must shutdown within 5 seconds (20 seconds for services).
  30.  
  31. c. CTRL_SHUTDOWN_EVENT: Console applications must shutdown immediately.
  32.  
  33. You could use the SystemEvents.SessionEnding event, which is fired when a user logs off or shuts down.
  34. This event is only raised if the message pump is running. In a Windows service, unless a hidden form is used or the message pump has been started manually, this event will not be raised.
  35.  
  36. For a code example that shows how to handle system events by using a hidden form in a Windows service, see the SystemEvents class.
  37.  
  38.  
  39.  
  40.  
  41. http://msdn.microsoft.com/en-us/library/windows/desktop/aa376881%28v=vs.85%29.aspx
  42.  
  43. You can listen to the WM_QUERYENDSESSION or WM_ENDSESSION messages. This works both in GUI and console apps as long as you have a window (doesn't have to be visible) with a message loop.
  44.  
  45. To shut down the system, use the ExitWindowsEx function with the EWX_SHUTDOWN flag. For an example, see How to Shut Down the System. To shut down and restart the system, use the
  46.  
  47. EWX_REBOOT flag. To restart any applications that have been registered for restart using the RegisterApplicationRestart function, use the EXW_RESTARTAPPS flag.
  48.  
  49. The InitiateShutdown, InitiateSystemShutdown, and InitiateSystemShutdownEx functions start a timer and display a dialog box that prompts the user to log off. While this dialog box is
  50.  
  51. displayed, the AbortSystemShutdown function can stop the timer and prevent the computer from shutting down. However, if the timer expires, the computer is shut down. These functions can
  52.  
  53. also restart the computer following a shutdown operation. For more information, see Displaying the Shutdown Dialog Box.
  54.  
  55. Shutdown Notifications
  56. Applications with a window and message queue receive shutdown notifications through the WM_QUERYENDSESSION and WM_ENDSESSION messages. These applications should return TRUE to indicate
  57.  
  58. that they can be terminated. Applications should not block system shutdown unless it is absolutely necessary. Applications should perform any required cleanup while processing
  59.  
  60. WM_ENDSESSION. Applications that have unsaved data could save the data to a temporary location and restore it the next time the application starts. It is recommended that applications
  61.  
  62. save their data and state frequently; for example, automatically save data between save operations initiated by the user to reduce the amount of data to be saved at shutdown.
  63.  
  64. Console applications receive shutdown notifications in their handler routines. To register a console handler, use the SetConsoleCtrlHandler function.
  65.  
  66. Service applications receive shutdown notifications in their handler routines. To register a service control handler, use the RegisterServiceCtrlHandlerEx function.
  67.  
  68. Blocking Shutdown
  69. If an application must block a potential system shutdown, it can call the ShutdownBlockReasonCreate function. The caller provides a reason string that will be displayed to the user.
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77. http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/abf09824-4e4c-4f2c-ae1e-5981f06c9c6e/windows-7-console-application-has-no-way-of-trapping-logoffshutdown-event?
  78.  
  79. forum=windowscompatibility
  80.  
  81. (scroll to end for c++ example)
  82. The only solution I can fathom is to convert the console application into a windows based application which has a hidden window which can respond to WM_ENDSESSION, which from my testing,
  83.  
  84. allows up to 5 seconds of processing before Windows terminates the process.
  85.  
  86. You also have the option of displaying some UI so that Windows will not terminate the application without the express approval of the user.
  87.  
  88. NOTE: This is for a process which must be run within the user context and not as a service.
  89.  
  90.  
  91.  
  92. This is the bahaviour of console applications using SetConsoleCtrlHandler() callback to receive logoff notifications:
  93. Windows XP - CTRL_LOGOFF_EVENT received and Windows will wait for the application to exit (with the user's blessing) no matter how long this takes.
  94.  
  95. Windows Vista - CTRL_LOGOFF_EVENT received with Windows terminating the application if it does not exit within 5 seconds (approx).
  96.  
  97. Windows 7 - Application is terminated - SetConsoleCtrlHandler() callback is not invoked.
  98.  
  99.  
  100.  
  101.  
  102. create subsys:windows app without console
  103. then use AllocConsole() to create a console for it
  104.  
  105. freopen( "CONOUT$", "wb", stdout);
  106.  
  107. Afterwards, cleanup by using:
  108. fclose( stdout );
  109. FreeConsole();
  110.  
  111.  
  112.  
  113.  
  114. SetConsoleCtrlHandler() does not get reliably called in win7 apparently, so using it to dispose out of process unmanaged resources does not work
  115. (console X-exit causes process termination and handles associated with the console process do get destroyed)
  116.  
  117.  
  118.  
  119. Because SafeHandle inherits from CriticalFinalizerObject, all the noncritical finalizers are called before any of the critical finalizers. The finalizers are called on objects that are no
  120.  
  121. longer live during the same garbage collection pass. For example, a FileStream object can run a normal finalizer to flush out existing buffered data without the risk of the handle being
  122.  
  123. leaked or recycled. This very weak ordering between critical and noncritical finalizers is not intended for general use. It exists primarily to assist in the migration of existing
  124.  
  125. libraries by allowing those libraries to use SafeHandle without altering their semantics. Additionally, the critical finalizer and anything it calls, such as the SafeHandle.ReleaseHandle
  126.  
  127. () method, must be in a constrained execution region. This imposes constraints on what code can be written within the finalizer's call graph.
  128.  
  129.  
  130.  
  131. in c# try:
  132.  
  133. Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
  134.  
  135.  
  136. namespace EventCloseConsole
  137. {
  138. using System.Runtime.InteropServices;
  139. using System;
  140.  
  141. class Program
  142. {
  143. [DllImport("Kernel32")]
  144. private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
  145.  
  146. private delegate bool EventHandler(CtrlType sig);
  147. static EventHandler _handler;
  148.  
  149. enum CtrlType
  150. {
  151. CTRL_C_EVENT = 0,
  152. CTRL_BREAK_EVENT = 1,
  153. CTRL_CLOSE_EVENT = 2,
  154. CTRL_LOGOFF_EVENT = 5,
  155. CTRL_SHUTDOWN_EVENT = 6
  156. }
  157.  
  158. private static bool Handler(CtrlType sig)
  159. {
  160. switch (sig)
  161. {
  162. case CtrlType.CTRL_C_EVENT:
  163. case CtrlType.CTRL_LOGOFF_EVENT:
  164. case CtrlType.CTRL_SHUTDOWN_EVENT:
  165. case CtrlType.CTRL_CLOSE_EVENT:
  166.  
  167. Console.WriteLine("Closing");
  168. System.Threading.Thread.Sleep(500);
  169. return false;
  170. default:
  171. return true;
  172. }
  173. }
  174.  
  175. static void Main(string[] args)
  176. {
  177.  
  178. _handler += new EventHandler(Handler);
  179. SetConsoleCtrlHandler(_handler, true);
  180. Console.ReadLine();
  181.  
  182.  
  183. }
  184. }
  185. }
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.  
  201.  
  202. Can we work together to come up with something that works for control-c, control-break, log off, window X button pressed, etc?
  203.  
  204. Here is what I have so far:
  205.  
  206. class Program
  207. {
  208. private static ConsoleEventHandlerDelegate consoleHandler;
  209. delegate bool ConsoleEventHandlerDelegate(CtrlTypes eventCode);
  210.  
  211. static void Main(string[] args)
  212. {
  213. consoleHandler = new ConsoleEventHandlerDelegate(ConsoleCtrlCheck);
  214. SetConsoleCtrlHandler(consoleHandler, true);
  215.  
  216. System.Diagnostics.Process.GetCurrentProcess().Exited
  217. += delegate(object sender, EventArgs e)
  218. {
  219. GeneralManager.Stop();
  220. };
  221.  
  222. Console.CancelKeyPress += delegate(object sender,
  223. ConsoleCancelEventArgs e)
  224. {
  225. e.Cancel = false;
  226. GeneralManager.Stop();
  227. };
  228.  
  229. GeneralManager.Start();
  230. }
  231.  
  232. private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
  233. {
  234. switch (ctrlType)
  235. {
  236. case CtrlTypes.CTRL_C_EVENT:
  237.  
  238. Console.WriteLine("CTRL+C received!");
  239. GeneralManager.Stop();
  240. break;
  241.  
  242. case CtrlTypes.CTRL_BREAK_EVENT:
  243. isclosing = true;
  244. Console.WriteLine("CTRL+BREAK received!");
  245. GeneralManager.Stop();
  246. break;
  247.  
  248. case CtrlTypes.CTRL_CLOSE_EVENT:
  249.  
  250. Console.WriteLine("Program being closed!");
  251. GeneralManager.Stop();
  252. break;
  253.  
  254. case CtrlTypes.CTRL_LOGOFF_EVENT:
  255. case CtrlTypes.CTRL_SHUTDOWN_EVENT:
  256.  
  257. Console.WriteLine("User is logging off!");
  258. GeneralManager.Stop();
  259. break;
  260. }
  261. return true;
  262. }
  263.  
  264. #region unmanaged
  265.  
  266. [DllImport("kernel32.dll")]
  267. static extern bool SetConsoleCtrlHandler(ConsoleEventHandlerDelegate
  268. handlerProc, bool add);
  269.  
  270. public delegate bool HandlerRoutine(CtrlTypes CtrlType);
  271.  
  272. public enum CtrlTypes
  273. {
  274. CTRL_C_EVENT = 0,
  275. CTRL_BREAK_EVENT,
  276. CTRL_CLOSE_EVENT,
  277. CTRL_LOGOFF_EVENT = 5,
  278. CTRL_SHUTDOWN_EVENT
  279. }
  280.  
  281. #endregion
  282. }
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305. you need to create an invisible window. Here's sample code
  306.  
  307.  
  308. / TrapLogoffShutdown.cpp : Defines the entry point for the console application.
  309.  
  310. //
  311.  
  312. #include <stdio.h>
  313.  
  314. #include <Windows.h>
  315.  
  316.  
  317.  
  318. LRESULT CALLBACK MainWndProc ( HWND hwnd , UINT msg , WPARAM wParam, LPARAM lParam )
  319.  
  320. {
  321.  
  322. FILE* fp=fopen("c:\\ajith\\mainwndproc.txt","a+");
  323.  
  324. fprintf(fp,"Received window message %d \n",msg);
  325.  
  326. switch(msg)
  327.  
  328. {
  329.  
  330. case WM_QUERYENDSESSION:
  331.  
  332. MessageBox(NULL,"Received WM_QUERYENDSESSION","MainWndProc",MB_OK);
  333.  
  334. fprintf(fp,"Received WM_QUERYENDSESSION\n");
  335.  
  336. fclose(fp);
  337.  
  338. return TRUE;
  339.  
  340.  
  341.  
  342. case WM_ENDSESSION:
  343.  
  344. MessageBox(NULL,"Received WM_ENDSESSION","MainWndProc",MB_OK);
  345.  
  346. fprintf(fp,"Received WM_ENDSESSION\n");
  347.  
  348. fclose(fp);
  349.  
  350. {
  351.  
  352. if (wParam)
  353.  
  354. MessageBox(hwnd, "ConsoleWaWindow", "WM_ENDSESSION at any TIME!!", MB_OK);
  355.  
  356. else
  357.  
  358. MessageBox(hwnd, "ConsoleWaWindow", "WM_ENDSESSION aNO!!", MB_OK);
  359.  
  360.  
  361.  
  362. }
  363.  
  364. return TRUE;
  365.  
  366.  
  367.  
  368. case WM_DESTROY:
  369.  
  370. {
  371.  
  372. PostQuitMessage(0);
  373.  
  374. }
  375.  
  376. break;
  377.  
  378.  
  379.  
  380. case WM_CLOSE:
  381.  
  382. fprintf(fp,"WM_CLOSE received\n");
  383.  
  384. break;
  385.  
  386. default:
  387.  
  388. return DefWindowProc(hwnd, msg, wParam, lParam);
  389.  
  390. break;
  391.  
  392. }
  393.  
  394. fclose(fp);
  395.  
  396. return TRUE;
  397.  
  398. }
  399.  
  400.  
  401.  
  402. void CreateInvisibleWindow()
  403.  
  404. {
  405.  
  406. HWND hwnd;
  407.  
  408. WNDCLASS wc={0};
  409.  
  410. wc.lpfnWndProc=(WNDPROC)MainWndProc;
  411.  
  412. wc.hInstance=GetModuleHandle(NULL);
  413.  
  414. wc.hIcon=LoadIcon(GetModuleHandle(NULL), "TestWClass");
  415.  
  416. wc.lpszClassName="TestWClass";
  417.  
  418. RegisterClass(&wc);
  419.  
  420.  
  421.  
  422. hwnd=CreateWindowEx(0,"TestWClass","TestWClass",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,(HWND) NULL, (HMENU) NULL, GetModuleHandle(NULL), (LPVOID)
  423.  
  424. NULL);
  425.  
  426. if(!hwnd)
  427.  
  428. printf("FAILED to create window!!! %d\n",GetLastError());
  429.  
  430. }
  431.  
  432.  
  433.  
  434. DWORD WINAPI RunInvisibleWindowThread(LPVOID lpParam)
  435.  
  436. {
  437.  
  438. MSG msg;
  439.  
  440. CreateInvisibleWindow();
  441.  
  442. printf(" Thread and window created ..whoa!!\n");
  443.  
  444. while (GetMessage(&msg,(HWND) NULL , 0 , 0))
  445.  
  446. {
  447.  
  448. TranslateMessage(&msg);
  449.  
  450. DispatchMessage(&msg);
  451.  
  452. }
  453.  
  454. return 0;
  455.  
  456. }
  457.  
  458.  
  459.  
  460. int main(int argc,char* argv)
  461.  
  462. {
  463.  
  464.  
  465.  
  466. DWORD tid;
  467.  
  468. HANDLE hInvisiblethread=CreateThread(NULL, 0, RunInvisibleWindowThread, NULL, 0, &tid);
  469.  
  470.  
  471.  
  472. while(TRUE)
  473.  
  474. {
  475.  
  476. printf(" Iam running ..whoa!!\n");
  477.  
  478. Sleep(3000);
  479.  
  480. }
  481.  
  482.  
  483.  
  484. printf("Finished\n");
  485.  
  486. CloseHandle(hInvisiblethread);
  487.  
  488. }
  489.  
  490.  
  491.  
  492.  
  493.  
  494.  
  495.  
  496.  
  497.  
  498.  
  499.  
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506. [DllImport("Kernel32")]
  507. private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
  508.  
  509. private delegate bool EventHandler(CtrlType sig);
  510. static EventHandler _handler;
  511.  
  512. enum CtrlType
  513. {
  514. CTRL_C_EVENT = 0,
  515. CTRL_BREAK_EVENT = 1,
  516. CTRL_CLOSE_EVENT = 2,
  517. CTRL_LOGOFF_EVENT = 5,
  518. CTRL_SHUTDOWN_EVENT = 6
  519. }
  520.  
  521. private static bool Handler(CtrlType sig)
  522. {
  523. switch (sig)
  524. {
  525. case CtrlType.CTRL_C_EVENT:
  526. case CtrlType.CTRL_LOGOFF_EVENT:
  527. case CtrlType.CTRL_SHUTDOWN_EVENT:
  528. case CtrlType.CTRL_CLOSE_EVENT:
  529. default:
  530. }
  531. }
  532.  
  533.  
  534. static void Main(string[] args)
  535. {
  536. // Some biolerplate to react to close window event
  537. _handler += new EventHandler(Handler);
  538. SetConsoleCtrlHandler(_handler, true);
  539. ...
  540. }
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549. [DllImport("kernel32")]
  550. static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool Add);
  551.  
  552. delegate bool HandlerRoutine(uint dwControlType);
  553.  
  554. static void Main()
  555. {
  556. AllocConsole();
  557. SetConsoleCtrlHandler(null, true);
  558. while (true) continue;
  559. }
  560.  
  561.  
  562.  
  563.  
  564.  
  565.  
  566.  
  567.  
  568.  
  569.  
  570. On closing the console window obtained using AllocConsole or AttachConsole, the associated process will exit. There is no escape from that.
  571.  
  572. Prior to Windows Vista, closing the console window would present a confirmation dialogue to the user asking him whether the process should be terminated or not but Windows Vista and later
  573.  
  574. do not provide any such dialogue and the process gets terminated.
  575.  
  576. One possible solution to work around this is avoiding AttachConsole altogether and achieving the desired functionality through other means.
  577.  
  578. For instance in the case described by OP, console window was needed to output some text on Console using Console static class.
  579.  
  580. This can be achieved very easily using inter-process communication. For example a console application can be developed to act as an echo server
  581.  
  582. namespace EchoServer
  583. {
  584. public class PipeServer
  585. {
  586. public static void Main()
  587. {
  588. var pipeServer = new NamedPipeServerStream(@"Com.MyDomain.EchoServer.PipeServer", PipeDirection.In);
  589. pipeServer.WaitForConnection();
  590.  
  591. StreamReader reader = new StreamReader(pipeServer);
  592.  
  593. try
  594. {
  595. int i = 0;
  596. while (i >= 0)
  597. {
  598. i = reader.Read();
  599. if (i >= 0)
  600. {
  601. Console.Write(Convert.ToChar(i));
  602. }
  603. }
  604. }
  605. catch (IOException)
  606. {
  607. //error handling code here
  608. }
  609. finally
  610. {
  611. pipeServer.Close();
  612. }
  613. }
  614. }
  615. } and then instead of allocating/attaching a console to the current application, the echo server can be started from within the application and Console's output stream can be redirected
  616.  
  617. to write to the pipe server.
  618.  
  619. class Program
  620. {
  621. private static NamedPipeClientStream _pipeClient;
  622.  
  623. static void Main(string[] args)
  624. {
  625. //Current application is a Win32 application without any console window
  626. var processStartInfo = new ProcessStartInfo("echoserver.exe");
  627.  
  628. Process serverProcess = new Process {StartInfo = processStartInfo};
  629. serverProcess.Start();
  630.  
  631. _pipeClient = new NamedPipeClientStream(".", @"Com.MyDomain.EchoServer.PipeServer", PipeDirection.Out, PipeOptions.None);
  632. _pipeClient.Connect();
  633. StreamWriter writer = new StreamWriter(_pipeClient) {AutoFlush = true};
  634. Console.SetOut(writer);
  635.  
  636. Console.WriteLine("Testing");
  637.  
  638. //Do rest of the work.
  639. //Also detect that the server has terminated (serverProcess.HasExited) and then close the _pipeClient
  640. //Also remember to terminate the server process when current process exits, serverProcess.Kill();
  641. while (true)
  642. continue;
  643. }
  644. }
  645.  
  646. This is just one of the possible solutions. In essence the work around is to allot the console window to its own process so that it can terminate without affecting the parent process.
  647.  
  648.  
  649.  
  650. at the point where the Ctrl Handler is called a new thread is created in the process to call the handler. My solution, then, is to kill the assaulting invading thread before the default
  651.  
  652. handler can call ExitProcess. In the handler routine (code in C++):
  653.  
  654. // Detach Console:
  655. FreeConsole();
  656. // Prevent closing:
  657. ExitThread(0);
  658. return TRUE; // Not reached
  659.  
  660.  
  661.  
  662.  
  663.  
  664. private void btn_to_console_Click(object sender, EventArgs e)
  665. {
  666. if (NativeMethods.AllocConsole())
  667. {
  668. lbl_console_alloc_result.Text = "Console allocation successfully!";
  669. IntPtr stdHandle = NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE);
  670. Console.WriteLine("from WinForm to Console!");
  671. lbl_console_alloc_result.Text = Console.ReadLine();
  672. }
  673. else
  674. lbl_console_alloc_result.Text = "Console allocation failed!";
  675. }
  676.  
  677. [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetStdHandle")]
  678. public static extern System.IntPtr GetStdHandle(Int32 nStdHandle);
  679.  
  680. /// Return Type: BOOL->int
  681. [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "AllocConsole")]
  682. [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
  683. public static extern bool AllocConsole();
  684.  
  685.  
  686.  
  687.  
  688.  
  689.  
  690.  
  691.  
  692.  
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699. static const wchar_t* devices_notify = L"devices";
  700. static const wchar_t* power_notify = L"power";
  701. static const wchar_t* environment_notify = L"environment";
  702. static const wchar_t* intl_notify = L"intl";
  703.  
  704. LRESULT CALLBACK WndProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  705. {
  706. switch(Msg)
  707. {
  708. case WM_CLOSE:
  709. DestroyWindow(Hwnd);
  710. break;
  711.  
  712. case WM_DESTROY:
  713. PostQuitMessage(0);
  714. break;
  715.  
  716. case WM_DEVICECHANGE:
  717. {
  718. //bool Arrival=false;
  719. switch(wParam)
  720. {
  721. case DBT_DEVICEARRIVAL:
  722. //Arrival=true;
  723. case DBT_DEVICEREMOVECOMPLETE:
  724. {
  725.  
  726. PDEV_BROADCAST_HDR Pbh=reinterpret_cast<PDEV_BROADCAST_HDR>(lParam);
  727. if(Pbh->dbch_devicetype==DBT_DEVTYP_VOLUME)
  728. {
  729. // currently we don't care what actually happened, "just a notification" is OK
  730.  
  731. //PDEV_BROADCAST_VOLUME Pdv=reinterpret_cast<PDEV_BROADCAST_VOLUME>(Pbh);
  732. //bool Media = Pdv->dbcv_flags & DBTF_MEDIA != 0;
  733. Global->Notifier->at(devices_notify).notify(std::make_unique<payload>());
  734. }
  735. }
  736. break;
  737.  
  738. }
  739. }
  740. break;
  741.  
  742. case WM_SETTINGCHANGE:
  743. if(lParam)
  744. {
  745. if (!StrCmp(reinterpret_cast<LPCWSTR>(lParam),L"Environment"))
  746. {
  747. if (Global->Opt->UpdateEnvironment)
  748. {
  749. Global->Notifier->at(environment_notify).notify(std::make_unique<payload>());
  750. }
  751. }
  752. else if (!StrCmp(reinterpret_cast<LPCWSTR>(lParam),L"intl"))
  753. {
  754. Global->Notifier->at(intl_notify).notify(std::make_unique<payload>());
  755. }
  756. }
  757. break;
  758.  
  759. case WM_POWERBROADCAST:
  760. switch(wParam)
  761. {
  762. case PBT_APMPOWERSTATUSCHANGE: // change status
  763.  
  764. case PBT_POWERSETTINGCHANGE: // change percent
  765. Global->Notifier->at(power_notify).notify(std::make_unique<payload>());
  766. break;
  767. // TODO:
  768. // PBT_APMSUSPEND & PBT_APMRESUMEAUTOMATIC handlers
  769.  
  770. }
  771.  
  772. break;
  773.  
  774. }
  775. return DefWindowProc(Hwnd, Msg, wParam, lParam);
  776. }
  777.  
  778. WindowHandler::WindowHandler():
  779. m_Hwnd(nullptr)
  780. {
  781. Global->Notifier->add(std::make_unique<notification>(devices_notify));
  782. Global->Notifier->add(std::make_unique<notification>(power_notify));
  783. Global->Notifier->add(std::make_unique<notification>(environment_notify));
  784. Global->Notifier->add(std::make_unique<notification>(intl_notify));
  785.  
  786. m_exitEvent.Open();
  787.  
  788. Check();
  789. }
  790.  
  791. WindowHandler::~WindowHandler()
  792. {
  793. m_exitEvent.Set();
  794. if(m_Hwnd)
  795. {
  796. SendMessage(m_Hwnd,WM_CLOSE, 0, 0);
  797. }
  798. if(m_Thread.Opened())
  799. {
  800. m_Thread.Wait();
  801. }
  802. }
  803.  
  804. void WindowHandler::Check()
  805. {
  806. if (!m_Thread.Opened() || m_Thread.Signaled())
  807. {
  808. m_Thread.Close();
  809. m_Thread.Start(&WindowHandler::WindowThreadRoutine, this);
  810. }
  811. }
  812.  
  813. unsigned int WindowHandler::WindowThreadRoutine(void* Param)
  814. {
  815. WNDCLASSEX wc={sizeof(wc)};
  816. wc.lpfnWndProc = WndProc;
  817. wc.lpszClassName = L"FarHiddenWindowClass";
  818. UnregisterClass(wc.lpszClassName, 0);
  819. if(RegisterClassEx(&wc))
  820. {
  821. m_Hwnd = CreateWindowEx(0, wc.lpszClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
  822. if(m_Hwnd)
  823. {
  824. // for PBT_POWERSETTINGCHANGE
  825. HPOWERNOTIFY hpn=Global->ifn->RegisterPowerSettingNotification(m_Hwnd,&GUID_BATTERY_PERCENTAGE_REMAINING,DEVICE_NOTIFY_WINDOW_HANDLE);
  826.  
  827. MSG Msg;
  828. while(!m_exitEvent.Signaled() && GetMessage(&Msg, nullptr, 0, 0) > 0)
  829. {
  830. TranslateMessage(&Msg);
  831. DispatchMessage(&Msg);
  832. }
  833.  
  834. if (hpn) // for PBT_POWERSETTINGCHANGE
  835. Global->ifn->UnregisterPowerSettingNotification(hpn);
  836.  
  837. }
  838. UnregisterClass(wc.lpszClassName, 0);
  839. }
  840. return 0;
  841. }
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848.  
  849. http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.sessionending.aspx
  850.  
  851. private static int WM_QUERYENDSESSION = 0x11;
  852. private static bool systemShutdown = false;
  853. protected override void WndProc(ref System.Windows.Forms.Message m)
  854. {
  855. if (m.Msg==WM_QUERYENDSESSION)
  856. {
  857. MessageBox.Show("queryendsession: this is a logoff, shutdown, or reboot");
  858. systemShutdown = true;
  859. }
  860.  
  861. // If this is WM_QUERYENDSESSION, the closing event should be
  862. // raised in the base WndProc.
  863. base.WndProc(ref m);
  864.  
  865. } //WndProc
  866.  
  867. private void Form1_Closing(
  868. System.Object sender,
  869. System.ComponentModel.CancelEventArgs e)
  870. {
  871. if (systemShutdown)
  872. // Reset the variable because the user might cancel the
  873. // shutdown.
  874. {
  875. systemShutdown = false;
  876. if (DialogResult.Yes==MessageBox.Show("My application",
  877. "Do you want to save your work before logging off?",
  878. MessageBoxButtons.YesNo))
  879. {
  880. e.Cancel = true;
  881. }
  882. else
  883. {
  884. e.Cancel = false;
  885. }
  886. }
  887. }
  888.  
  889.  
  890.  
  891.  
  892.  
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899.  
  900.  
  901.  
  902.  
  903.  
  904.  
  905.  
  906.  
  907.  
  908.  
  909.  
  910.  
  911.  
  912.  
  913.  
  914.  
  915.  
  916.  
  917.  
  918.  
  919.  
  920.  
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928. // It turns out that .NET 1.1 doesn't expose low level console access, and
  929. // although .NET 2.0 added this to the Console class, it is pretty buggy
  930. // at least in the beta I'm using (for instance if you press the shift
  931. // key, Console.KeyAvailable returns true even though Console.ReadKey()
  932. // will block). Ah well. Lucky it is so easy to call Win32 routines from
  933. // managed code!
  934.  
  935. using System;
  936. using System.Runtime.InteropServices;
  937. using System.Windows.Forms;
  938. using System.Threading;
  939.  
  940.  
  941.  
  942. class Conio
  943. {
  944. // modifier flags
  945. [Flags()]
  946. public enum Flags : int
  947. {
  948. RightAlt = 0x01,
  949. LeftAlt = 0x02,
  950. RightCtrl = 0x04,
  951. LeftCtrl = 0x08,
  952. Shift = 0x10,
  953. NumLock = 0x20,
  954. ScrollLock = 0x40,
  955. CapsLock = 0x80,
  956. Enhanced = 0x100,
  957.  
  958. Alt = LeftAlt | RightAlt,
  959. Ctrl = LeftCtrl | RightCtrl,
  960. }
  961.  
  962.  
  963.  
  964. // a keyboard input event
  965. [StructLayout(LayoutKind.Sequential)]
  966. public struct Key
  967. {
  968. public int Keydown;
  969. public short Repeat;
  970. public short Rawcode;
  971. public short Scancode;
  972. public char Unicode;
  973. public Flags Flags;
  974.  
  975.  
  976. // cast to the corresponding framework enum type
  977. public ConsoleKey Keycode
  978. {
  979. get { return (ConsoleKey)Rawcode; }
  980. }
  981. }
  982.  
  983.  
  984.  
  985. // input event type tag
  986. enum EventType : short
  987. {
  988. Key = 0x01,
  989. Mouse = 0x02,
  990. Size = 0x04,
  991. Menu = 0x08,
  992. Focus = 0x10,
  993. }
  994.  
  995.  
  996.  
  997. // combined input event
  998. [StructLayout(LayoutKind.Sequential)]
  999. struct InputEvent
  1000. {
  1001. public EventType Type;
  1002. public Key Key;
  1003. }
  1004.  
  1005.  
  1006.  
  1007. // a screen coordinate
  1008. [StructLayout(LayoutKind.Sequential)]
  1009. struct Coord
  1010. {
  1011. public short X;
  1012. public short Y;
  1013. }
  1014.  
  1015.  
  1016.  
  1017. // is standard input redirected?
  1018. public static bool InputRedirected()
  1019. {
  1020. int count;
  1021.  
  1022. return !PeekConsoleInput(InputHandle, new InputEvent[1], 1, out count);
  1023. }
  1024.  
  1025.  
  1026.  
  1027. // access to the parent console window
  1028. public class ConsoleWindow : IWin32Window
  1029. {
  1030. public IntPtr Handle
  1031. {
  1032. get { return GetConsoleWindow(); }
  1033. }
  1034. }
  1035.  
  1036.  
  1037.  
  1038. // read a single character
  1039. public static Key Read()
  1040. {
  1041. InputEvent[] events = new InputEvent[1];
  1042. int count;
  1043.  
  1044. for (;;) {
  1045. // pump GUI events while waiting for a keypress
  1046. if (Application.OpenForms.Count > 0) {
  1047. do {
  1048. Application.DoEvents();
  1049. Thread.Sleep(1);
  1050. PeekConsoleInput(InputHandle, events, 1, out count);
  1051. } while (count == 0);
  1052. }
  1053.  
  1054. // read input
  1055. ReadConsoleInput(InputHandle, events, 1, out count);
  1056.  
  1057. if (count == 1) {
  1058. InputEvent e = events[0];
  1059.  
  1060. if ((e.Type == EventType.Key) && (e.Key.Keydown != 0))
  1061. return e.Key;
  1062. }
  1063. }
  1064. }
  1065.  
  1066.  
  1067.  
  1068. // text output function
  1069. public static void Write(int x, int y, string s)
  1070. {
  1071. int discard;
  1072.  
  1073. Coord coord;
  1074.  
  1075. coord.X = (short)x;
  1076. coord.Y = (short)y;
  1077.  
  1078. WriteConsoleOutputCharacter(OutputHandle, s, s.Length, coord, out discard);
  1079. }
  1080.  
  1081.  
  1082.  
  1083. // magic console filehandles
  1084. static IntPtr InputHandle = GetStdHandle(-10);
  1085. static IntPtr OutputHandle = GetStdHandle(-11);
  1086.  
  1087.  
  1088.  
  1089. // Windows API imports
  1090. [DllImport("kernel32")] static extern IntPtr GetStdHandle(int handle);
  1091. [DllImport("kernel32")] static extern IntPtr GetConsoleWindow();
  1092. [DllImport("kernel32")] static extern bool PeekConsoleInput(IntPtr handle, [Out] InputEvent[] buffer, int length, out int count);
  1093. [DllImport("kernel32")] static extern bool ReadConsoleInput(IntPtr handle, [Out] InputEvent[] buffer, int length, out int count);
  1094. [DllImport("kernel32")] static extern bool WriteConsoleOutputCharacter(IntPtr handle, string chars, int length, Coord pos, out int count);
  1095. }
  1096.  
  1097.  
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103.  
  1104.  
  1105.  
  1106.  
  1107.  
  1108.  
  1109.  
  1110.  
  1111. far manager:
  1112.  
  1113.  
  1114. //stack buffer size + stack vars size must be less than 16384
  1115. const size_t StackBufferSize=0x3FC0;
  1116. static std::unique_ptr<Event> CancelIoInProgress;
  1117.  
  1118. unsigned int CancelSynchronousIoWrapper(void* Thread)
  1119. {
  1120. unsigned int Result = Global->ifn->CancelSynchronousIo(Thread);
  1121. CancelIoInProgress->Reset();
  1122. return Result;
  1123. }
  1124.  
  1125. BOOL WINAPI CtrlHandler(DWORD CtrlType)
  1126. {
  1127. switch(CtrlType)
  1128. {
  1129. case CTRL_C_EVENT:
  1130. return TRUE;
  1131.  
  1132. case CTRL_BREAK_EVENT:
  1133. if(!CancelIoInProgress->Signaled())
  1134. {
  1135. CancelIoInProgress->Set();
  1136. Thread CancelSynchronousIoThread;
  1137. CancelSynchronousIoThread.Start(CancelSynchronousIoWrapper, Global->MainThreadHandle());
  1138. }
  1139. WriteInput(KEY_BREAK);
  1140.  
  1141. if (Global->CtrlObject && Global->CtrlObject->Cp())
  1142. {
  1143. if (Global->CtrlObject->Cp()->LeftPanel && Global->CtrlObject->Cp()->LeftPanel->GetMode()==PLUGIN_PANEL)
  1144. Global->CtrlObject->Plugins->ProcessEvent(Global->CtrlObject->Cp()->LeftPanel->GetPluginHandle(),FE_BREAK, ToPtr(CtrlType));
  1145.  
  1146. if (Global->CtrlObject->Cp()->RightPanel && Global->CtrlObject->Cp()->RightPanel->GetMode()==PLUGIN_PANEL)
  1147. Global->CtrlObject->Plugins->ProcessEvent(Global->CtrlObject->Cp()->RightPanel->GetPluginHandle(),FE_BREAK, ToPtr(CtrlType));
  1148. }
  1149. return TRUE;
  1150.  
  1151. case CTRL_CLOSE_EVENT:
  1152. Global->CloseFAR=TRUE;
  1153. Global->AllowCancelExit=FALSE;
  1154.  
  1155. // trick to let wmain() finish correctly
  1156. ExitThread(1);
  1157. //return TRUE;
  1158. }
  1159. return FALSE;
  1160. }
  1161.  
  1162. void InitConsole(int FirstInit)
  1163. {
  1164. InitRecodeOutTable();
  1165.  
  1166. if (FirstInit)
  1167. {
  1168. CancelIoInProgress = std::make_unique<DECLTYPE(CancelIoInProgress)::element_type>();
  1169. CancelIoInProgress->Open(true);
  1170.  
  1171. DWORD Mode;
  1172. if(!Global->Console->GetMode(Global->Console->GetInputHandle(), Mode))
  1173. {
  1174. HANDLE ConIn = CreateFile(L"CONIN$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
  1175. SetStdHandle(STD_INPUT_HANDLE, ConIn);
  1176. }
  1177. if(!Global->Console->GetMode(Global->Console->GetOutputHandle(), Mode))
  1178. {
  1179. HANDLE ConOut = CreateFile(L"CONOUT$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
  1180. SetStdHandle(STD_OUTPUT_HANDLE, ConOut);
  1181. SetStdHandle(STD_ERROR_HANDLE, ConOut);
  1182. }
  1183. }
  1184.  
  1185. Global->Console->SetControlHandler(CtrlHandler,TRUE);
  1186. Global->Console->GetMode(Global->Console->GetInputHandle(),InitialConsoleMode);
  1187. Global->Console->GetTitle(Global->strInitTitle);
  1188. Global->Console->GetWindowRect(InitWindowRect);
  1189. Global->Console->GetSize(InitialSize);
  1190. Global->Console->GetCursorInfo(InitialCursorInfo);
  1191.  
  1192. // ðàçìåð êëàâèàòóðíîé î÷åðåäè = 1024 êîäà êëàâèøè
  1193. if (!KeyQueue)
  1194. KeyQueue = std::make_unique<DECLTYPE(KeyQueue)::element_type>();
  1195.  
  1196. SetFarConsoleMode();
  1197.  
  1198. /* $ 09.04.2002 DJ
  1199. åñëè ðàçìåð êîíñîëüíîãî áóôåðà áîëüøå ðàçìåðà îêíà, âûñòàâèì
  1200. èõ ðàâíûìè
  1201. */
  1202. if (FirstInit)
  1203. {
  1204. SMALL_RECT WindowRect;
  1205. Global->Console->GetWindowRect(WindowRect);
  1206. Global->Console->GetSize(InitSize);
  1207.  
  1208. if(Global->Opt->WindowMode)
  1209. {
  1210. Global->Console->ResetPosition();
  1211. }
  1212. else
  1213. {
  1214. if (WindowRect.Left || WindowRect.Top || WindowRect.Right != InitSize.X-1 || WindowRect.Bottom != InitSize.Y-1)
  1215. {
  1216. COORD newSize;
  1217. newSize.X = WindowRect.Right - WindowRect.Left + 1;
  1218. newSize.Y = WindowRect.Bottom - WindowRect.Top + 1;
  1219. Global->Console->SetSize(newSize);
  1220. Global->Console->GetSize(InitSize);
  1221. }
  1222. }
  1223. if (IsZoomed(Global->Console->GetWindow()))
  1224. ChangeVideoMode(1);
  1225. }
  1226.  
  1227. GetVideoMode(CurSize);
  1228. Global->ScrBuf->FillBuf();
  1229.  
  1230. Global->ConsoleIcons->setFarIcons();
  1231. }
  1232. void CloseConsole()
  1233. {
  1234. Global->ScrBuf->Flush();
  1235. Global->Console->SetCursorInfo(InitialCursorInfo);
  1236. ChangeConsoleMode(InitialConsoleMode);
  1237.  
  1238. Global->Console->SetTitle(Global->strInitTitle);
  1239. Global->Console->SetSize(InitialSize);
  1240. COORD CursorPos = {};
  1241. Global->Console->GetCursorPosition(CursorPos);
  1242. SHORT Height = InitWindowRect.Bottom-InitWindowRect.Top, Width = InitWindowRect.Right-InitWindowRect.Left;
  1243. if (CursorPos.Y > InitWindowRect.Bottom || CursorPos.Y < InitWindowRect.Top)
  1244. InitWindowRect.Top = std::max(0, CursorPos.Y-Height);
  1245. if (CursorPos.X > InitWindowRect.Right || CursorPos.X < InitWindowRect.Left)
  1246. InitWindowRect.Left = std::max(0, CursorPos.X-Width);
  1247. InitWindowRect.Bottom = InitWindowRect.Top + Height;
  1248. InitWindowRect.Right = InitWindowRect.Left + Width;
  1249. Global->Console->SetWindowRect(InitWindowRect);
  1250. Global->Console->SetSize(InitialSize);
  1251.  
  1252. KeyQueue.reset();
  1253. Global->ConsoleIcons->restorePreviousIcons();
  1254. CancelIoInProgress.reset();
  1255. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement