]> xenbits.xensource.com Git - pvdrivers/win/xencons.git/commitdiff
Add a monitor service
authorPaul Durrant <paul.durrant@citrix.com>
Fri, 5 May 2017 14:45:06 +0000 (15:45 +0100)
committerPaul Durrant <paul.durrant@citrix.com>
Fri, 5 May 2017 15:09:32 +0000 (16:09 +0100)
This patch adds a basic service to monitor the xencons interface.

All it does is open the interface when it becomes available and close it
down when either the device is going away, or the service is being
stopped.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
src/coinst/coinst.c
src/monitor/messages.mc [new file with mode: 0644]
src/monitor/monitor.c [new file with mode: 0644]
src/monitor/xencons_monitor.rc [new file with mode: 0644]
src/xencons.inf
vs2015/package/package.vcxproj
vs2015/xencons.sln
vs2015/xencons_monitor/xencons_monitor.vcxproj [new file with mode: 0644]
vs2015/xencons_monitor/xencons_monitor.vcxproj.user [new file with mode: 0644]

index 26c07f48ad7b8b4d3414cdda26066da9a63e2909..1a2343b1e45253500791f73f747d3e57e4233457 100644 (file)
@@ -43,6 +43,8 @@ __user_code;
 
 #define MAXIMUM_BUFFER_SIZE 1024
 
