![]() |
BatteryMonitor
|
00001 00008 #include "main.h" 00009 00010 using namespace BatteryMonitor; 00011 00014 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 00015 LPSTR lpCmdLine, int nCmdShow) { 00016 00017 // Do some initialization. 00018 strcpy(classname, "BatMonOverlay"); 00019 instance=hInstance; 00020 red = CreateSolidBrush(RGB(0xFF, 0, 0)); 00021 green = CreateSolidBrush(RGB(0, 0xFF, 0)); 00022 yellow = CreateSolidBrush(RGB(0xFF, 0xFF, 0)); 00023 blue = CreateSolidBrush(RGB(0, 0, 0xDF)); 00024 00025 // Register window class. 00026 if (!setupWindowClass()) { 00027 errOut(); 00028 return 0; 00029 } 00030 00031 // Show window. 00032 HWND hwnd=setupWindow(nCmdShow); 00033 if (hwnd == NULL) { 00034 00035 errOut(); 00036 return 0; 00037 } 00038 00039 /* Battery initialization. 00040 * 00041 * - Sets up battery device path name 00042 * - Commits initial update to window 00043 * - Starts timer for periodic updates (500 ms) 00044 */ 00045 initDevice(); 00046 SetTimer(hwnd, UPDATE_BATTERY, 500, NULL); 00047 SendMessage(hwnd, WM_TIMER, UPDATE_BATTERY, 0); 00048 00049 // Taskbar icon 00050 addNotifyIcon(hwnd); 00051 WM_TASKBARCREATED = RegisterWindowMessage(TEXT("TaskbarCreated")); 00052 00053 // Message loop 00054 MSG Msg; 00055 while (GetMessage(&Msg, NULL, 0, 0) > 0) { 00056 TranslateMessage(&Msg); 00057 DispatchMessage(&Msg); 00058 } 00059 00060 // Finish 00061 cleanUp(hwnd); 00062 return Msg.wParam; 00063 } 00064 00065 namespace BatteryMonitor { 00066 HWND setupWindow(int nCmdShow){ 00067 RECT desktop; 00068 GetWindowRect(GetDesktopWindow(), &desktop); 00069 HWND hwnd; 00070 /* Window creation. 00071 * 00072 * - Position: upper right 00073 * - No titlebar, no taskbar button 00074 * - Transparent (Opacity 120/255) 00075 * - Stay on top 00076 * - Click through (WS_EX_TRANSPARENT!) 00077 */ 00078 hwnd = CreateWindowEx( 00079 WS_EX_TOOLWINDOW | WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TRANSPARENT, 00080 classname, 00081 "Battery Monitor", 00082 WS_POPUP | WS_BORDER, 00083 desktop.right - 90, 20, 70, 30, 00084 NULL, NULL, instance, NULL); 00085 if(!hwnd)return 0; 00086 SetLayeredWindowAttributes(hwnd, 0, 120, LWA_ALPHA); 00087 ShowWindow(hwnd, nCmdShow); 00088 UpdateWindow(hwnd); 00089 return hwnd; 00090 } 00091 00092 void cleanUp(HWND hwnd) { 00093 // Delete icon and brushes. 00094 NOTIFYICONDATA nfi; 00095 nfi.cbSize = sizeof (nfi); 00096 nfi.hWnd = hwnd; 00097 nfi.uID = 0; 00098 Shell_NotifyIcon(NIM_DELETE, &nfi); 00099 DeleteObject(red); 00100 DeleteObject(yellow); 00101 DeleteObject(blue); 00102 DeleteObject(green); 00103 } 00104 00105 long setupWindowClass() { 00106 WNDCLASSEX wc; 00107 wc.cbSize = sizeof (WNDCLASSEX); 00108 wc.style = 0; 00109 wc.lpfnWndProc = wndProc; 00110 wc.cbClsExtra = 0; 00111 wc.cbWndExtra = 0; 00112 wc.hInstance = instance; 00113 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); 00114 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 00115 wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255)); 00116 wc.lpszMenuName = NULL; 00117 wc.lpszClassName = classname; 00118 wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); 00119 00120 return RegisterClassEx(&wc); 00121 } 00122 00123 void errOut() { 00124 char* buf = new char[255]; 00125 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, buf, 255, NULL); 00126 #ifdef DEBUG 00127 MessageBox(NULL, buf, "Error", 00128 MB_ICONEXCLAMATION | MB_OK); 00129 #endif 00130 delete[] buf; 00131 } 00132 00133 LRESULT CALLBACK wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { 00134 switch (msg) { 00135 case WM_CLOSE: 00136 DestroyWindow(hwnd); 00137 break; 00138 case WM_DESTROY: 00139 PostQuitMessage(0); 00140 break; 00141 case WM_TIMER: // This message is received periodically to update the battery 00142 if (wParam == UPDATE_BATTERY) { 00143 SYSTEM_POWER_STATUS pwr; 00144 GetSystemPowerStatus(&pwr); 00145 if (pwr.BatteryFlag == 128 || pwr.BatteryFlag == 255) { // Unknown state or Error 00146 battery = 2; 00147 } else if (pwr.ACLineStatus) { 00148 battery = -(double) pwr.BatteryLifePercent / 100.0; 00149 if(shutdown_enabled) { 00150 AbortSystemShutdown(NULL); 00151 shutdown_enabled=false; 00152 } 00153 } 00154 else { 00155 battery = (double) pwr.BatteryLifePercent / 100.0; 00156 batterylifetime = pwr.BatteryLifeTime; 00157 if (batterylifetime > 0 && batterylifetime < 300)shutdown(); // Shutdown if battery low 00158 } 00159 } 00160 InvalidateRect(hwnd, NULL, true); // Force repaint 00161 break; 00162 case WM_PAINT: // Paint window 00163 { 00164 PAINTSTRUCT p; 00165 HDC hdc = BeginPaint(hwnd, &p); 00166 if (hdc) { 00167 RECT r1,rtext; 00168 HBRUSH load; 00169 if (battery > 1.5) { // Yellow if no information available 00170 load = yellow; 00171 r1.top = 0; 00172 r1.left = 0; 00173 r1.right = 70; 00174 r1.bottom = 30; 00175 } else { // Green if dischargin, blue if charging 00176 load = battery > 0 ? green : blue; 00177 00178 r1.top = 0; 00179 r1.left = 0; 00180 r1.right = 70 * battery * (battery > 0 ? 1 : -1); 00181 r1.bottom = 30; 00182 00183 RECT r2; 00184 r2.top = 0; 00185 r2.left = r1.right; 00186 r2.right = 70; 00187 r2.bottom = 30; 00188 FillRect(hdc, &r2, red); 00189 00190 } 00191 FillRect(hdc, &r1, load); 00192 SetBkMode(hdc, TRANSPARENT); // Text background transparent 00193 SetTextColor(hdc, 0); 00194 // Used to center text 00195 rtext.bottom = 30; 00196 rtext.top = 0; 00197 rtext.left = 0; 00198 rtext.right = 70; 00199 char time[6]; 00200 batterylifetime /= 60; 00201 sprintf(time, "%02ld:%02ld", batterylifetime / 60, batterylifetime % 60); 00202 if (batterylifetime >= 0) 00203 DrawText(hdc, time, 5, &rtext, DT_CENTER | DT_VCENTER | DT_SINGLELINE); 00204 else 00205 DrawText(hdc, "N/A", 3, &rtext, DT_CENTER | DT_VCENTER | DT_SINGLELINE); 00206 00207 } 00208 EndPaint(hwnd, &p); 00209 } 00210 break; 00211 case WM_USER + 1: // Taskbar icon event. Now lParam contains the important window message. 00212 if (wParam != 0)break; 00213 switch (lParam) { 00214 case WM_RBUTTONDBLCLK: 00215 PostMessage(hwnd, WM_CLOSE, 0, 0); 00216 break; 00217 case WM_LBUTTONUP: 00218 showBatteryInfo(hwnd); 00219 break; 00220 default: 00221 break; 00222 } 00223 break; 00224 default: // Refresh icon if taskbar was newly created. This can't be handled in a case as WM_TASKBARCREATED is not constant. 00225 if (msg == WM_TASKBARCREATED) { 00226 addNotifyIcon(hwnd); 00227 break; 00228 } 00229 return DefWindowProc(hwnd, msg, wParam, lParam); // Do default message handling 00230 } 00231 return 0; 00232 } 00233 00234 void addNotifyIcon(HWND hwnd) { 00235 NOTIFYICONDATA nfi; 00236 HICON icon; 00237 if (!(icon = LoadIcon(instance, MAKEINTRESOURCE(MAIN_ICON)))) {errOut(); PostMessage(hwnd, WM_CLOSE, 0, 0);} // If icon can't be found, close application. 00238 nfi.cbSize = sizeof (nfi); 00239 nfi.hWnd = hwnd; 00240 nfi.hIcon = icon; 00241 nfi.uID = 0; 00242 strcpy(nfi.szTip, "BatteryMonitor"); 00243 nfi.uFlags = NIF_ICON | NIF_TIP | 0x80 | NIF_MESSAGE; 00244 nfi.uCallbackMessage = WM_USER + 1; 00245 00246 Shell_NotifyIcon(NIM_ADD, &nfi); 00247 } 00248 00249 void showBatteryInfo(HWND hwnd) { 00250 NOTIFYICONDATA nfi; 00251 nfi.cbSize = sizeof (nfi); 00252 nfi.hWnd = hwnd; 00253 nfi.uID = 0; 00254 nfi.uFlags = NIF_INFO; 00255 strcpy(nfi.szInfoTitle, "Battery Info"); 00256 nfi.uTimeout = 30000; 00257 nfi.dwInfoFlags = NIIF_INFO; 00258 BATTERY_INFORMATION info = getBatteryInformation(); 00259 SYSTEM_POWER_STATUS pwr; 00260 GetSystemPowerStatus(&pwr); 00261 if (info.DesignedCapacity) { 00262 char chem[5]; 00263 memcpy(chem, info.Chemistry, 4); 00264 chem[4] = 0; 00265 sprintf(nfi.szInfo, "Type: %s\nAC: %s\nCharge: %d%%\nWear Level: %lu%%", chem, pwr.ACLineStatus ? "Online" : "Offline", pwr.BatteryLifePercent, 100 - info.FullChargedCapacity * 100 / info.DesignedCapacity); 00266 } else { 00267 strcpy(nfi.szInfo, "No information available :("); 00268 } 00269 00270 Shell_NotifyIcon(NIM_MODIFY, &nfi); 00271 } 00272 00273 void shutdown() { 00274 HANDLE hToken; 00275 TOKEN_PRIVILEGES tkp; 00276 00277 // Get a token for this process. 00278 00279 if (!OpenProcessToken(GetCurrentProcess(), 00280 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 00281 MessageBox(0, "Low Battery! Shutdown failed.", "Error", MB_ICONERROR); 00282 00283 // Get the LUID for the shutdown privilege. 00284 00285 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); 00286 00287 tkp.PrivilegeCount = 1; 00288 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 00289 00290 // Get the shutdown privilege. 00291 00292 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); 00293 00294 if (GetLastError() != ERROR_SUCCESS) 00295 return; 00296 // Shutdown. 00297 InitiateSystemShutdown(NULL, "Low battery", 30, FALSE, FALSE); 00298 shutdown_enabled=true; 00299 } 00300 00301 void initDevice() { 00302 devicepath = 0; // If something fails, devicepath will be NULL 00303 HDEVINFO devinfo = SetupDiGetClassDevs(&GUID_DEVICE_BATTERY, NULL, NULL, DIGCF_DEVICEINTERFACE); // Get battery device information 00304 if (INVALID_HANDLE_VALUE != devinfo) { 00305 SP_DEVICE_INTERFACE_DATA deviceinfo; 00306 deviceinfo.cbSize = sizeof (deviceinfo); 00307 if (SetupDiEnumDeviceInterfaces(devinfo, 0, &GUID_DEVICE_BATTERY, 0, &deviceinfo)) { // Get device interface 00308 PSP_DEVICE_INTERFACE_DETAIL_DATA devdetails; 00309 DWORD reqSize = 0; 00310 SetupDiGetDeviceInterfaceDetail(devinfo, &deviceinfo, 0, 0, &reqSize, 0); // Get required size for details 00311 if (ERROR_INSUFFICIENT_BUFFER == GetLastError()) { 00312 devdetails = (PSP_DEVICE_INTERFACE_DETAIL_DATA) LocalAlloc(LPTR, reqSize); // Allocate 00313 if (devdetails) { 00314 devdetails->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA); 00315 if (SetupDiGetDeviceInterfaceDetail(devinfo, &deviceinfo, devdetails, reqSize, &reqSize, NULL)) { // Get some details on battery device 00316 devicepath = new char[strlen(devdetails->DevicePath)]; // There it is, the device path! 00317 strcpy(devicepath, devdetails->DevicePath); 00318 00319 } 00320 LocalFree(devdetails); // Free allocated memory 00321 } 00322 } 00323 } 00324 } 00325 if (GetLastError() != ERROR_SUCCESS)errOut(); 00326 } 00327 00328 BATTERY_INFORMATION getBatteryInformation() { 00329 BATTERY_INFORMATION batteryinformation; 00330 if (devicepath) { 00331 HANDLE bat = CreateFile(devicepath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // Open battery device file 00332 if (INVALID_HANDLE_VALUE != bat) { 00333 ULONG timeout = 100; 00334 ULONG tag; 00335 DWORD buf; 00336 if (DeviceIoControl(bat, IOCTL_BATTERY_QUERY_TAG, &timeout, sizeof (timeout), &tag, sizeof (tag), &buf, NULL)) { // Get the battery tag. 00337 BATTERY_QUERY_INFORMATION infoqueryin; 00338 infoqueryin.BatteryTag = tag; 00339 infoqueryin.InformationLevel = BatteryInformation; 00340 if (DeviceIoControl(bat, IOCTL_BATTERY_QUERY_INFORMATION, &infoqueryin, sizeof (infoqueryin), &batteryinformation, sizeof (batteryinformation), &buf, NULL)) { // Retrieve the wanted information. 00341 CloseHandle(bat); // Close battery file handle. 00342 return batteryinformation; 00343 } 00344 } 00345 } 00346 CloseHandle(bat); // If something fails close it, too. 00347 } 00348 errOut(); 00349 batteryinformation.DesignedCapacity = 0; // Error occured 00350 return batteryinformation; 00351 } 00352 00353 }