[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH 06/14 v2] Make monitor service multi-console aware



From: Owen Smith <owen.smith@xxxxxxxxxx>

* Move console specific data to a seperate structure
* Make all threads' use the console data
* Removes the Add and Remove event in favor of inline add/remove
* Convert Win32 calls to explicit narrow/wide character set as appropriate
* Removes tchar.h include to force narrow/wide character usage
* Renames structures and thread functions
* Pipe names are based on console name
* INF file stores "Executable" under console's name subkey
* Change pipe name tty.exe uses
* Add WaitNamedPipe() before connecting to pipes in tty.exe

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
 src/monitor/monitor.c | 1445 ++++++++++++++++++++++++++-----------------------
 src/tty/tty.c         |   20 +-
 src/xencons.inf       |    2 +-
 3 files changed, 792 insertions(+), 675 deletions(-)

diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
index 08ae0f2..510ba6f 100644
--- a/src/monitor/monitor.c
+++ b/src/monitor/monitor.c
@@ -32,7 +32,7 @@
 #define INITGUID 1
 
 #include <windows.h>
-#include <tchar.h>
+#include <winioctl.h>
 #include <stdlib.h>
 #include <strsafe.h>
 #include <wtsapi32.h>
@@ -50,40 +50,45 @@
 #define MONITOR_NAME        __MODULE__
 #define MONITOR_DISPLAYNAME MONITOR_NAME
 
-typedef struct _MONITOR_PIPE {
-    HANDLE                  Pipe;
-    HANDLE                  Event;
-    HANDLE                  Thread;
-    LIST_ENTRY              ListEntry;
-} MONITOR_PIPE, *PMONITOR_PIPE;
-
 typedef struct _MONITOR_CONTEXT {
     SERVICE_STATUS          Status;
     SERVICE_STATUS_HANDLE   Service;
-    HKEY                    ParametersKey;
     HANDLE                  EventLog;
     HANDLE                  StopEvent;
-    HANDLE                  AddEvent;
-    HANDLE                  RemoveEvent;
-    PTCHAR                  Executable;
+    HKEY                    ParametersKey;
     HDEVNOTIFY              InterfaceNotification;
-    PTCHAR                  DevicePath;
+    CRITICAL_SECTION        CriticalSection;
+    LIST_ENTRY              ListHead;
+    DWORD                   ListCount;
+} MONITOR_CONTEXT, *PMONITOR_CONTEXT;
+
+typedef struct _MONITOR_CONSOLE {
+    LIST_ENTRY              ListEntry;
+    PWCHAR                  DevicePath;
+    HANDLE                  DeviceHandle;
     HDEVNOTIFY              DeviceNotification;
-    HANDLE                  Device;
-    HANDLE                  MonitorEvent;
-    HANDLE                  MonitorThread;
-    HANDLE                  DeviceEvent;
+    PCHAR                   DeviceName; // protocol and instance?
+    HANDLE                  ExecutableThread;
+    HANDLE                  ExecutableEvent;
     HANDLE                  DeviceThread;
-    HANDLE                  ServerEvent;
+    HANDLE                  DeviceEvent;
     HANDLE                  ServerThread;
+    HANDLE                  ServerEvent;
     CRITICAL_SECTION        CriticalSection;
     LIST_ENTRY              ListHead;
     DWORD                   ListCount;
-} MONITOR_CONTEXT, *PMONITOR_CONTEXT;
+} MONITOR_CONSOLE, *PMONITOR_CONSOLE;
+
+typedef struct _MONITOR_CONNECTION {
+    PMONITOR_CONSOLE        Console;
+    LIST_ENTRY              ListEntry;
+    HANDLE                  Pipe;
+    HANDLE                  Thread;
+} MONITOR_CONNECTION, *PMONITOR_CONNECTION;
 
-MONITOR_CONTEXT MonitorContext;
+static MONITOR_CONTEXT MonitorContext;
 
-#define PIPE_NAME TEXT("\\\\.\\pipe\\xencons")
+#define PIPE_BASE_NAME "\\\\.\\pipe\\xencons\\"
 
 #define MAXIMUM_BUFFER_SIZE 1024
 
