2009-02-10 18:37:48 +00:00
|
|
|
/*
|
|
|
|
Copyright (C) 2002 Kimmo Pekkola
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <map>
|
|
|
|
#include <string>
|
|
|
|
#include <time.h>
|
|
|
|
#include <Powrprof.h>
|
2011-02-03 18:09:24 +00:00
|
|
|
#include "../../Library/Export.h" // Rainmeter's exported functions
|
2009-02-10 18:37:48 +00:00
|
|
|
|
2011-02-03 18:09:24 +00:00
|
|
|
#include "../../Library/DisableThreadLibraryCalls.h" // contains DllMain entry point
|
2011-01-30 09:31:41 +00:00
|
|
|
|
2011-03-29 19:21:57 +00:00
|
|
|
typedef struct _PROCESSOR_POWER_INFORMATION
|
2011-01-08 08:17:59 +00:00
|
|
|
{
|
|
|
|
ULONG Number;
|
|
|
|
ULONG MaxMhz;
|
|
|
|
ULONG CurrentMhz;
|
|
|
|
ULONG MhzLimit;
|
|
|
|
ULONG MaxIdleState;
|
|
|
|
ULONG CurrentIdleState;
|
2009-02-10 18:37:48 +00:00
|
|
|
} PROCESSOR_POWER_INFORMATION, *PPROCESSOR_POWER_INFORMATION;
|
|
|
|
|
|
|
|
typedef LONG (WINAPI *FPCALLNTPOWERINFORMATION)(POWER_INFORMATION_LEVEL, PVOID, ULONG, PVOID, ULONG);
|
|
|
|
|
|
|
|
/* The exported functions */
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
__declspec( dllexport ) UINT Initialize(HMODULE instance, LPCTSTR iniFile, LPCTSTR section, UINT id);
|
|
|
|
__declspec( dllexport ) void Finalize(HMODULE instance, UINT id);
|
|
|
|
__declspec( dllexport ) LPCTSTR GetString(UINT id, UINT flags);
|
2011-01-08 08:17:59 +00:00
|
|
|
__declspec( dllexport ) double Update2(UINT id);
|
2009-02-10 18:37:48 +00:00
|
|
|
__declspec( dllexport ) UINT GetPluginVersion();
|
|
|
|
__declspec( dllexport ) LPCTSTR GetPluginAuthor();
|
|
|
|
}
|
|
|
|
|
|
|
|
enum POWER_STATE
|
|
|
|
{
|
|
|
|
POWER_UNKNOWN,
|
|
|
|
POWER_ACLINE,
|
|
|
|
POWER_STATUS,
|
|
|
|
POWER_STATUS2,
|
|
|
|
POWER_LIFETIME,
|
|
|
|
POWER_PERCENT,
|
2011-01-08 08:17:59 +00:00
|
|
|
POWER_MHZ,
|
|
|
|
POWER_HZ
|
2009-02-10 18:37:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
std::map<UINT, POWER_STATE> g_States;
|
|
|
|
std::map<UINT, std::wstring> g_Formats;
|
|
|
|
HINSTANCE hDLL = NULL;
|
2011-01-08 08:17:59 +00:00
|
|
|
int g_Instances, g_NumOfProcessors = 0;
|
2009-02-10 18:37:48 +00:00
|
|
|
FPCALLNTPOWERINFORMATION fpCallNtPowerInformation = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
This function is called when the measure is initialized.
|
2011-03-29 19:21:57 +00:00
|
|
|
The function must return the maximum value that can be measured.
|
2009-02-10 18:37:48 +00:00
|
|
|
The return value can also be 0, which means that Rainmeter will
|
|
|
|
track the maximum value automatically. The parameters for this
|
|
|
|
function are:
|
|
|
|
|
|
|
|
instance The instance of this DLL
|
|
|
|
iniFile The name of the ini-file (usually Rainmeter.ini)
|
|
|
|
section The name of the section in the ini-file for this measure
|
|
|
|
id The identifier for the measure. This is used to identify the measures that use the same plugin.
|
|
|
|
*/
|
|
|
|
UINT Initialize(HMODULE instance, LPCTSTR iniFile, LPCTSTR section, UINT id)
|
|
|
|
{
|
2009-11-01 10:00:12 +00:00
|
|
|
g_Instances++;
|
|
|
|
if (hDLL == NULL)
|
2011-01-08 08:17:59 +00:00
|
|
|
{
|
|
|
|
hDLL = LoadLibrary(L"powrprof.dll");
|
|
|
|
if (hDLL)
|
|
|
|
{
|
|
|
|
fpCallNtPowerInformation = (FPCALLNTPOWERINFORMATION)GetProcAddress(hDLL, "CallNtPowerInformation");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
POWER_STATE powerState = POWER_UNKNOWN;
|
2009-02-10 18:37:48 +00:00
|
|
|
|
2011-01-08 08:17:59 +00:00
|
|
|
SYSTEM_INFO systemInfo = {0};
|
|
|
|
GetSystemInfo(&systemInfo);
|
|
|
|
g_NumOfProcessors = (int)systemInfo.dwNumberOfProcessors;
|
2009-02-10 18:37:48 +00:00
|
|
|
|
|
|
|
/* Read our own settings from the ini-file */
|
|
|
|
LPCTSTR type = ReadConfigString(section, L"PowerState", L"");
|
2011-03-29 19:21:57 +00:00
|
|
|
if (type)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
2010-09-17 08:47:22 +00:00
|
|
|
if (_wcsicmp(L"ACLINE", type) == 0)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
|
|
|
powerState = POWER_ACLINE;
|
2011-03-29 19:21:57 +00:00
|
|
|
}
|
2010-09-17 08:47:22 +00:00
|
|
|
else if (_wcsicmp(L"STATUS", type) == 0)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
|
|
|
powerState = POWER_STATUS;
|
2011-03-29 19:21:57 +00:00
|
|
|
}
|
2010-09-17 08:47:22 +00:00
|
|
|
else if (_wcsicmp(L"STATUS2", type) == 0)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
|
|
|
powerState = POWER_STATUS2;
|
2011-03-29 19:21:57 +00:00
|
|
|
}
|
2010-09-17 08:47:22 +00:00
|
|
|
else if (_wcsicmp(L"LIFETIME", type) == 0)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
|
|
|
powerState= POWER_LIFETIME;
|
|
|
|
|
|
|
|
LPCTSTR format = ReadConfigString(section, L"Format", L"%H:%M");
|
|
|
|
if (format)
|
|
|
|
{
|
|
|
|
g_Formats[id] = format;
|
|
|
|
}
|
2011-03-29 19:21:57 +00:00
|
|
|
}
|
2010-09-17 08:47:22 +00:00
|
|
|
else if (_wcsicmp(L"MHZ", type) == 0)
|
2011-01-08 08:17:59 +00:00
|
|
|
{
|
2009-02-10 18:37:48 +00:00
|
|
|
powerState= POWER_MHZ;
|
2011-01-08 08:17:59 +00:00
|
|
|
}
|
|
|
|
else if (_wcsicmp(L"HZ", type) == 0)
|
|
|
|
{
|
|
|
|
powerState= POWER_HZ;
|
|
|
|
}
|
2010-09-17 08:47:22 +00:00
|
|
|
else if (_wcsicmp(L"PERCENT", type) == 0)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
|
|
|
powerState = POWER_PERCENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_States[id] = powerState;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(powerState)
|
|
|
|
{
|
|
|
|
case POWER_ACLINE:
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case POWER_STATUS:
|
|
|
|
return 4;
|
|
|
|
|
|
|
|
case POWER_STATUS2:
|
|
|
|
return 255;
|
|
|
|
|
|
|
|
case POWER_LIFETIME:
|
|
|
|
{
|
|
|
|
SYSTEM_POWER_STATUS status;
|
|
|
|
if (GetSystemPowerStatus(&status))
|
|
|
|
{
|
|
|
|
return status.BatteryFullLifeTime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case POWER_PERCENT:
|
|
|
|
return 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
This function is called when new value should be measured.
|
|
|
|
The function returns the new value.
|
|
|
|
*/
|
2011-01-08 08:17:59 +00:00
|
|
|
double Update2(UINT id)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
|
|
|
SYSTEM_POWER_STATUS status;
|
|
|
|
if (GetSystemPowerStatus(&status))
|
|
|
|
{
|
|
|
|
std::map<UINT, POWER_STATE>::iterator i = g_States.find(id);
|
|
|
|
if (i != g_States.end())
|
|
|
|
{
|
|
|
|
switch((*i).second)
|
|
|
|
{
|
|
|
|
case POWER_ACLINE:
|
|
|
|
return status.ACLineStatus == 1 ? 1 : 0;
|
|
|
|
|
|
|
|
case POWER_STATUS:
|
|
|
|
if (status.BatteryFlag & 128)
|
|
|
|
{
|
|
|
|
return 0; // No battery
|
|
|
|
}
|
|
|
|
else if (status.BatteryFlag & 8)
|
|
|
|
{
|
|
|
|
return 1; // Charging
|
|
|
|
}
|
|
|
|
else if (status.BatteryFlag & 4)
|
|
|
|
{
|
|
|
|
return 2; // Critical
|
|
|
|
}
|
|
|
|
else if (status.BatteryFlag & 2)
|
|
|
|
{
|
|
|
|
return 3; // Low
|
|
|
|
}
|
|
|
|
else if (status.BatteryFlag & 1)
|
|
|
|
{
|
|
|
|
return 4; // High
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case POWER_STATUS2:
|
|
|
|
return status.BatteryFlag;
|
|
|
|
|
|
|
|
case POWER_LIFETIME:
|
|
|
|
return status.BatteryLifeTime;
|
|
|
|
|
|
|
|
case POWER_PERCENT:
|
|
|
|
return status.BatteryLifePercent > 100 ? 100 : status.BatteryLifePercent;
|
|
|
|
|
|
|
|
case POWER_MHZ:
|
2011-01-08 08:17:59 +00:00
|
|
|
case POWER_HZ:
|
|
|
|
if (fpCallNtPowerInformation && g_NumOfProcessors > 0)
|
|
|
|
{
|
|
|
|
PROCESSOR_POWER_INFORMATION* ppi = new PROCESSOR_POWER_INFORMATION [g_NumOfProcessors];
|
|
|
|
memset(ppi, 0, sizeof(PROCESSOR_POWER_INFORMATION) * g_NumOfProcessors);
|
|
|
|
fpCallNtPowerInformation(ProcessorInformation, NULL, 0, ppi, sizeof(PROCESSOR_POWER_INFORMATION) * g_NumOfProcessors);
|
|
|
|
double value = ((*i).second == POWER_MHZ) ? ppi[0].CurrentMhz : ppi[0].CurrentMhz * 1000000.0;
|
|
|
|
delete [] ppi;
|
|
|
|
return value;
|
|
|
|
}
|
2009-02-10 18:37:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
This function is called when the value should be
|
|
|
|
returned as a string.
|
|
|
|
*/
|
2011-03-29 19:21:57 +00:00
|
|
|
LPCTSTR GetString(UINT id, UINT flags)
|
2009-02-10 18:37:48 +00:00
|
|
|
{
|
|
|
|
static WCHAR buffer[256];
|
|
|
|
|
|
|
|
std::map<UINT, POWER_STATE>::iterator i = g_States.find(id);
|
|
|
|
if (i != g_States.end())
|
|
|
|
{
|
|
|
|
if ((*i).second == POWER_LIFETIME)
|
|
|
|
{
|
|
|
|
SYSTEM_POWER_STATUS status;
|
|
|
|
if (GetSystemPowerStatus(&status))
|
|
|
|
{
|
|
|
|
// Change it to time string
|
|
|
|
if (status.BatteryLifeTime == -1)
|
|
|
|
{
|
|
|
|
return L"Unknown";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::map<UINT, std::wstring>::iterator iter = g_Formats.find(id);
|
|
|
|
if (iter != g_Formats.end())
|
|
|
|
{
|
|
|
|
tm time;
|
|
|
|
memset(&time, 0, sizeof(tm));
|
|
|
|
time.tm_sec = status.BatteryLifeTime % 60;
|
|
|
|
time.tm_min = (status.BatteryLifeTime / 60) % 60;
|
|
|
|
time.tm_hour = status.BatteryLifeTime / 60 / 60;
|
|
|
|
|
|
|
|
wcsftime(buffer, 256, (*iter).second.c_str(), &time);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wsprintf(buffer, L"%i:%02i:%02i", status.BatteryLifeTime / 60 / 60, (status.BatteryLifeTime / 60) % 60, status.BatteryLifeTime % 60);
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If the measure needs to free resources before quitting.
|
|
|
|
The plugin can export Finalize function, which is called
|
|
|
|
when Rainmeter quits (or refreshes).
|
|
|
|
*/
|
|
|
|
void Finalize(HMODULE instance, UINT id)
|
|
|
|
{
|
|
|
|
std::map<UINT, POWER_STATE>::iterator i = g_States.find(id);
|
|
|
|
if (i != g_States.end())
|
|
|
|
{
|
|
|
|
g_States.erase(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<UINT, std::wstring>::iterator i2 = g_Formats.find(id);
|
|
|
|
if (i2 != g_Formats.end())
|
|
|
|
{
|
|
|
|
g_Formats.erase(i2);
|
|
|
|
}
|
|
|
|
|
2009-11-01 10:00:12 +00:00
|
|
|
g_Instances--;
|
2011-01-08 08:17:59 +00:00
|
|
|
if (hDLL != NULL && g_Instances == 0)
|
|
|
|
{
|
|
|
|
FreeLibrary(hDLL);
|
|
|
|
hDLL = NULL;
|
2009-11-01 10:00:12 +00:00
|
|
|
fpCallNtPowerInformation = NULL;
|
2011-01-08 08:17:59 +00:00
|
|
|
}
|
2009-02-10 18:37:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UINT GetPluginVersion()
|
|
|
|
{
|
2011-01-08 08:17:59 +00:00
|
|
|
return 1004;
|
2009-02-10 18:37:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LPCTSTR GetPluginAuthor()
|
|
|
|
{
|
|
|
|
return L"Rainy (rainy@iki.fi)";
|
|
|
|
}
|