update for HEAD-2003091401
[reactos.git] / lib / kernel32 / misc / console.c
index 117d364..14358df 100644 (file)
@@ -4,7 +4,8 @@
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/kernel32/misc/console.c
  * PURPOSE:         Win32 server console functions
- * PROGRAMMER:      ???
+ * PROGRAMMER:      James Tabor 
+ *                     <jimtabor@adsl-64-217-116-74.dsl.hstntx.swbell.net>
  * UPDATE HISTORY:
  *     199901?? ??     Created
  *     19990204 EA     SetConsoleTitleA
 #define NDEBUG
 #include <kernel32/kernel32.h>
 
+#define _NOACHS(__X) (sizeof(__X) / sizeof((__X)[0]))
+extern BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event);
+extern __declspec(noreturn) VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag);
+extern CRITICAL_SECTION ConsoleLock;
+extern BOOL WINAPI IsDebuggerPresent(VOID);
+
+
 /* GLOBALS *******************************************************************/
 
 static BOOL IgnoreCtrlEvents = FALSE;
-static ULONG NrCtrlHandlers = 0;
+
 static PHANDLER_ROUTINE* CtrlHandlers = NULL;
+static ULONG NrCtrlHandlers = 0;
+
+/* Default Console Control Handler *******************************************/
+
+BOOL WINAPI DefaultConsoleCtrlHandler(DWORD Event)
+{
+       switch(Event)
+       {
+       case CTRL_C_EVENT:
+               DPRINT("Ctrl-C Event\n");
+               ExitProcess(0);
+               break;
+               
+       case CTRL_BREAK_EVENT:
+               DPRINT("Ctrl-Break Event\n");
+               ExitProcess(0);
+               break;
+
+       case CTRL_SHUTDOWN_EVENT:
+               DPRINT("Ctrl Shutdown Event\n");
+               break;
+
+       case CTRL_CLOSE_EVENT:
+               DPRINT("Ctrl Close Event\n");
+               break;
+
+       case CTRL_LOGOFF_EVENT:         
+               DPRINT("Ctrl Logoff Event\n");
+               break;
+       }
+//     ExitProcess((UINT)&ExitCode);
+       return TRUE;
+}
+
+
+__declspec(noreturn) VOID CALLBACK ConsoleControlDispatcher(DWORD CodeAndFlag)
+{
+DWORD nExitCode = 0;
+DWORD nCode = CodeAndFlag & MAXLONG;
+UINT i;
+
+SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+
+       switch(nCode)
+       {
+       case CTRL_C_EVENT:
+       case CTRL_BREAK_EVENT:
+       {
+               if(IsDebuggerPresent())
+               {
+                       EXCEPTION_RECORD erException;
+                       erException.ExceptionCode = 
+                       (nCode == CTRL_C_EVENT ? DBG_CONTROL_C : DBG_CONTROL_BREAK);
+                       erException.ExceptionFlags = 0;
+                       erException.ExceptionRecord = NULL;
+                       erException.ExceptionAddress = &DefaultConsoleCtrlHandler;
+                       erException.NumberParameters = 0;
+                       RtlRaiseException(&erException);
+               }               
+               RtlEnterCriticalSection(&ConsoleLock);
+
+               if(!(nCode == CTRL_C_EVENT &&
+                       NtCurrentPeb()->ProcessParameters->ProcessGroup & 1))
+               {
+                       for(i = NrCtrlHandlers; i > 0; -- i)
+                               if(CtrlHandlers[i - 1](nCode)) break;
+               }
+               RtlLeaveCriticalSection(&ConsoleLock);
+               ExitThread(0);
+       }
+       case CTRL_CLOSE_EVENT:
+       case CTRL_LOGOFF_EVENT:
+       case CTRL_SHUTDOWN_EVENT:
+               break;
+
+       default: ExitThread(0);
+       }
+
+       RtlEnterCriticalSection(&ConsoleLock);
+
+       if(!(nCode == CTRL_C_EVENT &&
+               NtCurrentPeb()->ProcessParameters->ProcessGroup & 1))
+       {
+       i = NrCtrlHandlers;
+       while(i > 0)
+               {
+               if (i == 1 && (CodeAndFlag & MINLONG) && 
+                       (nCode == CTRL_LOGOFF_EVENT || nCode == CTRL_SHUTDOWN_EVENT))
+                               break;
+
+                       if(CtrlHandlers[i - 1](nCode))
+                       {
+                               switch(nCode)
+                               {
+                                       case CTRL_CLOSE_EVENT:
+                                       case CTRL_LOGOFF_EVENT:
+                                       case CTRL_SHUTDOWN_EVENT:
+                                               nExitCode = CodeAndFlag;
+                               }
+                               break;
+                       }
+                       --i;
+               }
+       }
+       RtlLeaveCriticalSection(&ConsoleLock);
+       ExitThread(nExitCode);
+}
+
 
 /* FUNCTIONS *****************************************************************/
 