+#define MONITOR_NAME    "XENCONS_MONITOR"
+
 static VOID
 #pragma prefast(suppress:6262) // Function uses '1036' bytes of stack: exceeds /analyze:stacksize'1024'
 __Log(
@@ -172,6 +174,79 @@ __FunctionName(
 #undef  _NAME
 }
 
+static BOOL
+MonitorDelete(
+    VOID
+    )
+{
+    SC_HANDLE           SCManager;
+    SC_HANDLE           Service;
+    BOOL                Success;
+    SERVICE_STATUS      Status;
+    HRESULT             Error;
+
+    Log("====>");
+
+    SCManager = OpenSCManager(NULL,
+                              NULL,
+                              SC_MANAGER_ALL_ACCESS);
+
+    if (SCManager == NULL)
+        goto fail1;
+
+    Service = OpenService(SCManager,
+                          MONITOR_NAME,
+                          SERVICE_ALL_ACCESS);
+
+    if (Service == NULL)
+        goto fail2;
+
+    Success = ControlService(Service,
+                             SERVICE_CONTROL_STOP,
+                             &Status);
+
+    if (!Success &&
+        GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
+        goto fail3;
+
+    Success = DeleteService(Service);
+
+    if (!Success)
+        goto fail4;
+
+    CloseServiceHandle(Service);
+    CloseServiceHandle(SCManager);
+
+    Log("<====");
+
+    return TRUE;
+
+fail4:
+    Log("fail4");
+
+fail3:
+    Log("fail3");
+
+    CloseServiceHandle(Service);
+
+fail2:
+    Log("fail2");
+
+    CloseServiceHandle(SCManager);
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return FALSE;
+}
+
 static HRESULT
 DifInstallPreProcess(
     IN  HDEVINFO                    DeviceInfoSet,
@@ -271,7 +346,11 @@ DifRemovePreProcess(
     UNREFERENCED_PARAMETER(DeviceInfoData);
     UNREFERENCED_PARAMETER(Context);
 
-    Log("<===>");
+    Log("====>");
+
+    (VOID) MonitorDelete();
+
+    Log("<====");
 
     return NO_ERROR;
 }
diff --git a/src/monitor/messages.mc b/src/monitor/messages.mc
new file mode 100644 (file)
index 0000000..9fff135
--- /dev/null
@@ -0,0 +1,54 @@
+; // Copyright (c) Citrix Systems Inc.
+; // All rights reserved.
+; //
+; // Redistribution and use in source and binary forms,
+; // with or without modification, are permitted provided
+; // that the following conditions are met:
+; //
+; // *   Redistributions of source code must retain the above
+; //     copyright notice, this list of conditions and the
+; //     following disclaimer.
+; // *   Redistributions in binary form must reproduce the above
+; //     copyright notice, this list of conditions and the
+; //     following disclaimer in the documentation and/or other
+; //     materials provided with the distribution.
+; //
+; // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+; // CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+; // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+; // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+; // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+; // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+; // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+; // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+; // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+; // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+; // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+; // SUCH DAMAGE.
+
+MessageIdTypedef=DWORD
+
+SeverityNames=(
+       Success=0x0:STATUS_SEVERITY_SUCCESS
+       Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
+       Warning=0x2:STATUS_SEVERITY_WARNING
+       Error=0x3:STATUS_SEVERITY_ERROR
+       )
+
+
+FacilityNames=(
+       System=0x0:FACILITY_SYSTEM
+       Runtime=0x2:FACILITY_RUNTIME
+       Stubs=0x3:FACILITY_STUBS
+       Io=0x4:FACILITY_IO_ERROR_CODE
+       )
+
+MessageId=0x1
+Severity=Informational
+Facility=System
+SymbolicName=MONITOR_LOG
+Language=English
+%1
+.
diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c
new file mode 100644 (file)
index 0000000..fabca77
--- /dev/null
@@ -0,0 +1,916 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source 1and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the23
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define INITGUID 1
+
+#include <windows.h>
+#include <tchar.h>
+#include <stdlib.h>
+#include <strsafe.h>
+#include <wtsapi32.h>
+#include <cfgmgr32.h>
+#include <dbt.h>
+#include <setupapi.h>
+#include <malloc.h>
+#include <assert.h>
+
+#include <xencons_device.h>
+#include <version.h>
+
+#include "messages.h"
+
+#define MONITOR_NAME        __MODULE__
+#define MONITOR_DISPLAYNAME MONITOR_NAME
+
+typedef struct _MONITOR_CONTEXT {
+    SERVICE_STATUS          Status;
+    SERVICE_STATUS_HANDLE   Service;
+    HKEY                    ParametersKey;
+    HANDLE                  EventLog;
+    HANDLE                  StopEvent;
+    HANDLE                  AddEvent;
+    HANDLE                  RemoveEvent;
+    HDEVNOTIFY              InterfaceNotification;
+    PTCHAR                  DevicePath;
+    HDEVNOTIFY              DeviceNotification;
+    HANDLE                  Device;
+} MONITOR_CONTEXT, *PMONITOR_CONTEXT;
+
+MONITOR_CONTEXT MonitorContext;
+
+#define MAXIMUM_BUFFER_SIZE 1024
+
+#define SERVICES_KEY "SYSTEM\\CurrentControlSet\\Services"
+
+#define SERVICE_KEY(_Service) \
+        SERVICES_KEY ## "\\" ## _Service
+
+#define PARAMETERS_KEY(_Service) \
+        SERVICE_KEY(_Service) ## "\\Parameters"
+
+static VOID
+#pragma prefast(suppress:6262) // Function uses '1036' bytes of stack: exceeds /analyze:stacksize'1024'
+__Log(
+    IN  const CHAR      *Format,
+    IN  ...
+    )
+{
+#if DBG
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+    const TCHAR         *Strings[1];
+#endif
+    TCHAR               Buffer[MAXIMUM_BUFFER_SIZE];
+    va_list             Arguments;
+    size_t              Length;
+    HRESULT             Result;
+
+    va_start(Arguments, Format);
+    Result = StringCchVPrintf(Buffer,
+                              MAXIMUM_BUFFER_SIZE,
+                              Format,
+                              Arguments);
+    va_end(Arguments);
+
+    if (Result != S_OK && Result != STRSAFE_E_INSUFFICIENT_BUFFER)
+        return;
+
+    Result = StringCchLength(Buffer, MAXIMUM_BUFFER_SIZE, &Length);
+    if (Result != S_OK)
+        return;
+
+    Length = __min(MAXIMUM_BUFFER_SIZE - 1, Length + 2);
+
+    __analysis_assume(Length < MAXIMUM_BUFFER_SIZE);
+    __analysis_assume(Length >= 2);
+    Buffer[Length] = '\0';
+    Buffer[Length - 1] = '\n';
+    Buffer[Length - 2] = '\r';
+
+    OutputDebugString(Buffer);
+
+#if DBG
+    Strings[0] = Buffer;
+
+    if (Context->EventLog != NULL)
+        ReportEvent(Context->EventLog,
+                    EVENTLOG_INFORMATION_TYPE,
+                    0,
+                    MONITOR_LOG,
+                    NULL,
+                    ARRAYSIZE(Strings),
+                    0,
+                    Strings,
+                    NULL);
+#endif
+}
+
+#define Log(_Format, ...) \
+    __Log(TEXT(__MODULE__ "|" __FUNCTION__ ": " _Format), __VA_ARGS__)
+
+static PTCHAR
+GetErrorMessage(
+    IN  HRESULT Error
+    )
+{
+    PTCHAR      Message;
+    ULONG       Index;
+
+    if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL,
+                       Error,
+                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                       (LPTSTR)&Message,
+                       0,
+                       NULL))
+        return NULL;
+
+    for (Index = 0; Message[Index] != '\0'; Index++) {
+        if (Message[Index] == '\r' || Message[Index] == '\n') {
+            Message[Index] = '\0';
+            break;
+        }
+    }
+
+    return Message;
+}
+
+static const CHAR *
+ServiceStateName(
+    IN  DWORD   State
+    )
+{
+#define _STATE_NAME(_State) \
+    case SERVICE_ ## _State: \
+        return #_State
+
+    switch (State) {
+    _STATE_NAME(START_PENDING);
+    _STATE_NAME(RUNNING);
+    _STATE_NAME(STOP_PENDING);
+    _STATE_NAME(STOPPED);
+    default:
+        break;
+    }
+
+    return "UNKNOWN";
+
+#undef  _STATE_NAME
+}
+
+static VOID
+ReportStatus(
+    IN  DWORD           CurrentState,
+    IN  DWORD           Win32ExitCode,
+    IN  DWORD           WaitHint)
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+    static DWORD        CheckPoint = 1;
+    BOOL                Success;
+    HRESULT             Error;
+
+    Log("====> (%s)", ServiceStateName(CurrentState));
+
+    Context->Status.dwCurrentState = CurrentState;
+    Context->Status.dwWin32ExitCode = Win32ExitCode;
+    Context->Status.dwWaitHint = WaitHint;
+
+    if (CurrentState == SERVICE_START_PENDING)
+        Context->Status.dwControlsAccepted = 0;
+    else
+        Context->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+                                             SERVICE_ACCEPT_SHUTDOWN |
+                                             SERVICE_ACCEPT_SESSIONCHANGE;
+
+    if (CurrentState == SERVICE_RUNNING ||
+        CurrentState == SERVICE_STOPPED )
+        Context->Status.dwCheckPoint = 0;
+    else
+        Context->Status.dwCheckPoint = CheckPoint++;
+
+    Success = SetServiceStatus(Context->Service, &Context->Status);
+
+    if (!Success)
+        goto fail1;
+
+    Log("<====");
+
+    return;
+
+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;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return FALSE;
+}
+
+static VOID
+PutString(
+    IN  HANDLE      Handle,
+    IN  PTCHAR      Buffer,
+    IN  DWORD       Length
+    )
+{
+    DWORD           Offset;
+
+    Offset = 0;
+    while (Offset < Length) {
+        DWORD   Written;
+        BOOL    Success;
+
+        Success = WriteFile(Handle,
+                            &Buffer[Offset],
+                            Length - Offset,
+                            &Written,
+                            NULL);
+        if (!Success)
+            break;
+
+        Offset += Written;
+    }
+}
+
+#define ECHO(_Handle, _Buffer) \
+    PutString((_Handle), TEXT(_Buffer), (DWORD)_tcslen(_Buffer))
+
+static VOID
+MonitorAdd(
+    VOID
+    )
+{
+    PMONITOR_CONTEXT        Context = &MonitorContext;
+    PTCHAR                  Path;
+    DEV_BROADCAST_HANDLE    Handle;
+    HRESULT                 Error;
+    BOOL                    Success;
+
+    if (Context->Device != INVALID_HANDLE_VALUE)
+        return;
+
+    Log("====>");
+
+    Success = MonitorGetPath(&GUID_XENCONS_DEVICE, &Path);
+
+    if (!Success)
+        goto fail1;
+
+    Context->Device = CreateFile(Path,
+                                 GENERIC_WRITE,
+                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_ATTRIBUTE_NORMAL,
+                                 NULL);
+
+    if (Context->Device == INVALID_HANDLE_VALUE)
+        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;
+
+    Log("<====");
+
+    return;
+
+fail3:
+    Log("fail3");
+
+    CloseHandle(Context->Device);
+    Context->Device = INVALID_HANDLE_VALUE;
+
+fail2:
+    Log("fail2");
+
+    free(Path);
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+}
+
+static VOID
+MonitorRemove(
+    VOID
+    )
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+
+    if (Context->Device == INVALID_HANDLE_VALUE)
+        return;
+
+    Log("====>");
+
+    free(Context->DevicePath);
+    Context->DevicePath = NULL;
+
+    UnregisterDeviceNotification(Context->DeviceNotification);
+    Context->DeviceNotification = NULL;
+
+    ECHO(Context->Device, "\r\n[DETACHED]\r\n");
+
+    CloseHandle(Context->Device);
+    Context->Device = INVALID_HANDLE_VALUE;
+
+    Log("<====");
+}
+
+DWORD WINAPI
+MonitorCtrlHandlerEx(
+    IN  DWORD           Ctrl,
+    IN  DWORD           EventType,
+    IN  LPVOID          EventData,
+    IN  LPVOID          Argument
+    )
+{
+    PMONITOR_CONTEXT    Context = &MonitorContext;
+
+    UNREFERENCED_PARAMETER(Argument);
+
+    switch (Ctrl) {
+    case SERVICE_CONTROL_STOP:
+    case SERVICE_CONTROL_SHUTDOWN:
+        ReportStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
+        SetEvent(Context->StopEvent);
+        return NO_ERROR;
+
+    case SERVICE_CONTROL_INTERROGATE:
+        ReportStatus(SERVICE_RUNNING, NO_ERROR, 0);
+        return NO_ERROR;
+
+    case SERVICE_CONTROL_DEVICEEVENT: {
+        PDEV_BROADCAST_HDR  Header = EventData;
+
+        switch (EventType) {
+        case DBT_DEVICEARRIVAL:
+            if (Header->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
+                PDEV_BROADCAST_DEVICEINTERFACE  Interface = EventData;
+
+                if (IsEqualGUID(&Interface->dbcc_classguid,
+                               &GUID_XENCONS_DEVICE))
+                    SetEvent(Context->AddEvent);
+            }
+            break;
+
+        case DBT_DEVICEQUERYREMOVE:
+            if (Header->dbch_devicetype == DBT_DEVTYP_HANDLE) {
+                PDEV_BROADCAST_HANDLE Device = EventData;
+
+                if (Device->dbch_handle == Context->Device)
+                    SetEvent(Context->RemoveEvent);
+            }
+            break;
+        }
+
+        return NO_ERROR;
+    }
+    default:
+        break;
+    }
+
+    ReportStatus(SERVICE_RUNNING, NO_ERROR, 0);
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+VOID WINAPI
+MonitorMain(
+    _In_    DWORD                   argc,
+    _In_    LPTSTR                  *argv
+    )
+{
+    PMONITOR_CONTEXT                Context = &MonitorContext;
+    DEV_BROADCAST_DEVICEINTERFACE   Interface;
+    HRESULT                         Error;
+
+    UNREFERENCED_PARAMETER(argc);
+    UNREFERENCED_PARAMETER(argv);
+
+    Log("====>");
+
+    Error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                         PARAMETERS_KEY(__MODULE__),
+                         0,
+                         KEY_READ,
+                         &Context->ParametersKey);
+    if (Error != ERROR_SUCCESS)
+        goto fail1;
+
+    Context->Service = RegisterServiceCtrlHandlerEx(MONITOR_NAME,
+                                                    MonitorCtrlHandlerEx,
+                                                    NULL);
+    if (Context->Service == NULL)
+        goto fail2;
+
+    Context->EventLog = RegisterEventSource(NULL,
+                                            MONITOR_NAME);
+    if (Context->EventLog == NULL)
+        goto fail3;
+
+    Context->Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+    Context->Status.dwServiceSpecificExitCode = 0;
+
+    ReportStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
+
+    Context->StopEvent = CreateEvent(NULL,
+                                     TRUE,
+                                     FALSE,
+                                     NULL);
+
+    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;
+
+    Context->Device = INVALID_HANDLE_VALUE;
+
+    ZeroMemory(&Interface, sizeof (Interface));
+    Interface.dbcc_size = sizeof (Interface);
+    Interface.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
+    Interface.dbcc_classguid = GUID_XENCONS_DEVICE;
+
+    Context->InterfaceNotification =
+        RegisterDeviceNotification(Context->Service,
+                                   &Interface,
+                                   DEVICE_NOTIFY_SERVICE_HANDLE);
+    if (Context->InterfaceNotification == NULL)
+        goto fail7;
+
+    // The device may already by present
+    SetEvent(Context->AddEvent);
+
+    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;
+
+        case WAIT_OBJECT_1:
+            ResetEvent(Context->AddEvent);
+            MonitorAdd();
+            break;
+
+        case WAIT_OBJECT_2:
+            ResetEvent(Context->RemoveEvent);
+            MonitorRemove();
+
+        default:
+            break;
+        }
+
+#undef WAIT_OBJECT_1
+#undef WAIT_OBJECT_2
+    }
+
+done:
+    MonitorRemove();
+
+    UnregisterDeviceNotification(Context->InterfaceNotification);
+
+    CloseHandle(Context->RemoveEvent);
+
+    CloseHandle(Context->AddEvent);
+
+    CloseHandle(Context->StopEvent);
+
+    ReportStatus(SERVICE_STOPPED, NO_ERROR, 0);
+
+    (VOID) DeregisterEventSource(Context->EventLog);
+
+    CloseHandle(Context->ParametersKey);
+
+    Log("<====");
+
+    return;
+
+fail7:
+    Log("fail7");
+
+    CloseHandle(Context->RemoveEvent);
+
+fail6:
+    Log("fail6");
+
+    CloseHandle(Context->AddEvent);
+
+fail5:
+    Log("fail5");
+
+    CloseHandle(Context->StopEvent);
+
+fail4:
+    Log("fail4");
+
+    ReportStatus(SERVICE_STOPPED, GetLastError(), 0);
+
+    (VOID) DeregisterEventSource(Context->EventLog);
+
+fail3:
+    Log("fail3");
+
+fail2:
+    Log("fail2");
+
+    CloseHandle(Context->ParametersKey);
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+}
+
+static BOOL
+MonitorCreate(
+    VOID
+    )
+{
+    SC_HANDLE   SCManager;
+    SC_HANDLE   Service;
+    TCHAR       Path[MAX_PATH];
+    HRESULT     Error;
+
+    Log("====>");
+
+    if(!GetModuleFileName(NULL, Path, MAX_PATH))
+        goto fail1;
+
+    SCManager = OpenSCManager(NULL,
+                              NULL,
+                              SC_MANAGER_ALL_ACCESS);
+
+    if (SCManager == NULL)
+        goto fail2;
+
+    Service = CreateService(SCManager,
+                            MONITOR_NAME,
+                            MONITOR_DISPLAYNAME,
+                            SERVICE_ALL_ACCESS,
+                            SERVICE_WIN32_OWN_PROCESS,
+                            SERVICE_AUTO_START,
+                            SERVICE_ERROR_NORMAL,
+                            Path,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL,
+                            NULL);
+
+    if (Service == NULL)
+        goto fail3;
+
+    CloseServiceHandle(Service);
+    CloseServiceHandle(SCManager);
+
+    Log("<====");
+
+    return TRUE;
+
+fail3:
+    Log("fail3");
+
+    CloseServiceHandle(SCManager);
+
+fail2:
+    Log("fail2");
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return FALSE;
+}
+
+static BOOL
+MonitorDelete(
+    VOID
+    )
+{
+    SC_HANDLE           SCManager;
+    SC_HANDLE           Service;
+    BOOL                Success;
+    SERVICE_STATUS      Status;
+    HRESULT             Error;
+
+    Log("====>");
+
+    SCManager = OpenSCManager(NULL,
+                              NULL,
+                              SC_MANAGER_ALL_ACCESS);
+
+    if (SCManager == NULL)
+        goto fail1;
+
+    Service = OpenService(SCManager,
+                          MONITOR_NAME,
+                          SERVICE_ALL_ACCESS);
+
+    if (Service == NULL)
+        goto fail2;
+
+    Success = ControlService(Service,
+                             SERVICE_CONTROL_STOP,
+                             &Status);
+
+    if (!Success)
+        goto fail3;
+
+    Success = DeleteService(Service);
+
+    if (!Success)
+        goto fail4;
+
+    CloseServiceHandle(Service);
+    CloseServiceHandle(SCManager);
+
+    Log("<====");
+
+    return TRUE;
+
+fail4:
+    Log("fail4");
+
+fail3:
+    Log("fail3");
+
+    CloseServiceHandle(Service);
+
+fail2:
+    Log("fail2");
+
+    CloseServiceHandle(SCManager);
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return FALSE;
+}
+
+static BOOL
+MonitorEntry(
+    VOID
+    )
+{
+    SERVICE_TABLE_ENTRY Table[] = {
+        { MONITOR_NAME, MonitorMain },
+        { NULL, NULL }
+    };
+    HRESULT             Error;
+
+    Log("%s (%s) ====>",
+        MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR,
+        DAY_STR "/" MONTH_STR "/" YEAR_STR);
+
+    if (!StartServiceCtrlDispatcher(Table))
+        goto fail1;
+
+    Log("%s (%s) <====",
+        MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR,
+        DAY_STR "/" MONTH_STR "/" YEAR_STR);
+
+    return TRUE;
+
+fail1:
+    Error = GetLastError();
+
+    {
+        PTCHAR  Message;
+        Message = GetErrorMessage(Error);
+        Log("fail1 (%s)", Message);
+        LocalFree(Message);
+    }
+
+    return FALSE;
+}
+
+int CALLBACK
+_tWinMain(
+    _In_        HINSTANCE   Current,
+    _In_opt_    HINSTANCE   Previous,
+    _In_        LPSTR       CmdLine,
+    _In_        int         CmdShow
+    )
+{
+    BOOL                    Success;
+
+    UNREFERENCED_PARAMETER(Current);
+    UNREFERENCED_PARAMETER(Previous);
+    UNREFERENCED_PARAMETER(CmdShow);
+
+    if (_tcslen(CmdLine) != 0) {
+         if (_tcsicmp(CmdLine, TEXT("create")) == 0)
+             Success = MonitorCreate();
+         else if (_tcsicmp(CmdLine, TEXT("delete")) == 0)
+             Success = MonitorDelete();
+         else
+             Success = FALSE;
+    } else
+        Success = MonitorEntry();
+
+    return Success ? 0 : 1;
+}
diff --git a/src/monitor/xencons_monitor.rc b/src/monitor/xencons_monitor.rc
new file mode 100644 (file)
index 0000000..bd3b141
--- /dev/null
@@ -0,0 +1,56 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <windows.h>
+#include <ntverp.h>
+
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+
+#include <version.h>
+
+#define VER_COMPANYNAME_STR         VENDOR_NAME_STR
+#define VER_LEGALCOPYRIGHT_STR      "Copyright (c) Citrix Systems Inc."
+
+#define VER_PRODUCTNAME_STR         "XENCONS"
+#define VER_PRODUCTVERSION          MAJOR_VERSION,MINOR_VERSION,MICRO_VERSION,BUILD_NUMBER
+#define VER_PRODUCTVERSION_STR      MAJOR_VERSION_STR "." MINOR_VERSION_STR "." MICRO_VERSION_STR "." BUILD_NUMBER_STR
+
+#define VER_INTERNALNAME_STR       "XENCONS_MONITOR.EXE"
+#define VER_FILEDESCRIPTION_STR     "XENCONS_MONITOR"
+
+#define VER_FILETYPE               VFT_APP
+#define VER_FILESUBTYPE                    VFT2_UNKNOWN
+
+#include "common.ver"
+#include "messages.rc"
index c64c667ffcd35e99ba18fced98e05e22c01403ca..dbff121149acba13286b3a1d46243272c6d81026 100644 (file)
@@ -41,6 +41,7 @@ DriverPackageDisplayName=%DiskDesc%
 [DestinationDirs]
 DefaultDestDir=12
 CoInst_CopyFiles=11
