rainmeter-studio/Plugins/PluginAdvancedCPU/AdvancedCPU.cpp

365 lines
8.8 KiB
C++
Raw Normal View History

2009-02-10 18:37:48 +00:00
/*
Copyright (C) 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
2009-02-10 18:37:48 +00:00
*/
#include <windows.h>
#include "AdvancedCPU.h"
#include <string>
#include <vector>
#include <map>
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
2009-02-10 18:37:48 +00:00
//ULONGLONG GetPerfData(PCTSTR ObjectName, PCTSTR InstanceName, PCTSTR CounterName);
void UpdateProcesses();
struct CPUMeasure
{
std::vector< std::wstring > includes;
std::vector< std::wstring > excludes;
int topProcess;
std::wstring topProcessName;
LONGLONG topProcessValue;
};
struct ProcessValues
{
std::wstring name;
LONGLONG oldValue;
LONGLONG newValue;
bool found;
};
static CPerfTitleDatabase g_CounterTitles( PERF_TITLE_COUNTER );
std::vector< ProcessValues > g_Processes;
static std::map<UINT, CPUMeasure*> g_CPUMeasures;
void SplitName(WCHAR* names, std::vector< std::wstring >& splittedNames)
{
WCHAR* token;
2011-03-29 19:21:57 +00:00
2009-02-10 18:37:48 +00:00
token = wcstok(names, L";");
2011-03-29 19:21:57 +00:00
while (token != NULL)
2009-02-10 18:37:48 +00:00
{
splittedNames.push_back(token);
token = wcstok(NULL, L";");
}
}
/*
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)
{
WCHAR buffer[4096];
CPUMeasure* measure = new CPUMeasure;
measure->topProcess = 0;
measure->topProcessValue = 0;
LPCTSTR data = ReadConfigString(section, L"CPUInclude", L"");
if (data)
{
wcsncpy(buffer, data, 4096);
buffer[4095] = 0;
SplitName(buffer, measure->includes);
}
data = ReadConfigString(section, L"CPUExclude", L"");
if (data)
{
wcsncpy(buffer, data, 4096);
buffer[4095] = 0;
SplitName(buffer, measure->excludes);
}
measure->topProcess = 0;
data = ReadConfigString(section, L"TopProcess", L"0");
if (data)
{
measure->topProcess = _wtoi(data);
}
g_CPUMeasures[id] = measure;
return 10000000; // The values are 100 * 100000
}
bool CheckProcess(CPUMeasure* measure, const std::wstring& name)
{
2011-03-29 19:21:57 +00:00
if (measure->includes.empty())
2009-02-10 18:37:48 +00:00
{
2009-02-14 10:11:28 +00:00
for (size_t i = 0; i < measure->excludes.size(); i++)
2009-02-10 18:37:48 +00:00
{
2010-09-17 08:47:22 +00:00
if (_wcsicmp(measure->excludes[i].c_str(), name.c_str()) == 0)
2009-02-10 18:37:48 +00:00
{
return false; // Exclude
}
}
return true; // Include
}
else
{
2009-02-14 10:11:28 +00:00
for (size_t i = 0; i < measure->includes.size(); i++)
2009-02-10 18:37:48 +00:00
{
2010-09-17 08:47:22 +00:00
if (_wcsicmp(measure->includes[i].c_str(), name.c_str()) == 0)
2009-02-10 18:37:48 +00:00
{
return true; // Include
}
}
}
return false;
}
/*
This function is called when new value should be measured.
The function returns the new value.
*/
double Update2(UINT id)
{
static DWORD oldTime = 0;
2011-03-29 19:21:57 +00:00
2009-02-10 18:37:48 +00:00
// Only update twice per second
DWORD time = GetTickCount();
if (oldTime == 0 || time - oldTime > 500)
{
UpdateProcesses();
oldTime = time;
}
LONGLONG newValue = 0;
std::map<UINT, CPUMeasure*>::iterator i = g_CPUMeasures.find(id);
2011-03-29 19:21:57 +00:00
if (i != g_CPUMeasures.end())
2009-02-10 18:37:48 +00:00
{
CPUMeasure* measure = (*i).second;
2011-03-29 19:21:57 +00:00
if (measure)
2009-02-10 18:37:48 +00:00
{
2011-03-29 19:21:57 +00:00
for (size_t i = 0; i < g_Processes.size(); i++)
2009-02-10 18:37:48 +00:00
{
// Check process include/exclude
2011-03-29 19:21:57 +00:00
if (CheckProcess(measure, g_Processes[i].name))
2009-02-10 18:37:48 +00:00
{
2011-03-29 19:21:57 +00:00
if (g_Processes[i].oldValue != 0)
2009-02-10 18:37:48 +00:00
{
2011-03-29 19:21:57 +00:00
if (measure->topProcess == 0)
2009-02-10 18:37:48 +00:00
{
// Add all values together
newValue += g_Processes[i].newValue - g_Processes[i].oldValue;
}
2011-03-29 19:21:57 +00:00
else
2009-02-10 18:37:48 +00:00
{
// Find the top process
if (newValue < g_Processes[i].newValue - g_Processes[i].oldValue)
{
newValue = g_Processes[i].newValue - g_Processes[i].oldValue;
measure->topProcessName = g_Processes[i].name;
measure->topProcessValue = newValue;
}
}
}
}
}
}
// LONGLONG newValue = 0;
// ULONGLONG longvalue = 0;
//
// if (measure->includes.empty())
// {
// // First get the total CPU value
// longvalue = GetPerfData(L"Processor", L"_Total", L"% Processor Time");
// newValue = longvalue;
//
// // Then substract the excluded processes
// std::vector< std::wstring >::iterator j = measure->excludes.begin();
2011-03-29 19:21:57 +00:00
// for ( ; j != measure->excludes.end(); j++)
2009-02-10 18:37:48 +00:00
// {
// longvalue = GetPerfData(L"Process", (*j).c_str(), L"% Processor Time");
// newValue += longvalue; // Adding means actually substraction
// }
//
// // Compare with the old value
2011-03-29 19:21:57 +00:00
// if (measure->oldValue != 0)
2009-02-10 18:37:48 +00:00
// {
// int val = 10000000 - (UINT)(newValue - measure->oldValue);
// if (val < 0) val = 0;
// value = val;
// }
// measure->oldValue = newValue;
// }
// else
// {
// // Add the included processes
// std::vector< std::wstring >::iterator j = measure->includes.begin();
2011-03-29 19:21:57 +00:00
// for ( ; j != measure->includes.end(); j++)
2009-02-10 18:37:48 +00:00
// {
// longvalue = GetPerfData(L"Process", (*j).c_str(), L"% Processor Time");
// newValue += longvalue;
// }
//
// // Compare with the old value
2011-03-29 19:21:57 +00:00
// if (measure->oldValue != 0)
2009-02-10 18:37:48 +00:00
// {
// value = (UINT)(newValue - measure->oldValue);
// }
// measure->oldValue = newValue;
//
// }
//
// }
}
return (double)newValue;
}
/*
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
{
std::map<UINT, CPUMeasure*>::iterator i = g_CPUMeasures.find(id);
2011-03-29 19:21:57 +00:00
if (i != g_CPUMeasures.end())
2009-02-10 18:37:48 +00:00
{
CPUMeasure* measure = (*i).second;
2011-03-29 19:21:57 +00:00
if (measure->topProcess == 2)
2009-02-10 18:37:48 +00:00
{
return measure->topProcessName.c_str();
}
}
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)
{
// delete the measure
std::map<UINT, CPUMeasure*>::iterator i = g_CPUMeasures.find(id);
2011-03-29 19:21:57 +00:00
if (i != g_CPUMeasures.end())
2009-02-10 18:37:48 +00:00
{
delete (*i).second;
g_CPUMeasures.erase(i);
}
CPerfSnapshot::CleanUp();
}
/*
This updates the process status
*/
void UpdateProcesses()
{
CPerfObject* pPerfObj;
CPerfObjectInstance* pObjInst;
CPerfCounter* pPerfCntr;
BYTE data[256];
WCHAR name[256];
std::vector< ProcessValues > newProcesses;
CPerfSnapshot snapshot(&g_CounterTitles);
CPerfObjectList objList(&snapshot, &g_CounterTitles);
2011-03-29 19:21:57 +00:00
if (snapshot.TakeSnapshot(L"Process"))
2009-02-10 18:37:48 +00:00
{
pPerfObj = objList.GetPerfObject(L"Process");
2011-03-29 19:21:57 +00:00
if (pPerfObj)
2009-02-10 18:37:48 +00:00
{
2011-03-29 19:21:57 +00:00
for (pObjInst = pPerfObj->GetFirstObjectInstance();
2009-02-10 18:37:48 +00:00
pObjInst != NULL;
pObjInst = pPerfObj->GetNextObjectInstance())
{
2011-03-29 19:21:57 +00:00
if (pObjInst->GetObjectInstanceName(name, 256))
2009-02-10 18:37:48 +00:00
{
2010-09-17 08:47:22 +00:00
if (_wcsicmp(name, L"_Total") == 0)
2009-02-10 18:37:48 +00:00
{
delete pObjInst;
2009-02-10 18:37:48 +00:00
continue;
}
pPerfCntr = pObjInst->GetCounterByName(L"% Processor Time");
2011-03-29 19:21:57 +00:00
if (pPerfCntr != NULL)
2009-02-10 18:37:48 +00:00
{
pPerfCntr->GetData(data, 256, NULL);
2011-03-29 19:21:57 +00:00
if (pPerfCntr->GetSize() == 8)
2009-02-10 18:37:48 +00:00
{
ProcessValues values;
values.name = name;
values.oldValue = 0;
// Check if we can find the old value
2011-03-29 19:21:57 +00:00
for (size_t i = 0; i < g_Processes.size(); i++)
2009-02-10 18:37:48 +00:00
{
2011-03-29 19:21:57 +00:00
if (!g_Processes[i].found && g_Processes[i].name == name)
2009-02-10 18:37:48 +00:00
{
values.oldValue = g_Processes[i].newValue;
g_Processes[i].found = true;
break;
}
}
values.newValue = *(ULONGLONG*)data;
values.found = false;
newProcesses.push_back(values);
// LSLog(LOG_DEBUG, NULL, name); // DEBUG
2009-02-10 18:37:48 +00:00
}
delete pPerfCntr;
}
}
2009-02-10 18:37:48 +00:00
delete pObjInst;
}
delete pPerfObj;
}
}
g_Processes = newProcesses;
}
UINT GetPluginVersion()
{
return 1005;
}
LPCTSTR GetPluginAuthor()
{
return L"Rainy (rainy@iki.fi)";
}