/*
Скрипт предназначен для отображения сведений о загрузке CPU на кнопке Пуск (вместо
надписи "Пуск"). При наведении курсора на кнопку Пуск появляется ToolTip, в котором
отображается информация о нескольких (по умолчанию 3-х) процессах, занимающих в данный
период (1 секунду) наибольшую часть процессорного времени.
ToolTip можно передвинуть левой кнопкой мыши в любое удобное место на экране, новое
положение будет сохранено в ini-файле.
Щёлкнув левой кнопкой мыши по ToolTip'у, можно вызвать Диспетчер задач Windows,
правой — окно настроек. Пункты настроек:
1. Сколько процессов показать?
Выбрать, сколько процессов, загрузка которых не менее 1% будут отображаться
в ToolTip'е.
2. Показывать заголовок.
При снятии галочки в ToolTip'е не будет появляться заголовок "Max Load Info"
с иконкой.
3. Показывать дату.
При запуске скрипта уничтожается системная всплывающая подсказка при наведении
курсора на часы на панели задач с отображением даты. При установленной галочке
скрипт покажет её. Работает, только если панель задач не растянута в несколько
строк (при этом дата отображается на панели задач).
4. Настройка размеров кнопки Пуск.
Можно скорректировать размеры кнопки Пуск, изменяя положение её левой и правой
границы. Для этого поместите курсор в соответствующее поле, нажмите левую кнопку
мыши и двигайте влево или вправо. Соответственно будет сдвигаться граница кнопки.
Новые размеры будут сохранены в ini-файле, по окончании работы скрипта система
восстановит первоначальные.
5. Знак % на кнопке.
Показывать ли знак % при отображении загрузки CPU на кнопке Пуск.
Прошу свои отзывы о работе скрипта, предложения и сообщения о замеченных багах
оставлять здесь: http://forum.script-coding.com/viewtopic.php?id=5038
*/
#Persistent
SetBatchLines, -1
CoordMode, Mouse
CoordMode, ToolTip
SetWinDelay, 0
Title = Max Load Info ; заголовок ToolTip'а
AttemptKill = 0
IniName := A_ScriptDir "\" RegExReplace(A_ScriptName, "(.*)\..*", "$1") ".ini"
IniRead, HowManyProcShow, % IniName, Settings, HowManyProcShow, 3
IniRead, ShowTitle, % IniName, Settings, ShowTitle, 1
IniRead, ShowDate, % IniName, Settings, ShowDate, 1
IniRead, ShowPercent, % IniName, Settings, ShowPercent, 1
IniRead, xTT, % IniName, Positions, xTT, % " "
IniRead, yTT, % IniName, Positions, yTT, % " "
IniRead, xSett, % IniName, Positions, xSett, % " "
IniRead, ySett, % IniName, Positions, ySett, % " "
IniRead, xButt, % IniName, Positions, xButt, % " "
IniRead, wButt, % IniName, Positions, wButt, % " "
ControlGetPos, _XButt,, _WButt,, Button1, ahk_class Shell_TrayWnd
WinGetPos, XTray, YTray, WTray, HTray, ahk_class Shell_TrayWnd
if (xTT = "" || yTT = "")
{
xTT := XTray > 10 ? XTray-120 : XTray+30
yTT := YTray > 10 ? YTray-100 : 50
}
if (xSett = "" || ySett = "")
{
xSett := XTray > 10 ? XTray-220 : XTray+25
ySett := YTray > 10 ? YTray-230 : 50
}
hTT := TrackToolTip("", "", "", "", "")
AdjustPrivileges()
EnvGet, NumCPU, NUMBER_OF_PROCESSORS
OnMessage(WM_LBUTTONDOWN := 0x201, "ToolMove")
OnMessage(WM_RBUTTONUP := 0x205, "Settings")
SetTimer, CheckCPULoad, 1000
CheckCPULoad:
WinWait, ahk_class Shell_TrayWnd
SetFormat, float, 02
CPULoad := GetCPULoad()
List := GetProcessList()
ProcessList := ShortProcessList := ""
Loop, parse, List, |
{
PID := RegExReplace(A_LoopField, ".*?,(.*),.*", "$1")
Time%PID% := RegExReplace(A_LoopField, ".*,(.*)", "$1")
Load := Round((Time%PID% - OldTime%PID%)/NumCPU/10000000 * 100)
OldTime%PID% := Time%PID%
ProcessList .= Load . "%" . RegExReplace(A_LoopField, "(.*?),.*", "$1") "`n"
}
if !once
{
once = 1
Return
}
ControlMove, Button1, xButt ? XButt : _XButt - 5,
, wButt ? wButt : (WTray > 100 ? _WButt + 10 : _WButt + 15)
if ShowPercent
ControlSetText, Button1, % CPULoad < 100 ? " " CPULoad " %" : CPULoad "%"
Else
ControlSetText, Button1, % CPULoad < 100 ? " " CPULoad : " " CPULoad
MouseGetPos,, yMouse, WinID, Control
WinGetClass, Class, ahk_id %WinID%
if (ShowDate && Class = "Shell_TrayWnd" && Control = "TrayClockWClass1")
{
FormatTime, Date
WinGetPos, XTray, YTray, WTray, HTray, ahk_class Shell_TrayWnd
if !((WTray > 200 && HTray > 40) || (HTray > 200 && WTray > 40))
{
if !(AttemptKill > 2 || ToolTipDead)
ToolTipDead := ToolTipKill(A_YYYY), ++AttemptKill
Date := RegExReplace(Date, ".*:.. +(.*)", " $1")
ToolTip, % Date,, YTray > 40 ? YTray - 25 : YTray + HTray + 10
}
}
Else
ToolTip
if !((Class = "Shell_TrayWnd" && Control = "Button1") || WinID = hTT)
{
SetTimer, CloseToolTip, -300
Return
}
if !(AttemptKill > 2 || ToolTipDead)
ToolTipDead := ToolTipKill("Начните работу"), ++AttemptKill
StringTrimRight, ProcessList, ProcessList, 1
Sort, ProcessList, N R D`n
EmptyString =
Loop % HowManyProcShow
EmptyString .= "`n"
Loop, parse, ProcessList, `n
{
if (RegExReplace(A_LoopField, "(.*)%.*", "$1") = 0 || A_Index = HowManyProcShow + 1)
Break
ShortProcessList .= A_LoopField . "`n"
StringTrimRight, EmptyString, EmptyString, 1
}
SPL := RegExReplace(SubStr(ShortProcessList, 1, -1), "m`a)(.*%)(.*)", "$2 $1")
ToolTipText := SPL ? SPL . EmptyString : "Нет загрузки" . SubStr(EmptyString, 1, -1)
TrackToolTip(xTT, yTT, ToolTipText, ShowTitle ? Title : "", 1)
PosCorrection()
Return
CloseToolTip:
DllCall("SendMessage", UInt, hTT, UInt, 1041, UInt, 0, UInt, &TOOLINFO) ; TTM_TRACKACTIVATE
Return
ToolTipKill(Text)
{
local PID
DetectHiddenWindows, On
WinGet, TTList, List, ahk_class tooltips_class32
Loop % TTList
{
ControlGetText, Content,, % "ahk_id " TTList%A_Index%
if InStr(Content, Text)
{
WinGet, PID, PID, % "ahk_id " TTList%A_Index%
if (PID != DllCall("GetCurrentProcessId"))
WinClose, % "ahk_id " TTList%A_Index%
if !WinExist("ahk_id " TTList%A_Index%)
ToolTipDead = 1
Break
}
}
Return ToolTipDead
}
AdjustPrivileges()
{
Process, Exist ; sets ErrorLevel to the PID of this running script
; Get the handle of this script with PROCESS_QUERY_INFORMATION (0x0400)
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel)
; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
DllCall("Advapi32.dll\OpenProcessToken", "UInt", h, "UInt", 32, "UIntP", t)
VarSetCapacity(ti, 16, 0) ; structure of privileges
NumPut(1, ti, 0) ; one entry in the privileges array...
; Retrieves the locally unique identifier of the debug privilege:
if A_IsUnicode
DllCall("Advapi32.dll\LookupPrivilegeValueW", "UInt", 0, "Str", "SeDebugPrivilege"
, "Int64P", luid)
else
DllCall("Advapi32.dll\LookupPrivilegeValueA", "UInt", 0, "Str", "SeDebugPrivilege"
, "Int64P", luid)
NumPut(luid, ti, 4, "int64")
NumPut(2, ti, 12) ; enable this privilege: SE_PRIVILEGE_ENABLED = 2
; Update the privileges of this process with the new access token:
DllCall("Advapi32.dll\AdjustTokenPrivileges", "UInt", t, "Int", false
, "UInt", &ti, "UInt", 0
, "UInt", 0, "UInt", 0)
DllCall("CloseHandle", "UInt", h) ; close this process handle to save memory
}
GetCPULoad()
{
static
global NumCPU
IdleTime0 = %IdleTime% ; Save previous values
Tick0 = %Tick%
if !IdleTicksCapacity
IdleTicksCapacity := VarSetCapacity(IdleTicks, 8)
DllCall("kernel32.dll\GetSystemTimes", UInt, &IdleTicks, UInt, 0, UInt, 0)
IdleTime := *(&IdleTicks)
Loop 7 ; Ticks when Windows was idle
IdleTime += *( &IdleTicks + A_Index ) << ( 8 * A_Index )
Tick := A_TickCount ; Ticks all together
load := 100 - 0.01*(IdleTime - IdleTime0)/NumCPU/(Tick - Tick0)
Return, InStr(load, "-") ? 00 : load
}
GetProcessList()
{
s := 4096 ; size of buffers and arrays (4 KB)
hModule := DllCall("LoadLibrary", "Str", "Psapi.dll") ; increase performance by preloading the libaray
s := VarSetCapacity(a, s) ; an array that receives the list of process identifiers:
DllCall("Psapi.dll\EnumProcesses", "UInt", &a, "UInt", s, "UIntP", r)
Loop, % r // 4 ; parse array for identifiers as DWORDs (32 bits):
{
id := NumGet(a, A_Index * 4)
; Open process with: PROCESS_VM_READ (0x0010) | PROCESS_QUERY_INFORMATION (0x0400)
h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id)
VarSetCapacity(n, s, 0) ; a buffer that receives the base name of the module:
e := DllCall("Psapi.dll\GetModuleBaseName" . (A_IsUnicode ? "W" : "A")
, "UInt", h, "UInt", 0, "Str", n, "UInt", s)
DllCall("GetProcessTimes", "Uint", h, "int64P", CreationTime, "int64P"
, ExitTime, "int64P", KrnlTime, "int64P", UserTime)
DllCall("CloseHandle", "UInt", h) ; close process handle to save memory
if (n && e) ; if image is not null add to list:
l .= n . "," . id . "," . KrnlTime + UserTime . "|"
}
Process, Exist, System
id := ErrorLevel
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", id)
DllCall("GetProcessTimes", "Uint", h, "int64P", CreationTime, "int64P"
, ExitTime, "int64P", KrnlTime, "int64P", UserTime)
DllCall("CloseHandle", "UInt", h)
l .= "System," . id . "," . KrnlTime + UserTime
DllCall("FreeLibrary", "UInt", hModule) ; unload the library to free memory
Return l
}
TrackToolTip(x, y, sText, sTitle = "", h_icon = 0)
{
; h_icon — 0: None, 1:Info, 2: Warning, 3: Error. n > 3: assumed to be an hIcon.
static
global hTT, TOOLINFO
WS_EX_TOPMOST := 8, TTS_NOPREFIX := 2, TTS_ALWAYSTIP := 1
if !hTT
{
hWnd := DllCall("CreateWindowEx" , UInt, WS_EX_TOPMOST
, Str, "tooltips_class32"
, Str, ""
, UInt, TTS_NOPREFIX|TTS_ALWAYSTIP
, Int, 0, Int, 0, Int, 0, Int, 0
, UInt, 0, UInt, 0, UInt, 0, UInt, 0)
VarSetCapacity(TOOLINFO, 40, 0)
NumPut(40, TOOLINFO)
NumPut(0x20, TOOLINFO, 4) ; TTF_TRACK = 0x20
NumPut(&sText, TOOLINFO, 36)
VarSetCapacity(Rect, 16)
NumPut(4, Rect)
NumPut(5, Rect, 4)
NumPut(5, Rect, 8)
NumPut(5, Rect, 12)
VarSetCapacity(Rect0, 16)
NumPut(0, Rect0)
NumPut(0, Rect0, 4)
NumPut(0, Rect0, 8)
NumPut(0, Rect0, 12)
; используется DllCall, т. к. работает и со скрытыми окнами, в отличие от SendMessage.
DllCall("SendMessage", UInt, hWnd, UInt, 1048, UInt, 0, UInt, 500) ; TTM_SETMAXTIPWIDTH
DllCall("SendMessage", UInt, hWnd, UInt, 1028, UInt, 0, UInt, &TOOLINFO) ; TTM_ADDTOOL
Return hWnd
}
else
{
if sTitle
DllCall("SendMessage", UInt, hWnd, UInt, 1050, UInt, 0, UInt, &Rect0) ; TTM_SETMARGIN
Else
DllCall("SendMessage", UInt, hWnd, UInt, 1050, UInt, 0, UInt, &Rect) ; TTM_SETMARGIN
NumPut(&sText, TOOLINFO, 36)
if A_IsUnicode
{
DllCall("SendMessage", UInt, hWnd, UInt, 1057, UInt, h_icon ; TTM_SETTITLEW
, UInt, &sTitle)
DllCall("SendMessage", UInt, hWnd, UInt, 1081, UInt, 0, UInt, &TOOLINFO) ; TTM_UPDATETIPTEXTW
}
Else
{
DllCall("SendMessage", UInt, hWnd, UInt, 1056, UInt, h_icon ; TTM_SETTITLE
, UInt, &sTitle)
DllCall("SendMessage", UInt, hWnd, UInt, 1036, UInt, 0, UInt, &TOOLINFO) ; TTM_UPDATETIPTEXT
}
DllCall("SendMessage", UInt, hWnd, UInt, 1042, UInt, 0, UInt ; TTM_TRACKPOSITION
, (x & 0xFFFF)|(y & 0xFFFF)<<16)
DllCall("SendMessage", UInt, hWnd, UInt, 1041, UInt, 1, UInt, &TOOLINFO) ; TTM_TRACKACTIVATE
}
}
ToolMove(wParam, lParam, msg, hwnd)
{
global
if (hwnd = hSett)
PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
if (hwnd != hTT)
Return
StartTime := A_TickCount
MouseGetPos, _MouseX, _MouseY
SetTimer, CheckCPULoad, Off
While GetKeyState("Lbutton", "P")
{
MouseGetPos, MouseX_, MouseY_
WinMove, ahk_id %hTT%,, MouseX_ - _MouseX + xTT, MouseY_ - _MouseY + yTT
Sleep, 10
}
if (A_TickCount - StartTime) < 200
Run Taskmgr
else
{
xTT += (MouseX_ - _MouseX), yTT += (MouseY_ - _MouseY)
DllCall("SendMessage", UInt, hwnd, UInt, 1042, UInt, 0, UInt ; TTM_TRACKPOSITION
, (xTT & 0xFFFF)|(yTT <<16))
IniWrite, % xTT, % IniName, Positions, xTT
IniWrite, % yTT, % IniName, Positions, yTT
PosCorrection()
}
SetTimer, CheckCPULoad, On
}
Settings(wParam, lParam, msg, hwnd)
{
local Str
if (hwnd != hTT || WinExist("Настройки CPULoad ahk_class AutoHotkeyGUI"))
Return
DllCall("SendMessage", UInt, hTT, UInt, 1041, UInt, 0, UInt, &TOOLINFO) ; TTM_TRACKACTIVATE
Gui, -Caption +Border +AlwaysOnTop +Owner +LastFound
WinGet, hSett
Gui, Color, FFFEE1
Gui, Add, Text, gWinMove x0 y0 w209 h12 +0x5
Gui, Add, Text, x7 yp+24, Сколько процессов показать?
Loop 10
Str .= A_Index "|"
StringReplace, Str, Str, % HowManyProcShow "|", % HowManyProcShow "||"
Gui, Add, DDL, vHowManyProcShow gSettChange xp+160 yp-3 w35, % Str
Gui, Add, Checkbox, vShowTitle gSettChange x8 yp+29, Показывать заголовок
Gui, Add, Checkbox, VShowDate gSettChange xp yp+28, Показывать дату
Gui, Add, GroupBox, x8 yp+28 w193 h60, Настройка размеров кнопки Пуск
Gui, Add, Text, x105 yp+17 w1 hp-24 +0x8
Gui, Add, Text, vLeft gButtonMove x9 yp-4 w96 h46 cAAAAAA BackgroundTrans Center, `nЛевая сторона
Gui, Add, Text, vRight gButtonMove x106 yp wp-1 hp cAAAAAA BackgroundTrans Center, `nПравая сторона
Gui, Add, Checkbox, vShowPercent gSettChange x8 y185, Знак `% на кнопке
Gui, Add, Button, x150 y187 w53 h23 Default, OK
GuiControl,, ShowTitle, % ShowTitle ? 1 : 0
GuiControl,, ShowPercent, % ShowPercent ? 1 : 0
GuiControl,, ShowDate, % ShowDate ? 1 : 0
Gui, Show, x%xSett% y%ySett% w209 h218, Настройки CPULoad
GuiControl, Focus, Static1
Return
SettChange:
Gui, Submit, NoHide
IniWrite, % %A_GuiControl%, % IniName, Settings, % A_GuiControl
Return
WinMove:
PostMessage, WM_NCLBUTTONDOWN := 0xA1, HTCAPTION := 2
Return
ButtonMove:
WinWait, ahk_class Shell_TrayWnd
SetTimer, CheckCPULoad, Off
Gui, Font, c00AA00
GuiControl, Font, % A_GuiControl
MouseGetPos, xM
ControlGetPos, xB,, wB,, Button1, ahk_class Shell_TrayWnd
hCursor := DllCall("LoadCursor" . (A_IsUnicode ? "W" : "A"), UInt, 0, Int, OCR_SIZEWE := 32644)
DllCall("SetSystemCursor", Uint, hCursor, Int, OCR_NORMAL := 32512)
While GetKeyState("LButton", "P")
{
MouseGetPos, xM_
Shift := (xM_ - xM)/4
if A_GuiControl = Left
ControlMove, Button1, xButt := xB + Shift,, wButt := wB - Shift
Else
ControlMove, Button1,,, wButt := wB + Shift
Sleep, 10
}
; DllCall("SystemParametersInfo" . (A_IsUnicode ? "W" : "A") ; на офф. форуме восстанавливают
; , UInt, SPI_SETCURSORS := 0x57, UInt, 0, UInt, 0, UInt, 0) ; курсор так
DllCall("SetSystemCursor", UInt, hCursor, Int, OCR_NORMAL := 32512) ; но вроде, можно и так
Gui, Font, cAAAAAA
GuiControl, Font, % A_GuiControl
IniWrite, % xButt, % IniName, Positions, xButt
IniWrite, % wButt, % IniName, Positions, wButt
SetTimer, CheckCPULoad, On
Return
GuiClose:
GuiEscape:
Gui, Destroy
Return
ButtonOK:
WinGetPos, xSett, ySett,,, ahk_id %hSett%
Gui, Destroy
IniWrite, % xSett, % IniName, Positions, xSett
IniWrite, % ySett, % IniName, Positions, ySett
Return
}
PosCorrection()
{
global
WinGetPos, _xTT, _yTT, _wTT, _hTT, ahk_id %hTT%
if (yTT != _yTT || xTT != _xTT)
{
yTT := (yTT - _yTT > 300) ? A_ScreenHeight - _hTT - 5 : _yTT
xTT := _xTT
WinMove, ahk_id %hTT%,, xTT, yTT
DllCall("SendMessage", UInt, hwnd, UInt, 1042, UInt, 0, UInt ; TTM_TRACKPOSITION
, (xTT & 0xFFFF)|(yTT <<16))
IniWrite, % xTT, % IniName, Positions, xTT
IniWrite, % yTT, % IniName, Positions, yTT
}
}
У меня скрипт не видит процессы фаервола (Outpost), при попытке дописать их вручную показывает всякую ерунду — 1450%.
Пользуйтесь только последней версией, в предыдущих обнаружены баги!