+/*
+ * @unimplemented
+ */
 BOOL STDCALL
 AddConsoleAliasA (LPSTR Source,
                  LPSTR Target,
@@ -35,6 +154,10 @@ AddConsoleAliasA (LPSTR Source,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 BOOL STDCALL
 AddConsoleAliasW (LPWSTR Source,
                  LPWSTR Target,
@@ -44,6 +167,10 @@ AddConsoleAliasW (LPWSTR Source,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 BOOL STDCALL
 ConsoleMenuControl (HANDLE     hConsole,
                    DWORD       Unknown1,
@@ -56,6 +183,10 @@ ConsoleMenuControl (HANDLE  hConsole,
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 HANDLE STDCALL
 DuplicateConsoleHandle (HANDLE hConsole,
                        DWORD   dwDesiredAccess,
@@ -87,6 +218,10 @@ DuplicateConsoleHandle (HANDLE      hConsole,
   return Reply.Data.DuplicateHandleReply.Handle;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 ExpungeConsoleCommandHistoryW (DWORD   Unknown0)
      /*
@@ -98,6 +233,9 @@ ExpungeConsoleCommandHistoryW (DWORD Unknown0)
 }
 
 
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 ExpungeConsoleCommandHistoryA (DWORD   Unknown0)
      /*
@@ -108,6 +246,10 @@ ExpungeConsoleCommandHistoryA (DWORD       Unknown0)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasW (DWORD        Unknown0,
                  DWORD Unknown1,
@@ -122,6 +264,9 @@ GetConsoleAliasW (DWORD     Unknown0,
 }
 
 
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasA (DWORD        Unknown0,
                  DWORD Unknown1,
@@ -135,6 +280,10 @@ GetConsoleAliasA (DWORD    Unknown0,
        return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasExesW (DWORD    Unknown0,
                      DWORD     Unknown1)
@@ -147,7 +296,9 @@ GetConsoleAliasExesW (DWORD Unknown0,
 }
 
 
-
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasExesA (DWORD    Unknown0,
                      DWORD     Unknown1)
@@ -160,7 +311,9 @@ GetConsoleAliasExesA (DWORD Unknown0,
 }
 
 
-
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasExesLengthA (VOID)
      /*
@@ -171,6 +324,10 @@ GetConsoleAliasExesLengthA (VOID)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasExesLengthW (VOID)
      /*
@@ -181,6 +338,10 @@ GetConsoleAliasExesLengthW (VOID)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasesW (DWORD      Unknown0,
                    DWORD       Unknown1,
@@ -193,6 +354,10 @@ GetConsoleAliasesW (DWORD  Unknown0,
   return 0;
 }
  
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasesA (DWORD      Unknown0,
                    DWORD       Unknown1,
@@ -205,6 +370,10 @@ GetConsoleAliasesA (DWORD  Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasesLengthW (DWORD Unknown0)
      /*
@@ -215,6 +384,10 @@ GetConsoleAliasesLengthW (DWORD Unknown0)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleAliasesLengthA (DWORD Unknown0)
      /*
@@ -225,6 +398,10 @@ GetConsoleAliasesLengthA (DWORD Unknown0)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleCommandHistoryW (DWORD       Unknown0,
                           DWORD        Unknown1,
@@ -237,6 +414,10 @@ GetConsoleCommandHistoryW (DWORD   Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleCommandHistoryA (DWORD       Unknown0,
                           DWORD        Unknown1,
@@ -249,6 +430,10 @@ GetConsoleCommandHistoryA (DWORD   Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleCommandHistoryLengthW (DWORD Unknown0)
      /*
@@ -259,6 +444,10 @@ GetConsoleCommandHistoryLengthW (DWORD     Unknown0)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleCommandHistoryLengthA (DWORD Unknown0)
      /*
@@ -269,6 +458,9 @@ GetConsoleCommandHistoryLengthA (DWORD      Unknown0)
   return 0;
 }
 
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleDisplayMode (LPDWORD lpdwMode)
      /*
@@ -283,6 +475,10 @@ GetConsoleDisplayMode (LPDWORD lpdwMode)
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleFontInfo (DWORD      Unknown0,
                    DWORD       Unknown1,
@@ -296,6 +492,10 @@ GetConsoleFontInfo (DWORD  Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleFontSize(HANDLE hConsoleOutput,
                   DWORD nFont)
@@ -304,18 +504,43 @@ GetConsoleFontSize(HANDLE hConsoleOutput,
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
 DWORD STDCALL
-GetConsoleHardwareState (DWORD Unknown0,
-                        DWORD  Unknown1,
-                        DWORD  Unknown2)
+GetConsoleHardwareState (HANDLE        hConsole,
+                        DWORD  Flags,
+                        PDWORD State)
      /*
       * Undocumented
       */
 {
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+  CSRSS_API_REQUEST Request;
+  CSRSS_API_REPLY   Reply;
+  NTSTATUS          Status;
+
+  Request.Type = CSRSS_SETGET_CONSOLE_HW_STATE;
+  Request.Data.ConsoleHardwareStateRequest.ConsoleHandle = hConsole;
+  Request.Data.ConsoleHardwareStateRequest.SetGet = CONSOLE_HARDWARE_STATE_GET;
+
+  Status = CsrClientCallServer(& Request,
+                              & Reply,
+                              sizeof(CSRSS_API_REQUEST),
+                              sizeof(CSRSS_API_REPLY));
+  if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
+  {
+    SetLastErrorByStatus(Status);
+    return FALSE;
+  }
+  *State = Reply.Data.ConsoleHardwareStateReply.State;
+  return TRUE;  
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetConsoleInputWaitHandle (VOID)
      /*
@@ -326,6 +551,10 @@ GetConsoleInputWaitHandle (VOID)
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 GetCurrentConsoleFont(HANDLE hConsoleOutput,
                      BOOL bMaximumWindow,
@@ -335,6 +564,10 @@ GetCurrentConsoleFont(HANDLE hConsoleOutput,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 ULONG STDCALL
 GetNumberOfConsoleFonts (VOID)
      /*
@@ -345,6 +578,10 @@ GetNumberOfConsoleFonts (VOID)
   return 1; /* FIXME: call csrss.exe */
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 InvalidateConsoleDIBits (DWORD Unknown0,
                         DWORD  Unknown1)
@@ -356,19 +593,66 @@ InvalidateConsoleDIBits (DWORD    Unknown0,
   return 0;
 }
 
-DWORD STDCALL
-OpenConsoleW (DWORD    Unknown0,
-             DWORD     Unknown1,
-             DWORD     Unknown2,
-             DWORD     Unknown3)
+
+/*
+ * @unimplemented
+ */
+HANDLE STDCALL
+OpenConsoleW (LPWSTR  wsName,
+             DWORD   dwDesiredAccess,
+             BOOL    bInheritHandle,
+             DWORD   dwCreationDistribution)
      /*
       * Undocumented
       */
 {
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return 0;
+  CSRSS_API_REQUEST Request;
+  CSRSS_API_REPLY   Reply;
+  PHANDLE           phConsole = NULL;
+  NTSTATUS          Status = STATUS_SUCCESS;
+  
+  
+  if(0 == _wcsicmp(wsName, L"CONIN$"))
+  {
+    Request.Type = CSRSS_GET_INPUT_HANDLE;
+    phConsole = & Reply.Data.GetInputHandleReply.InputHandle;
+  }
+  else if (0 == _wcsicmp(wsName, L"CONOUT$"))
+  {
+    Request.Type = CSRSS_GET_OUTPUT_HANDLE;
+    phConsole = & Reply.Data.GetOutputHandleReply.OutputHandle;
+  }
+  else
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return(INVALID_HANDLE_VALUE);
+  }
+  if ((GENERIC_READ|GENERIC_WRITE) != dwDesiredAccess)
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return(INVALID_HANDLE_VALUE);
+  }
+  if (OPEN_EXISTING != dwCreationDistribution)
+  {
+    SetLastError(ERROR_INVALID_PARAMETER);
+    return(INVALID_HANDLE_VALUE);
+  }
+  Status = CsrClientCallServer(& Request,
+                              & Reply,
+                              sizeof(CSRSS_API_REQUEST),
+                              sizeof(CSRSS_API_REPLY));
+  if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
+  {
+    SetLastErrorByStatus(Status);
+    return INVALID_HANDLE_VALUE;
+  }
+  return(*phConsole);
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleCommandHistoryMode (DWORD    dwMode)
      /*
@@ -379,6 +663,10 @@ SetConsoleCommandHistoryMode (DWORD        dwMode)
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleCursor (DWORD        Unknown0,
                  DWORD Unknown1)
@@ -390,6 +678,10 @@ SetConsoleCursor (DWORD    Unknown0,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleDisplayMode (HANDLE hOut,
                       DWORD dwNewMode,
@@ -406,6 +698,10 @@ SetConsoleDisplayMode (HANDLE hOut,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleFont (DWORD  Unknown0,
                DWORD   Unknown1)
@@ -417,18 +713,43 @@ SetConsoleFont (DWORD     Unknown0,
   return FALSE;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
-SetConsoleHardwareState (DWORD Unknown0,
-                        DWORD  Unknown1,
-                        DWORD  Unknown2)
+SetConsoleHardwareState (HANDLE        hConsole,
+                        DWORD  Flags,
+                        DWORD  State)
      /*
       * Undocumented
       */
 {
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+  CSRSS_API_REQUEST Request;
+  CSRSS_API_REPLY   Reply;
+  NTSTATUS          Status;
+
+  Request.Type = CSRSS_SETGET_CONSOLE_HW_STATE;
+  Request.Data.ConsoleHardwareStateRequest.ConsoleHandle = hConsole;
+  Request.Data.ConsoleHardwareStateRequest.SetGet = CONSOLE_HARDWARE_STATE_SET;
+  Request.Data.ConsoleHardwareStateRequest.State = State;
+
+  Status = CsrClientCallServer(& Request,
+                              & Reply,
+                              sizeof(CSRSS_API_REQUEST),
+                              sizeof(CSRSS_API_REPLY));
+  if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
+  {
+    SetLastErrorByStatus(Status);
+    return FALSE;
+  }
+  return TRUE;  
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleKeyShortcuts (DWORD  Unknown0,
                        DWORD   Unknown1,
@@ -442,6 +763,10 @@ SetConsoleKeyShortcuts (DWORD      Unknown0,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleMaximumWindowSize (DWORD     Unknown0,
                             DWORD      Unknown1)
@@ -453,6 +778,10 @@ SetConsoleMaximumWindowSize (DWORD Unknown0,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleMenuClose (DWORD     Unknown0)
      /*
@@ -463,6 +792,10 @@ SetConsoleMenuClose (DWORD Unknown0)
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleNumberOfCommandsA (DWORD     Unknown0,
                             DWORD      Unknown1)
@@ -474,6 +807,10 @@ SetConsoleNumberOfCommandsA (DWORD Unknown0,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsoleNumberOfCommandsW (DWORD     Unknown0,
                             DWORD      Unknown1)
@@ -485,6 +822,10 @@ SetConsoleNumberOfCommandsW (DWORD Unknown0,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetConsolePalette (DWORD       Unknown0,
                   DWORD        Unknown1,
@@ -497,6 +838,10 @@ SetConsolePalette (DWORD   Unknown0,
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 WINBOOL STDCALL
 SetLastConsoleEventActive (VOID)
      /*
@@ -507,6 +852,10 @@ SetLastConsoleEventActive (VOID)
   return FALSE;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 ShowConsoleCursor (DWORD       Unknown0,
                   DWORD        Unknown1)
@@ -527,6 +876,8 @@ ShowConsoleCursor (DWORD    Unknown0,
  *      TRUE: Handle is a valid console handle
  *      FALSE: Handle is not a valid console handle.
  * STATUS: Officially undocumented
+ *
+ * @implemented
  */
 BOOL STDCALL
 VerifyConsoleIoHandle(HANDLE Handle)
@@ -551,6 +902,9 @@ VerifyConsoleIoHandle(HANDLE Handle)
 }
 
 
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 WriteConsoleInputVDMA (DWORD   Unknown0,
                       DWORD    Unknown1,
@@ -561,6 +915,10 @@ WriteConsoleInputVDMA (DWORD       Unknown0,
   return 0;
 }
 
+
+/*
+ * @unimplemented
+ */
 DWORD STDCALL
 WriteConsoleInputVDMW (DWORD   Unknown0,
                       DWORD    Unknown1,
@@ -571,6 +929,10 @@ WriteConsoleInputVDMW (DWORD       Unknown0,
   return 0;
 }
 
+
+/*
+ * @implemented
+ */
 WINBOOL STDCALL
 CloseConsoleHandle(HANDLE Handle)
      /*
@@ -603,6 +965,9 @@ CloseConsoleHandle(HANDLE Handle)
 }
 
 
+/*
+ * @implemented
+ */
 BOOLEAN STDCALL 
 IsConsoleHandle(HANDLE Handle)
 {
@@ -613,6 +978,10 @@ IsConsoleHandle(HANDLE Handle)
   return(FALSE);
 }
 
+
+/*
+ * @implemented
+ */
 HANDLE STDCALL 
 GetStdHandle(DWORD nStdHandle)
      /*
@@ -643,6 +1012,10 @@ GetStdHandle(DWORD nStdHandle)
   return INVALID_HANDLE_VALUE;
 }
 
+
+/*
+ * @implemented
+ */
 WINBASEAPI BOOL WINAPI 
 SetStdHandle(DWORD nStdHandle,
             HANDLE hHandle)
@@ -690,6 +1063,8 @@ SetStdHandle(DWORD nStdHandle,
 
 /*--------------------------------------------------------------
  *     WriteConsoleA
+ *
+ * @implemented
  */
 WINBOOL STDCALL 
 WriteConsoleA(HANDLE hConsoleOutput,
@@ -757,6 +1132,8 @@ WriteConsoleA(HANDLE hConsoleOutput,
 
 /*--------------------------------------------------------------
  *     ReadConsoleA
+ *
+ * @implemented
  */
 WINBOOL STDCALL ReadConsoleA(HANDLE hConsoleInput,
                             LPVOID lpBuffer,
@@ -850,6 +1227,8 @@ WINBOOL STDCALL ReadConsoleA(HANDLE hConsoleInput,
 
 /*--------------------------------------------------------------
  *     AllocConsole
+ *
+ * @implemented
  */
 WINBOOL STDCALL AllocConsole(VOID)
 {
@@ -858,6 +1237,15 @@ WINBOOL STDCALL AllocConsole(VOID)
    NTSTATUS Status;
    HANDLE hStdError;
 
+   if(NtCurrentPeb()->ProcessParameters->hConsole)
+   {
+       DPRINT("AllocConsole: Allocate duplicate console to the same Process\n");
+       SetLastErrorByStatus (STATUS_OBJECT_EXISTS); 
+       return FALSE;    
+   }
+
+   Request.Data.AllocConsoleRequest.CtrlDispatcher = (PCONTROLDISPATCHER) &ConsoleControlDispatcher;
+
    Request.Type = CSRSS_ALLOC_CONSOLE;
    Status = CsrClientCallServer( &Request, &Reply, sizeof( CSRSS_API_REQUEST ), sizeof( CSRSS_API_REPLY ) );
    if( !NT_SUCCESS( Status ) || !NT_SUCCESS( Status = Reply.Status ) )
@@ -878,16 +1266,34 @@ WINBOOL STDCALL AllocConsole(VOID)
 
 /*--------------------------------------------------------------
  *     FreeConsole
+ *
+ * @implemented
  */
 WINBOOL STDCALL FreeConsole(VOID)
 {
-   DbgPrint("FreeConsole() is unimplemented\n");
-   return FALSE;
+    // AG: I'm not sure if this is correct (what happens to std handles?)
+    // but I just tried to reverse what AllocConsole() does...
+
+   CSRSS_API_REQUEST Request;
+   CSRSS_API_REPLY Reply;
+   NTSTATUS Status;
+
+   Request.Type = CSRSS_FREE_CONSOLE;
+   Status = CsrClientCallServer( &Request, &Reply, sizeof( CSRSS_API_REQUEST ), sizeof( CSRSS_API_REPLY ) );
+   if( !NT_SUCCESS( Status ) || !NT_SUCCESS( Status = Reply.Status ) )
+      {
+        SetLastErrorByStatus ( Status );
+        return FALSE;
+      }
+
+   return TRUE;
 }
 
 
 /*--------------------------------------------------------------
  *     GetConsoleScreenBufferInfo
+ *
+ * @implemented
  */
 WINBOOL
 STDCALL
@@ -915,6 +1321,8 @@ GetConsoleScreenBufferInfo(
 
 /*--------------------------------------------------------------
  *     SetConsoleCursorPosition
+ *
+ * @implemented
  */
 WINBOOL
 STDCALL
@@ -942,6 +1350,8 @@ SetConsoleCursorPosition(
 
 /*--------------------------------------------------------------
  *     FillConsoleOutputCharacterA
+ *
+ * @implemented
  */
 WINBOOL STDCALL
 FillConsoleOutputCharacterA(
@@ -975,6 +1385,8 @@ FillConsoleOutputCharacterA(
 
 /*--------------------------------------------------------------
  *     FillConsoleOutputCharacterW
+ *
+ * @unimplemented
  */
 WINBOOL
 STDCALL
@@ -993,6 +1405,8 @@ FillConsoleOutputCharacterW(
 
 /*--------------------------------------------------------------
  *     PeekConsoleInputA
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1062,6 +1476,8 @@ PeekConsoleInputA(
 
 /*--------------------------------------------------------------
  *     PeekConsoleInputW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1080,6 +1496,8 @@ PeekConsoleInputW(
 
 /*--------------------------------------------------------------
  *     ReadConsoleInputA
+ *
+ * @implemented
  */
 WINBASEAPI BOOL WINAPI
 ReadConsoleInputA(HANDLE hConsoleInput,
@@ -1156,6 +1574,8 @@ ReadConsoleInputA(HANDLE hConsoleInput,
 
 /*--------------------------------------------------------------
  *     ReadConsoleInputW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1174,6 +1594,8 @@ ReadConsoleInputW(
 
 /*--------------------------------------------------------------
  *     WriteConsoleInputA
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1239,6 +1661,8 @@ WriteConsoleInputA(
 
 /*--------------------------------------------------------------
  *     WriteConsoleInputW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1257,6 +1681,8 @@ WriteConsoleInputW(
 
 /*--------------------------------------------------------------
  *     ReadConsoleOutputA
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1330,6 +1756,8 @@ ReadConsoleOutputA(
 
 /*--------------------------------------------------------------
  *     ReadConsoleOutputW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1348,6 +1776,8 @@ ReadConsoleOutputW(
 
 /*--------------------------------------------------------------
  *     WriteConsoleOutputA
+ *
+ * @implemented
  */
 WINBASEAPI BOOL WINAPI
 WriteConsoleOutputA(HANDLE              hConsoleOutput,
@@ -1360,8 +1790,6 @@ WriteConsoleOutputA(HANDLE                 hConsoleOutput,
   CSRSS_API_REPLY Reply;
   NTSTATUS Status;
   ULONG Size;
-  BOOLEAN Result;
-  ULONG i, j;
   PVOID BufferBase;
   PVOID BufferTargetBase;
 
@@ -1413,6 +1841,8 @@ WriteConsoleOutputA(HANDLE                 hConsoleOutput,
 
 /*--------------------------------------------------------------
  *     WriteConsoleOutputW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1432,6 +1862,8 @@ WriteConsoleOutputW(
 
 /*--------------------------------------------------------------
  *     ReadConsoleOutputCharacterA
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1499,6 +1931,8 @@ ReadConsoleOutputCharacterA(
 
 /*--------------------------------------------------------------
  *      ReadConsoleOutputCharacterW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1518,6 +1952,8 @@ ReadConsoleOutputCharacterW(
 
 /*--------------------------------------------------------------
  *     ReadConsoleOutputAttribute
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1587,6 +2023,8 @@ ReadConsoleOutputAttribute(
 
 /*--------------------------------------------------------------
  *     WriteConsoleOutputCharacterA
+ *
+ * @implemented
  */
 WINBASEAPI BOOL WINAPI
 WriteConsoleOutputCharacterA(HANDLE            hConsoleOutput,
@@ -1639,26 +2077,71 @@ WriteConsoleOutputCharacterA(HANDLE             hConsoleOutput,
 
 /*--------------------------------------------------------------
  *     WriteConsoleOutputCharacterW
+ *
+ * @implemented
  */
-WINBASEAPI
-BOOL
-WINAPI
-WriteConsoleOutputCharacterW(
-       HANDLE          hConsoleOutput,
-       LPCWSTR         lpCharacter,
-       DWORD           nLength,
-       COORD           dwWriteCoord,
-       LPDWORD         lpNumberOfCharsWritten
-       )
+WINBASEAPI BOOL WINAPI
+WriteConsoleOutputCharacterW(HANDLE            hConsoleOutput,
+                            LPCWSTR            lpCharacter,
+                            DWORD              nLength,
+                            COORD              dwWriteCoord,
+                            LPDWORD            lpNumberOfCharsWritten)
 {
-/* TO DO */
-       return FALSE;
-}
+  PCSRSS_API_REQUEST Request;
+  CSRSS_API_REPLY Reply;
+  NTSTATUS Status;
+  WORD Size;
+  
+  Request = RtlAllocateHeap(GetProcessHeap(),
+                           HEAP_ZERO_MEMORY,
+                           sizeof(CSRSS_API_REQUEST) + CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR);
+  if( !Request )
+    {
+      SetLastError( ERROR_OUTOFMEMORY );
+      return FALSE;
+    }
+  Request->Type = CSRSS_WRITE_CONSOLE_OUTPUT_CHAR;
+  Request->Data.WriteConsoleOutputCharRequest.ConsoleHandle = hConsoleOutput;
+  Request->Data.WriteConsoleOutputCharRequest.Coord = dwWriteCoord;
+  if( lpNumberOfCharsWritten )
+    *lpNumberOfCharsWritten = nLength;
+  while( nLength )
+    {
+      Size = nLength > CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR ? CSRSS_MAX_WRITE_CONSOLE_OUTPUT_CHAR : nLength;
+      Request->Data.WriteConsoleOutputCharRequest.Length = Size;
+      Status = RtlUnicodeToOemN (&Request->Data.WriteConsoleOutputCharRequest.String[0],
+                                Size,
+                                NULL,
+                                (PWCHAR)lpCharacter,
+                                Size * sizeof(WCHAR));
+      if (!NT_SUCCESS(Status))
+       {
+         RtlFreeHeap (GetProcessHeap(), 0, Request);
+         SetLastErrorByStatus (Status);
+         return FALSE;
+       }
 
+      Status = CsrClientCallServer( Request, &Reply, sizeof( CSRSS_API_REQUEST ) + Size, sizeof( CSRSS_API_REPLY ) );
+      if( !NT_SUCCESS( Status ) || !NT_SUCCESS( Status = Reply.Status ) )
+       {
+         RtlFreeHeap( GetProcessHeap(), 0, Request );
+         SetLastErrorByStatus ( Status );
+         return FALSE;
+       }
+      nLength -= Size;
+      lpCharacter += Size;
+      Request->Data.WriteConsoleOutputCharRequest.Coord = Reply.Data.WriteConsoleOutputCharReply.EndCoord;
+    }
+  
+  RtlFreeHeap( GetProcessHeap(), 0, Request );
+  return TRUE;
+}
 
 
 /*--------------------------------------------------------------
  *     WriteConsoleOutputAttribute
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1715,6 +2198,8 @@ WriteConsoleOutputAttribute(
 
 /*--------------------------------------------------------------
  *     FillConsoleOutputAttribute
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1750,6 +2235,8 @@ FillConsoleOutputAttribute(
 
 /*--------------------------------------------------------------
  *     GetConsoleMode
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1778,6 +2265,8 @@ GetConsoleMode(
 
 /*--------------------------------------------------------------
  *     GetNumberOfConsoleInputEvents
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1814,6 +2303,8 @@ GetNumberOfConsoleInputEvents(
 
 /*--------------------------------------------------------------
  *     GetLargestConsoleWindowSize
+ *
+ * @unimplemented
  */
 WINBASEAPI
 COORD
@@ -1833,6 +2324,8 @@ GetLargestConsoleWindowSize(
 
 /*--------------------------------------------------------------
  *     GetConsoleCursorInfo
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1862,6 +2355,8 @@ GetConsoleCursorInfo(
 
 /*--------------------------------------------------------------
  *     GetNumberOfConsoleMouseButtons
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1877,6 +2372,8 @@ GetNumberOfConsoleMouseButtons(
 
 /*--------------------------------------------------------------
  *     SetConsoleMode
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1905,6 +2402,8 @@ SetConsoleMode(
 
 /*--------------------------------------------------------------
  *     SetConsoleActiveScreenBuffer
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1931,6 +2430,8 @@ SetConsoleActiveScreenBuffer(
 
 /*--------------------------------------------------------------
  *     FlushConsoleInputBuffer
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -1957,6 +2458,8 @@ FlushConsoleInputBuffer(
 
 /*--------------------------------------------------------------
  *     SetConsoleScreenBufferSize
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -1972,6 +2475,8 @@ SetConsoleScreenBufferSize(
 
 /*--------------------------------------------------------------
  *     SetConsoleCursorInfo
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -2001,6 +2506,8 @@ SetConsoleCursorInfo(
 
 /*--------------------------------------------------------------
  *     ScrollConsoleScreenBufferA
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -2046,6 +2553,8 @@ ScrollConsoleScreenBufferA(
 
 /*--------------------------------------------------------------
  *     ScrollConsoleScreenBufferW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -2065,6 +2574,8 @@ ScrollConsoleScreenBufferW(
 
 /*--------------------------------------------------------------
  *     SetConsoleWindowInfo
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -2082,6 +2593,8 @@ SetConsoleWindowInfo(
 
 /*--------------------------------------------------------------
  *      SetConsoleTextAttribute
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -2107,6 +2620,7 @@ SetConsoleTextAttribute(
    return TRUE;
 }
 
+
 BOOL STATIC
 AddConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
 {
@@ -2125,6 +2639,7 @@ AddConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
                           NrCtrlHandlers * sizeof(PHANDLER_ROUTINE)); 
       if (CtrlHandlers == NULL)
        {
+         NrCtrlHandlers = 0;
          SetLastError(ERROR_NOT_ENOUGH_MEMORY);
          return(FALSE);
        }
@@ -2133,6 +2648,7 @@ AddConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
     }
 }
 
+
 BOOL STATIC
 RemoveConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
 {
@@ -2147,10 +2663,11 @@ RemoveConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
     {
       for (i = 0; i < NrCtrlHandlers; i++)
        {
-         if (CtrlHandlers[i] == HandlerRoutine)
+         if ( ((void*)(CtrlHandlers[i])) == (void*)HandlerRoutine)
            {
-             CtrlHandlers[i] = CtrlHandlers[NrCtrlHandlers - 1];
              NrCtrlHandlers--;
+             memmove(CtrlHandlers + i, CtrlHandlers + i + 1, 
+                     (NrCtrlHandlers - i) * sizeof(PHANDLER_ROUTINE));
              CtrlHandlers = 
                RtlReAllocateHeap(RtlGetProcessHeap(),
                                  HEAP_ZERO_MEMORY,
@@ -2163,8 +2680,12 @@ RemoveConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine)
   return(FALSE);
 }
 
+
+/*
+ * @implemented
+ */
 WINBASEAPI BOOL WINAPI
-SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,
+SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,
                      BOOL Add)
 {
   BOOLEAN Ret;
@@ -2185,6 +2706,8 @@ SetConsoleCtrlHandler(PHANDLER_ROUTINE    HandlerRoutine,
 
 /*--------------------------------------------------------------
  *     GenerateConsoleCtrlEvent
+ *
+ * @unimplemented
  */
 WINBASEAPI BOOL WINAPI
 GenerateConsoleCtrlEvent(
@@ -2199,8 +2722,9 @@ GenerateConsoleCtrlEvent(
 
 /*--------------------------------------------------------------
  *     GetConsoleTitleW
+ *
+ * @implemented
  */
-
 WINBASEAPI
 DWORD
 WINAPI
@@ -2261,6 +2785,8 @@ GetConsoleTitleW(
  *     GetConsoleTitleA
  *
  *     19990306 EA
+ *
+ * @implemented
  */
 WINBASEAPI
 DWORD
@@ -2299,6 +2825,8 @@ GetConsoleTitleA(
 
 /*--------------------------------------------------------------
  *     SetConsoleTitleW
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -2358,6 +2886,8 @@ SetConsoleTitleW(
  *     SetConsoleTitleA
  *     
  *     19990204 EA     Added
+ *
+ * @implemented
  */
 WINBASEAPI
 BOOL
@@ -2415,6 +2945,8 @@ SetConsoleTitleA(
 
 /*--------------------------------------------------------------
  *     ReadConsoleW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -2434,6 +2966,8 @@ ReadConsoleW(
 
 /*--------------------------------------------------------------
  *     WriteConsoleW
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -2498,6 +3032,8 @@ WriteConsoleW(
 
 /*--------------------------------------------------------------
  *     CreateConsoleScreenBuffer
+ *
+ * @implemented
  */
 WINBASEAPI
 HANDLE
@@ -2528,6 +3064,8 @@ CreateConsoleScreenBuffer(
 
 /*--------------------------------------------------------------
  *     GetConsoleCP
+ *
+ * @unimplemented
  */
 WINBASEAPI
 UINT
@@ -2541,6 +3079,8 @@ GetConsoleCP( VOID )
 
 /*--------------------------------------------------------------
  *     SetConsoleCP
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -2556,6 +3096,8 @@ SetConsoleCP(
 
 /*--------------------------------------------------------------
  *     GetConsoleOutputCP
+ *
+ * @unimplemented
  */
 WINBASEAPI
 UINT
@@ -2569,6 +3111,8 @@ GetConsoleOutputCP( VOID )
 
 /*--------------------------------------------------------------
  *     SetConsoleOutputCP
+ *
+ * @unimplemented
  */
 WINBASEAPI
 BOOL
@@ -2584,6 +3128,8 @@ SetConsoleOutputCP(
 
 /*--------------------------------------------------------------
  *     GetConsoleProcessList
+ *
+ * @unimplemented
  */
 DWORD STDCALL
 GetConsoleProcessList(LPDWORD lpdwProcessList,
@@ -2597,6 +3143,8 @@ GetConsoleProcessList(LPDWORD lpdwProcessList,
 
 /*--------------------------------------------------------------
  *     GetConsoleSelectionInfo
+ *
+ * @unimplemented
  */
 BOOL STDCALL
 GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo)
@@ -2609,6 +3157,8 @@ GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo)
 
 /*--------------------------------------------------------------
  *     AttachConsole
+ *
+ * @unimplemented
  */
 BOOL STDCALL 
 AttachConsole(DWORD dwProcessId)
@@ -2617,4 +3167,32 @@ AttachConsole(DWORD dwProcessId)
    return FALSE;
 }
 
+/*--------------------------------------------------------------
+ *     GetConsoleWindow/0
+ *
+ * @implemented
+ */
+HWND STDCALL
+GetConsoleWindow (VOID)
+{
+  CSRSS_API_REQUEST Request;
+  CSRSS_API_REPLY   Reply;
+  NTSTATUS          Status;
+   
+  Request.Data.ConsoleWindowRequest.ConsoleHandle =
+    OpenConsoleW (L"CONOUT$", (GENERIC_READ|GENERIC_WRITE), FALSE, OPEN_EXISTING);
+  if (INVALID_HANDLE_VALUE == Request.Data.ConsoleWindowRequest.ConsoleHandle)
+  {
+    return (HWND) NULL;
+  }
+  Request.Type = CSRSS_GET_CONSOLE_WINDOW;
+  Status = CsrClientCallServer( &Request, &Reply, sizeof( CSRSS_API_REQUEST ), sizeof( CSRSS_API_REPLY ) );
+  if (!NT_SUCCESS(Status ) || !NT_SUCCESS(Status = Reply.Status))
+  {
+    SetLastErrorByStatus (Status);
+    return (HWND) NULL;
+  }
+  return Reply.Data.ConsoleWindowReply.WindowHandle;
+}
+
 /* EOF */