+Monitor_CopyFiles=11
 
 [SourceDisksNames]
 0=%DiskDesc%
@@ -48,10 +49,16 @@ CoInst_CopyFiles=11
 [SourceDisksFiles]
 xencons.sys=0,,
 xencons_coinst.dll=0,,
+xencons_monitor.exe=0,,
+xencons_monitor.dll=0,,
 
 [CoInst_CopyFiles]
 xencons_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,xencons_coinst.dll
 
+[Monitor_CopyFiles]
+xencons_monitor_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.exe,xencons_monitor.exe
+xencons_monitor_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll,xencons_monitor.dll
+
 [Manufacturer]
 %Vendor%=Inst,NT$ARCH$
 
@@ -59,35 +66,56 @@ xencons_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dl
 ; DisplayName          Section         DeviceID
 ; -----------          -------         --------
 
-%XenconsName%          =Xencons_Inst,  XENBUS\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_CONS&REV_09000000
-%XenconsName%          =Xencons_Inst,  XENBUS\VEN_@VENDOR_PREFIX@0001&DEV_CONS&REV_09000000
-%XenconsName%          =Xencons_Inst,  XENBUS\VEN_@VENDOR_PREFIX@0002&DEV_CONS&REV_09000000
+%XenConsName%          =XenCons_Inst,  XENBUS\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_CONS&REV_09000000
+%XenConsName%          =XenCons_Inst,  XENBUS\VEN_@VENDOR_PREFIX@0001&DEV_CONS&REV_09000000
+%XenConsName%          =XenCons_Inst,  XENBUS\VEN_@VENDOR_PREFIX@0002&DEV_CONS&REV_09000000
 
