|
|
/*
TZTool - Thermal Zone Information Tool tztool.c This the MAIN TZTool - C file.
Copyright (c) 1999 Microsoft Corporation
Module Name:
TZTool - TZTool.c
Abstract:
TZTool - Thermal Zone Information Tool
Author:
Vincent Geglia (VincentG)
Notes:
Revision History:
1.2 - (VincentG) Port to Win64
1.1 - (JVert) add Kelvin to Farenheit conversion. Add throttling gauge.
1.0 - Original version
*/
// Includes
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <ole2.h>
#include <stdio.h>
#include <stdlib.h>
#include <ntpoapi.h>
#include <commctrl.h>
#include "resource.h"
#include "wmium.h"
// Definitions
#define THERMAL_ZONE_GUID {0xa1bc18c0, 0xa7c8, 0x11d1, {0xbf, 0x3c, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10} }
#define COOLING_PASSIVE 0
#define COOLING_ACTIVE 1
#define COOLING_UPDATE_TZONE 2
#define TIMER_ID 1
#define TIMER_POLL_INTERVAL 500
#define MAX_ACTIVE_COOLING_LEVELS 10
#define MAX_THERMAL_ZONES 10
#define K_TO_F(_deg_) (((_deg_) - 2731) * 9 / 5 + 320)
GUID ThermalZoneGuid = THERMAL_ZONE_GUID;
// Structures
typedef struct _THERMAL_INFORMATION { ULONG ThermalStamp; ULONG ThermalConstant1; ULONG ThermalConstant2; KAFFINITY Processors; ULONG SamplingPeriod; ULONG CurrentTemperature; ULONG PassiveTripPoint; ULONG CriticalTripPoint; UCHAR ActiveTripPointCount; ULONG ActiveTripPoint[MAX_ACTIVE_COOLING_LEVELS]; } THERMAL_INFORMATION, *PTHERMAL_INFORMATION;
typedef struct _TZONE_INFO {
THERMAL_INFORMATION ThermalInfo; ULONG64 TimeStamp; ULONG TZoneIndex; UCHAR TZoneName[100]; } TZONE_INFO, *PTZONE_INFO;
// Global variables
PTZONE_INFO g_TZonePtr = 0; WMIHANDLE g_WmiHandle; INT g_PollTz = 0; BOOL g_Fahrenheit = FALSE;
// Function declarations
WINAPI WinMain ( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN PSTR CmdLine, IN INT CmdShow );
INT_PTR CALLBACK TZoneDlgProc ( IN HWND wnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam );
ULONG UpdateTZoneData ( IN OUT PTZONE_INFO ReturnedTZoneInfo, IN WMIHANDLE *Handle );
ULONG64 SystemTimeToUlong ( IN LPSYSTEMTIME SysTime );
VOID SetCoolingMode ( IN UCHAR Mode );
VOID UpgradePrivileges ( VOID );
VOID UpdateTZoneListBox ( IN HANDLE wnd );
VOID UpdateTZoneDetails ( IN HANDLE wnd );
VOID UpdateTZoneGauge ( IN HANDLE wnd );
VOID UpdateCPUGauge( IN HWND hwnd );
VOID UpdateCoolingMode ( IN HWND hwnd );
/*++
Routine Description:
Windows application Entry Point
Arguments:
<standard winmain arguments>
Return Value:
0 if successful, otherwise error status
--*/
WINAPI WinMain ( IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN PSTR CmdLine, IN INT CmdShow )
{
UCHAR text [200]; INITCOMMONCONTROLSEX CommonCtl; TZONE_INFO TZones [MAX_THERMAL_ZONES]; ULONG status = 0; INT64 RetVal = 0;
// Initialize TZ structures
ZeroMemory (&TZones, sizeof (TZones)); g_TZonePtr = (PTZONE_INFO) &TZones;
// Initialize Common Controls DLL for gauge control
CommonCtl.dwSize = sizeof (CommonCtl); CommonCtl.dwICC = ICC_PROGRESS_CLASS;
InitCommonControlsEx (&CommonCtl);
// Open WMI data source for the TZs
status = WmiOpenBlock ((LPGUID) &ThermalZoneGuid, GENERIC_READ, &g_WmiHandle);
if (status != ERROR_SUCCESS) {
sprintf (text, "Unable to open thermal zone GUIDs. This computer may not be equipped with thermal zones, or may not be in ACPI mode.\nError: %d", status);
MessageBox (NULL, text, "Fatal Error", MB_ICONERROR | MB_OK);
return status; }
// In order to change the policies, we need greater access privileges
UpgradePrivileges ();
// Show the main dialog box
DialogBox (hInstance, MAKEINTRESOURCE (IDD_TZDLG), NULL, TZoneDlgProc);
return 0; }
/*++
Routine Description:
Standard Windows Dialog Message Loop
Arguments:
<standard dialog message loop arguments>
Return Value:
FALSE if message not handled, TRUE if message handled
--*/
INT_PTR CALLBACK TZoneDlgProc ( IN HWND wnd, IN UINT Msg, IN WPARAM wParam, IN LPARAM lParam ) { ULONG Count = 0; INT_PTR RetVal = 0; switch (Msg) {
case WM_TIMER:
if (g_PollTz) { SetCoolingMode (COOLING_UPDATE_TZONE); }
if (UpdateTZoneData (g_TZonePtr, g_WmiHandle)) { UpdateCoolingMode (wnd); UpdateTZoneDetails (wnd); UpdateTZoneGauge (wnd); } UpdateCPUGauge(wnd); return TRUE;
case WM_INITDIALOG:
// Fill TZ structure with initial values
UpdateTZoneData (g_TZonePtr, g_WmiHandle);
// Initialize all controls
UpdateTZoneListBox (wnd); UpdateTZoneDetails (wnd); UpdateTZoneGauge (wnd); UpdateCPUGauge(wnd); UpdateCoolingMode(wnd);
// Initialize polling timer
SetTimer (wnd, TIMER_ID, TIMER_POLL_INTERVAL, NULL);
// Set gauge colors
SendDlgItemMessage (wnd, IDC_TZTEMP1, PBM_SETBARCOLOR, 0, (LPARAM) (COLORREF) (0x0000FF));
SendDlgItemMessage (wnd, IDC_TZTEMP1, PBM_SETBKCOLOR, 0, (LPARAM) (COLORREF) (0x000000));
SendDlgItemMessage (wnd, IDC_THROTTLE, PBM_SETBARCOLOR, 0, (LPARAM) (COLORREF) (0x0000FF));
SendDlgItemMessage (wnd, IDC_THROTTLE, PBM_SETBKCOLOR, 0, (LPARAM) (COLORREF) (0x000000));
return TRUE;
case WM_COMMAND: switch (LOWORD (wParam)) {
// Cleanup and exit
case IDOK: KillTimer (wnd, TIMER_ID); EndDialog (wnd, 0); return TRUE;
// Check to see if user selected a new TZ
case IDC_TZSELECT: if (HIWORD (wParam) == CBN_SELCHANGE) { UpdateTZoneDetails (wnd); UpdateTZoneGauge (wnd); return TRUE; } break;
case IDC_POLLTZ:
// Check to see if user changed the TZ Polling setting
if (HIWORD (wParam) == BN_CLICKED) {
RetVal = SendDlgItemMessage (wnd, IDC_POLLTZ, BM_GETCHECK, 0, 0);
if (!g_PollTz && RetVal == BST_CHECKED) { g_PollTz = TRUE; }
if (g_PollTz && RetVal == BST_UNCHECKED) { g_PollTz = FALSE; } } break;
case IDC_FAHR:
// Check to see if user changed the Fahrenheit setting
if (HIWORD(wParam) == BN_CLICKED) { RetVal = SendDlgItemMessage(wnd, IDC_FAHR, BM_GETCHECK, 0, 0); if (!g_Fahrenheit && RetVal == BST_CHECKED) { g_Fahrenheit = TRUE; SetDlgItemText(wnd, IDC_MINTEMP, "37F"); UpdateTZoneDetails(wnd); UpdateTZoneGauge(wnd); } else if (g_Fahrenheit && RetVal == BST_UNCHECKED) { g_Fahrenheit = FALSE; SetDlgItemText(wnd, IDC_MINTEMP, "276K"); UpdateTZoneDetails(wnd); UpdateTZoneGauge(wnd); } } break;
default: break;
} break;
case WM_CLOSE: KillTimer (wnd, TIMER_ID); EndDialog (wnd, 0); break; case WM_DESTROY: PostQuitMessage(0); break;
default: break;
}
return 0; }
/*++
Routine Description:
Issue WMI call to update TZ structures
Arguments:
ReturnedTZoneInfo - Pointer to array of TZ structures Handle - Handle to WMI
Return Value:
FALSE if no TZs were updated, TRUE if one or more TZs have an update
--*/
ULONG UpdateTZoneData ( IN OUT PTZONE_INFO ReturnedTZoneInfo, IN WMIHANDLE *Handle ) { ULONG status = 0; ULONG BufferSize = 0; PWNODE_ALL_DATA WmiAllData; PTHERMAL_INFORMATION ThermalInfo; ULONG Offset = 0; UCHAR *AllDataBuffer = 0; UCHAR *AllDataBufferSave = 0; UCHAR *OrigDataBuffer = 0; UCHAR *InstanceName = 0; ULONG TZCount = 0; ULONG Temp = 0; SYSTEMTIME SysTime; BOOL Updated = FALSE;
status = WmiQueryAllData (Handle, &BufferSize, 0);
if (status != ERROR_INSUFFICIENT_BUFFER) { return FALSE; }
AllDataBuffer = malloc (BufferSize);
if (!AllDataBuffer) {
return FALSE;
}
//
// Save original pointer to use with free()
//
OrigDataBuffer = AllDataBuffer;
status = WmiQueryAllData (Handle, &BufferSize, AllDataBuffer);
if (status != ERROR_SUCCESS) { free (AllDataBuffer); return FALSE; }
// BUG BUG Assuming Thermal GUID only has one instance
// Save away the buffer pointer as it wll get moved in the following while loop
AllDataBufferSave = AllDataBuffer;
while (TZCount < MAX_THERMAL_ZONES) {
WmiAllData = (PWNODE_ALL_DATA) AllDataBuffer;
if (WmiAllData->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE) {
ThermalInfo = (PTHERMAL_INFORMATION) &AllDataBuffer[WmiAllData->DataBlockOffset]; } else {
ThermalInfo = (PTHERMAL_INFORMATION) &AllDataBuffer[WmiAllData->OffsetInstanceDataAndLength[0].OffsetInstanceData]; }
Offset = (ULONG) AllDataBuffer[WmiAllData->OffsetInstanceNameOffsets];
InstanceName = (UCHAR *) &AllDataBuffer[Offset + 2];
// Update TZone structure if timestamp has changed
if (!ReturnedTZoneInfo[TZCount].TZoneIndex || (ThermalInfo->ThermalStamp != ReturnedTZoneInfo[TZCount].ThermalInfo.ThermalStamp)) {
strcpy (ReturnedTZoneInfo[TZCount].TZoneName, InstanceName); GetSystemTime (&SysTime); ReturnedTZoneInfo[TZCount].TimeStamp = SystemTimeToUlong (&SysTime); ReturnedTZoneInfo[TZCount].TZoneIndex = TZCount + 1; memcpy (&ReturnedTZoneInfo[TZCount].ThermalInfo, ThermalInfo, sizeof (THERMAL_INFORMATION)); Updated = TRUE; }
if (!WmiAllData->WnodeHeader.Linkage) {
break; }
AllDataBuffer += WmiAllData->WnodeHeader.Linkage;
TZCount ++; }
// Restore the buffer pointer to the orginal location
AllDataBuffer = AllDataBufferSave;
free (OrigDataBuffer);
return Updated; }
/*++
Routine Description:
Convert a system time structure to a 64bit ULONG
Arguments:
SysTime - Pointer to system time structure to compare against current time
Return Value:
Number of elapsed seconds between SysTime and current time
--*/
ULONG64 SystemTimeToUlong ( IN LPSYSTEMTIME SysTime )
{ ULONG64 TimeCount = 0;
// BUG BUG Doesn't account for leap year
TimeCount += SysTime->wYear * 31536000; TimeCount += SysTime->wMonth * 2628000; TimeCount += SysTime->wDay * 86400; TimeCount += SysTime->wHour * 3600; TimeCount += SysTime->wMinute * 60; TimeCount += SysTime->wSecond;
return TimeCount; }
/*++
Routine Description:
Sets the cooling mode to ACTIVE, PASSIVE, or UPDATE ONLY. This is accomplished by changing the FanThrottleTolerance value in the power policy. Setting it to maxthrottle effectively puts the system into PASSIVE cooling mode. Setting it to 100% will put the system in ACTIVE cooling mode UNLESS the current temperature exceeds the passive cooling trip points.
Arguments:
Mode - Value to select the new cooling mode
Return Value:
None
--*/
VOID SetCoolingMode ( IN UCHAR Mode )
{ SYSTEM_POWER_POLICY SysPolicy; ULONG Status = 0; UCHAR TempFanThrottleTolerance = 0;
// BUG BUG - This mechanism will currently only for while the machine is on AC.
Status = NtPowerInformation( SystemPowerPolicyAc, 0, 0, &SysPolicy, sizeof (SysPolicy) );
if (Status != ERROR_SUCCESS) {
return; }
switch (Mode) {
case COOLING_PASSIVE: SysPolicy.FanThrottleTolerance = SysPolicy.MinThrottle; break;
case COOLING_ACTIVE: SysPolicy.FanThrottleTolerance = 100; break;
case COOLING_UPDATE_TZONE: TempFanThrottleTolerance = SysPolicy.FanThrottleTolerance; SysPolicy.FanThrottleTolerance = SysPolicy.FanThrottleTolerance != SysPolicy.MinThrottle ? SysPolicy.MinThrottle : 100; break;
default: return; }
Status = NtPowerInformation( SystemPowerPolicyAc, &SysPolicy, sizeof (SysPolicy), &SysPolicy, sizeof (SysPolicy) );
if (Status != ERROR_SUCCESS) {
return; }
if (Mode == COOLING_UPDATE_TZONE) {
SysPolicy.FanThrottleTolerance = TempFanThrottleTolerance;
Status = NtPowerInformation( SystemPowerPolicyAc, &SysPolicy, sizeof (SysPolicy), &SysPolicy, sizeof (SysPolicy) );
if (Status != ERROR_SUCCESS) {
return; } }
}
/*++
Routine Description:
Upgrades the process's access permission to change system power policy
Arguments:
None
Return Value:
None
--*/
VOID UpgradePrivileges ( VOID ) { TOKEN_PRIVILEGES tkp; HANDLE hToken;
OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
LookupPrivilegeValue (NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
tkp.PrivilegeCount = 1; tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges (hToken, FALSE, &tkp, 0, NULL, 0);
}
/*++
Routine Description:
Updates the entries presented in the TZ selection combo box
Arguments:
wnd - A handle to the control's window
Return Value:
None
--*/
VOID UpdateTZoneListBox ( IN HANDLE wnd )
{ ULONG Count = 0;
// Reset the contents
SendDlgItemMessage (wnd, IDC_TZSELECT, CB_RESETCONTENT, 0, 0);
while (Count < MAX_THERMAL_ZONES) {
if (g_TZonePtr[Count].TZoneIndex) {
SendDlgItemMessage (wnd, IDC_TZSELECT, CB_ADDSTRING, 0, (LPARAM) g_TZonePtr[Count].TZoneName); } else {
break; }
Count ++; }
// Automatically select first TZone
SendDlgItemMessage (wnd, IDC_TZSELECT, CB_SETCURSEL, 0, 0);
}
/*++
Routine Description:
Updates the details for the currently selected TZ
Arguments:
wnd - A handle to the control's window
Return Value:
None
--*/
VOID UpdateTZoneDetails ( IN HANDLE wnd ) { UCHAR text[1000], texttmp [1000]; UCHAR CurrentTZone = 0; INT_PTR RetVal = 0; UCHAR Count = 0; ULONG Fahrenheit;
RetVal = SendDlgItemMessage (wnd, IDC_TZSELECT, CB_GETCURSEL, 0, 0);
if (RetVal == CB_ERR) {
return; }
if (g_Fahrenheit) { Fahrenheit = K_TO_F(g_TZonePtr[RetVal].ThermalInfo.PassiveTripPoint); sprintf (text, "Passive Trip Point:\t%d.%dF\nThermal Constant 1:\t%d\nThermal Constant 2:\t%d", Fahrenheit / 10, Fahrenheit % 10, g_TZonePtr[RetVal].ThermalInfo.ThermalConstant1, g_TZonePtr[RetVal].ThermalInfo.ThermalConstant2);
} else { sprintf (text, "Passive Trip Point:\t%d.%dK\nThermal Constant 1:\t%d\nThermal Constant 2:\t%d", g_TZonePtr[RetVal].ThermalInfo.PassiveTripPoint / 10, g_TZonePtr[RetVal].ThermalInfo.PassiveTripPoint % 10, g_TZonePtr[RetVal].ThermalInfo.ThermalConstant1, g_TZonePtr[RetVal].ThermalInfo.ThermalConstant2); }
SetDlgItemText (wnd, IDC_PSVDETAILS, text);
ZeroMemory (&text, sizeof (text));
while (Count < g_TZonePtr[RetVal].ThermalInfo.ActiveTripPointCount) { if (g_Fahrenheit) { Fahrenheit = K_TO_F(g_TZonePtr[RetVal].ThermalInfo.ActiveTripPoint[Count]); sprintf (texttmp, "Active Trip Point #%d:\t%d.%dF\n", Count, Fahrenheit / 10, Fahrenheit % 10); } else { sprintf (texttmp, "Active Trip Point #%d:\t%d.%dK\n", Count, g_TZonePtr[RetVal].ThermalInfo.ActiveTripPoint[Count] / 10, g_TZonePtr[RetVal].ThermalInfo.ActiveTripPoint[Count] % 10); }
strcat (text, texttmp); Count ++; }
SetDlgItemText (wnd, IDC_ACXDETAILS, text);
}
/*++
Routine Description:
Updates the progress bar control (temp gauge) for the currently selected TZ
Arguments:
wnd - A handle to the control's window
Return Value:
None
--*/
VOID UpdateTZoneGauge ( IN HANDLE wnd )
{ UCHAR CurrentTZone = 0; INT_PTR RetVal = 0; UCHAR text[20]; ULONG Fahrenheit;
RetVal = SendDlgItemMessage (wnd, IDC_TZSELECT, CB_GETCURSEL, 0, 0);
if (RetVal == CB_ERR) {
return; }
if (g_Fahrenheit) {
Fahrenheit = K_TO_F(g_TZonePtr[RetVal].ThermalInfo.CriticalTripPoint); sprintf (text, "%d.%dF", Fahrenheit / 10, Fahrenheit % 10);
} else { sprintf (text, "%d.%dK", g_TZonePtr[RetVal].ThermalInfo.CriticalTripPoint / 10, g_TZonePtr[RetVal].ThermalInfo.CriticalTripPoint % 10); }
SetDlgItemText (wnd, IDC_CRTTEMP, text);
if (g_Fahrenheit) {
Fahrenheit = K_TO_F(g_TZonePtr[RetVal].ThermalInfo.CurrentTemperature); sprintf (text, "Current: %d.%dF", Fahrenheit / 10, Fahrenheit % 10);
} else { sprintf (text, "Current: %d.%dK", g_TZonePtr[RetVal].ThermalInfo.CurrentTemperature / 10, g_TZonePtr[RetVal].ThermalInfo.CurrentTemperature % 10);
} SetDlgItemText (wnd, IDC_CURTEMP, text);
SendDlgItemMessage (wnd, IDC_TZTEMP1, PBM_SETRANGE, 0, MAKELPARAM(2760, g_TZonePtr[RetVal].ThermalInfo.CriticalTripPoint));
SendDlgItemMessage (wnd, IDC_TZTEMP1, PBM_SETPOS, (INT) g_TZonePtr[RetVal].ThermalInfo.CurrentTemperature, 0); return; }
VOID UpdateCPUGauge( IN HWND hwnd ) /*++
Routine Description:
Updates the current CPU throttling gauge
Arguments:
hwnd - Supplies the parent dialog hwnd
Return Value:
None
--*/
{ PROCESSOR_POWER_INFORMATION ProcInfo; NTSTATUS Status; UCHAR text[40];
Status = NtPowerInformation(ProcessorInformation, NULL, 0, &ProcInfo, sizeof(ProcInfo)); if (NT_SUCCESS(Status)) { sprintf(text, "%d MHz", ProcInfo.MaxMhz); SetDlgItemText(hwnd, IDC_MAXTHROTTLE, text);
sprintf(text, "Current %d MHz (%d %%)", ProcInfo.CurrentMhz, ProcInfo.CurrentMhz*100/ProcInfo.MaxMhz); SetDlgItemText(hwnd, IDC_CURTHROTTLE, text);
//
// update throttle gauge
//
SendDlgItemMessage (hwnd, IDC_THROTTLE, PBM_SETRANGE, 0, MAKELPARAM(0, ProcInfo.MaxMhz));
SendDlgItemMessage (hwnd, IDC_THROTTLE, PBM_SETPOS, (INT) ProcInfo.CurrentMhz, 0);
//
// update idle information
//
sprintf(text, "C%d", ProcInfo.MaxIdleState); SetDlgItemText(hwnd, IDC_MAXIDLE, text);
//
// BUGBUG John Vert (jvert) 9/16/1999
// the current idle state reporting ranges from 0-2
// the max idle state reporting ranges from 1-3
// probably current is wrong and should be 0-3 representing C0-C3
// for now add one and don't run this on an MP machine!
//
sprintf(text, "C%d", ProcInfo.CurrentIdleState + 1); SetDlgItemText(hwnd, IDC_CURIDLE, text);
}
}
VOID UpdateCoolingMode ( IN HWND hwnd ) { SYSTEM_POWER_INFORMATION SystemInformation; UCHAR uCoolingMode; UCHAR text[50]; NTSTATUS Status;
Status = NtPowerInformation(SystemPowerInformation, NULL, 0, &SystemInformation, sizeof(SystemInformation)); uCoolingMode = SystemInformation.CoolingMode; // 0 = Active Mode
// 1 = Passive Mode
switch (uCoolingMode) { case 0: SetDlgItemText(hwnd, IDC_COOLINGMODE, "Active"); break;
case 1: SetDlgItemText(hwnd, IDC_COOLINGMODE, "Passive"); break;
default: SetDlgItemText(hwnd, IDC_COOLINGMODE, "Error!"); } }
|