Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- http://www.mischel.com/pubs/consoledotnetconsoledotnet.zip
- 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
- glean how they do it. svn co http://farmanager.googlecode.com/svn/trunk fardev
- case CTRL_CLOSE_EVENT:
- Global->CloseFAR=TRUE;
- Global->AllowCancelExit=FALSE;
- // trick to let wmain() finish correctly
- ExitThread(1);
- 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
- tools can be downloaded here: http://download.microsoft.com/download/d/2/5/d2522ce4-a441-459d-8302-be8f3321823c/LogoToolsv1.0.msi
- Then you can simulate shutdown for your process:
- rmtool.exe -p [PID] -S
- where [PID] is the process ID. According to the Vista Logo Certification Test Cases document,
- Restart Manager shutdown messages are:
- a. WM_QUERYENDSESSION with LPARAM = ENDSESSION_CLOSEAPP(0x1): GUI applications must respond (TRUE) immediately to prepare for a restart.
- b. WM_ENDSESSION with LPARAM = ENDSESSION_CLOSEAPP(0x1): The application must shutdown within 5 seconds (20 seconds for services).
- c. CTRL_SHUTDOWN_EVENT: Console applications must shutdown immediately.
- You could use the SystemEvents.SessionEnding event, which is fired when a user logs off or shuts down.
- 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.
- For a code example that shows how to handle system events by using a hidden form in a Windows service, see the SystemEvents class.
- http://msdn.microsoft.com/en-us/library/windows/desktop/aa376881%28v=vs.85%29.aspx
- 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.
- 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
- EWX_REBOOT flag. To restart any applications that have been registered for restart using the RegisterApplicationRestart function, use the EXW_RESTARTAPPS flag.
- 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
- 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
- also restart the computer following a shutdown operation. For more information, see Displaying the Shutdown Dialog Box.
- Shutdown Notifications
- 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
- that they can be terminated. Applications should not block system shutdown unless it is absolutely necessary. Applications should perform any required cleanup while processing
- 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
- 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.
- Console applications receive shutdown notifications in their handler routines. To register a console handler, use the SetConsoleCtrlHandler function.
- Service applications receive shutdown notifications in their handler routines. To register a service control handler, use the RegisterServiceCtrlHandlerEx function.
- Blocking Shutdown
- 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.
- 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?
- forum=windowscompatibility
- (scroll to end for c++ example)
- 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,
- allows up to 5 seconds of processing before Windows terminates the process.
- You also have the option of displaying some UI so that Windows will not terminate the application without the express approval of the user.
- NOTE: This is for a process which must be run within the user context and not as a service.
- This is the bahaviour of console applications using SetConsoleCtrlHandler() callback to receive logoff notifications:
- 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.
- Windows Vista - CTRL_LOGOFF_EVENT received with Windows terminating the application if it does not exit within 5 seconds (approx).
- Windows 7 - Application is terminated - SetConsoleCtrlHandler() callback is not invoked.
- create subsys:windows app without console
- then use AllocConsole() to create a console for it
- freopen( "CONOUT$", "wb", stdout);
- Afterwards, cleanup by using:
- fclose( stdout );
- FreeConsole();
- SetConsoleCtrlHandler() does not get reliably called in win7 apparently, so using it to dispose out of process unmanaged resources does not work
- (console X-exit causes process termination and handles associated with the console process do get destroyed)
- 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
- 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
- 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
- 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
- () method, must be in a constrained execution region. This imposes constraints on what code can be written within the finalizer's call graph.
- in c# try:
- Console.CancelKeyPress += new ConsoleCancelEventHandler(myHandler);
- namespace EventCloseConsole
- {
- using System.Runtime.InteropServices;
- using System;
- class Program
- {
- [DllImport("Kernel32")]
- private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
- private delegate bool EventHandler(CtrlType sig);
- static EventHandler _handler;
- enum CtrlType
- {
- CTRL_C_EVENT = 0,
- CTRL_BREAK_EVENT = 1,
- CTRL_CLOSE_EVENT = 2,
- CTRL_LOGOFF_EVENT = 5,
- CTRL_SHUTDOWN_EVENT = 6
- }
- private static bool Handler(CtrlType sig)
- {
- switch (sig)
- {
- case CtrlType.CTRL_C_EVENT:
- case CtrlType.CTRL_LOGOFF_EVENT:
- case CtrlType.CTRL_SHUTDOWN_EVENT:
- case CtrlType.CTRL_CLOSE_EVENT:
- Console.WriteLine("Closing");
- System.Threading.Thread.Sleep(500);
- return false;
- default:
- return true;
- }
- }
- static void Main(string[] args)
- {
- _handler += new EventHandler(Handler);
- SetConsoleCtrlHandler(_handler, true);
- Console.ReadLine();
- }
- }
- }
- Can we work together to come up with something that works for control-c, control-break, log off, window X button pressed, etc?
- Here is what I have so far:
- class Program
- {
- private static ConsoleEventHandlerDelegate consoleHandler;
- delegate bool ConsoleEventHandlerDelegate(CtrlTypes eventCode);
- static void Main(string[] args)
- {
- consoleHandler = new ConsoleEventHandlerDelegate(ConsoleCtrlCheck);
- SetConsoleCtrlHandler(consoleHandler, true);
- System.Diagnostics.Process.GetCurrentProcess().Exited
- += delegate(object sender, EventArgs e)
- {
- GeneralManager.Stop();
- };
- Console.CancelKeyPress += delegate(object sender,
- ConsoleCancelEventArgs e)
- {
- e.Cancel = false;
- GeneralManager.Stop();
- };
- GeneralManager.Start();
- }
- private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
- {
- switch (ctrlType)
- {
- case CtrlTypes.CTRL_C_EVENT:
- Console.WriteLine("CTRL+C received!");
- GeneralManager.Stop();
- break;
- case CtrlTypes.CTRL_BREAK_EVENT:
- isclosing = true;
- Console.WriteLine("CTRL+BREAK received!");
- GeneralManager.Stop();
- break;
- case CtrlTypes.CTRL_CLOSE_EVENT:
- Console.WriteLine("Program being closed!");
- GeneralManager.Stop();
- break;
- case CtrlTypes.CTRL_LOGOFF_EVENT:
- case CtrlTypes.CTRL_SHUTDOWN_EVENT:
- Console.WriteLine("User is logging off!");
- GeneralManager.Stop();
- break;
- }
- return true;
- }
- #region unmanaged
- [DllImport("kernel32.dll")]
- static extern bool SetConsoleCtrlHandler(ConsoleEventHandlerDelegate
- handlerProc, bool add);
- public delegate bool HandlerRoutine(CtrlTypes CtrlType);
- public enum CtrlTypes
- {
- CTRL_C_EVENT = 0,
- CTRL_BREAK_EVENT,
- CTRL_CLOSE_EVENT,
- CTRL_LOGOFF_EVENT = 5,
- CTRL_SHUTDOWN_EVENT
- }
- #endregion
- }
- you need to create an invisible window. Here's sample code
- / TrapLogoffShutdown.cpp : Defines the entry point for the console application.
- //
- #include <stdio.h>
- #include <Windows.h>
- LRESULT CALLBACK MainWndProc ( HWND hwnd , UINT msg , WPARAM wParam, LPARAM lParam )
- {
- FILE* fp=fopen("c:\\ajith\\mainwndproc.txt","a+");
- fprintf(fp,"Received window message %d \n",msg);
- switch(msg)
- {
- case WM_QUERYENDSESSION:
- MessageBox(NULL,"Received WM_QUERYENDSESSION","MainWndProc",MB_OK);
- fprintf(fp,"Received WM_QUERYENDSESSION\n");
- fclose(fp);
- return TRUE;
- case WM_ENDSESSION:
- MessageBox(NULL,"Received WM_ENDSESSION","MainWndProc",MB_OK);
- fprintf(fp,"Received WM_ENDSESSION\n");
- fclose(fp);
- {
- if (wParam)
- MessageBox(hwnd, "ConsoleWaWindow", "WM_ENDSESSION at any TIME!!", MB_OK);
- else
- MessageBox(hwnd, "ConsoleWaWindow", "WM_ENDSESSION aNO!!", MB_OK);
- }
- return TRUE;
- case WM_DESTROY:
- {
- PostQuitMessage(0);
- }
- break;
- case WM_CLOSE:
- fprintf(fp,"WM_CLOSE received\n");
- break;
- default:
- return DefWindowProc(hwnd, msg, wParam, lParam);
- break;
- }
- fclose(fp);
- return TRUE;
- }
- void CreateInvisibleWindow()
- {
- HWND hwnd;
- WNDCLASS wc={0};
- wc.lpfnWndProc=(WNDPROC)MainWndProc;
- wc.hInstance=GetModuleHandle(NULL);
- wc.hIcon=LoadIcon(GetModuleHandle(NULL), "TestWClass");
- wc.lpszClassName="TestWClass";
- RegisterClass(&wc);
- hwnd=CreateWindowEx(0,"TestWClass","TestWClass",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,(HWND) NULL, (HMENU) NULL, GetModuleHandle(NULL), (LPVOID)
- NULL);
- if(!hwnd)
- printf("FAILED to create window!!! %d\n",GetLastError());
- }
- DWORD WINAPI RunInvisibleWindowThread(LPVOID lpParam)
- {
- MSG msg;
- CreateInvisibleWindow();
- printf(" Thread and window created ..whoa!!\n");
- while (GetMessage(&msg,(HWND) NULL , 0 , 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
- }
- int main(int argc,char* argv)
- {
- DWORD tid;
- HANDLE hInvisiblethread=CreateThread(NULL, 0, RunInvisibleWindowThread, NULL, 0, &tid);
- while(TRUE)
- {
- printf(" Iam running ..whoa!!\n");
- Sleep(3000);
- }
- printf("Finished\n");
- CloseHandle(hInvisiblethread);
- }
- [DllImport("Kernel32")]
- private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
- private delegate bool EventHandler(CtrlType sig);
- static EventHandler _handler;
- enum CtrlType
- {
- CTRL_C_EVENT = 0,
- CTRL_BREAK_EVENT = 1,
- CTRL_CLOSE_EVENT = 2,
- CTRL_LOGOFF_EVENT = 5,
- CTRL_SHUTDOWN_EVENT = 6
- }
- private static bool Handler(CtrlType sig)
- {
- switch (sig)
- {
- case CtrlType.CTRL_C_EVENT:
- case CtrlType.CTRL_LOGOFF_EVENT:
- case CtrlType.CTRL_SHUTDOWN_EVENT:
- case CtrlType.CTRL_CLOSE_EVENT:
- default:
- }
- }
- static void Main(string[] args)
- {
- // Some biolerplate to react to close window event
- _handler += new EventHandler(Handler);
- SetConsoleCtrlHandler(_handler, true);
- ...
- }
- [DllImport("kernel32")]
- static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool Add);
- delegate bool HandlerRoutine(uint dwControlType);
- static void Main()
- {
- AllocConsole();
- SetConsoleCtrlHandler(null, true);
- while (true) continue;
- }
- On closing the console window obtained using AllocConsole or AttachConsole, the associated process will exit. There is no escape from that.
- 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
- do not provide any such dialogue and the process gets terminated.
- One possible solution to work around this is avoiding AttachConsole altogether and achieving the desired functionality through other means.
- For instance in the case described by OP, console window was needed to output some text on Console using Console static class.
- This can be achieved very easily using inter-process communication. For example a console application can be developed to act as an echo server
- namespace EchoServer
- {
- public class PipeServer
- {
- public static void Main()
- {
- var pipeServer = new NamedPipeServerStream(@"Com.MyDomain.EchoServer.PipeServer", PipeDirection.In);
- pipeServer.WaitForConnection();
- StreamReader reader = new StreamReader(pipeServer);
- try
- {
- int i = 0;
- while (i >= 0)
- {
- i = reader.Read();
- if (i >= 0)
- {
- Console.Write(Convert.ToChar(i));
- }
- }
- }
- catch (IOException)
- {
- //error handling code here
- }
- finally
- {
- pipeServer.Close();
- }
- }
- }
- } 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
- to write to the pipe server.
- class Program
- {
- private static NamedPipeClientStream _pipeClient;
- static void Main(string[] args)
- {
- //Current application is a Win32 application without any console window
- var processStartInfo = new ProcessStartInfo("echoserver.exe");
- Process serverProcess = new Process {StartInfo = processStartInfo};
- serverProcess.Start();
- _pipeClient = new NamedPipeClientStream(".", @"Com.MyDomain.EchoServer.PipeServer", PipeDirection.Out, PipeOptions.None);
- _pipeClient.Connect();
- StreamWriter writer = new StreamWriter(_pipeClient) {AutoFlush = true};
- Console.SetOut(writer);
- Console.WriteLine("Testing");
- //Do rest of the work.
- //Also detect that the server has terminated (serverProcess.HasExited) and then close the _pipeClient
- //Also remember to terminate the server process when current process exits, serverProcess.Kill();
- while (true)
- continue;
- }
- }
- 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.
- 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
- handler can call ExitProcess. In the handler routine (code in C++):
- // Detach Console:
- FreeConsole();
- // Prevent closing:
- ExitThread(0);
- return TRUE; // Not reached
- private void btn_to_console_Click(object sender, EventArgs e)
- {
- if (NativeMethods.AllocConsole())
- {
- lbl_console_alloc_result.Text = "Console allocation successfully!";
- IntPtr stdHandle = NativeMethods.GetStdHandle(NativeMethods.STD_OUTPUT_HANDLE);
- Console.WriteLine("from WinForm to Console!");
- lbl_console_alloc_result.Text = Console.ReadLine();
- }
- else
- lbl_console_alloc_result.Text = "Console allocation failed!";
- }
- [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "GetStdHandle")]
- public static extern System.IntPtr GetStdHandle(Int32 nStdHandle);
- /// Return Type: BOOL->int
- [System.Runtime.InteropServices.DllImportAttribute("kernel32.dll", EntryPoint = "AllocConsole")]
- [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.Bool)]
- public static extern bool AllocConsole();
- static const wchar_t* devices_notify = L"devices";
- static const wchar_t* power_notify = L"power";
- static const wchar_t* environment_notify = L"environment";
- static const wchar_t* intl_notify = L"intl";
- LRESULT CALLBACK WndProc(HWND Hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
- {
- switch(Msg)
- {
- case WM_CLOSE:
- DestroyWindow(Hwnd);
- break;
- case WM_DESTROY:
- PostQuitMessage(0);
- break;
- case WM_DEVICECHANGE:
- {
- //bool Arrival=false;
- switch(wParam)
- {
- case DBT_DEVICEARRIVAL:
- //Arrival=true;
- case DBT_DEVICEREMOVECOMPLETE:
- {
- PDEV_BROADCAST_HDR Pbh=reinterpret_cast<PDEV_BROADCAST_HDR>(lParam);
- if(Pbh->dbch_devicetype==DBT_DEVTYP_VOLUME)
- {
- // currently we don't care what actually happened, "just a notification" is OK
- //PDEV_BROADCAST_VOLUME Pdv=reinterpret_cast<PDEV_BROADCAST_VOLUME>(Pbh);
- //bool Media = Pdv->dbcv_flags & DBTF_MEDIA != 0;
- Global->Notifier->at(devices_notify).notify(std::make_unique<payload>());
- }
- }
- break;
- }
- }
- break;
- case WM_SETTINGCHANGE:
- if(lParam)
- {
- if (!StrCmp(reinterpret_cast<LPCWSTR>(lParam),L"Environment"))
- {
- if (Global->Opt->UpdateEnvironment)
- {
- Global->Notifier->at(environment_notify).notify(std::make_unique<payload>());
- }
- }
- else if (!StrCmp(reinterpret_cast<LPCWSTR>(lParam),L"intl"))
- {
- Global->Notifier->at(intl_notify).notify(std::make_unique<payload>());
- }
- }
- break;
- case WM_POWERBROADCAST:
- switch(wParam)
- {
- case PBT_APMPOWERSTATUSCHANGE: // change status
- case PBT_POWERSETTINGCHANGE: // change percent
- Global->Notifier->at(power_notify).notify(std::make_unique<payload>());
- break;
- // TODO:
- // PBT_APMSUSPEND & PBT_APMRESUMEAUTOMATIC handlers
- }
- break;
- }
- return DefWindowProc(Hwnd, Msg, wParam, lParam);
- }
- WindowHandler::WindowHandler():
- m_Hwnd(nullptr)
- {
- Global->Notifier->add(std::make_unique<notification>(devices_notify));
- Global->Notifier->add(std::make_unique<notification>(power_notify));
- Global->Notifier->add(std::make_unique<notification>(environment_notify));
- Global->Notifier->add(std::make_unique<notification>(intl_notify));
- m_exitEvent.Open();
- Check();
- }
- WindowHandler::~WindowHandler()
- {
- m_exitEvent.Set();
- if(m_Hwnd)
- {
- SendMessage(m_Hwnd,WM_CLOSE, 0, 0);
- }
- if(m_Thread.Opened())
- {
- m_Thread.Wait();
- }
- }
- void WindowHandler::Check()
- {
- if (!m_Thread.Opened() || m_Thread.Signaled())
- {
- m_Thread.Close();
- m_Thread.Start(&WindowHandler::WindowThreadRoutine, this);
- }
- }
- unsigned int WindowHandler::WindowThreadRoutine(void* Param)
- {
- WNDCLASSEX wc={sizeof(wc)};
- wc.lpfnWndProc = WndProc;
- wc.lpszClassName = L"FarHiddenWindowClass";
- UnregisterClass(wc.lpszClassName, 0);
- if(RegisterClassEx(&wc))
- {
- m_Hwnd = CreateWindowEx(0, wc.lpszClassName, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, nullptr, nullptr);
- if(m_Hwnd)
- {
- // for PBT_POWERSETTINGCHANGE
- HPOWERNOTIFY hpn=Global->ifn->RegisterPowerSettingNotification(m_Hwnd,&GUID_BATTERY_PERCENTAGE_REMAINING,DEVICE_NOTIFY_WINDOW_HANDLE);
- MSG Msg;
- while(!m_exitEvent.Signaled() && GetMessage(&Msg, nullptr, 0, 0) > 0)
- {
- TranslateMessage(&Msg);
- DispatchMessage(&Msg);
- }
- if (hpn) // for PBT_POWERSETTINGCHANGE
- Global->ifn->UnregisterPowerSettingNotification(hpn);
- }
- UnregisterClass(wc.lpszClassName, 0);
- }
- return 0;
- }
- http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.sessionending.aspx
- private static int WM_QUERYENDSESSION = 0x11;
- private static bool systemShutdown = false;
- protected override void WndProc(ref System.Windows.Forms.Message m)
- {
- if (m.Msg==WM_QUERYENDSESSION)
- {
- MessageBox.Show("queryendsession: this is a logoff, shutdown, or reboot");
- systemShutdown = true;
- }
- // If this is WM_QUERYENDSESSION, the closing event should be
- // raised in the base WndProc.
- base.WndProc(ref m);
- } //WndProc
- private void Form1_Closing(
- System.Object sender,
- System.ComponentModel.CancelEventArgs e)
- {
- if (systemShutdown)
- // Reset the variable because the user might cancel the
- // shutdown.
- {
- systemShutdown = false;
- if (DialogResult.Yes==MessageBox.Show("My application",
- "Do you want to save your work before logging off?",
- MessageBoxButtons.YesNo))
- {
- e.Cancel = true;
- }
- else
- {
- e.Cancel = false;
- }
- }
- }
- // It turns out that .NET 1.1 doesn't expose low level console access, and
- // although .NET 2.0 added this to the Console class, it is pretty buggy
- // at least in the beta I'm using (for instance if you press the shift
- // key, Console.KeyAvailable returns true even though Console.ReadKey()
- // will block). Ah well. Lucky it is so easy to call Win32 routines from
- // managed code!
- using System;
- using System.Runtime.InteropServices;
- using System.Windows.Forms;
- using System.Threading;
- class Conio
- {
- // modifier flags
- [Flags()]
- public enum Flags : int
- {
- RightAlt = 0x01,
- LeftAlt = 0x02,
- RightCtrl = 0x04,
- LeftCtrl = 0x08,
- Shift = 0x10,
- NumLock = 0x20,
- ScrollLock = 0x40,
- CapsLock = 0x80,
- Enhanced = 0x100,
- Alt = LeftAlt | RightAlt,
- Ctrl = LeftCtrl | RightCtrl,
- }
- // a keyboard input event
- [StructLayout(LayoutKind.Sequential)]
- public struct Key
- {
- public int Keydown;
- public short Repeat;
- public short Rawcode;
- public short Scancode;
- public char Unicode;
- public Flags Flags;
- // cast to the corresponding framework enum type
- public ConsoleKey Keycode
- {
- get { return (ConsoleKey)Rawcode; }
- }
- }
- // input event type tag
- enum EventType : short
- {
- Key = 0x01,
- Mouse = 0x02,
- Size = 0x04,
- Menu = 0x08,
- Focus = 0x10,
- }
- // combined input event
- [StructLayout(LayoutKind.Sequential)]
- struct InputEvent
- {
- public EventType Type;
- public Key Key;
- }
- // a screen coordinate
- [StructLayout(LayoutKind.Sequential)]
- struct Coord
- {
- public short X;
- public short Y;
- }
- // is standard input redirected?
- public static bool InputRedirected()
- {
- int count;
- return !PeekConsoleInput(InputHandle, new InputEvent[1], 1, out count);
- }
- // access to the parent console window
- public class ConsoleWindow : IWin32Window
- {
- public IntPtr Handle
- {
- get { return GetConsoleWindow(); }
- }
- }
- // read a single character
- public static Key Read()
- {
- InputEvent[] events = new InputEvent[1];
- int count;
- for (;;) {
- // pump GUI events while waiting for a keypress
- if (Application.OpenForms.Count > 0) {
- do {
- Application.DoEvents();
- Thread.Sleep(1);
- PeekConsoleInput(InputHandle, events, 1, out count);
- } while (count == 0);
- }
- // read input
- ReadConsoleInput(InputHandle, events, 1, out count);
- if (count == 1) {
- InputEvent e = events[0];
- if ((e.Type == EventType.Key) && (e.Key.Keydown != 0))
- return e.Key;
- }
- }
- }
- // text output function
- public static void Write(int x, int y, string s)
- {
- int discard;
- Coord coord;
- coord.X = (short)x;
- coord.Y = (short)y;
- WriteConsoleOutputCharacter(OutputHandle, s, s.Length, coord, out discard);
- }
- // magic console filehandles
- static IntPtr InputHandle = GetStdHandle(-10);
- static IntPtr OutputHandle = GetStdHandle(-11);
- // Windows API imports
- [DllImport("kernel32")] static extern IntPtr GetStdHandle(int handle);
- [DllImport("kernel32")] static extern IntPtr GetConsoleWindow();
- [DllImport("kernel32")] static extern bool PeekConsoleInput(IntPtr handle, [Out] InputEvent[] buffer, int length, out int count);
- [DllImport("kernel32")] static extern bool ReadConsoleInput(IntPtr handle, [Out] InputEvent[] buffer, int length, out int count);
- [DllImport("kernel32")] static extern bool WriteConsoleOutputCharacter(IntPtr handle, string chars, int length, Coord pos, out int count);
- }
- far manager:
- //stack buffer size + stack vars size must be less than 16384
- const size_t StackBufferSize=0x3FC0;
- static std::unique_ptr<Event> CancelIoInProgress;
- unsigned int CancelSynchronousIoWrapper(void* Thread)
- {
- unsigned int Result = Global->ifn->CancelSynchronousIo(Thread);
- CancelIoInProgress->Reset();
- return Result;
- }
- BOOL WINAPI CtrlHandler(DWORD CtrlType)
- {
- switch(CtrlType)
- {
- case CTRL_C_EVENT:
- return TRUE;
- case CTRL_BREAK_EVENT:
- if(!CancelIoInProgress->Signaled())
- {
- CancelIoInProgress->Set();
- Thread CancelSynchronousIoThread;
- CancelSynchronousIoThread.Start(CancelSynchronousIoWrapper, Global->MainThreadHandle());
- }
- WriteInput(KEY_BREAK);
- if (Global->CtrlObject && Global->CtrlObject->Cp())
- {
- if (Global->CtrlObject->Cp()->LeftPanel && Global->CtrlObject->Cp()->LeftPanel->GetMode()==PLUGIN_PANEL)
- Global->CtrlObject->Plugins->ProcessEvent(Global->CtrlObject->Cp()->LeftPanel->GetPluginHandle(),FE_BREAK, ToPtr(CtrlType));
- if (Global->CtrlObject->Cp()->RightPanel && Global->CtrlObject->Cp()->RightPanel->GetMode()==PLUGIN_PANEL)
- Global->CtrlObject->Plugins->ProcessEvent(Global->CtrlObject->Cp()->RightPanel->GetPluginHandle(),FE_BREAK, ToPtr(CtrlType));
- }
- return TRUE;
- case CTRL_CLOSE_EVENT:
- Global->CloseFAR=TRUE;
- Global->AllowCancelExit=FALSE;
- // trick to let wmain() finish correctly
- ExitThread(1);
- //return TRUE;
- }
- return FALSE;
- }
- void InitConsole(int FirstInit)
- {
- InitRecodeOutTable();
- if (FirstInit)
- {
- CancelIoInProgress = std::make_unique<DECLTYPE(CancelIoInProgress)::element_type>();
- CancelIoInProgress->Open(true);
- DWORD Mode;
- if(!Global->Console->GetMode(Global->Console->GetInputHandle(), Mode))
- {
- HANDLE ConIn = CreateFile(L"CONIN$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
- SetStdHandle(STD_INPUT_HANDLE, ConIn);
- }
- if(!Global->Console->GetMode(Global->Console->GetOutputHandle(), Mode))
- {
- HANDLE ConOut = CreateFile(L"CONOUT$", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
- SetStdHandle(STD_OUTPUT_HANDLE, ConOut);
- SetStdHandle(STD_ERROR_HANDLE, ConOut);
- }
- }
- Global->Console->SetControlHandler(CtrlHandler,TRUE);
- Global->Console->GetMode(Global->Console->GetInputHandle(),InitialConsoleMode);
- Global->Console->GetTitle(Global->strInitTitle);
- Global->Console->GetWindowRect(InitWindowRect);
- Global->Console->GetSize(InitialSize);
- Global->Console->GetCursorInfo(InitialCursorInfo);
- // ðàçìåð êëàâèàòóðíîé î÷åðåäè = 1024 êîäà êëàâèøè
- if (!KeyQueue)
- KeyQueue = std::make_unique<DECLTYPE(KeyQueue)::element_type>();
- SetFarConsoleMode();
- /* $ 09.04.2002 DJ
- åñëè ðàçìåð êîíñîëüíîãî áóôåðà áîëüøå ðàçìåðà îêíà, âûñòàâèì
- èõ ðàâíûìè
- */
- if (FirstInit)
- {
- SMALL_RECT WindowRect;
- Global->Console->GetWindowRect(WindowRect);
- Global->Console->GetSize(InitSize);
- if(Global->Opt->WindowMode)
- {
- Global->Console->ResetPosition();
- }
- else
- {
- if (WindowRect.Left || WindowRect.Top || WindowRect.Right != InitSize.X-1 || WindowRect.Bottom != InitSize.Y-1)
- {
- COORD newSize;
- newSize.X = WindowRect.Right - WindowRect.Left + 1;
- newSize.Y = WindowRect.Bottom - WindowRect.Top + 1;
- Global->Console->SetSize(newSize);
- Global->Console->GetSize(InitSize);
- }
- }
- if (IsZoomed(Global->Console->GetWindow()))
- ChangeVideoMode(1);
- }
- GetVideoMode(CurSize);
- Global->ScrBuf->FillBuf();
- Global->ConsoleIcons->setFarIcons();
- }
- void CloseConsole()
- {
- Global->ScrBuf->Flush();
- Global->Console->SetCursorInfo(InitialCursorInfo);
- ChangeConsoleMode(InitialConsoleMode);
- Global->Console->SetTitle(Global->strInitTitle);
- Global->Console->SetSize(InitialSize);
- COORD CursorPos = {};
- Global->Console->GetCursorPosition(CursorPos);
- SHORT Height = InitWindowRect.Bottom-InitWindowRect.Top, Width = InitWindowRect.Right-InitWindowRect.Left;
- if (CursorPos.Y > InitWindowRect.Bottom || CursorPos.Y < InitWindowRect.Top)
- InitWindowRect.Top = std::max(0, CursorPos.Y-Height);
- if (CursorPos.X > InitWindowRect.Right || CursorPos.X < InitWindowRect.Left)
- InitWindowRect.Left = std::max(0, CursorPos.X-Width);
- InitWindowRect.Bottom = InitWindowRect.Top + Height;
- InitWindowRect.Right = InitWindowRect.Left + Width;
- Global->Console->SetWindowRect(InitWindowRect);
- Global->Console->SetSize(InitialSize);
- KeyQueue.reset();
- Global->ConsoleIcons->restorePreviousIcons();
- CancelIoInProgress.reset();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement