* SUCH DAMAGE.
*/
+#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <powrprof.h>
#include "service.h"
#include "convdevice.h"
#include "devicelist.h"
+#include "messages.h"
+
+/* 317fc439-3f77-41c8-b09e-08ad63272aa3 */
+DEFINE_GUID(GUID_GPIOBUTTONS_LAPTOPSLATE_INTERFACE, \
+ 0x317fc439, 0x3f77, 0x41c8, 0xb0, 0x9e, 0x08, 0xad, 0x63, 0x27, 0x2a, 0xa3);
CConvDevice::CConvDevice(const wchar_t* path) : CDevice(path)
{
if (current_mode == new_mode)
break;
- Write(&buffer, sizeof(buffer));
+ if (Open()) {
+ Write(&buffer, sizeof(buffer));
+ Close();
+ }
+
Sleep(1000); // yield
}
}
fail1:
return false;
}
+
+CConvDeviceList::CConvDeviceList(CXenAgent* agent) : CDeviceList(GUID_GPIOBUTTONS_LAPTOPSLATE_INTERFACE), m_agent(agent)
+{}
+
+/*virtual*/ CConvDeviceList::~CConvDeviceList()
+{}
+
+/*virtual*/ CDevice* CConvDeviceList::Create(const wchar_t* path)
+{
+ return new CConvDevice(path);
+}
+
+/*virtual*/ void CConvDeviceList::OnDeviceAdded(CDevice* dev)
+{
+ UNREFERENCED_PARAMETER(dev);
+}
+
+/*virtual*/ void CConvDeviceList::OnDeviceRemoved(CDevice* dev)
+{
+ UNREFERENCED_PARAMETER(dev);
+}
+
+/*virtual*/ void CConvDeviceList::OnDeviceSuspend(CDevice* dev)
+{
+ UNREFERENCED_PARAMETER(dev);
+}
+
+/*virtual*/ void CConvDeviceList::OnDeviceResume(CDevice* dev)
+{
+ UNREFERENCED_PARAMETER(dev);
+}
+
+void CConvDeviceList::SetSlateMode(std::string& mode)
+{
+ CCritSec crit(&m_crit);
+ CConvDevice* device = (CConvDevice*)GetFirstDevice();
+
+ if (device == NULL)
+ return;
+
+ m_agent->EventLog(EVENT_XENUSER_MODE_SWITCH);
+
+ if (mode == "laptop")
+ device->SetMode(CCONV_DEVICE_LAPTOP_MODE);
+ else if (mode == "slate")
+ device->SetMode(CCONV_DEVICE_SLATE_MODE);
+}
bool GetMode(DWORD *mode);
};
+class CXenAgent;
+
+class CConvDeviceList : public CDeviceList
+{
+public:
+ CConvDeviceList(CXenAgent* agent);
+ virtual ~CConvDeviceList();
+
+protected: // CDeviceList
+ virtual CDevice* Create(const wchar_t* path);
+ virtual void OnDeviceAdded(CDevice* dev);
+ virtual void OnDeviceRemoved(CDevice* dev);
+ virtual void OnDeviceSuspend(CDevice* dev);
+ virtual void OnDeviceResume(CDevice* dev);
+
+public:
+ void SetSlateMode(std::string& mode);
+
+private:
+ CXenAgent* m_agent;
+};
+
#endif
OutputDebugStringW(buffer);
}
+CCritSec::CCritSec(LPCRITICAL_SECTION crit) : m_crit(crit)
+{
+ EnterCriticalSection(m_crit);
+}
+CCritSec::~CCritSec()
+{
+ LeaveCriticalSection(m_crit);
+}
+
CDevice::CDevice(const wchar_t* path) :
m_handle(INVALID_HANDLE_VALUE), m_path(path), m_notify(NULL)
{
return m_path.c_str();
}
+HDEVNOTIFY CDevice::Notify() const
+{
+ return m_notify;
+}
+
bool CDevice::Open()
{
Close();
m_handle = INVALID_HANDLE_VALUE;
}
-HDEVNOTIFY CDevice::Register(HANDLE svc)
+bool CDevice::Register(HANDLE svc)
{
Unregister();
devhdl.dbch_handle = m_handle;
m_notify = RegisterDeviceNotification(svc, &devhdl, DEVICE_NOTIFY_SERVICE_HANDLE);
- return m_notify;
+ return (m_notify != NULL);
}
void CDevice::Unregister()
}
CDeviceList::CDeviceList(const GUID& itf) :
- m_guid(itf), m_notify(NULL), m_handle(NULL), m_impl(NULL)
+ m_guid(itf), m_notify(NULL), m_handle(NULL)
{
+ InitializeCriticalSection(&m_crit);
}
CDeviceList::~CDeviceList()
{
- Stop();
+ UnregisterForDeviceChange();
+ CleanupDeviceList();
+
+ DeleteCriticalSection(&m_crit);
}
-#pragma warning(push)
-#pragma warning(disable:6102) // Using value from failed function call
+CDevice* CDeviceList::GetFirstDevice()
+{
+ DeviceMap::iterator it = m_devs.begin();
+ if (it == m_devs.end())
+ return NULL;
+ return *it;
+}
-bool CDeviceList::Start(HANDLE handle, IDeviceCreator* impl)
+bool CDeviceList::RegisterForDeviceChange(HANDLE handle)
{
- Stop();
+ UnregisterForDeviceChange();
m_handle = handle;
- m_impl = impl;
DEV_BROADCAST_DEVICEINTERFACE dev = { 0 };
dev.dbcc_size = sizeof(dev);
dev.dbcc_classguid = m_guid;
m_notify = RegisterDeviceNotificationA(handle, &dev, DEVICE_NOTIFY_SERVICE_HANDLE);
- if (m_notify == NULL)
- return false;
+ return m_notify != NULL;
+}
+
+void CDeviceList::UnregisterForDeviceChange()
+{
+ if (m_notify != NULL)
+ UnregisterDeviceNotification(m_notify);
+ m_notify = NULL;
+}
+#pragma warning(push)
+#pragma warning(disable:6102) // Using value from failed function call
+
+void CDeviceList::EnumerateDevices()
+{
HDEVINFO info;
SP_DEVICE_INTERFACE_DATA itf;
PSP_DEVICE_INTERFACE_DETAIL_DATA detail;
NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if (info == INVALID_HANDLE_VALUE)
- return true; // non fatal, just missing already present device(s)
+ return; // non fatal, just missing already present device(s)
itf.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for (idx = 0;
itf.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
}
SetupDiDestroyDeviceInfoList(info);
- return true;
}
#pragma warning(pop)
-void CDeviceList::Stop()
+void CDeviceList::CleanupDeviceList()
{
- if (m_notify != NULL)
- UnregisterDeviceNotification(m_notify);
- m_notify = NULL;
-
for (DeviceMap::iterator it = m_devs.begin();
it != m_devs.end();
++it) {
- if (m_impl)
- m_impl->OnDeviceRemoved(it->second);
- delete it->second;
+ OnDeviceRemoved(*it);
+ delete *it;
}
m_devs.clear();
}
for (DeviceMap::iterator it = m_devs.begin();
it != m_devs.end();
++it)
- m_impl->OnDeviceResume(it->second);
+ OnDeviceResume(*it);
break;
case PBT_APMSUSPEND:
for (DeviceMap::iterator it = m_devs.begin();
it != m_devs.end();
++it)
- m_impl->OnDeviceSuspend(it->second);
+ OnDeviceSuspend(*it);
break;
default:
}
}
-CDevice* CDeviceList::GetFirstDevice()
-{
- DeviceMap::iterator it = m_devs.begin();
- if (it == m_devs.end())
- return NULL;
- return it->second;
-}
-
void CDeviceList::DeviceArrival(const std::wstring& path)
{
DebugPrint(L"DeviceArrival(%ws)\n", path.c_str());
- CDevice* dev;
- if (m_impl)
- dev = m_impl->Create(path.c_str());
- else
- dev = new CDevice(path.c_str());
+ CDevice* dev = Create(path.c_str());
if (dev == NULL)
goto fail1;
+ if (m_handle == NULL)
+ goto done;
+
if (!dev->Open())
goto fail2;
- HDEVNOTIFY nfy = dev->Register(m_handle);
- if (nfy == NULL)
+ if (!dev->Register(m_handle))
goto fail3;
- m_devs[nfy] = dev;
-
- if (m_impl)
- m_impl->OnDeviceAdded(dev);
-
+done:
+ OnDeviceAdded(dev);
+ m_devs.push_back(dev);
return;
fail3:
void CDeviceList::DeviceRemoved(HDEVNOTIFY nfy)
{
- DeviceMap::iterator it = m_devs.find(nfy);
- if (it == m_devs.end())
- return; // spurious event?
+ for (DeviceMap::iterator it = m_devs.begin();
+ it != m_devs.end();
+ ++it) {
+ CDevice* dev = *it;
+
+ if (dev->Notify() != nfy)
+ continue;
- CDevice* dev = it->second;
- DebugPrint(L"DeviceRemoved(%ws)\n", dev->Path());
+ DebugPrint(L"DeviceRemoved(%ws)\n", dev->Path());
- delete dev; // handles unregister()
- m_devs.erase(it);
+ delete dev; // handles unregister()
+ m_devs.erase(it);
+ return;
+ }
+ // Spurious event?
}
void CDeviceList::DeviceRemovePending(HDEVNOTIFY nfy)
{
- DeviceMap::iterator it = m_devs.find(nfy);
- if (it == m_devs.end())
- return; // spurious event?
+ for (DeviceMap::iterator it = m_devs.begin();
+ it != m_devs.end();
+ ++it) {
+ CDevice* dev = *it;
- CDevice* dev = it->second;
- DebugPrint(L"DeviceRemovePending(%ws)\n", dev->Path());
+ if (dev->Notify() != nfy)
+ continue;
+
+ DebugPrint(L"DeviceRemovePending(%ws)\n", dev->Path());
- if (m_impl)
- m_impl->OnDeviceRemoved(dev);
+ OnDeviceRemoved(dev);
- dev->Close();
+ dev->Close();
+ return;
+ }
+ // Spurious event?
}
void CDeviceList::DeviceRemoveFailed(HDEVNOTIFY nfy)
{
- DeviceMap::iterator it = m_devs.find(nfy);
- if (it == m_devs.end())
- return; // spurious event?
+ for (DeviceMap::iterator it = m_devs.begin();
+ it != m_devs.end();
+ ++it) {
+ CDevice* dev = *it;
- CDevice* dev = it->second;
- DebugPrint(L"DeviceRemoveFailed(%ws)\n", dev->Path());
+ if (dev->Notify() != nfy)
+ continue;
- if (!dev->Open())
- DeviceRemoved(nfy);
+ DebugPrint(L"DeviceRemoveFailed(%ws)\n", dev->Path());
+
+ if (!dev->Open())
+ DeviceRemoved(nfy);
- if (m_impl)
- m_impl->OnDeviceAdded(dev);
+ OnDeviceAdded(dev);
+ return;
+ }
+ // Spurious event?
}
#include <windows.h>
#include <dbt.h>
-#include <map>
+#include <vector>
#include <string>
+class CCritSec
+{
+public:
+ CCritSec(LPCRITICAL_SECTION crit);
+ ~CCritSec();
+private:
+ LPCRITICAL_SECTION m_crit;
+};
+
class CDevice
{
public:
virtual ~CDevice();
const wchar_t* Path() const;
+ HDEVNOTIFY Notify() const;
bool Open();
void Close();
- HDEVNOTIFY Register(HANDLE svc);
+ bool Register(HANDLE svc);
void Unregister();
protected:
HDEVNOTIFY m_notify;
};
-class IDeviceCreator
+class CDeviceList
{
-public:
+protected:
+ CDeviceList(const GUID& itf);
+
virtual CDevice* Create(const wchar_t* path) = 0;
- virtual void OnDeviceAdded(CDevice* dev) = 0;
- virtual void OnDeviceRemoved(CDevice* dev) = 0;
- virtual void OnDeviceSuspend(CDevice* dev) = 0;
- virtual void OnDeviceResume(CDevice* dev) = 0;
-};
+ virtual void OnDeviceAdded(CDevice* dev) = 0;
+ virtual void OnDeviceRemoved(CDevice* dev) = 0;
+ virtual void OnDeviceSuspend(CDevice* dev) = 0;
+ virtual void OnDeviceResume(CDevice* dev) = 0;
+
+ CRITICAL_SECTION m_crit;
-class CDeviceList
-{
public:
- CDeviceList(const GUID& itf);
- ~CDeviceList();
+ virtual ~CDeviceList();
+
+ CDevice* GetFirstDevice();
+
+ bool RegisterForDeviceChange(HANDLE svc);
+ void UnregisterForDeviceChange();
+ void EnumerateDevices();
+ void CleanupDeviceList();
- bool Start(HANDLE svc, IDeviceCreator* impl);
- void Stop();
void OnDeviceEvent(DWORD evt, LPVOID data);
void OnPowerEvent(DWORD evt, LPVOID data);
- CDevice* GetFirstDevice();
private:
void DeviceArrival(const std::wstring& path);
void DeviceRemovePending(HDEVNOTIFY nfy);
void DeviceRemoveFailed(HDEVNOTIFY nfy);
- typedef std::map< HDEVNOTIFY, CDevice* > DeviceMap;
+ typedef std::vector< CDevice* > DeviceMap;
- GUID m_guid;
- DeviceMap m_devs;
- HDEVNOTIFY m_notify;
- HANDLE m_handle;
- IDeviceCreator* m_impl;
+ GUID m_guid;
+ DeviceMap m_devs;
+ HDEVNOTIFY m_notify;
+ HANDLE m_handle;
};
#endif
* SUCH DAMAGE.
*/
-#define INITGUID
#include <windows.h>
#include <stdio.h>
#include <powrprof.h>
#include <winuser.h>
-#include <xeniface_ioctls.h>
-
#include "service.h"
#include "messages.h"
-
-class CCritSec
-{
-public:
- CCritSec(LPCRITICAL_SECTION crit);
- ~CCritSec();
-private:
- LPCRITICAL_SECTION m_crit;
-};
-
-CCritSec::CCritSec(LPCRITICAL_SECTION crit) : m_crit(crit)
-{
- EnterCriticalSection(m_crit);
-}
-CCritSec::~CCritSec()
-{
- LeaveCriticalSection(m_crit);
-}
-
-CXenIfaceCreator::CXenIfaceCreator(CXenAgent& agent) :
- m_devlist(GUID_INTERFACE_XENIFACE), m_device(NULL),
- m_ctxt_shutdown(NULL), m_ctxt_suspend(NULL),
- m_ctxt_slate_mode(NULL), m_agent(agent)
-{
- m_evt_shutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
- m_evt_suspend = CreateEvent(NULL, TRUE, FALSE, NULL);
- m_evt_slate_mode = CreateEvent(NULL, TRUE, FALSE, NULL);
- m_count = 0;
-
- InitializeCriticalSection(&m_crit);
-}
-
-CXenIfaceCreator::~CXenIfaceCreator()
-{
- CloseHandle(m_evt_slate_mode);
- CloseHandle(m_evt_suspend);
- CloseHandle(m_evt_shutdown);
-
- DeleteCriticalSection(&m_crit);
-}
-
-bool CXenIfaceCreator::Start(HANDLE svc)
-{
- return m_devlist.Start(svc, this);
-}
-
-void CXenIfaceCreator::Stop()
-{
- // Check if registry key is present, implies Windows Update
- // require a reboot, which may spend time installing updates
- LogIfRebootPending();
-
- m_devlist.Stop();
-}
-
-void CXenIfaceCreator::OnDeviceEvent(DWORD evt, LPVOID data)
-{
- m_devlist.OnDeviceEvent(evt, data);
-}
-
-void CXenIfaceCreator::OnPowerEvent(DWORD evt, LPVOID data)
-{
- m_devlist.OnPowerEvent(evt, data);
-}
-
-void CXenIfaceCreator::Log(const char* message)
-{
- // if possible, send to xeniface to forward to logs
- if (m_device && TryEnterCriticalSection(&m_crit)) {
- m_device->Log(message);
- LeaveCriticalSection(&m_crit);
- }
-}
-
-/*virtual*/ CDevice* CXenIfaceCreator::Create(const wchar_t* path)
-{
- return new CXenIfaceDevice(path);
-}
-
-/*virtual*/ void CXenIfaceCreator::OnDeviceAdded(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceAdded(%ws)\n", dev->Path());
-
- CCritSec crit(&m_crit);
- if (m_device == NULL) {
- m_device = (CXenIfaceDevice*)dev;
-
- m_device->SuspendRegister(m_evt_suspend, &m_ctxt_suspend);
-
- StartShutdownWatch();
-
- if (m_agent.ConvDevicePresent())
- StartSlateModeWatch();
-
- SetXenTime();
- }
-}
-
-/*virtual*/ void CXenIfaceCreator::OnDeviceRemoved(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceRemoved(%ws)\n", dev->Path());
-
- CCritSec crit(&m_crit);
- if (m_device == dev) {
- if (m_ctxt_suspend) {
- m_device->SuspendDeregister(m_ctxt_suspend);
- m_ctxt_suspend = NULL;
- }
-
- if (m_agent.ConvDevicePresent())
- StopSlateModeWatch();
-
- StopShutdownWatch();
-
- m_device = NULL;
- }
-}
-
-/*virtual*/ void CXenIfaceCreator::OnDeviceSuspend(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceSuspend(%ws)\n", dev->Path());
-
- if (m_agent.ConvDevicePresent())
- StopSlateModeWatch();
-
- StopShutdownWatch();
-}
-
-/*virtual*/ void CXenIfaceCreator::OnDeviceResume(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceResume(%ws)\n", dev->Path());
-
- StartShutdownWatch();
-
- if (m_agent.ConvDevicePresent())
- StartSlateModeWatch();
-}
-
-bool CXenIfaceCreator::CheckShutdown()
-{
- CCritSec crit(&m_crit);
- if (m_device == NULL)
- return false;
-
- std::string type;
- if (!m_device->StoreRead("control/shutdown", type))
- return false;
-
- if (type != "")
- CXenAgent::Log("Shutdown(%ws) = '%s'\n", m_device->Path(), type.c_str());
-
- if (type == "poweroff") {
- m_device->StoreWrite("control/shutdown", "");
- m_agent.EventLog(EVENT_XENUSER_POWEROFF);
-
- AcquireShutdownPrivilege();
-#pragma warning(suppress:28159) /* Consider using a design alternative... Rearchitect to avoid Reboot */
- if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, FALSE,
- SHTDN_REASON_MAJOR_OTHER |
- SHTDN_REASON_MINOR_ENVIRONMENT |
- SHTDN_REASON_FLAG_PLANNED)) {
- CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", GetLastError());
- }
- return true;
- } else if (type == "reboot") {
- m_device->StoreWrite("control/shutdown", "");
- m_agent.EventLog(EVENT_XENUSER_REBOOT);
-
- AcquireShutdownPrivilege();
-#pragma warning(suppress:28159) /* Consider using a design alternative... Rearchitect to avoid Reboot */
- if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, TRUE,
- SHTDN_REASON_MAJOR_OTHER |
- SHTDN_REASON_MINOR_ENVIRONMENT |
- SHTDN_REASON_FLAG_PLANNED)) {
- CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", GetLastError());
- }
- return true;
- } else if (type == "s4") {
- m_device->StoreWrite("control/shutdown", "");
- m_agent.EventLog(EVENT_XENUSER_S4);
-
- AcquireShutdownPrivilege();
- if (!SetSystemPowerState(FALSE, FALSE)) {
- CXenAgent::Log("SetSystemPowerState failed %08x\n", GetLastError());
- }
- return false;
- } else if (type == "s3") {
- m_device->StoreWrite("control/shutdown", "");
- m_agent.EventLog(EVENT_XENUSER_S3);
-
- AcquireShutdownPrivilege();
- if (!SetSuspendState(FALSE, TRUE, FALSE)) {
- CXenAgent::Log("SetSuspendState failed %08x\n", GetLastError());
- }
- return false;
- }
-
- return false;
-}
-
-void CXenIfaceCreator::CheckXenTime()
-{
- CCritSec crit(&m_crit);
- if (m_device == NULL)
- return;
-
- SetXenTime();
-}
-
-void CXenIfaceCreator::CheckSuspend()
-{
- CCritSec crit(&m_crit);
- if (m_device == NULL)
- return;
-
- DWORD count = 0;
-
- if (!m_device->SuspendGetCount(&count))
- return;
-
- if (m_count == count)
- return;
-
- CXenAgent::Log("Suspend(%ws)\n", m_device->Path());
-
- m_agent.EventLog(EVENT_XENUSER_UNSUSPENDED);
-
- // recreate watches, as suspending deactivated the watch
- if (m_agent.ConvDevicePresent())
- StopSlateModeWatch();
-
- StopShutdownWatch();
-
- StartShutdownWatch();
-
- if (m_agent.ConvDevicePresent())
- StartSlateModeWatch();
-
- m_count = count;
-}
-
-bool CXenIfaceCreator::CheckSlateMode(std::string *mode)
-{
- CCritSec crit(&m_crit);
- if (m_device == NULL)
- return false;
-
- if (!m_device->StoreRead("control/laptop-slate-mode", *mode))
- return false;
-
- if (*mode != "")
- m_device->StoreWrite("control/laptop-slate-mode", "");
-
- return true;
-}
-
-void CXenIfaceCreator::LogIfRebootPending()
-{
- HKEY Key;
- LONG lResult;
-
- lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
- "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\RebootRequired",
- 0,
- KEY_READ,
- &Key);
- if (lResult != ERROR_SUCCESS)
- return; // key doesnt exist, dont log anything
-
- RegCloseKey(Key);
-
- CXenAgent::Log("RebootRequired detected\n");
-}
-
-void CXenIfaceCreator::StartShutdownWatch()
-{
- if (m_ctxt_shutdown)
- return;
-
- m_device->StoreAddWatch("control/shutdown", m_evt_shutdown, &m_ctxt_shutdown);
-
- m_device->StoreWrite("control/feature-poweroff", "1");
- m_device->StoreWrite("control/feature-reboot", "1");
- m_device->StoreWrite("control/feature-s3", "1");
- m_device->StoreWrite("control/feature-s4", "1");
-}
-
-void CXenIfaceCreator::StopShutdownWatch()
-{
- if (!m_ctxt_shutdown)
- return;
-
- m_device->StoreWrite("control/feature-poweroff", "");
- m_device->StoreWrite("control/feature-reboot", "");
- m_device->StoreWrite("control/feature-s3", "");
- m_device->StoreWrite("control/feature-s4", "");
-
- m_device->StoreRemoveWatch(m_ctxt_shutdown);
- m_ctxt_shutdown = NULL;
-}
-
-void CXenIfaceCreator::StartSlateModeWatch()
-{
- if (m_ctxt_slate_mode)
- return;
-
- m_device->StoreAddWatch("control/laptop-slate-mode", m_evt_slate_mode, &m_ctxt_slate_mode);
- m_device->StoreWrite("control/feature-laptop-slate-mode", "1");
-}
-
-void CXenIfaceCreator::StopSlateModeWatch()
-{
- if (!m_ctxt_slate_mode)
- return;
-
- m_device->StoreRemove("control/feature-laptop-slate-mode");
-
- m_device->StoreRemoveWatch(m_ctxt_slate_mode);
- m_ctxt_slate_mode = NULL;
-}
-
-void CXenIfaceCreator::AcquireShutdownPrivilege()
-{
- HANDLE token;
- TOKEN_PRIVILEGES tp;
-
- LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid);
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
-
- tp.PrivilegeCount = 1;
-
- if (!OpenProcessToken(GetCurrentProcess(),
- TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
- &token))
- return;
-
- AdjustTokenPrivileges(token, FALSE, &tp, NULL, 0, NULL);
- CloseHandle(token);
-}
-
-void CXenIfaceCreator::SetXenTime()
-{
- bool local;
-
- FILETIME now = { 0 };
- if (!m_device->SharedInfoGetTime(&now, &local))
- return;
-
- SYSTEMTIME cur = { 0 };
- if (local)
- GetLocalTime(&cur);
- else
- GetSystemTime(&cur);
-
- SYSTEMTIME sys = { 0 };
- if (!FileTimeToSystemTime(&now, &sys))
- return;
-
- if (memcmp(&cur, &sys, sizeof(SYSTEMTIME)) == 0)
- return;
-
- CXenAgent::Log("RTC is in %s\n", local ? "local time" : "UTC");
- CXenAgent::Log("Time Now = %d/%d/%d %d:%02d:%02d.%d\n",
- cur.wYear, cur.wMonth, cur.wDay,
- cur.wHour, cur.wMinute, cur.wSecond, cur.wMilliseconds);
- CXenAgent::Log("New Time = %d/%d/%d %d:%02d:%02d.%d\n",
- sys.wYear, sys.wMonth, sys.wDay,
- sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds);
-
- if (local)
- SetLocalTime(&sys);
- else
- SetSystemTime(&sys);
-}
-
-/* 317fc439-3f77-41c8-b09e-08ad63272aa3 */
-DEFINE_GUID(GUID_GPIOBUTTONS_LAPTOPSLATE_INTERFACE, \
- 0x317fc439, 0x3f77, 0x41c8, 0xb0, 0x9e, 0x08, 0xad, 0x63, 0x27, 0x2a, 0xa3);
-
-CConvCreator::CConvCreator(CXenAgent& agent) :
- m_devlist(GUID_GPIOBUTTONS_LAPTOPSLATE_INTERFACE), m_device(NULL),
- m_agent(agent)
-{
- InitializeCriticalSection(&m_crit);
-}
-
-CConvCreator::~CConvCreator()
-{
- DeleteCriticalSection(&m_crit);
-}
-
-bool CConvCreator::Start(HANDLE svc)
-{
- return m_devlist.Start(svc, this);
-}
-
-void CConvCreator::Stop()
-{
- m_devlist.Stop();
-}
-
-void CConvCreator::OnDeviceEvent(DWORD evt, LPVOID data)
-{
- m_devlist.OnDeviceEvent(evt, data);
-}
-
-void CConvCreator::OnPowerEvent(DWORD evt, LPVOID data)
-{
- m_devlist.OnPowerEvent(evt, data);
-}
-
-void CConvCreator::SetSlateMode(std::string mode)
-{
- CCritSec crit(&m_crit);
- if (m_device == NULL)
- return;
-
- m_agent.EventLog(EVENT_XENUSER_MODE_SWITCH);
-
- if (mode == "laptop")
- m_device->SetMode(CCONV_DEVICE_LAPTOP_MODE);
- else if (mode == "slate")
- m_device->SetMode(CCONV_DEVICE_SLATE_MODE);
-}
-
-bool CConvCreator::DevicePresent()
-{
- return m_device != NULL;
-}
-
-/*virtual*/ CDevice* CConvCreator::Create(const wchar_t* path)
-{
- return new CConvDevice(path);
-}
-
-/*virtual*/ void CConvCreator::OnDeviceAdded(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceAdded(%ws)\n", dev->Path());
-
- CCritSec crit(&m_crit);
- if (m_device == NULL)
- m_device = (CConvDevice*)dev;
-}
-
-/*virtual*/ void CConvCreator::OnDeviceRemoved(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceRemoved(%ws)\n", dev->Path());
-
- CCritSec crit(&m_crit);
- if (m_device == dev)
- m_device = NULL;
-}
-
-/*virtual*/ void CConvCreator::OnDeviceSuspend(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceSuspend(%ws)\n", dev->Path());
-}
-
-/*virtual*/ void CConvCreator::OnDeviceResume(CDevice* dev)
-{
- CXenAgent::Log("OnDeviceResume(%ws)\n", dev->Path());
-}
+#include "xeniface_ioctls.h"
static CXenAgent s_service;
#pragma warning(push)
#pragma warning(disable:4355)
-CXenAgent::CXenAgent() noexcept : m_handle(NULL), m_evtlog(NULL), m_xeniface(*this),
- m_conv(*this)
+CXenAgent::CXenAgent() noexcept : m_handle(NULL), m_evtlog(NULL),
+ m_xeniface(this), m_conv(this)
{
m_status.dwServiceType = SERVICE_WIN32;
m_status.dwCurrentState = SERVICE_START_PENDING;
void CXenAgent::OnServiceStart()
{
CXenAgent::Log("OnServiceStart()\n");
- m_conv.Start(m_handle);
- m_xeniface.Start(m_handle);
+ m_xeniface.RegisterForDeviceChange(m_handle);
+ m_xeniface.EnumerateDevices();
+ m_conv.EnumerateDevices();
}
void CXenAgent::OnServiceStop()
{
CXenAgent::Log("OnServiceStop()\n");
- m_xeniface.Stop();
- m_conv.Stop();
+ m_xeniface.LogIfRebootPending();
+ m_xeniface.UnregisterForDeviceChange();
+ m_xeniface.CleanupDeviceList();
+ m_conv.CleanupDeviceList();
}
void CXenAgent::OnDeviceEvent(DWORD evt, LPVOID data)
{
- m_conv.OnDeviceEvent(evt, data);
m_xeniface.OnDeviceEvent(evt, data);
}
std::string mode;
ResetEvent(m_xeniface.m_evt_slate_mode);
- if (m_xeniface.CheckSlateMode(&mode))
+ if (m_xeniface.CheckSlateMode(mode))
m_conv.SetSlateMode(mode);
return true; // continue loop
bool CXenAgent::ConvDevicePresent()
{
- return m_conv.DevicePresent();
+ return m_conv.GetFirstDevice() != NULL;
}
void CXenAgent::SetServiceStatus(DWORD state, DWORD exit /*= 0*/, DWORD hint /*= 0*/)
#include "xenifacedevice.h"
#include "convdevice.h"
-class CXenAgent;
-
-class CXenIfaceCreator : public IDeviceCreator
-{
-public:
- CXenIfaceCreator(CXenAgent&);
- virtual ~CXenIfaceCreator();
- CXenIfaceCreator& operator=(const CXenIfaceCreator&);
-
- bool Start(HANDLE svc);
- void Stop();
- void OnDeviceEvent(DWORD evt, LPVOID data);
- void OnPowerEvent(DWORD evt, LPVOID data);
- void Log(const char *message);
-
-public: // IDeviceCreator
- virtual CDevice* Create(const wchar_t* path);
- virtual void OnDeviceAdded(CDevice* dev);
- virtual void OnDeviceRemoved(CDevice* dev);
- virtual void OnDeviceSuspend(CDevice* dev);
- virtual void OnDeviceResume(CDevice* dev);
-
-public:
- bool CheckShutdown();
- void CheckXenTime();
- void CheckSuspend();
- bool CheckSlateMode(std::string *mode);
-
-public:
- HANDLE m_evt_shutdown;
- HANDLE m_evt_suspend;
- HANDLE m_evt_slate_mode;
-
-private:
- void LogIfRebootPending();
- void StartShutdownWatch();
- void StopShutdownWatch();
- void StartSlateModeWatch();
- void StopSlateModeWatch();
- void AcquireShutdownPrivilege();
- bool IsRTCInUTC();
- void SetXenTime();
-
-private:
- CXenAgent& m_agent;
- CDeviceList m_devlist;
- CXenIfaceDevice* m_device;
- CRITICAL_SECTION m_crit;
- void* m_ctxt_shutdown;
- void* m_ctxt_suspend;
- void* m_ctxt_slate_mode;
- DWORD m_count;
-};
-
-class CConvCreator : public IDeviceCreator
-{
-public:
- CConvCreator(CXenAgent&);
- virtual ~CConvCreator();
- CConvCreator& operator=(const CConvCreator&);
-
- bool Start(HANDLE svc);
- void Stop();
- void OnDeviceEvent(DWORD evt, LPVOID data);
- void OnPowerEvent(DWORD evt, LPVOID data);
- void SetSlateMode(std::string mode);
- bool DevicePresent();
-
-public:
- virtual CDevice* Create(const wchar_t* path);
- virtual void OnDeviceAdded(CDevice* dev);
- virtual void OnDeviceRemoved(CDevice* dev);
- virtual void OnDeviceSuspend(CDevice* dev);
- virtual void OnDeviceResume(CDevice* dev);
-
-private:
- CXenAgent& m_agent;
- CDeviceList m_devlist;
- CConvDevice* m_device;
- CRITICAL_SECTION m_crit;
-};
-
class CXenAgent
{
public: // statics
SERVICE_STATUS_HANDLE m_handle;
HANDLE m_evtlog;
HANDLE m_svc_stop;
- CXenIfaceCreator m_xeniface;
- CConvCreator m_conv;
+ CXenIfaceDeviceList m_xeniface;
+ CConvDeviceList m_conv;
};
#endif
* SUCH DAMAGE.
*/
+#define INITGUID
#include <windows.h>
#include <winioctl.h>
+#include <powrprof.h>
+#include "service.h"
#include "xenifacedevice.h"
#include "devicelist.h"
#include "xeniface_ioctls.h"
+#include "messages.h"
CXenIfaceDevice::CXenIfaceDevice(const wchar_t* path) : CDevice(path)
{}
(void*)msg.c_str(), (DWORD)msg.length() + 1,
NULL, 0);
}
+
+CXenIfaceDeviceList::CXenIfaceDeviceList(CXenAgent* agent) : CDeviceList(GUID_INTERFACE_XENIFACE),
+ m_agent(agent),
+ m_ctxt_suspend(NULL),
+ m_ctxt_shutdown(NULL),
+ m_ctxt_slate_mode(NULL)
+{
+ m_evt_shutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_evt_suspend = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_evt_slate_mode = CreateEvent(NULL, TRUE, FALSE, NULL);
+ m_count = 0;
+}
+
+/*virtual*/ CXenIfaceDeviceList::~CXenIfaceDeviceList()
+{
+ CloseHandle(m_evt_slate_mode);
+ CloseHandle(m_evt_suspend);
+ CloseHandle(m_evt_shutdown);
+}
+
+/*virtual*/ CDevice* CXenIfaceDeviceList::Create(const wchar_t* path)
+{
+ return new CXenIfaceDevice(path);
+}
+
+/*virtual*/ void CXenIfaceDeviceList::OnDeviceAdded(CDevice* dev)
+{
+ CCritSec crit(&m_crit);
+
+ if (GetFirstDevice() != NULL)
+ return;
+
+ CXenIfaceDevice* device = (CXenIfaceDevice*)dev;
+
+ device->SuspendRegister(m_evt_suspend, &m_ctxt_suspend);
+ StartShutdownWatch(device);
+
+ if (m_agent->ConvDevicePresent())
+ StartSlateModeWatch(device);
+
+ SetXenTime(device);
+}
+
+/*virtual*/ void CXenIfaceDeviceList::OnDeviceRemoved(CDevice* dev)
+{
+ CCritSec crit(&m_crit);
+ CXenIfaceDevice* device = (CXenIfaceDevice*)dev;
+
+ if (dev != GetFirstDevice())
+ return;
+
+ if (m_ctxt_suspend)
+ device->SuspendDeregister(m_ctxt_suspend);
+ m_ctxt_suspend = NULL;
+
+ if (m_agent->ConvDevicePresent())
+ StopSlateModeWatch(device);
+
+ StopShutdownWatch(device);
+}
+
+/*virtual*/ void CXenIfaceDeviceList::OnDeviceSuspend(CDevice* dev)
+{
+ CCritSec crit(&m_crit);
+ CXenIfaceDevice* device = (CXenIfaceDevice*)dev;
+
+ if (dev != GetFirstDevice())
+ return;
+
+ if (m_agent->ConvDevicePresent())
+ StopSlateModeWatch(device);
+
+ StopShutdownWatch(device);
+}
+
+/*virtual*/ void CXenIfaceDeviceList::OnDeviceResume(CDevice* dev)
+{
+ CCritSec crit(&m_crit);
+ CXenIfaceDevice* device = (CXenIfaceDevice*)dev;
+
+ if (dev != GetFirstDevice())
+ return;
+
+ StartShutdownWatch(device);
+
+ if (m_agent->ConvDevicePresent())
+ StartSlateModeWatch(device);
+}
+
+void CXenIfaceDeviceList::Log(const char* message)
+{
+ // if possible, send to xeniface to forward to logs
+ if (TryEnterCriticalSection(&m_crit)) {
+ CXenIfaceDevice* device = (CXenIfaceDevice*)GetFirstDevice();
+ if (device != NULL)
+ device->Log(message);
+ LeaveCriticalSection(&m_crit);
+ }
+}
+
+bool CXenIfaceDeviceList::CheckShutdown()
+{
+ CCritSec crit(&m_crit);
+ CXenIfaceDevice* device = (CXenIfaceDevice*)GetFirstDevice();
+
+ if (device == NULL)
+ return false;
+
+ std::string type;
+ if (!device->StoreRead("control/shutdown", type))
+ return false;
+
+ if (type != "")
+ CXenAgent::Log("Shutdown(%ws) = '%s'\n", device->Path(), type.c_str());
+
+ if (type == "poweroff") {
+ device->StoreWrite("control/shutdown", "");
+ m_agent->EventLog(EVENT_XENUSER_POWEROFF);
+
+ AcquireShutdownPrivilege();
+#pragma warning(suppress:28159) /* Consider using a design alternative... Rearchitect to avoid Reboot */
+ if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, FALSE,
+ SHTDN_REASON_MAJOR_OTHER |
+ SHTDN_REASON_MINOR_ENVIRONMENT |
+ SHTDN_REASON_FLAG_PLANNED)) {
+ CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", GetLastError());
+ }
+ return true;
+ } else if (type == "reboot") {
+ device->StoreWrite("control/shutdown", "");
+ m_agent->EventLog(EVENT_XENUSER_REBOOT);
+
+ AcquireShutdownPrivilege();
+#pragma warning(suppress:28159) /* Consider using a design alternative... Rearchitect to avoid Reboot */
+ if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, TRUE,
+ SHTDN_REASON_MAJOR_OTHER |
+ SHTDN_REASON_MINOR_ENVIRONMENT |
+ SHTDN_REASON_FLAG_PLANNED)) {
+ CXenAgent::Log("InitiateSystemShutdownEx failed %08x\n", GetLastError());
+ }
+ return true;
+ } else if (type == "s4") {
+ device->StoreWrite("control/shutdown", "");
+ m_agent->EventLog(EVENT_XENUSER_S4);
+
+ AcquireShutdownPrivilege();
+ if (!SetSystemPowerState(FALSE, FALSE)) {
+ CXenAgent::Log("SetSystemPowerState failed %08x\n", GetLastError());
+ }
+ return false;
+ } else if (type == "s3") {
+ device->StoreWrite("control/shutdown", "");
+ m_agent->EventLog(EVENT_XENUSER_S3);
+
+ AcquireShutdownPrivilege();
+ if (!SetSuspendState(FALSE, TRUE, FALSE)) {
+ CXenAgent::Log("SetSuspendState failed %08x\n", GetLastError());
+ }
+ return false;
+ }
+
+ return false;
+}
+
+void CXenIfaceDeviceList::CheckXenTime()
+{
+ CCritSec crit(&m_crit);
+ CXenIfaceDevice* device = (CXenIfaceDevice*)GetFirstDevice();
+
+ if (device == NULL)
+ return;
+
+ SetXenTime(device);
+}
+
+void CXenIfaceDeviceList::CheckSuspend()
+{
+ CCritSec crit(&m_crit);
+ CXenIfaceDevice* device = (CXenIfaceDevice*)GetFirstDevice();
+
+ if (device == NULL)
+ return;
+
+ DWORD count = 0;
+
+ if (!device->SuspendGetCount(&count))
+ return;
+
+ if (m_count == count)
+ return;
+
+ CXenAgent::Log("Suspend(%ws)\n", device->Path());
+
+ m_agent->EventLog(EVENT_XENUSER_UNSUSPENDED);
+
+ // recreate watches, as suspending deactivated the watch
+ if (m_agent->ConvDevicePresent())
+ StopSlateModeWatch(device);
+
+ StopShutdownWatch(device);
+
+ StartShutdownWatch(device);
+
+ if (m_agent->ConvDevicePresent())
+ StartSlateModeWatch(device);
+
+ m_count = count;
+}
+
+bool CXenIfaceDeviceList::CheckSlateMode(std::string& mode)
+{
+ CCritSec crit(&m_crit);
+ CXenIfaceDevice* device = (CXenIfaceDevice*)GetFirstDevice();
+
+ if (device == NULL)
+ return false;
+
+ if (!device->StoreRead("control/laptop-slate-mode", mode))
+ return false;
+
+ if (mode != "")
+ device->StoreWrite("control/laptop-slate-mode", "");
+
+ return true;
+}
+
+void CXenIfaceDeviceList::LogIfRebootPending()
+{
+ HKEY Key;
+ LONG lResult;
+
+ lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\Auto Update\\RebootRequired",
+ 0,
+ KEY_READ,
+ &Key);
+ if (lResult != ERROR_SUCCESS)
+ return; // key doesnt exist, dont log anything
+
+ RegCloseKey(Key);
+
+ CXenAgent::Log("RebootRequired detected\n");
+}
+
+void CXenIfaceDeviceList::StartShutdownWatch(CXenIfaceDevice* device)
+{
+ if (m_ctxt_shutdown)
+ return;
+
+ device->StoreAddWatch("control/shutdown", m_evt_shutdown, &m_ctxt_shutdown);
+
+ device->StoreWrite("control/feature-poweroff", "1");
+ device->StoreWrite("control/feature-reboot", "1");
+ device->StoreWrite("control/feature-s3", "1");
+ device->StoreWrite("control/feature-s4", "1");
+}
+
+void CXenIfaceDeviceList::StopShutdownWatch(CXenIfaceDevice* device)
+{
+ if (!m_ctxt_shutdown)
+ return;
+
+ device->StoreWrite("control/feature-poweroff", "");
+ device->StoreWrite("control/feature-reboot", "");
+ device->StoreWrite("control/feature-s3", "");
+ device->StoreWrite("control/feature-s4", "");
+
+ device->StoreRemoveWatch(m_ctxt_shutdown);
+ m_ctxt_shutdown = NULL;
+}
+
+void CXenIfaceDeviceList::StartSlateModeWatch(CXenIfaceDevice* device)
+{
+ if (m_ctxt_slate_mode)
+ return;
+
+ device->StoreAddWatch("control/laptop-slate-mode", m_evt_slate_mode, &m_ctxt_slate_mode);
+ device->StoreWrite("control/feature-laptop-slate-mode", "1");
+}
+
+void CXenIfaceDeviceList::StopSlateModeWatch(CXenIfaceDevice* device)
+{
+ if (!m_ctxt_slate_mode)
+ return;
+
+ device->StoreRemove("control/feature-laptop-slate-mode");
+
+ device->StoreRemoveWatch(m_ctxt_slate_mode);
+ m_ctxt_slate_mode = NULL;
+}
+
+void CXenIfaceDeviceList::AcquireShutdownPrivilege()
+{
+ HANDLE token;
+ TOKEN_PRIVILEGES tp;
+
+ LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tp.Privileges[0].Luid);
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ tp.PrivilegeCount = 1;
+
+ if (!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+ &token))
+ return;
+
+ AdjustTokenPrivileges(token, FALSE, &tp, NULL, 0, NULL);
+ CloseHandle(token);
+}
+
+void CXenIfaceDeviceList::SetXenTime(CXenIfaceDevice* device)
+{
+ bool local;
+
+ FILETIME now = { 0 };
+ if (!device->SharedInfoGetTime(&now, &local))
+ return;
+
+ SYSTEMTIME cur = { 0 };
+ if (local)
+ GetLocalTime(&cur);
+ else
+ GetSystemTime(&cur);
+
+ SYSTEMTIME sys = { 0 };
+ if (!FileTimeToSystemTime(&now, &sys))
+ return;
+
+ if (memcmp(&cur, &sys, sizeof(SYSTEMTIME)) == 0)
+ return;
+
+ CXenAgent::Log("RTC is in %s\n", local ? "local time" : "UTC");
+ CXenAgent::Log("Time Now = %d/%d/%d %d:%02d:%02d.%d\n",
+ cur.wYear, cur.wMonth, cur.wDay,
+ cur.wHour, cur.wMinute, cur.wSecond, cur.wMilliseconds);
+ CXenAgent::Log("New Time = %d/%d/%d %d:%02d:%02d.%d\n",
+ sys.wYear, sys.wMonth, sys.wDay,
+ sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds);
+
+ if (local)
+ SetLocalTime(&sys);
+ else
+ SetSystemTime(&sys);
+}
bool Log(const std::string& msg);
};
+class CXenAgent;
+
+class CXenIfaceDeviceList : public CDeviceList
+{
+public:
+ CXenIfaceDeviceList(CXenAgent* agent);
+ virtual ~CXenIfaceDeviceList();
+
+protected: // CDeviceList
+ virtual CDevice* Create(const wchar_t* path);
+ virtual void OnDeviceAdded(CDevice* dev);
+ virtual void OnDeviceRemoved(CDevice* dev);
+ virtual void OnDeviceSuspend(CDevice* dev);
+ virtual void OnDeviceResume(CDevice* dev);
+
+public:
+ HANDLE m_evt_shutdown;
+ HANDLE m_evt_suspend;
+ HANDLE m_evt_slate_mode;
+
+ void Log(const char* message);
+ bool CheckShutdown();
+ void CheckXenTime();
+ void CheckSuspend();
+ bool CheckSlateMode(std::string& mode);
+
+private:
+ void LogIfRebootPending();
+ void StartShutdownWatch(CXenIfaceDevice* device);
+ void StopShutdownWatch(CXenIfaceDevice* device);
+ void StartSlateModeWatch(CXenIfaceDevice* device);
+ void StopSlateModeWatch(CXenIfaceDevice* device);
+ void AcquireShutdownPrivilege();
+ void SetXenTime(CXenIfaceDevice* device);
+
+private:
+ CXenAgent* m_agent;
+ DWORD m_count;
+ void* m_ctxt_suspend;
+ void* m_ctxt_shutdown;
+ void* m_ctxt_slate_mode;
+};
+
#endif