-[Xencons_Inst]
-CopyFiles=Xencons_Copyfiles
+[XenCons_Inst]
+CopyFiles=XenCons_Copyfiles
+CopyFiles=Monitor_Copyfiles
 
-[Xencons_Copyfiles]
+[XenCons_Copyfiles]
 xencons.sys
 
-[Xencons_Inst.Services]
-AddService=xencons,0x02,Xencons_Service,
+[XenCons_Inst.Services]
+AddService=xencons_monitor,%SPSVCSINST_STARTSERVICE%,Monitor_Service,Monitor_EventLog
+AddService=xencons,%SPSVCINST_ASSOCSERVICE%,XenCons_Service
 
-[Xencons_Service]
-DisplayName=%XenconsName%
+[XenCons_Service]
+DisplayName=%XenConsName%
 ServiceType=%SERVICE_KERNEL_DRIVER%
 StartType=%SERVICE_DEMAND_START%
 ErrorControl=%SERVICE_ERROR_NORMAL%
 ServiceBinary=%12%\xencons.sys
 LoadOrderGroup="Extended Base"
-AddReg = Xencons_BootFlags, Xencons_Parameters
+AddReg = XenCons_BootFlags, XenCons_Parameters
 
-[Xencons_BootFlags]
+[XenCons_BootFlags]
 HKR,,"BootFlags",0x00010003,0x81
 
