VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/win/HostPowerWin.cpp@ 93115

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.2 KB
Line 
1/* $Id: HostPowerWin.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * VirtualBox interface to host's power notification service
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_MAIN_HOST
23#include <iprt/win/windows.h>
24/* Some SDK versions lack the extern "C" and thus cause linking failures.
25 * This workaround isn't pretty, but there are not many options. */
26extern "C" {
27#include <PowrProf.h>
28}
29
30#include <VBox/com/ptr.h>
31#include <iprt/errcore.h>
32#include "HostPower.h"
33#include "LoggingNew.h"
34
35
36/*********************************************************************************************************************************
37* Global Variables *
38*********************************************************************************************************************************/
39static WCHAR gachWindowClassName[] = L"VBoxPowerNotifyClass";
40
41
42HostPowerServiceWin::HostPowerServiceWin(VirtualBox *aVirtualBox) : HostPowerService(aVirtualBox), mThread(NIL_RTTHREAD)
43{
44 mHwnd = 0;
45
46 int rc = RTThreadCreate(&mThread, HostPowerServiceWin::NotificationThread, this, 65536,
47 RTTHREADTYPE_GUI, RTTHREADFLAGS_WAITABLE, "MainPower");
48
49 if (RT_FAILURE(rc))
50 {
51 Log(("HostPowerServiceWin::HostPowerServiceWin: RTThreadCreate failed with %Rrc\n", rc));
52 return;
53 }
54}
55
56HostPowerServiceWin::~HostPowerServiceWin()
57{
58 if (mHwnd)
59 {
60 Log(("HostPowerServiceWin::!HostPowerServiceWin: destroy window %x\n", mHwnd));
61
62 /* Poke the thread out of the event loop and wait for it to clean up. */
63 PostMessage(mHwnd, WM_CLOSE, 0, 0);
64 RTThreadWait(mThread, 5000, NULL);
65 mThread = NIL_RTTHREAD;
66 }
67}
68
69
70
71DECLCALLBACK(int) HostPowerServiceWin::NotificationThread(RTTHREAD hThreadSelf, void *pInstance)
72{
73 RT_NOREF(hThreadSelf);
74 HostPowerServiceWin *pPowerObj = (HostPowerServiceWin *)pInstance;
75 HWND hwnd = 0;
76
77 /* Create a window and make it a power event notification handler. */
78 int rc = VINF_SUCCESS;
79
80 HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
81
82 /* Register the Window Class. */
83 WNDCLASS wc;
84
85 wc.style = CS_NOCLOSE;
86 wc.lpfnWndProc = HostPowerServiceWin::WndProc;
87 wc.cbClsExtra = 0;
88 wc.cbWndExtra = sizeof(void *);
89 wc.hInstance = hInstance;
90 wc.hIcon = NULL;
91 wc.hCursor = NULL;
92 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
93 wc.lpszMenuName = NULL;
94 wc.lpszClassName = gachWindowClassName;
95
96 ATOM atomWindowClass = RegisterClass(&wc);
97
98 if (atomWindowClass == 0)
99 {
100 rc = VERR_NOT_SUPPORTED;
101 Log(("HostPowerServiceWin::NotificationThread: RegisterClassA failed with %x\n", GetLastError()));
102 }
103 else
104 {
105 /* Create the window. */
106 hwnd = pPowerObj->mHwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
107 gachWindowClassName, gachWindowClassName,
108 WS_POPUPWINDOW,
109 -200, -200, 100, 100, NULL, NULL, hInstance, NULL);
110
111 if (hwnd == NULL)
112 {
113 Log(("HostPowerServiceWin::NotificationThread: CreateWindowExA failed with %x\n", GetLastError()));
114 rc = VERR_NOT_SUPPORTED;
115 }
116 else
117 {
118 SetWindowLongPtr(hwnd, 0, (LONG_PTR)pPowerObj);
119 SetWindowPos(hwnd, HWND_TOPMOST, -200, -200, 0, 0,
120 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
121
122 MSG msg;
123 BOOL fRet;
124 while ((fRet = GetMessage(&msg, NULL, 0, 0)) > 0)
125 {
126 TranslateMessage(&msg);
127 DispatchMessage(&msg);
128 }
129 /*
130 * Window procedure can return error,
131 * but this is exceptional situation
132 * that should be identified in testing
133 */
134 Assert(fRet >= 0);
135 }
136 }
137
138 Log(("HostPowerServiceWin::NotificationThread: exit thread\n"));
139
140 if (atomWindowClass != 0)
141 {
142 UnregisterClass(gachWindowClassName, hInstance);
143 atomWindowClass = 0;
144 }
145
146 return 0;
147}
148
149LRESULT CALLBACK HostPowerServiceWin::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
150{
151 switch (msg)
152 {
153 case WM_POWERBROADCAST:
154 {
155 HostPowerServiceWin *pPowerObj;
156
157 pPowerObj = (HostPowerServiceWin *)GetWindowLongPtr(hwnd, 0);
158 if (pPowerObj)
159 {
160 switch(wParam)
161 {
162 case PBT_APMSUSPEND:
163 pPowerObj->notify(Reason_HostSuspend);
164 break;
165
166 case PBT_APMRESUMEAUTOMATIC:
167 pPowerObj->notify(Reason_HostResume);
168 break;
169
170 case PBT_APMPOWERSTATUSCHANGE:
171 {
172 SYSTEM_POWER_STATUS SystemPowerStatus;
173
174 Log(("PBT_APMPOWERSTATUSCHANGE\n"));
175 if (GetSystemPowerStatus(&SystemPowerStatus) == TRUE)
176 {
177 Log(("PBT_APMPOWERSTATUSCHANGE ACLineStatus=%d BatteryFlag=%d\n", SystemPowerStatus.ACLineStatus,
178 SystemPowerStatus.BatteryFlag));
179
180 if (SystemPowerStatus.ACLineStatus == 0) /* offline */
181 {
182 if (SystemPowerStatus.BatteryFlag == 2 /* low > 33% */)
183 {
184 LONG rc;
185 SYSTEM_BATTERY_STATE BatteryState;
186
187 rc = CallNtPowerInformation(SystemBatteryState, NULL, 0, (PVOID)&BatteryState,
188 sizeof(BatteryState));
189#ifdef LOG_ENABLED
190 if (rc == 0 /* STATUS_SUCCESS */)
191 Log(("CallNtPowerInformation claims %d seconds of power left\n",
192 BatteryState.EstimatedTime));
193#endif
194 if ( rc == 0 /* STATUS_SUCCESS */
195 && BatteryState.EstimatedTime < 60*5)
196 {
197 pPowerObj->notify(Reason_HostBatteryLow);
198 }
199 }
200 /* If the machine has less than 5% battery left (and is not connected
201 * to the AC), then we should save the state. */
202 else if (SystemPowerStatus.BatteryFlag == 4 /* critical battery status; less than 5% */)
203 {
204 pPowerObj->notify(Reason_HostBatteryLow);
205 }
206 }
207 }
208 break;
209 }
210 default:
211 return DefWindowProc(hwnd, msg, wParam, lParam);
212 }
213 }
214 return TRUE;
215 }
216
217 case WM_DESTROY:
218 {
219 /* moved here. it can't work across theads */
220 SetWindowLongPtr(hwnd, 0, 0);
221 PostQuitMessage(0);
222 return 0;
223 }
224
225 default:
226 return DefWindowProc(hwnd, msg, wParam, lParam);
227 }
228}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette