I have been searching for how to get processes memory usage, is this possible using only an AutoHotkey script?
If someone could point where to start, thanks.
How about this function?
GetProcessMemoryInfo(PID) {
size := 440
VarSetCapacity(pmcex,size,0)
ret := ""
hProcess := DllCall( "OpenProcess", UInt,0x400|0x0010,Int,0,Ptr,PID, Ptr )
if (hProcess)
{
if (DllCall("psapi.dll\GetProcessMemoryInfo", Ptr, hProcess, Ptr, &pmcex, UInt,size))
ret := NumGet(pmcex, (A_PtrSize=8 ? "16" : "12"), "UInt")/1024 . " K"
DllCall("CloseHandle", Ptr, hProcess)
}
return % ret
}
Taken from AHK_Task Manager:
https://www.autohotkey.com/board/topic/79151-ahk-task-manager/
Related
I have several different computers that have an extra drive F:\dropbox\autohotkey or c:\dropbox\autohotkey or a remapped b:\ drive.
I want to create a startup script to determine which drive exists, set it to A_Scriptdir, and execute a file.
This is a script created by ChatGPT with an array. It does not work yet, but it added an array to determine which location to execute.
It does not work correctly. any help would be greatly appreciated.
#noenv
#SingleInstance, force
#noenv
#SingleInstance, force
#requires autohotkey v1
setscriptdir()
SetScriptDir()
{
static scriptDir := ""
if (scriptDir != "")
{
scriptDir := A_ScriptDir
;~ A_ScriptDir := scriptDir
return
}
pathArray := ["b:\", "f:\dropbox\autohotkey", "c:\dropbox\autohotkey"]
loop % pathArray.Length()
{
path := pathArray[A_Index]
;~ MsgBox %path%
if FileExist(path . "\" . bbb-1-myahkdefault.ahk)
{
scriptDir := path
scriptDir := A_ScriptDir
MsgBox %scriptDir%
;~A_ScriptDir := scriptDir
return
}
}
}
I'm trying to use a simple AHK DLLCall to the user32 api function CreateCaret. I want it to give notepad a thick text caret.
caretWidth := 10
NULL := 0
Ptr := A_PtrSize ? "Ptr" : "UInt" ; If A_PtrSize is not defined, use UInt instead.
WinHwnd := WinExist("A")
result := Dllcall("CreateCaret", Ptr, WinHwnd, Ptr, NULL, "Int", caretWidth, "Int", 0)
msgbox % "LE " A_lasterror ; Gives LE 0
msgbox % result ; Gives 0
This should be equivalent to the following c++ call:
CreateCaret(0x37072c, NULL, 10, 0);
Purposefully screwing up the function name makes result blank, so I believe the function is being called correctly. I just don't know why it is failing
Using similar code for GetCursorBlinkRate returns a sensible number.
I have also tried with caretWidth := 0
Similar questions about GetLastError are c++ calls, and AHK supposedly ensures that GetLastError is called in a timely enough manner to ensure A_lasterror is set correctly. Why is it showing no error code when the function apparently fails?
You can't change the caret of an external process.
If you try this for example, you'll see it works just fine if you own the process:
#Persistent
Gui, +hwndHWND
Gui, Add, Edit
Gui, Show
DllCall("CreateCaret", Ptr, HWND, Ptr, 0, Int, 50, Int, 50)
DllCall("ShowCaret", Ptr, HWND)
ESC::
GuiClose:
ExitApp
I've been using a short AutoHotKey script to simulate Alt Tab on Windows 10 using the middle mouse button, so that I can quickly open my most recently opened app, or toggle between two apps, with the click of a button. This is what I'm using
Mbutton::SendEvent {Alt Down}{Tab}{Alt Up}
But I've been using two monitors recently, and what I really want to do is switch to the most recently opened app ON THE ACTIVE MONITOR (or the monitor that the mouse is currently on). Alt Tab alone doesn't work obviously, because often the most recently opened app is on the other monitor and I only want to bring the window of the most recently used app forward if it is in the monitor I'm currently working in. Does anyone know if this is possible and how I might go about doing it?
I am pasting here my script. It is very ugly, but it works on my two-monitor setup as you described: switches to the previous (for the monitor where you click middle button) active window.
#WinActivateForce
#SingleInstance
#Persistent
CoordMode, Mouse, Screen
CoordMode, ToolTip, Screen
DetectHiddenWindows, On
SetTitleMatchMode , 2
SetBatchLines , -1
SetWorkingDir %A_ScriptDir%
Thread, interrupt, 0
SetTimer, UpdateCurrentWindow, 100
isDebug := true
SysGet, monitors_total, MonitorCount
SysGet, monitor_primary, MonitorPrimary
Hotkey, MButton, SwitchToLastWindow, On
return
SwitchToLastWindow:
WinGet, active_id, ID, A
Loop , %monitors_total%
{
if (A_Index != current_monitor)
continue
switch_to_window := (active_id = winlast%A_Index%)
? winprelast%A_Index%
: winlast%A_Index%
}
WinActivate , ahk_id %switch_to_window%
return
UpdateCurrentWindow:
WinGet, active_id, ID, A
monitor_index := GetMonitorIndexFromWindow(active_id)
current_monitor := GetMonitorIndexFromMouse()
if (monitor_index > monitors_total)
monitors_total := monitor_index
if (winlast%monitor_index% != active_id)
{
winprelast%monitor_index% := winlast%monitor_index%
winlast%monitor_index% := active_id
}
if isDebug
{
DebugToolTip := ""
Loop , %monitors_total%
{
DebugToolTip .= "Monitor # " . A_Index
. ":`n`nLast window: " . winlast%A_Index%
. "`nPre-last window: " . winprelast%A_Index% . "`n`n"
}
MouseGetPos, xpos, ypos
DebugToolTip .= "x: " . xpos . "`ny: " . ypos . "`ncurrent_monitor: " . current_monitor
. "`n`nA_ScreenHeight: " . A_ScreenHeight . "`nA_ScreenWidth: " . A_ScreenWidth
. "`n`nmonitors_total: " . monitors_total . "`nmonitor_primary: " . monitor_primary
ToolTip , %DebugToolTip%, 10, 10
}
return
; only done for one case: total 2 monitors, monitor to the left is primary
; need to redo for the generic case
GetMonitorIndexFromMouse()
{
SysGet, monitors_total, MonitorCount
SysGet, monitor_primary, MonitorPrimary
MouseGetPos, xpos, ypos
current_monitor := (xpos > A_ScreenWidth) ? 2 : 1
return current_monitor
}
; this function is from autohotkey.com/board/topic/69464-how-to-determine-a-window-is-in-which-monitor/?p=440355
GetMonitorIndexFromWindow(windowHandle)
{
; Starts with 1.
monitorIndex := 1
VarSetCapacity(monitorInfo, 40)
NumPut(40, monitorInfo)
if (monitorHandle := DllCall("MonitorFromWindow", "uint", windowHandle, "uint", 0x2))
&& DllCall("GetMonitorInfo", "uint", monitorHandle, "uint", &monitorInfo)
{
monitorLeft := NumGet(monitorInfo, 4, "Int")
monitorTop := NumGet(monitorInfo, 8, "Int")
monitorRight := NumGet(monitorInfo, 12, "Int")
monitorBottom := NumGet(monitorInfo, 16, "Int")
workLeft := NumGet(monitorInfo, 20, "Int")
workTop := NumGet(monitorInfo, 24, "Int")
workRight := NumGet(monitorInfo, 28, "Int")
workBottom := NumGet(monitorInfo, 32, "Int")
isPrimary := NumGet(monitorInfo, 36, "Int") & 1
SysGet, monitorCount, MonitorCount
Loop, %monitorCount%
{
SysGet, tempMon, Monitor, %A_Index%
; Compare location to determine the monitor index.
if ((monitorLeft = tempMonLeft) and (monitorTop = tempMonTop)
and (monitorRight = tempMonRight) and (monitorBottom = tempMonBottom))
{
monitorIndex := A_Index
break
}
}
}
return monitorIndex
}
One of the functions (GetMonitorIndexFromWindow(windowHandle)) is not mine, taken from here.
Note that I haven’t got time to work on generic case for my GetMonitorIndexFromMouse() function, so it’s just good for my specific case (2 monitors, with the left one as primary).
I have isDebug := true here, so that you could see the tooltip with variables − feel free to change it to isDebug := false of course, if the script works for you.
I'm trying to use Autohotkey for reading out some RAM values. To do this I'm using the following library:
https://github.com/Kalamity/SC2-MacroTrainer/blob/master/Lib/classMemory.ahk
Documention on how this library works is clearly written on top of it, but it lacks any documentation on how to use this with a module.
My base pointer is: "jvm.dll"+00338E84
My offsets are (top to bottom): 0x8, 0x294, 0x4B8, 0x24, 0x20
My code so far is:
#include %a_scriptdir%/classMemory.ahk
java := new _ClassMemory("ahk_exe javaw.exe", "", hProcessCopy)
if !isObject(java)
msgbox failed to open a handle
myBase := java.getModuleBaseAddress("jvm.dll")
pointerBase := myBase + 0x00338E84
arrayPointerOffsets := [0x20, 0x24, 0x4B8, 0x294, 0x8]
value := java.read(pointerBase, "UInt", arrayPointerOffsets*)
msgbox %value%
Unfortunately this is not working. Obviously the pointerBase calculation is wrong. Been trying to use all kinds of variations for 2 days now without success. Could anyone explain me what I'm doing wrong and how to fix it?
I don't really have time to check the library you are using, but here are some tips:
If your target process runs as admin your program will have to, too. Also you might wanna set SeDebugPrivileges (if the lib isn't doing it on it's own).
If !A_IsAdmin {
Run *RunAs "%A_ScriptFullPath%"
ExitApp
}
SetSeDebugPrivilege()
SetSeDebugPrivilege(enable := True)
{
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", DllCall("GetCurrentProcessId"), "Ptr")
; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32)
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0) ; structure of privileges
NumPut(1, ti, 0, "UInt") ; one entry in the privileges array...
; Retrieves the locally unique identifier of the debug privilege:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
if enable
NumPut(2, ti, 12, "UInt") ; enable this privilege: SE_PRIVILEGE_ENABLED = 2
; Update the privileges of this process with the new access token:
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t) ; close this access token handle to save memory
DllCall("CloseHandle", "Ptr", h) ; close this process handle to save memory
return r
}
To read offsets you simply have to add them to your address.
So let's pretend you are memory reading a game. And you wanna read the health of player one which is always stored in ["example.dll"+0x01088450]+0x4 (as float value). Then you would have to go like this (if you work with raw ReadProcessMemory or similar):
player1moduleOffset := 0x01088450
healthOffset := 0x4
moduleBaseAddress := GetModuleAddr("example.dll")
player1BaseAddress := moduleBaseAddress+player1moduleOffset
player1Base := MemoryReasAsInt(player1BaseAddress)
player1HealthAddress := player1Base+healthOffset
player1Health := MemoryReasAsFloat(player1HealthAddress)
With the help of the library developer I managed to fix the issue. This is the working code:
#include %a_scriptdir%/classMemory.ahk
java := new _ClassMemory("ahk_exe javaw.exe")
if !isObject(java)
msgbox failed to open a handle
baseAddress := java.getModuleBaseAddress("jvm.dll")
arrayPointerOffsets := [0x20, 0x24, 0x4B8, 0x294, 0x8]
value := java.read(baseAddress + 0x00338E84, "UInt", arrayPointerOffsets*)
msgbox %value%
Say I call a function that uses a byref modifier. Once in the function, I want to fetch the string value of the passed variable.
myvar := "george"
passit(myvar)
passit(byref whatvar){
msgbox % %whatvar% ;I should see a messagebox reporting the string "myvar"
}
Getting the string value of the variable works fine if I'm not passing the variable byref.
Maybe I'm going about this the wrong way. I want the function to know the string name for the variable being referenced.
This approch uses the buildin ListLines-Command to access the needed metadata.
The command ListLines opens the main window of the current script and displays the last executed script lines.
Content looks like this:
Script lines most recently executed (oldest first). Press [F5] to refresh. The seconds elapsed between a line and the one after it is in parentheses to the right (if not 0). The bottommost line's elapsed time is the number of seconds since it executed.
---- D:\Eigene_Dateien\ahk scripts\test3.ahk
002: myvar := "george"
003: passit(myvar)
007: MsgBox,GetOriginalVariableNameForSingleArgumentOfCurrentCall(A_ThisFunc)
012: lines := ListLines()
Press [F5] to refresh.
This data can be parsed to extract the wanted information (what is passed to 'passit').
One problem here is, that there is no buildin programmatically way of access this info.
The function ListLines overrides temporary User32.ShowWindow and User32.SetForgroundWindow to return simply true, so the buildin command ListLines can be used without displaying its window (Might produce problems with multithreaded scripts). From this 'hidden' window its text is received and cleaned up. Function is written by Lexikos (http://www.autohotkey.com/board/topic/20925-listvars/#entry156570 http://www.autohotkey.com/board/topic/58110-printing-listlines-into-a-file/#entry365156).
GetOriginalVariableNameForSingleArgumentOfCurrentCall extracts the variable name with a regular expression, which searches the first call to the passed function above the current call (call to GetOriginalVariableNameForSingleArgumentOfCurrentCall).
myvar := "george"
passit(myvar)
return
passit(whatvar){
msgbox % GetOriginalVariableNameForSingleArgumentOfCurrentCall(A_ThisFunc)
}
GetOriginalVariableNameForSingleArgumentOfCurrentCall(callerFuncName)
{
lines := ListLines()
pattern = O)%callerFuncName%\((.*?)\).*?%A_ThisFunc%\(.*?\)
RegExMatch(lines, pattern, match)
return match[1]
}
; Originally written by Lexikos / Copy of ListGlobalVars http://www.autohotkey.com/board/topic/20925-listvars/#entry156570
; with modifications from here http://www.autohotkey.com/board/topic/58110-printing-listlines-into-a-file/#entry365156
; Tested/Modified for AHK Unicode 64bit v1.1.14.03
ListLines()
{
static hwndEdit, pSFW, pSW, bkpSFW, bkpSW
ListLines Off
if !hwndEdit
{
dhw := A_DetectHiddenWindows
DetectHiddenWindows, On
Process, Exist
ControlGet, hwndEdit, Hwnd,, Edit1, ahk_class AutoHotkey ahk_pid %ErrorLevel%
DetectHiddenWindows, %dhw%
astr := A_IsUnicode ? "astr":"str"
ptr := A_PtrSize=8 ? "ptr":"uint"
hmod := DllCall("GetModuleHandle", "str", "user32.dll")
pSFW := DllCall("GetProcAddress", ptr, hmod, astr, "SetForegroundWindow")
pSW := DllCall("GetProcAddress", ptr, hmod, astr, "ShowWindow")
DllCall("VirtualProtect", ptr, pSFW, ptr, 8, "uint", 0x40, "uint*", 0)
DllCall("VirtualProtect", ptr, pSW, ptr, 8, "uint", 0x40, "uint*", 0)
bkpSFW := NumGet(pSFW+0, 0, "int64")
bkpSW := NumGet(pSW+0, 0, "int64")
}
if (A_PtrSize=8) {
NumPut(0x0000C300000001B8, pSFW+0, 0, "int64") ; return TRUE
NumPut(0x0000C300000001B8, pSW+0, 0, "int64") ; return TRUE
} else {
NumPut(0x0004C200000001B8, pSFW+0, 0, "int64") ; return TRUE
NumPut(0x0008C200000001B8, pSW+0, 0, "int64") ; return TRUE
}
ListLines
NumPut(bkpSFW, pSFW+0, 0, "int64")
NumPut(bkpSW, pSW+0, 0, "int64")
; Retrieve ListLines text and strip out some unnecessary stuff:
ControlGetText, ListLinesText,, ahk_id %hwndEdit%
RegExMatch(ListLinesText, ".*`r`n`r`n\K[\s\S]*(?=`r`n`r`n.*$)", ListLinesText)
StringReplace, ListLinesText, ListLinesText, `r`n, `n, All
ListLines On
return ListLinesText ; This line appears in ListLines if we're called more than once.
}
The closest to what you would want...? This reminds of a question I had.
See http://ahkscript.org/boards/viewtopic.php?f=14&t=3651
myvar:="test"
passit("myvar") ; display value, and change it
msgbox % "myvar = " myvar
passit(byref whatvar){ ; no more need for byref here...
msgbox % whatvar " = " (%whatvar%)
%whatvar%:="blah" ; edit globalvar "hack"
}