-[Xencons_Parameters]
+[XenCons_Parameters]
+HKR,"Parameters",,0x00000010
+
+[Monitor_Service]
+DisplayName=%MonitorName%
+Description=%MonitorDesc%
+ServiceType=%SERVICE_WIN32_OWN_PROCESS%
+StartType=%SERVICE_AUTO_START%
+ErrorControl=%SERVICE_ERROR_NORMAL%
+ServiceBinary=%11%\xencons_monitor_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.exe
+AddReg = Monitor_Parameters
+
+[Monitor_Parameters]
 HKR,"Parameters",,0x00000010
 
-[Xencons_Inst.CoInstallers]
+[Monitor_EventLog]
+AddReg=Monitor_EventLog_AddReg
+
+[Monitor_EventLog_AddReg]
+HKR,,EventMessageFile,0x00020000,"%%SystemRoot%%\System32\xencons_monitor_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll"
+HKR,,TypesSupported,0x00010001,7
+
+[XenCons_Inst.CoInstallers]
 CopyFiles=CoInst_CopyFiles
 AddReg=CoInst_AddReg
 
@@ -98,7 +126,10 @@ HKR,,CoInstallers32,0x00010000,"xencons_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@
 
 Vendor="@VENDOR_NAME@"
 DiskDesc="@PRODUCT_NAME@ PV Console Package"