@@ -104,15 +109,15 @@ __Log(
 {
 #if DBG
     PMONITOR_CONTEXT    Context = &MonitorContext;
-    const TCHAR         *Strings[1];
+    const CHAR          *Strings[1];
 #endif
-    TCHAR               Buffer[MAXIMUM_BUFFER_SIZE];
+    CHAR                Buffer[MAXIMUM_BUFFER_SIZE];
     va_list             Arguments;
     size_t              Length;
     HRESULT             Result;
 
     va_start(Arguments, Format);
-    Result = StringCchVPrintf(Buffer,
+    Result = StringCchVPrintfA(Buffer,
                               MAXIMUM_BUFFER_SIZE,
                               Format,
                               Arguments);
@@ -121,7 +126,7 @@ __Log(
     if (Result != S_OK && Result != STRSAFE_E_INSUFFICIENT_BUFFER)
         return;
 
-    Result = StringCchLength(Buffer, MAXIMUM_BUFFER_SIZE, &Length);
+    Result = StringCchLengthA(Buffer, MAXIMUM_BUFFER_SIZE, &Length);
     if (Result != S_OK)
         return;
 
@@ -139,7 +144,7 @@ __Log(
     Strings[0] = Buffer;
 
     if (Context->EventLog != NULL)
-        ReportEvent(Context->EventLog,
+        ReportEventA(Context->EventLog,
                     EVENTLOG_INFORMATION_TYPE,
                     0,
                     MONITOR_LOG,
@@ -152,23 +157,23 @@ __Log(
 }
 
 #define Log(_Format, ...) \
-    __Log(TEXT(__MODULE__ "|" __FUNCTION__ ": " _Format), __VA_ARGS__)
+    __Log(__MODULE__ "|" __FUNCTION__ ": " _Format, __VA_ARGS__)
 
-static PTCHAR
+static PCHAR
 GetErrorMessage(
     IN  HRESULT Error
     )
 {
-    PTCHAR      Message;
+    PCHAR       Message;
     ULONG       Index;
 
-    if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+    if (!FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                        FORMAT_MESSAGE_FROM_SYSTEM |
                        FORMAT_MESSAGE_IGNORE_INSERTS,
                        NULL,
                        Error,
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                       (LPTSTR)&Message,
+                       (LPSTR)&Message,
                        0,
                        NULL))
         return NULL;
@@ -210,7 +215,8 @@ static VOID
 ReportStatus(
     IN  DWORD           CurrentState,
     IN  DWORD           Win32ExitCode,
-    IN  DWORD           WaitHint)
+    IN  DWORD           WaitHint
+    )
 {
     PMONITOR_CONTEXT    Context = &MonitorContext;
     static DWORD        CheckPoint = 1;
@@ -249,116 +255,11 @@ fail1:
     Error = GetLastError();
 
     {
-        PTCHAR  Message;
-        Message = GetErrorMessage(Error);
-        Log("fail1 (%s)", Message);
-        LocalFree(Message);
-    }
-}
-
-static BOOL
-MonitorGetPath(
-    IN  const GUID  *Guid,
-    OUT PTCHAR      *Path
-    )
-{
-    HDEVINFO                            DeviceInfoSet;
-    SP_DEVICE_INTERFACE_DATA            DeviceInterfaceData;
-    PSP_DEVICE_INTERFACE_DETAIL_DATA    DeviceInterfaceDetail;
-    DWORD                               Size;
-    HRESULT                             Error;
-    BOOL                                Success;
-
-    Log("====>");
-
-    DeviceInfoSet = SetupDiGetClassDevs(Guid,
-                                        NULL,
-                                        NULL,
-                                        DIGCF_PRESENT |
-                                        DIGCF_DEVICEINTERFACE);
-    if (DeviceInfoSet == INVALID_HANDLE_VALUE)
-        goto fail1;
-
-    DeviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
-
-    Success = SetupDiEnumDeviceInterfaces(DeviceInfoSet,
-                                          NULL,
-                                          Guid,
-                                          0,
-                                          &DeviceInterfaceData);
-    if (!Success)
-        goto fail2;
-
-    Success = SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
-                                              &DeviceInterfaceData,
-                                              NULL,
-                                              0,
-                                              &Size,
-                                              NULL);
-    if (!Success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
-        goto fail3;
-
-    DeviceInterfaceDetail = calloc(1, Size);
-    if (DeviceInterfaceDetail == NULL)
-        goto fail4;
-
-    DeviceInterfaceDetail->cbSize =
-        sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
-
-    Success = SetupDiGetDeviceInterfaceDetail(DeviceInfoSet,
-                                              &DeviceInterfaceData,
-                                              DeviceInterfaceDetail,
-                                              Size,
-                                              NULL,
-                                              NULL);
-    if (!Success)
-        goto fail5;
-
-    *Path = _tcsdup(DeviceInterfaceDetail->DevicePath);
-
-    if (*Path == NULL)
-        goto fail6;
-
-    Log("%s", *Path);
-
-    free(DeviceInterfaceDetail);
-
-    SetupDiDestroyDeviceInfoList(DeviceInfoSet);
-
-    Log("<====");
-
-    return TRUE;
-
-fail6:
-    Log("fail6");
-
-fail5:
-    Log("fail5");
-
-    free(DeviceInterfaceDetail);
-
-fail4:
-    Log("fail4");
-
-fail3:
-    Log("fail3");
-
-fail2:
-    Log("fail2");
-
-    SetupDiDestroyDeviceInfoList(DeviceInfoSet);
-
-fail1:
-    Error = GetLastError();
-
-    {
-        PTCHAR  Message;
+        PCHAR  Message;
         Message = GetErrorMessage(Error);
         Log("fail1 (%s)", Message);
         LocalFree(Message);
     }
-
-    return FALSE;
 }
 
 static FORCEINLINE VOID
@@ -425,22 +326,25 @@ PutString(
     }
 }
 
+#define ECHO(_Handle, _Buffer) \
+    PutString((_Handle), (PUCHAR)_Buffer, (DWORD)strlen((_Buffer)) * 
sizeof(CHAR))
+
 DWORD WINAPI
-PipeThread(
+ConnectionThread(
     IN  LPVOID          Argument
     )
 {
-    PMONITOR_CONTEXT    Context = &MonitorContext;
-    PMONITOR_PIPE       Pipe = (PMONITOR_PIPE)Argument;
+    PMONITOR_CONNECTION Connection = (PMONITOR_CONNECTION)Argument;
+    PMONITOR_CONSOLE    Console = Connection->Console;
     UCHAR               Buffer[MAXIMUM_BUFFER_SIZE];
     OVERLAPPED          Overlapped;
     HANDLE              Handle[2];
     DWORD               Length;
     DWORD               Object;
     HRESULT             Error;
-
-    Log("====>");
-
+    
+    Log("====> %s", Console->DeviceName);
+    
     ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
     Overlapped.hEvent = CreateEvent(NULL,
                                     TRUE,
@@ -448,69 +352,69 @@ PipeThread(
                                     NULL);
     if (Overlapped.hEvent == NULL)
         goto fail1;
-
-    Handle[0] = Pipe->Event;
+    
+    Handle[0] = Console->ServerEvent;
     Handle[1] = Overlapped.hEvent;
-
-    EnterCriticalSection(&Context->CriticalSection);
-    __InsertTailList(&Context->ListHead, &Pipe->ListEntry);
-    ++Context->ListCount;
-    LeaveCriticalSection(&Context->CriticalSection);
-
+    
+    EnterCriticalSection(&Console->CriticalSection);
+    __InsertTailList(&Console->ListHead, &Connection->ListEntry);
+    ++Console->ListCount;
+    LeaveCriticalSection(&Console->CriticalSection);
+    
     for (;;) {
-        (VOID) ReadFile(Pipe->Pipe,
+        (VOID) ReadFile(Connection->Pipe,
                         Buffer,
                         sizeof(Buffer),
                         NULL,
                         &Overlapped);
-
+    
         Object = WaitForMultipleObjects(ARRAYSIZE(Handle),
                                         Handle,
                                         FALSE,
                                         INFINITE);
         if (Object == WAIT_OBJECT_0)
             break;
-
-        if (!GetOverlappedResult(Pipe->Pipe,
+    
+        if (!GetOverlappedResult(Connection->Pipe,
                                  &Overlapped,
                                  &Length,
                                  FALSE))
             break;
-
+    
         ResetEvent(Overlapped.hEvent);
-
-        PutString(Context->Device,
+    
+        PutString(Console->DeviceHandle,
                   Buffer,
                   Length);
     }
-
-    EnterCriticalSection(&Context->CriticalSection);
-    __RemoveEntryList(&Pipe->ListEntry);
-    --Context->ListCount;
-    LeaveCriticalSection(&Context->CriticalSection);
-
+    
+    EnterCriticalSection(&Console->CriticalSection);
+    __RemoveEntryList(&Connection->ListEntry);
+    --Console->ListCount;
+    LeaveCriticalSection(&Console->CriticalSection);
+    
     CloseHandle(Overlapped.hEvent);
-
-    FlushFileBuffers(Pipe->Pipe);
-    DisconnectNamedPipe(Pipe->Pipe);
-    CloseHandle(Pipe->Pipe);
-    CloseHandle(Pipe->Thread);
-    free(Pipe);
-
-    Log("<====");
-
+    
+    FlushFileBuffers(Connection->Pipe);
+    DisconnectNamedPipe(Connection->Pipe);
+    CloseHandle(Connection->Pipe);
+    CloseHandle(Connection->Thread);
+    free(Connection);
+    
+    Log("<==== %s", Console->DeviceName);
+    
     return 0;
-
+    
 fail1:
     Error = GetLastError();
-
+    
     {
         PTCHAR  Message;
         Message = GetErrorMessage(Error);
         Log("fail1 (%s)", Message);
         LocalFree(Message);
     }
-
+    
     return 1;
 }
 
@@ -519,18 +423,17 @@ ServerThread(
     IN  LPVOID          Argument
     )
 {
-    PMONITOR_CONTEXT    Context = &MonitorContext;
+    PMONITOR_CONSOLE    Console = (PMONITOR_CONSOLE)Argument;
+    CHAR                PipeName[MAXIMUM_BUFFER_SIZE];
     OVERLAPPED          Overlapped;
     HANDLE              Handle[2];
     HANDLE              Pipe;
     DWORD               Object;
-    PMONITOR_PIPE       Instance;
+    PMONITOR_CONNECTION Connection;
     HRESULT             Error;
-
-    UNREFERENCED_PARAMETER(Argument);
-
-    Log("====>");
-
+    
+    Log("====> %s", Console->DeviceName);
+    
     ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
     Overlapped.hEvent = CreateEvent(NULL,
                                     TRUE,
@@ -538,12 +441,22 @@ ServerThread(
                                     NULL);
     if (Overlapped.hEvent == NULL)
         goto fail1;
-
-    Handle[0] = Context->ServerEvent;
+    
+    Handle[0] = Console->ServerEvent;
     Handle[1] = Overlapped.hEvent;
+    
+    Error = StringCchPrintfA(PipeName,
+                             MAXIMUM_BUFFER_SIZE,
+                             "%s%s",
+                             PIPE_BASE_NAME,
+                             Console->DeviceName);
+    if (Error != S_OK && Error != STRSAFE_E_INSUFFICIENT_BUFFER)
+        goto fail2;
+
+    Log("%s", PipeName);
 
     for (;;) {
-        Pipe = CreateNamedPipe(PIPE_NAME,
+        Pipe = CreateNamedPipe(PipeName,
                                PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
                                PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
                                PIPE_UNLIMITED_INSTANCES,
@@ -552,11 +465,11 @@ ServerThread(
                                0,
                                NULL);
         if (Pipe == INVALID_HANDLE_VALUE)
-            goto fail2;
-
+            goto fail3;
+    
         (VOID) ConnectNamedPipe(Pipe,
                                 &Overlapped);
-
+    
         Object = WaitForMultipleObjects(ARRAYSIZE(Handle),
                                         Handle,
                                         FALSE,
@@ -565,146 +478,60 @@ ServerThread(
             CloseHandle(Pipe);
             break;
         }
-
+    
         ResetEvent(Overlapped.hEvent);
-
-        Instance = (PMONITOR_PIPE)malloc(sizeof(MONITOR_PIPE));
-        if (Instance == NULL)
-            goto fail3;
-
-        __InitializeListHead(&Instance->ListEntry);
-        Instance->Pipe = Pipe;
-        Instance->Event = Context->ServerEvent;
-        Instance->Thread = CreateThread(NULL,
-                                        0,
-                                        PipeThread,
-                                        Instance,
-                                        0,
-                                        NULL);
-        if (Instance->Thread == INVALID_HANDLE_VALUE)
+    
+        Connection = (PMONITOR_CONNECTION)malloc(sizeof(MONITOR_CONNECTION));
+        if (Connection == NULL)
             goto fail4;
+    
+        __InitializeListHead(&Connection->ListEntry);
+        Connection->Console = Console;
+        Connection->Pipe = Pipe;
+        Connection->Thread = CreateThread(NULL,
+                                          0,
+                                          ConnectionThread,
+                                          Connection,
+                                          0,
+                                          NULL);
+        if (Connection->Thread == NULL)
+            goto fail5;
     }
-
+    
     CloseHandle(Overlapped.hEvent);
+    
+    Log("<==== %s", Console->DeviceName);
+    
+    return 0;
 
-    Log("<====");
+fail5:
+    Log("fail5");
 
-    return 0;
+    free(Connection);
 
 fail4:
     Log("fail4");
 
-    free(Instance);
+    CloseHandle(Pipe);
 
 fail3:
     Log("fail3");
 
-    CloseHandle(Pipe);
-
 fail2:
     Log("fail2");
+    
+    CloseHandle(Overlapped.hEvent);
 
 fail1:
     Error = GetLastError();
-
-    {
-        PTCHAR  Message;
-        Message = GetErrorMessage(Error);
-        Log("fail1 (%s)", Message);
-        LocalFree(Message);
-    }
-
-    return 1;
-}
-
-DWORD WINAPI
-MonitorThread(
-    IN  LPVOID          Argument
-    )
-{
-    PMONITOR_CONTEXT    Context = &MonitorContext;
-    PROCESS_INFORMATION ProcessInfo;
-    STARTUPINFO         StartupInfo;
-    BOOL                Success;
-    HANDLE              Handle[2];
-    DWORD               Object;
-    HRESULT             Error;
-
-    UNREFERENCED_PARAMETER(Argument);
-
-    Log("====>");
-
-    // If there is no executable, this thread can finish now.
-    if (Context->Executable == NULL)
-        goto done;
-
-again:
-    ZeroMemory(&ProcessInfo, sizeof (ProcessInfo));
-    ZeroMemory(&StartupInfo, sizeof (StartupInfo));
-    StartupInfo.cb = sizeof (StartupInfo);
-
-    Log("Executing: %s", Context->Executable);
-
-#pragma warning(suppress:6053) // CommandLine might not be NUL-terminated
-    Success = CreateProcess(NULL,
-                            Context->Executable,
-                            NULL,
-                            NULL,
-                            FALSE,
-                            CREATE_NO_WINDOW |
-                            CREATE_NEW_PROCESS_GROUP,
-                            NULL,
-                            NULL,
-                            &StartupInfo,
-                            &ProcessInfo);
-    if (!Success)
-        goto fail1;
-
-    Handle[0] = Context->MonitorEvent;
-    Handle[1] = ProcessInfo.hProcess;
-
-    Object = WaitForMultipleObjects(ARRAYSIZE(Handle),
-                                   Handle,
-                                   FALSE,
-                                   INFINITE);
-
-#define WAIT_OBJECT_1 (WAIT_OBJECT_0 + 1)
-
-    switch (Object) {
-    case WAIT_OBJECT_0:
-        ResetEvent(Context->MonitorEvent);
-
-        TerminateProcess(ProcessInfo.hProcess, 1);
-        CloseHandle(ProcessInfo.hProcess);
-        CloseHandle(ProcessInfo.hThread);
-        break;
-
-    case WAIT_OBJECT_1:
-        CloseHandle(ProcessInfo.hProcess);
-        CloseHandle(ProcessInfo.hThread);
-        goto again;
-
-    default:
-        break;
-    }
-
-//#undef WAIT_OBJECT_1
-
-done:
-    Log("<====");
-
-    return 0;
-
-fail1:
-    Error = GetLastError();
-
+    
     {
         PTCHAR  Message;
         Message = GetErrorMessage(Error);
         Log("fail1 (%s)", Message);
         LocalFree(Message);
     }
-
+    
     return 1;
 }
 
@@ -713,7 +540,7 @@ DeviceThread(
     IN  LPVOID          Argument
     )
 {
-    PMONITOR_CONTEXT    Context = &MonitorContext;
+    PMONITOR_CONSOLE    Console = (PMONITOR_CONSOLE)Argument;
     OVERLAPPED          Overlapped;
     HANDLE              Device;
     UCHAR               Buffer[MAXIMUM_BUFFER_SIZE];
@@ -721,11 +548,9 @@ DeviceThread(
     DWORD               Wait;
     HANDLE              Handles[2];
     DWORD               Error;
-
-    UNREFERENCED_PARAMETER(Argument);
-
-    Log("====>");
-
+    
+    Log("====> %s", Console->DeviceName);
+    
     ZeroMemory(&Overlapped, sizeof(OVERLAPPED));
     Overlapped.hEvent = CreateEvent(NULL,
                                     TRUE,
@@ -733,72 +558,172 @@ DeviceThread(
                                     NULL);
     if (Overlapped.hEvent == NULL)
         goto fail1;
-
-    Handles[0] = Context->DeviceEvent;
+    
+    Handles[0] = Console->DeviceEvent;
     Handles[1] = Overlapped.hEvent;
-
-    Device = CreateFile(Context->DevicePath,
-                        GENERIC_READ,
-                        FILE_SHARE_READ | FILE_SHARE_WRITE,
-                        NULL,
-                        OPEN_EXISTING,
-                        FILE_FLAG_OVERLAPPED,
-                        NULL);
+    
+    Device = CreateFileW(Console->DevicePath,
+                         GENERIC_READ,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE,
+                         NULL,
+                         OPEN_EXISTING,
+                         FILE_FLAG_OVERLAPPED,
+                         NULL);
     if (Device == INVALID_HANDLE_VALUE)
         goto fail2;
-
+    
     for (;;) {
         PLIST_ENTRY     ListEntry;
-
+    
         (VOID) ReadFile(Device,
                         Buffer,
                         sizeof(Buffer),
                         NULL,
                         &Overlapped);
-
+    
         Wait = WaitForMultipleObjects(ARRAYSIZE(Handles),
                                       Handles,
                                       FALSE,
                                       INFINITE);
         if (Wait == WAIT_OBJECT_0)
             break;
-
+    
         if (!GetOverlappedResult(Device,
                                  &Overlapped,
                                  &Length,
                                  FALSE))
             break;
-
+    
         ResetEvent(Overlapped.hEvent);
+    
+        EnterCriticalSection(&Console->CriticalSection);
+    
+        for (ListEntry = Console->ListHead.Flink;
+                ListEntry != &Console->ListHead;
+                ListEntry = ListEntry->Flink) {
+            PMONITOR_CONNECTION Connection;
+    
+            Connection = CONTAINING_RECORD(ListEntry,
+                                           MONITOR_CONNECTION,
+                                           ListEntry);
+    
+            PutString(Connection->Pipe,
+                      Buffer,
+                      Length);
+        }
 
-        EnterCriticalSection(&Context->CriticalSection);
+        LeaveCriticalSection(&Console->CriticalSection);
+    }
+    
+    CloseHandle(Device);
+    
+    CloseHandle(Overlapped.hEvent);
+    
+    Log("<==== %s", Console->DeviceName);
+    
+    return 0;
+    
+fail2:
+    Log("fail2\n");
+    
+    CloseHandle(Overlapped.hEvent);
+    
+fail1:
+    Error = GetLastError();
+    
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+    
+    return 1;
+}
 
-        for (ListEntry = Context->ListHead.Flink;
-             ListEntry != &Context->ListHead;
-             ListEntry = ListEntry->Flink) {
-            PMONITOR_PIPE   Instance;
+static BOOL
+GetExecutable(
+    IN  PCHAR           DeviceName,
+    OUT PCHAR           *Executable
+    )
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+    HKEY                Key;
+    DWORD               MaxValueLength;
+    DWORD               ExecutableLength;
+    DWORD               Type;
+    HRESULT             Error;
 
-            Instance = CONTAINING_RECORD(ListEntry, MONITOR_PIPE, ListEntry);
+    Error = RegOpenKeyExA(Context->ParametersKey,
+                          DeviceName,
+                          0,
+                          KEY_READ,
+                          &Key);
+    if (Error != ERROR_SUCCESS) {
+        SetLastError(Error);
+        goto fail1;
+    }
 
-            PutString(Instance->Pipe,
-                      Buffer,
-                      Length);
-        }
-        LeaveCriticalSection(&Context->CriticalSection);
+    Error = RegQueryInfoKey(Key,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            &MaxValueLength,
+                            NULL,
+                            NULL);
+    if (Error != ERROR_SUCCESS) {
+        SetLastError(Error);
+        goto fail2;
     }
 
-    CloseHandle(Device);
+    ExecutableLength = MaxValueLength;
 
-    CloseHandle(Overlapped.hEvent);
+    *Executable = calloc(1, ExecutableLength);
+    if (Executable == NULL)
+        goto fail3;
 
-    Log("<====");
+    Error = RegQueryValueExA(Key,
+                             "Executable",
+                             NULL,
+                             &Type,
+                             (LPBYTE)(*Executable),
+                             &ExecutableLength);
+    if (Error != ERROR_SUCCESS) {
+        SetLastError(Error);
+        goto fail4;
+    }
 
-    return 0;
+    if (Type != REG_SZ) {
+        SetLastError(ERROR_BAD_FORMAT);
+        goto fail5;
+    }
+
+    Log("%s = %s", DeviceName, *Executable);
+
+    RegCloseKey(Key);
+
+    return TRUE;
+
+fail5:
+    Log("fail5");
+
+fail4:
+    Log("fail4");
+
+    free(*Executable);
+
+fail3:
+    Log("fail3");
 
 fail2:
-    Log("fail2\n");
+    Log("fail2");
 
-    CloseHandle(Overlapped.hEvent);
+    RegCloseKey(Key);
 
 fail1:
     Error = GetLastError();
@@ -810,278 +735,614 @@ fail1:
         LocalFree(Message);
     }
 
-    return 1;
+    return FALSE;
 }
 
-#define ECHO(_Handle, _Buffer) \
-    PutString((_Handle), (PUCHAR)TEXT(_Buffer), (DWORD)_tcslen((_Buffer)) * 
sizeof(TCHAR))
+DWORD WINAPI
+ExecutableThread(
+    IN  LPVOID          Argument
+    )
+{
+    PMONITOR_CONSOLE    Console = (PMONITOR_CONSOLE)Argument;
+    PCHAR               Executable;
+    PROCESS_INFORMATION ProcessInfo;
+    STARTUPINFO         StartupInfo;
+    BOOL                Success;
+    HANDLE              Handle[2];
+    DWORD               Object;
+    HRESULT             Error;
+    
+    Log("====> %s", Console->DeviceName);
+    
+    // If there is no executable, this thread can finish now.
+    if (!GetExecutable(Console->DeviceName,
+                       &Executable))
+        goto done;
+    if (Executable == NULL)
+        goto done;
+    
+again:
+    ZeroMemory(&ProcessInfo, sizeof (ProcessInfo));
+    ZeroMemory(&StartupInfo, sizeof (StartupInfo));
+    StartupInfo.cb = sizeof (StartupInfo);
+    
+    Log("Executing: %s", Executable);
+    
+#pragma warning(suppress:6053) // CommandLine might not be NUL-terminated
+    Success = CreateProcess(NULL,
+                            Executable,
+                            NULL,
+                            NULL,
+                            FALSE,
+                            CREATE_NO_WINDOW |
+                            CREATE_NEW_PROCESS_GROUP,
+                            NULL,
+                            NULL,
+                            &StartupInfo,
+                            &ProcessInfo);
+    if (!Success)
+        goto fail1;
+    
+    Handle[0] = Console->ExecutableEvent;
+    Handle[1] = ProcessInfo.hProcess;
+    
+    Object = WaitForMultipleObjects(ARRAYSIZE(Handle),
+                                    Handle,
+                                    FALSE,
+                                    INFINITE);
+    
+#define WAIT_OBJECT_1 (WAIT_OBJECT_0 + 1)
+    
+    switch (Object) {
+    case WAIT_OBJECT_0:
+        ResetEvent(Console->ExecutableEvent);
+    
+        TerminateProcess(ProcessInfo.hProcess, 1);
+        CloseHandle(ProcessInfo.hProcess);
+        CloseHandle(ProcessInfo.hThread);
+        break;
+    
+    case WAIT_OBJECT_1:
+        CloseHandle(ProcessInfo.hProcess);
+        CloseHandle(ProcessInfo.hThread);
+        goto again;
+    
+    default:
+        break;
+    }
+    
+//#undef WAIT_OBJECT_1
+    
+    free(Executable);
 
-static VOID
-MonitorAdd(
-    VOID
+done:
+    Log("<==== %s", Console->DeviceName);
+    
+    return 0;
+    
+fail1:
+    Error = GetLastError();
+    
+    free(Executable);
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+    
+    return 1;
+}
+
+static PMONITOR_CONSOLE
+ConsoleCreate(
+    IN  PWCHAR              DevicePath
     )
 {
     PMONITOR_CONTEXT        Context = &MonitorContext;
-    PTCHAR                  Path;
+    PMONITOR_CONSOLE        Console;
     DEV_BROADCAST_HANDLE    Handle;
-    HRESULT                 Error;
+    CHAR                    DeviceName[MAX_PATH];
+    DWORD                   Bytes;
     BOOL                    Success;
+    HRESULT                 Error;
 
-    if (Context->Device != INVALID_HANDLE_VALUE)
-        return;
-
-    Log("====>");
-
-    Success = MonitorGetPath(&GUID_XENCONS_DEVICE, &Path);
+    Log("====> %ws", DevicePath);
 
-    if (!Success)
+    Console = malloc(sizeof(MONITOR_CONSOLE));
+    if (Console == NULL)
         goto fail1;
 
-    Context->Device = CreateFile(Path,
-                                 GENERIC_WRITE,
-                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                 NULL,
-                                 OPEN_EXISTING,
-                                 FILE_ATTRIBUTE_NORMAL,
-                                 NULL);
+    memset(Console, 0, sizeof(MONITOR_CONSOLE));
+    __InitializeListHead(&Console->ListHead);
+    __InitializeListHead(&Console->ListEntry);
+    InitializeCriticalSection(&Console->CriticalSection);
 
-    if (Context->Device == INVALID_HANDLE_VALUE)
+    Console->DevicePath = _wcsdup(DevicePath);
+    if (Console->DevicePath == NULL)
         goto fail2;
 
-    ECHO(Context->Device, "\r\n[ATTACHED]\r\n");
-
-    ZeroMemory(&Handle, sizeof (Handle));
-    Handle.dbch_size = sizeof (Handle);
-    Handle.dbch_devicetype = DBT_DEVTYP_HANDLE;
-    Handle.dbch_handle = Context->Device;
-
-    Context->DeviceNotification =
-        RegisterDeviceNotification(Context->Service,
-                                   &Handle,
-                                   DEVICE_NOTIFY_SERVICE_HANDLE);
-    if (Context->DeviceNotification == NULL)
-        goto fail3;
-
-    Context->DevicePath = Path;
-    __InitializeListHead(&Context->ListHead);
-    InitializeCriticalSection(&Context->CriticalSection);
-
-    Context->MonitorEvent = CreateEvent(NULL,
-                                        TRUE,
-                                        FALSE,
+    Console->DeviceHandle = CreateFileW(DevicePath,
+                                        GENERIC_READ | GENERIC_WRITE,
+                                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                        NULL,
+                                        OPEN_EXISTING,
+                                        FILE_ATTRIBUTE_NORMAL,
                                         NULL);
+    if (Console->DeviceHandle == INVALID_HANDLE_VALUE)
+        goto fail3;
 
-    if (Context->MonitorEvent == NULL)
+    Success = DeviceIoControl(Console->DeviceHandle,
+                              IOCTL_XENCONS_GET_NAME,
+                              NULL,
+                              0,
+                              DeviceName,
+                              sizeof(DeviceName),
+                              &Bytes,
+                              NULL);
+    if (!Success)
         goto fail4;
 
-    Context->MonitorThread = CreateThread(NULL,
-                                          0,
-                                          MonitorThread,
-                                          NULL,
-                                          0,
-                                          NULL);
+    DeviceName[MAX_PATH - 1] = '\0';
 
-    if (Context->MonitorThread == INVALID_HANDLE_VALUE)
+    Console->DeviceName = _strdup(DeviceName);
+    if (Console->DeviceName == NULL)
         goto fail5;
 
-    Context->DeviceEvent = CreateEvent(NULL,
+    ECHO(Console->DeviceHandle, "\r\n[ATTACHED]\r\n");
+
+    ZeroMemory(&Handle, sizeof (Handle));
+    Handle.dbch_size = sizeof (Handle);
+    Handle.dbch_devicetype = DBT_DEVTYP_HANDLE;
+    Handle.dbch_handle = Console->DeviceHandle;
+    
+    Console->DeviceNotification =
+        RegisterDeviceNotification(Context->Service,
+                                    &Handle,
+                                    DEVICE_NOTIFY_SERVICE_HANDLE);
+    if (Console->DeviceNotification == NULL)
+        goto fail6;
+
+    Console->DeviceEvent = CreateEvent(NULL,
                                        TRUE,
                                        FALSE,
                                        NULL);
+    if (Console->DeviceEvent == NULL)
+        goto fail7;
 
-    if (Context->DeviceEvent == NULL)
-        goto fail6;
-
-    Context->DeviceThread = CreateThread(NULL,
+    Console->DeviceThread = CreateThread(NULL,
                                          0,
                                          DeviceThread,
-                                         NULL,
+                                         Console,
                                          0,
                                          NULL);
+    if (Console->DeviceThread == NULL)
+        goto fail8;
 
-    if (Context->DeviceThread == INVALID_HANDLE_VALUE)
-        goto fail7;
-
-    Context->ServerEvent = CreateEvent(NULL,
+    Console->ServerEvent = CreateEvent(NULL,
                                        TRUE,
                                        FALSE,
                                        NULL);
-    if (Context->ServerEvent == NULL)
-        goto fail8;
+    if (Console->ServerEvent == NULL)
+        goto fail9;
 
-    Context->ServerThread = CreateThread(NULL,
+    Console->ServerThread = CreateThread(NULL,
                                          0,
                                          ServerThread,
-                                         NULL,
+                                         Console,
                                          0,
                                          NULL);
-    if (Context->ServerThread == INVALID_HANDLE_VALUE)
-        goto fail9;
+    if (Console->ServerThread == NULL)
+        goto fail10;
 
-    Log("<====");
+    Console->ExecutableEvent = CreateEvent(NULL,
+                                           TRUE,
+                                           FALSE,
+                                           NULL);
+    if (Console->ExecutableEvent == NULL)
+        goto fail11;
 
-    return;
+    Console->ExecutableThread = CreateThread(NULL,
+                                             0,
+                                             ExecutableThread,
+                                             Console,
+                                             0,
+                                             NULL);
+    if (Console->ExecutableThread == NULL)
+        goto fail12;
+
+    Log("<==== %s", Console->DeviceName);
+
+    return Console;
+
+fail12:
+    Log("fail12");
+
+    CloseHandle(Console->ExecutableEvent);
+    Console->ExecutableEvent = NULL;
+
+fail11:
+    Log("fail11");
+
+    SetEvent(Console->ServerEvent);
+    WaitForSingleObject(Console->ServerThread, INFINITE);
+
+fail10:
+    Log("fail10");
+
+    CloseHandle(Console->ServerEvent);
+    Console->ServerEvent = NULL;
 
 fail9:
     Log("fail9");
 
-    CloseHandle(Context->ServerEvent);
-    Context->ServerEvent = NULL;
+    SetEvent(Console->DeviceEvent);
+    WaitForSingleObject(Console->DeviceThread, INFINITE);
 
 fail8:
     Log("fail8");
 
-    SetEvent(Context->DeviceEvent);
-    WaitForSingleObject(Context->DeviceThread, INFINITE);
+    CloseHandle(Console->DeviceEvent);
+    Console->DeviceEvent = NULL;
 
 fail7:
-    Log("fail7\n");
+    Log("fail7");
 
-    CloseHandle(Context->DeviceEvent);
-    Context->DeviceEvent = NULL;
+    UnregisterDeviceNotification(Console->DeviceNotification);
+    Console->DeviceNotification = NULL;
 
 fail6:
-    Log("fail6\n");
+    Log("fail6");
 
-    SetEvent(Context->MonitorThread);
-    WaitForSingleObject(Context->MonitorThread, INFINITE);
+    ECHO(Console->DeviceHandle, "\r\n[DETACHED]\r\n");
+
+    free(Console->DevicePath);
+    Console->DevicePath = NULL;
 
 fail5:
     Log("fail5");
 
-    CloseHandle(Context->MonitorEvent);
-    Context->MonitorEvent = NULL;
-
 fail4:
     Log("fail4");
 
-    DeleteCriticalSection(&Context->CriticalSection);
-    ZeroMemory(&Context->ListHead, sizeof(LIST_ENTRY));
-
-    free(Context->DevicePath);
-    Context->DevicePath = NULL;
-
-    UnregisterDeviceNotification(Context->DeviceNotification);
-    Context->DeviceNotification = NULL;
+    CloseHandle(Console->DeviceHandle);
+    Console->DeviceHandle = INVALID_HANDLE_VALUE;
 
 fail3:
     Log("fail3");
 
-    CloseHandle(Context->Device);
-    Context->Device = INVALID_HANDLE_VALUE;
+    free(Console->DevicePath);
+    Console->DevicePath = NULL;
 
 fail2:
     Log("fail2");
 
-    free(Path);
+    DeleteCriticalSection(&Console->CriticalSection);
+    ZeroMemory(&Console->ListHead, sizeof(LIST_ENTRY));
+    ZeroMemory(&Console->ListEntry, sizeof(LIST_ENTRY));
+
+    free(Console);
 
 fail1:
     Error = GetLastError();
 
     {
-        PTCHAR  Message;
+        PCHAR  Message;
         Message = GetErrorMessage(Error);
         Log("fail1 (%s)", Message);
         LocalFree(Message);
     }
+
+    return NULL;
 }
 
-static VOID
-MonitorWaitForPipeThreads(
-    VOID
+static FORCEINLINE VOID
+ConsoleWaitForPipes(
+    IN  PMONITOR_CONSOLE    Console
     )
 {
-    PMONITOR_CONTEXT    Context = &MonitorContext;
-    HANDLE              *Handles;
-    DWORD               Index;
-    PLIST_ENTRY         ListEntry;
+    PLIST_ENTRY             ListEntry;
+    HANDLE                  *Events;
+    DWORD                   Count;
+    DWORD                   Index;
 
-    EnterCriticalSection(&Context->CriticalSection);
+    EnterCriticalSection(&Console->CriticalSection);
 
-    if (Context->ListCount == 0)
+    Count = Console->ListCount + 1;
+    Events = malloc(Count * sizeof(HANDLE));
+    if (Events == NULL)
         goto fail1;
 
-    Handles = (HANDLE*)malloc(sizeof(HANDLE) * Context->ListCount);
-    if (Handles == NULL)
-        goto fail2;
-
     Index = 0;
-    for (ListEntry = Context->ListHead.Flink;
-         ListEntry != &Context->ListHead && Index < Context->ListCount;
+    for (ListEntry = Console->ListHead.Flink;
+         ListEntry != &Console->ListHead;
          ListEntry = ListEntry->Flink) {
-        PMONITOR_PIPE Pipe = CONTAINING_RECORD(ListEntry, MONITOR_PIPE, 
ListEntry);
-        Handles[Index++] = Pipe->Thread;
+        PMONITOR_CONNECTION Connection;
+
+        Connection = CONTAINING_RECORD(ListEntry,
+                                       MONITOR_CONNECTION,
+                                       ListEntry);
+
+#pragma warning(suppress: 6386) // Buffer overflow
+        Events[Index] = Connection->Thread;
+        ++Index;
     }
+    Events[Count - 1] = Console->ServerThread;
 
-    Context->ListCount = 0;
+    LeaveCriticalSection(&Console->CriticalSection);
 
-    LeaveCriticalSection(&Context->CriticalSection);
+    SetEvent(Console->ServerEvent);
+    WaitForMultipleObjects(Count, Events, TRUE, INFINITE);
 
-#pragma warning(suppress:6385) // Reading invalid data from 'Handles'...
-    WaitForMultipleObjects(Index,
-                           Handles,
-                           TRUE,
-                           INFINITE);
-    free(Handles);
     return;
 
-fail2:
-    Log("fail2");
-
 fail1:
-    Log("fail1");
+    LeaveCriticalSection(&Console->CriticalSection);
+
+    // set the event and wait for the server thread anyway
+    SetEvent(Console->ServerEvent);
+    WaitForSingleObject(Console->ServerThread, INFINITE);
+}
+
+static VOID
+ConsoleDestroy(
+    IN  PMONITOR_CONSOLE    Console
+    )
+{
+    Log("====> %s", Console->DeviceName);
+
+    SetEvent(Console->ExecutableEvent);
+    WaitForSingleObject(Console->ExecutableThread, INFINITE);
+
+    CloseHandle(Console->ExecutableEvent);
+    Console->ExecutableEvent = NULL;
+
+    ConsoleWaitForPipes(Console);
+
+    CloseHandle(Console->ServerEvent);
+    Console->ServerEvent = NULL;
+
+    SetEvent(Console->DeviceEvent);
+    WaitForSingleObject(Console->DeviceThread, INFINITE);
+
+    CloseHandle(Console->DeviceEvent);
+    Console->DeviceEvent = NULL;
+
+    UnregisterDeviceNotification(Console->DeviceNotification);
+    Console->DeviceNotification = NULL;
+
+    ECHO(Console->DeviceHandle, "\r\n[DETACHED]\r\n");
+
+    free(Console->DevicePath);
+    Console->DevicePath = NULL;
+
+    CloseHandle(Console->DeviceHandle);
+    Console->DeviceHandle = INVALID_HANDLE_VALUE;
+
+    free(Console->DevicePath);
+    Console->DevicePath = NULL;
+
+    DeleteCriticalSection(&Console->CriticalSection);
+    ZeroMemory(&Console->ListHead, sizeof(LIST_ENTRY));
+    ZeroMemory(&Console->ListEntry, sizeof(LIST_ENTRY));
+
+    free(Console);
 
+    Log("<====");
+}
+
+static BOOL
+MonitorAdd(
+    IN  PWCHAR          DevicePath
+    )
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+    PMONITOR_CONSOLE    Console;
+
+    Log("=====> %ws", DevicePath);
+
+    Console = ConsoleCreate(DevicePath);
+    if (Console == NULL)
+        goto fail1;
+
+    EnterCriticalSection(&Context->CriticalSection);
+    __InsertTailList(&Context->ListHead, &Console->ListEntry);
+    ++Context->ListCount;
     LeaveCriticalSection(&Context->CriticalSection);
 
-    return;
+    Log("<===== %s", Console->DeviceName);
+
+    return TRUE;
+
+fail1:
+    Log("fail1");
+
+    return FALSE;
 }
 
-static VOID
+static BOOL
 MonitorRemove(
-    VOID
+    IN  HANDLE          DeviceHandle
     )
 {
     PMONITOR_CONTEXT    Context = &MonitorContext;
+    PMONITOR_CONSOLE    Console;
+    PLIST_ENTRY         ListEntry;
 
-    if (Context->Device == INVALID_HANDLE_VALUE)
-        return;
+    Log("=====> 0x%p", DeviceHandle);
+
+    EnterCriticalSection(&Context->CriticalSection);
+    for (ListEntry = Context->ListHead.Flink;
+         ListEntry != &Context->ListHead;
+         ListEntry = ListEntry->Flink) {
+        Console = CONTAINING_RECORD(ListEntry,
+                                    MONITOR_CONSOLE,
+                                    ListEntry);
+
+        if (Console->DeviceHandle == DeviceHandle)
+            goto found;        
+    }
+    LeaveCriticalSection(&Context->CriticalSection);
 
+    Log("DeviceHandle 0x%p not found", DeviceHandle);
+
+    return FALSE;
+    
+found:
+    __RemoveEntryList(&Console->ListEntry);
+    --Context->ListCount;
+    LeaveCriticalSection(&Context->CriticalSection);
+
+    ConsoleDestroy(Console);
+
+    Log("<=====");
+
+    return TRUE;
+}
+
+static BOOL
+MonitorEnumerate(
+    VOID
+    )
+{
+    PMONITOR_CONTEXT                    Context = &MonitorContext;
+    HDEVINFO                            DeviceInfoSet;
+    SP_DEVICE_INTERFACE_DATA            DeviceInterfaceData;
+    PSP_DEVICE_INTERFACE_DETAIL_DATA_W  DeviceInterfaceDetail;
+    PMONITOR_CONSOLE                    Console;
+    DWORD                               Size;
+    DWORD                               Index;
+    HRESULT                             Error;
+    BOOL                                Success;
+    
     Log("====>");
+    
+    DeviceInfoSet = SetupDiGetClassDevs(&GUID_XENCONS_DEVICE,
+                                        NULL,
+                                        NULL,
+                                        DIGCF_PRESENT |
+                                        DIGCF_DEVICEINTERFACE);
+    if (DeviceInfoSet == INVALID_HANDLE_VALUE)
+        goto fail1;
+    
+    DeviceInterfaceData.cbSize = sizeof (SP_DEVICE_INTERFACE_DATA);
 
-    SetEvent(Context->ServerEvent);
-    MonitorWaitForPipeThreads();
-    WaitForSingleObject(Context->ServerThread, INFINITE);
+    for (Index = 0; TRUE; ++Index) {
+        Success = SetupDiEnumDeviceInterfaces(DeviceInfoSet,
+                                              NULL,
+                                              &GUID_XENCONS_DEVICE,
+                                              Index,
+                                              &DeviceInterfaceData);
+        if (!Success)
+            break;
 
-    CloseHandle(Context->ServerEvent);
-    Context->ServerEvent = NULL;
+        Success = SetupDiGetDeviceInterfaceDetailW(DeviceInfoSet,
+                                                  &DeviceInterfaceData,
+                                                  NULL,
+                                                  0,
+                                                  &Size,
+                                                  NULL);
+        if (!Success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+            goto fail2;
+        
+        DeviceInterfaceDetail = calloc(1, Size);
+        if (DeviceInterfaceDetail == NULL)
+            goto fail3;
+        
+        DeviceInterfaceDetail->cbSize =
+            sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA_W);
+        
+        Success = SetupDiGetDeviceInterfaceDetailW(DeviceInfoSet,
+                                                   &DeviceInterfaceData,
+                                                   DeviceInterfaceDetail,
+                                                   Size,
+                                                   NULL,
+                                                   NULL);
+        if (!Success)
+            goto fail4;
 
-    SetEvent(Context->DeviceEvent);
-    WaitForSingleObject(Context->DeviceThread, INFINITE);
+        Console = ConsoleCreate(DeviceInterfaceDetail->DevicePath);
+        if (Console == NULL)
+            goto fail5;
 
-    CloseHandle(Context->DeviceEvent);
-    Context->DeviceEvent = NULL;
+        EnterCriticalSection(&Context->CriticalSection);
+        __InsertTailList(&Context->ListHead, &Console->ListEntry);
+        ++Context->ListCount;
+        LeaveCriticalSection(&Context->CriticalSection);
 
-    SetEvent(Context->MonitorEvent);
-    WaitForSingleObject(Context->MonitorThread, INFINITE);
+        free(DeviceInterfaceDetail);
 
-    CloseHandle(Context->MonitorEvent);
-    Context->MonitorEvent = NULL;
+        continue;
 
-    DeleteCriticalSection(&Context->CriticalSection);
-    ZeroMemory(&Context->ListHead, sizeof(LIST_ENTRY));
+    fail5:
+        Log("fail5");
+    fail4:
+        Log("fail4");
 
-    free(Context->DevicePath);
-    Context->DevicePath = NULL;
+        free(DeviceInterfaceDetail);
 
-    UnregisterDeviceNotification(Context->DeviceNotification);
-    Context->DeviceNotification = NULL;
+    fail3:
+        Log("fail3");
+    fail2:
+        Error = GetLastError();
 
-    ECHO(Context->Device, "\r\n[DETACHED]\r\n");
+        {
+            PCHAR  Message;
+            Message = GetErrorMessage(Error);
+            Log("fail2 (%s)", Message);
+            LocalFree(Message);
+        }
+    }
 
-    CloseHandle(Context->Device);
-    Context->Device = INVALID_HANDLE_VALUE;
+    SetupDiDestroyDeviceInfoList(DeviceInfoSet);
 
     Log("<====");
+
+    return TRUE;
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return FALSE;
+}
+
+static VOID
+MonitorRemoveAll(
+    VOID
+    )
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+    PMONITOR_CONSOLE    Console;
+
+    Log("=====>");
+
+    for (;;) {
+        EnterCriticalSection(&Context->CriticalSection);
+        if (Context->ListHead.Flink == &Context->ListHead)
+            break;
+
+        Console = CONTAINING_RECORD(Context->ListHead.Flink,
+                                    MONITOR_CONSOLE,
+                                    ListEntry);
+
+        __RemoveEntryList(&Console->ListEntry);
+        --Context->ListCount;
+
+        LeaveCriticalSection(&Context->CriticalSection);
+
+        ConsoleDestroy(Console);
+    }
+    LeaveCriticalSection(&Context->CriticalSection);
+
+    Log("<=====");
 }
 
 DWORD WINAPI
@@ -1113,11 +1374,11 @@ MonitorCtrlHandlerEx(
         switch (EventType) {
         case DBT_DEVICEARRIVAL:
             if (Header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
-                PDEV_BROADCAST_DEVICEINTERFACE  Interface = EventData;
+                PDEV_BROADCAST_DEVICEINTERFACE_W Interface = EventData;
 
                 if (IsEqualGUID(&Interface->dbcc_classguid,
-                               &GUID_XENCONS_DEVICE))
-                    SetEvent(Context->AddEvent);
+                                &GUID_XENCONS_DEVICE))
+                    MonitorAdd(Interface->dbcc_name);
             }
             break;
 
@@ -1127,8 +1388,7 @@ MonitorCtrlHandlerEx(
             if (Header->dbch_devicetype == DBT_DEVTYP_HANDLE) {
                 PDEV_BROADCAST_HANDLE Device = EventData;
 
-                if (Device->dbch_handle == Context->Device)
-                    SetEvent(Context->RemoveEvent);
+                MonitorRemove(Device->dbch_handle);
             }
             break;
         }
@@ -1143,84 +1403,6 @@ MonitorCtrlHandlerEx(
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
-static BOOL
-GetExecutable(
-    OUT PTCHAR          *Executable
-    )
-{
-    PMONITOR_CONTEXT    Context = &MonitorContext;
-    DWORD               MaxValueLength;
-    DWORD               ExecutableLength;
-    DWORD               Type;
-    HRESULT             Error;
-
-    Error = RegQueryInfoKey(Context->ParametersKey,
-                            NULL,
-                            NULL,
-                            NULL,
-                            NULL,
-                            NULL,
-                            NULL,
-                            NULL,
-                            NULL,
-                            &MaxValueLength,
-                            NULL,
-                            NULL);
-    if (Error != ERROR_SUCCESS) {
-        SetLastError(Error);
-        goto fail1;
-    }
-
-    ExecutableLength = MaxValueLength + sizeof (TCHAR);
-
-    *Executable = calloc(1, ExecutableLength);
-    if (Executable == NULL)
-        goto fail2;
-
-    Error = RegQueryValueEx(Context->ParametersKey,
-                            "Executable",
-                            NULL,
-                            &Type,
-                            (LPBYTE)(*Executable),
-                            &ExecutableLength);
-    if (Error != ERROR_SUCCESS) {
-        SetLastError(Error);
-        goto fail3;
-    }
-
-    if (Type != REG_SZ) {
-        SetLastError(ERROR_BAD_FORMAT);
-        goto fail4;
-    }
-
-    Log("%s", *Executable);
-
-    return TRUE;
-
-fail4:
-    Log("fail4");
-
-fail3:
-    Log("fail3");
-
-    free(*Executable);
-
-fail2:
-    Log("fail2");
-
-fail1:
-    Error = GetLastError();
-
-    {
-        PTCHAR  Message;
-        Message = GetErrorMessage(Error);
-        Log("fail1 (%s)", Message);
-        LocalFree(Message);
-    }
-
-    return FALSE;
-}
-
 VOID WINAPI
 MonitorMain(
     _In_    DWORD                   argc,
@@ -1230,14 +1412,13 @@ MonitorMain(
     PMONITOR_CONTEXT                Context = &MonitorContext;
     DEV_BROADCAST_DEVICEINTERFACE   Interface;
     HRESULT                         Error;
-    BOOL                            Success;
 
     UNREFERENCED_PARAMETER(argc);
     UNREFERENCED_PARAMETER(argv);
 
     Log("====>");
 
-    Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+    Error = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
                          PARAMETERS_KEY(__MODULE__),
                          0,
                          KEY_READ,
@@ -1245,13 +1426,13 @@ MonitorMain(
     if (Error != ERROR_SUCCESS)
         goto fail1;
 
-    Context->Service = RegisterServiceCtrlHandlerEx(MONITOR_NAME,
+    Context->Service = RegisterServiceCtrlHandlerExA(MONITOR_NAME,
                                                     MonitorCtrlHandlerEx,
                                                     NULL);
     if (Context->Service == NULL)
         goto fail2;
 
-    Context->EventLog = RegisterEventSource(NULL,
+    Context->EventLog = RegisterEventSourceA(NULL,
                                             MONITOR_NAME);
     if (Context->EventLog == NULL)
         goto fail3;
@@ -1269,28 +1450,6 @@ MonitorMain(
     if (Context->StopEvent == NULL)
         goto fail4;
 
-    Context->AddEvent = CreateEvent(NULL,
-                                    TRUE,
-                                    FALSE,
-                                    NULL);
-
-    if (Context->AddEvent == NULL)
-        goto fail5;
-
-    Context->RemoveEvent = CreateEvent(NULL,
-                                       TRUE,
-                                       FALSE,
-                                       NULL);
-
-    if (Context->RemoveEvent == NULL)
-        goto fail6;
-
-    Success = GetExecutable(&Context->Executable);
-    if (!Success)
-        Context->Executable = NULL;
-
-    Context->Device = INVALID_HANDLE_VALUE;
-
     ZeroMemory(&Interface, sizeof (Interface));
     Interface.dbcc_size = sizeof (Interface);
     Interface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
@@ -1301,64 +1460,26 @@ MonitorMain(
                                    &Interface,
                                    DEVICE_NOTIFY_SERVICE_HANDLE);
     if (Context->InterfaceNotification == NULL)
-        goto fail7;
-
-    // The device may already by present
-    SetEvent(Context->AddEvent);
+        goto fail5;
 
     ReportStatus(SERVICE_RUNNING, NO_ERROR, 0);
 
-    for (;;) {
-        HANDLE  Events[3];
-        DWORD   Object;
-
-        Events[0] = Context->StopEvent;
-        Events[1] = Context->AddEvent;
-        Events[2] = Context->RemoveEvent;
-
-        Log("waiting (%u)...", ARRAYSIZE(Events));
-        Object = WaitForMultipleObjects(ARRAYSIZE(Events),
-                                        Events,
-                                        FALSE,
-                                        INFINITE);
-        Log("awake");
-
-#define WAIT_OBJECT_1 (WAIT_OBJECT_0 + 1)
-#define WAIT_OBJECT_2 (WAIT_OBJECT_0 + 2)
-
-        switch (Object) {
-        case WAIT_OBJECT_0:
-            ResetEvent(Context->StopEvent);
-            goto done;
+    __InitializeListHead(&Context->ListHead);
+    InitializeCriticalSection(&Context->CriticalSection);
 
-        case WAIT_OBJECT_1:
-            ResetEvent(Context->AddEvent);
-            MonitorAdd();
-            break;
+    MonitorEnumerate();
 
-        case WAIT_OBJECT_2:
-            ResetEvent(Context->RemoveEvent);
-            MonitorRemove();
+    Log("Waiting...");
+    WaitForSingleObject(Context->StopEvent, INFINITE);
+    Log("Wait Complete");
 
-        default:
-            break;
-        }
-
-#undef WAIT_OBJECT_1
-#undef WAIT_OBJECT_2
-    }
+    MonitorRemoveAll();
 
-done:
-    MonitorRemove();
+    DeleteCriticalSection(&Context->CriticalSection);
+    ZeroMemory(&Context->ListHead, sizeof(LIST_ENTRY));
 
     UnregisterDeviceNotification(Context->InterfaceNotification);
 
-    free(Context->Executable);
-
-    CloseHandle(Context->RemoveEvent);
-
-    CloseHandle(Context->AddEvent);
-
     CloseHandle(Context->StopEvent);
 
     ReportStatus(SERVICE_STOPPED, NO_ERROR, 0);
@@ -1371,16 +1492,6 @@ done:
 
     return;
 
-fail7:
-    Log("fail7");
-
-    CloseHandle(Context->RemoveEvent);
-
-fail6:
-    Log("fail6");
-
-    CloseHandle(Context->AddEvent);
-
 fail5:
     Log("fail5");
 
@@ -1419,12 +1530,12 @@ MonitorCreate(
 {
     SC_HANDLE   SCManager;
     SC_HANDLE   Service;
-    TCHAR       Path[MAX_PATH];
+    CHAR        Path[MAX_PATH];
     HRESULT     Error;
 
     Log("====>");
 
-    if(!GetModuleFileName(NULL, Path, MAX_PATH))
+    if(!GetModuleFileNameA(NULL, Path, MAX_PATH))
         goto fail1;
 
     SCManager = OpenSCManager(NULL,
@@ -1589,7 +1700,7 @@ fail1:
 }
 
 int CALLBACK
-_tWinMain(
+WinMain(
     _In_        HINSTANCE   Current,
     _In_opt_    HINSTANCE   Previous,
     _In_        LPSTR       CmdLine,
@@ -1602,10 +1713,10 @@ _tWinMain(
     UNREFERENCED_PARAMETER(Previous);
     UNREFERENCED_PARAMETER(CmdShow);
 
-    if (_tcslen(CmdLine) != 0) {
-         if (_tcsicmp(CmdLine, TEXT("create")) == 0)
+    if (strlen(CmdLine) != 0) {
+         if (_stricmp(CmdLine, "create") == 0)
              Success = MonitorCreate();
-         else if (_tcsicmp(CmdLine, TEXT("delete")) == 0)
+         else if (_stricmp(CmdLine, "delete") == 0)
              Success = MonitorDelete();
          else
              Success = FALSE;
diff --git a/src/tty/tty.c b/src/tty/tty.c
index 94d4f65..d623c21 100644
--- a/src/tty/tty.c
+++ b/src/tty/tty.c
@@ -39,7 +39,7 @@ typedef struct _TTY_STREAM {
     HANDLE  Write;
 } TTY_STREAM, *PTTY_STREAM;
 
-#define PIPE_NAME TEXT("\\\\.\\pipe\\xencons")
+#define PIPE_NAME TEXT("\\\\.\\pipe\\xencons\\default")
 #define MAXIMUM_BUFFER_SIZE 1024
 
 typedef struct _TTY_CONTEXT {
@@ -402,17 +402,23 @@ _tmain(
     UNREFERENCED_PARAMETER(argc);
     UNREFERENCED_PARAMETER(argv);
 
+    if (!WaitNamedPipe(PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT))
+        ExitProcess(1);
+
     Context->Device.Read = CreateFile(PIPE_NAME,
-                                      GENERIC_READ,
-                                      FILE_SHARE_WRITE,
-                                      NULL,
-                                      OPEN_EXISTING,
-                                      FILE_ATTRIBUTE_NORMAL,
-                                      NULL);
+                                        GENERIC_READ,
+                                        FILE_SHARE_WRITE,
+                                        NULL,
+                                        OPEN_EXISTING,
+                                        FILE_ATTRIBUTE_NORMAL,
+                                        NULL);
 
     if (Context->Device.Read == INVALID_HANDLE_VALUE)
         ExitProcess(1);
 
+    if (!WaitNamedPipe(PIPE_NAME, NMPWAIT_USE_DEFAULT_WAIT))
+        ExitProcess(1);
+
     Context->Device.Write = CreateFile(PIPE_NAME,
                                        GENERIC_WRITE,
                                        FILE_SHARE_READ | FILE_SHARE_WRITE,
diff --git a/src/xencons.inf b/src/xencons.inf
index 3cbdd96..37bc628 100644
--- a/src/xencons.inf
+++ b/src/xencons.inf
@@ -113,7 +113,7 @@ AddReg = Monitor_Parameters
 
 [Monitor_Parameters]
 HKR,"Parameters",,0x00000010
-HKR,"Parameters","Executable",0x00000000,"xencons_tty_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.exe"
+HKR,"Parameters\default","Executable",0x00000000,"xencons_tty_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.exe"
 
 [Monitor_EventLog]
 AddReg=Monitor_EventLog_AddReg
-- 
2.8.3


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.