VirtualBox

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

Last change on this file was 98292, checked in by vboxsync, 16 months ago

Main/src-server: rc -> hrc/vrc. Enabled scm rc checks. bugref:10223

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

© 2023 Oracle
ContactPrivacy policyTerms of Use