-XenconsName="@PRODUCT_NAME@ PV Console"
+XenConsName="@PRODUCT_NAME@ PV Console"
+MonitorName="@PRODUCT_NAME@ PV Console Monitor"
+MonitorDesc="Provides a monitor for the @PRODUCT_NAME@ PV Console"
+
 
 SERVICE_BOOT_START=0x0
 SERVICE_SYSTEM_START=0x1
@@ -106,8 +137,12 @@ SERVICE_AUTO_START=0x2
 SERVICE_DEMAND_START=0x3
 SERVICE_DISABLED=0x4
 
+SERVICE_WIN32_OWN_PROCESS=0x10
 SERVICE_KERNEL_DRIVER=0x1
 SERVICE_ERROR_IGNORE=0x0
 SERVICE_ERROR_NORMAL=0x1
 SERVICE_ERROR_SEVERE=0x2
 SERVICE_ERROR_CRITICAL=0x3
+
+SPSVCINST_ASSOCSERVICE=0x00000002
+SPSVCSINST_STARTSERVICE=0x00000800
index 53594067c67ee78ed670f1e2a90333809e6fe466..65f912554d1eef2155e7b7b327ee7a5f598c02a6 100644 (file)
@@ -39,6 +39,9 @@
     <ProjectReference Include="..\xencons_coinst\xencons_coinst.vcxproj">
       <Project>{6CC9B8DD-A5AE-427D-8157-E91D21DD7E19}</Project>
     </ProjectReference>
+    <ProjectReference Include="..\xencons_monitor\xencons_monitor.vcxproj">
+      <Project>{8991F0A5-408B-43E0-88CC-9550D4AAE616}</Project>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <FilesToPackage Include="$(DPINST_REDIST)\x86\dpinst.exe" Condition="'$(Platform)'=='Win32'" />
index 88baf2114f210c621d276289546519dfa3aaaf56..6801b45631acd8cbea9d444d48cc47159c6576fb 100644 (file)
@@ -6,10 +6,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencons", "xencons\xencons.
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencons_coinst", "xencons_coinst\xencons_coinst.vcxproj", "{6CC9B8DD-A5AE-427D-8157-E91D21DD7E19}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencons_monitor", "xencons_monitor\xencons_monitor.vcxproj", "{8991F0A5-408B-43E0-88CC-9550D4AAE616}"
+EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.vcxproj", "{8B5B8F4B-7FF3-4B64-AC4A-5246026217E7}"
        ProjectSection(ProjectDependencies) = postProject
                {4674B8C2-876B-4F2A-AB71-BAC968A9B529} = {4674B8C2-876B-4F2A-AB71-BAC968A9B529}
                {6CC9B8DD-A5AE-427D-8157-E91D21DD7E19} = {6CC9B8DD-A5AE-427D-8157-E91D21DD7E19}
+               {8991F0A5-408B-43E0-88CC-9550D4AAE616} = {8991F0A5-408B-43E0-88CC-9550D4AAE616}
        EndProjectSection
 EndProject
 Global
diff --git a/vs2015/xencons_monitor/xencons_monitor.vcxproj b/vs2015/xencons_monitor/xencons_monitor.vcxproj
new file mode 100644 (file)
index 0000000..05b5e45
--- /dev/null
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\configs.props" />
+  <PropertyGroup Label="PropertySheets">
+    <CharacterSet>MultiByte</CharacterSet>
+    <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+    <ConfigurationType>Application</ConfigurationType>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{8991F0A5-408B-43E0-88CC-9550D4AAE616}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="..\targets.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <PropertyGroup>
+    <IncludePath>$(IncludePath)</IncludePath>
+    <RunCodeAnalysis>true</RunCodeAnalysis>
+    <EnableInf2cat>false</EnableInf2cat>
+  </PropertyGroup>
+  <PropertyGroup>
+    <CustomBuildAfterTargets>Link</CustomBuildAfterTargets>
+  </PropertyGroup>
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <PreprocessorDefinitions>WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;__MODULE__="XENCONS_MONITOR";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <WarningLevel>EnableAllWarnings</WarningLevel>
+      <DisableSpecificWarnings>4127;4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <EnablePREfast>true</EnablePREfast>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='true'">MultiThreadedDebug</RuntimeLibrary>
+      <RuntimeLibrary Condition="'$(UseDebugLibraries)'=='false'">MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+    <Link>
+      <AdditionalDependencies>wtsapi32.lib;cfgmgr32.lib;setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+    <ResourceCompile>
+      <AdditionalIncludeDirectories>$(SolutionDir)..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+    </ResourceCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <CustomBuildStep>
+      <Outputs>$(TargetDir)$(TargetName).dll</Outputs>
+      <Inputs>$(IntDir)$(TargetName).res</Inputs>
+      <Command>link -machine:x86 -dll -noentry -out:%(Outputs) %(Inputs)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+    <CustomBuildStep>
+      <Outputs>$(TargetDir)$(TargetName).dll</Outputs>
+      <Inputs>$(IntDir)$(TargetName).res</Inputs>
+      <Command>link -machine:x64 -dll -noentry -out:%(Outputs) %(Inputs)</Command>
+    </CustomBuildStep>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <FilesToPackage Include="$(TargetPath)" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+    <FilesToPackage Include="$(OutDir)$(TargetName).dll" />
+    <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
+  </ItemGroup>
+  <ItemGroup>
+    <MessageCompile Include="..\..\src\monitor\messages.mc" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="..\..\src\monitor\monitor.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="..\..\src\monitor\xencons_monitor.rc" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/vs2015/xencons_monitor/xencons_monitor.vcxproj.user b/vs2015/xencons_monitor/xencons_monitor.vcxproj.user
new file mode 100644 (file)
index 0000000..a427c80
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <SignMode>TestSign</SignMode>
+    <TestCertificate>..\..\src\xencons.pfx</TestCertificate>
+    <TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+  </PropertyGroup>
+</Project>