 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
OceanMachine
Joined: 15 Oct 2007 Posts: 780 Location: England
|
Posted: Fri Mar 19, 2010 6:41 pm Post subject: COM help - AddEnum() Method in AHK? (Trying to find % CPU) |
|
|
Hi All,
I have used IE COM in the past to manupulate web pages, and I have found that great, once I got my head around it. I am trying to learn other things that can be done with COM, and am trying to convert some VBscript I have found to work with AHK.
The VBScript gets the % Processor time of all processes and displays them.
Below is the VBScript and what I have tried so far:
VBScript: | Code: | strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set objRefresher = CreateObject("WbemScripting.SWbemRefresher")
Set colItems = objRefresher.AddEnum _
(objWMIService, "Win32_PerfFormattedData_PerfProc_Process").objectSet
For i = 1 to 5
objRefresher.Refresh
For Each objItem in colItems
Wscript.Echo objItem.Name & " -- " & objItem.PercentProcessorTime
Next
Wscript.Echo
Wscript.Sleep 5000
Next |
And here is the "approximate AHK equivalent" that I am trying:
| Code: | #NoEnv
COM_Init()
Namespace := "root\cimv2"
Class := "Win32_PerfFormattedData_PerfProc_Process"
; objWMIService := COM_GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\" . Namespace)
objWMIService := COM_GetObject("winmgmts:\\.\" . Namespace)
objRefresher := COM_CreateObject("WbemScripting.SWbemRefresher")
colItems := COM_Invoke(COM_Invoke(objRefresher,"AddEnum",objWMIService,Class),"objectSet")
Loop, 5
{
COM_Invoke(objRefresher,"Refresh")
Loop, % COM_Invoke(colItems,"Length")
{
pItm := COM_Invoke(colItems,"Item",A_Index-1)
MsgBox, % COM_Invoke(pItm,"Name") . " -- " . COM_Invoke(pItm,"PercentProcecssorTime")
COM_Release(pItm), pItm := 0
}
Sleep, 5000
}
COM_Release(objWMIService), objWMIService := 0
COM_Release(objRefresher), objRefresher := 0
COM_Release(colItems), colItems := 0
COM_Term()
ExitApp |
Now I know I am probably doing something completely wrong (or not realising I have to use another COM function to achieve this), but I am getting a COM error as follows:
| Quote: | ---------------------------
COM Error Notification
---------------------------
Function Name: "AddEnum"
ERROR: Type mismatch.
(0x80020005)
ERROR2: Member not found.
(0x80020003)
Will Continue?
---------------------------
Yes No
--------------------------- |
Can anyone help with where I am going wrong please?
TIA |
|
| Back to top |
|
 |
OceanMachine
Joined: 15 Oct 2007 Posts: 780 Location: England
|
Posted: Sat Mar 20, 2010 4:57 pm Post subject: |
|
|
I managed to get something to work using the below code (based on some code I found by Sean), but the values always come back as 0 for this class (as explained here) unless you use a SWbemRefresher object... which is what I am trying to do above without success
I would like to get this working with a refresher, if anyone has any pointers?
Thanks in advance
| Code: | #NoEnv
COM_Init()
NameSpace := "root\cimv2"
Class := "Win32_PerfFormattedData_PerfProc_Process"
Query := "SELECT PercentProcessorTime FROM " . Class
objWMIService := COM_GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\" . NameSpace)
pset := COM_Invoke(objWMIService, "ExecQuery", Query)
penm := COM_Invoke(pset, "_NewEnum")
Loop
{
If COM_Enumerate(penm, pobj) = 0
{
MsgBox, % "Name: " COM_Invoke(pobj, "Name") " % Time: " COM_Invoke(pobj, "PercentProcessorTime")
COM_Release(pobj), pobj := 0
}
Else
Break
}
COM_Release(penm)
COM_Release(pset)
COM_Release(objWMIService)
COM_Term()
ExitApp
|
|
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sun Mar 21, 2010 5:52 am Post subject: |
|
|
| OceanMachine wrote: | ---------------------------
COM Error Notification
---------------------------
Function Name: "AddEnum"
ERROR: Type mismatch.
(0x80020005)
ERROR2: Member not found.
(0x80020003)
Will Continue?
---------------------------
Yes No
--------------------------- |
With COM.ahk, you should write it as:
| Code: | | COM_Invoke(objRefresher, "AddEnum", "+" objWMIService, Class) |
|
|
| Back to top |
|
 |
OceanMachine
Joined: 15 Oct 2007 Posts: 780 Location: England
|
Posted: Sun Mar 21, 2010 12:16 pm Post subject: |
|
|
Excellent, thanks Sean, that got rid of the error with AddEnum
What does the "+" actually do? Sorry for my ignorance, never seen that in the COM syntax before (I am a newb, as you can see).
Now I am having an issue accessing items within the objSet.
I can get a count of the number of processes (that matches how many processes I have running on my PC) with COM_Invoke(colItems,"Count") but I can't seem to access the items with COM_Invoke(colItems, "Item", A_Index-1 ). I tried several variations of this like COM_Invoke(colItems, "Item[" A_Index-1 "]") but obviously this is not the way to access the items...
The seems to be "Member Not Found" for member "Item" in "SWbemObjectSet", but looking on msdn here, the Item method is supposed to exist... - what am I doing wrong?
I get the following error:
| Quote: | ---------------------------
COM Error Notification
---------------------------
Function Name: "Item"
ERROR: (0x80041001)
PROG: SWbemObjectSet
DESC: Generic failure
HELP: ,0
ERROR2: Member not found.
(0x80020003)
Will Continue?
---------------------------
Yes No
--------------------------- |
Here is the code I am using now:
| Code: | #NoEnv
COM_Init()
Namespace := "root\cimv2"
Class := "Win32_PerfFormattedData_PerfProc_Process"
; objWMIService := COM_GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\" . Namespace)
objWMIService := COM_GetObject("winmgmts:\\.\" . Namespace)
objRefresher := COM_CreateObject("WbemScripting.SWbemRefresher")
colItems := COM_Invoke(COM_Invoke(objRefresher, "AddEnum", "+" objWMIService, Class), "objectSet")
Loop, 5
{
COM_Invoke(objRefresher, "Refresh")
MsgBox, % "Count: " COM_Invoke(colItems, "Count") ; <-- this works
Loop, % COM_Invoke(colItems, "Count")
{
pItm := COM_Invoke(colItems, "Item", A_Index-1 ) ; <-- this isn't working
sMsgTxt .= COM_Invoke(pItm, "Name") . " -- " . COM_Invoke(pItm, "PercentProcecssorTime") . "`n"
COM_Release(pItm), pItm := 0
}
MsgBox, %sMsgTxt%
}
COM_Release(objWMIService), objWMIService := 0
COM_Release(objRefresher), objRefresher := 0
COM_Release(colItems), colItems := 0
COM_Term()
ExitApp |
|
|
| Back to top |
|
 |
Sean
Joined: 12 Feb 2007 Posts: 2462
|
Posted: Sun Mar 21, 2010 3:48 pm Post subject: |
|
|
| OceanMachine wrote: | | What does the "+" actually do? Sorry for my ignorance, never seen that in the COM syntax before (I am a newb, as you can see). | It's explained in the post.
http://www.autohotkey.com/forum/viewtopic.php?t=22923
BTW, you're confused between Item of SWbemRefresher and Item of SWbemObjectSet which should be passed a string. Anyway, I don't recommend using Item which will be slow. Use instead:
| Code: | oEnum := COM_Invoke(colItems, "_NewEnum")
While COM_Enumerate(oEnum, pItm) = 0
...
|
|
|
| Back to top |
|
 |
OceanMachine
Joined: 15 Oct 2007 Posts: 780 Location: England
|
Posted: Sun Mar 21, 2010 6:41 pm Post subject: |
|
|
| Sean wrote: | | It's explained in the post. | So it is, sorry for that, I didn't think to use that.
| Sean wrote: | | BTW, you're confused between Item of SWbemRefresher and Item of SWbemObjectSet which should be passed a string. | Ah yes, sorry I meant to link here instead, which says there should be an Item method, no?
Anyway, if you advise it will be slower, I will use the "_NewEnum" way you suggested instead.
I used this in the below code (which is working BTW), but it seems that I have to refresh twice to get the values (probably for the same reason as I linked in my second post?) and also without a sleep of about 500ms-1 second between the refreshes, strange values come back...
Anyway if anyone is interested, here is the code I ended up with. Thanks Sean for all your help (once again) I will probably get round to making a more useful version of this and posting it, but this will be OK for now.
Please bear in mind that the second MsgBox showing both 'used' and 'idle' percentages is just a demo... you will probably find that they don't add up to 100% due to them being from different refreshes. They may not even add up to 100% when the parameter "all" is passed (maybe due to rounding issues) but the Idle and Total values should be OK, meaning you can use them to get values that add up to 100%.
| Code: | #NoEnv
OnExit, ExitSub
Hotkey, Esc, ExitSub
COM_Init()
MsgBox, % "##### ALL PROCESSES #####:`n`n" . GetCPUTime("all")
MsgBox, % "Called Separately (these values may not add up to 100%!):`n`nCPU Usage = " . GetCPUTime("used") . "%`nIdle: " . GetCPUTime("idle") . "%"
SetTimer, ShowCPUTip, 1000 ; will show a tip with the correct values for Used, Idle and _Total (which will add up to 100% as they are from the same refresh)
GoSub, ShowCPUTip
Return
ShowCPUTip:
CPUVals := GetCPUTime("all")
Loop, Parse, CPUVals , `n, `r
{
Loop, Parse, A_LoopField, `:
{
If ( A_Index = 1 )
ProcName := A_LoopField
Else If ( A_Index = 2 )
ProcVal := A_LoopField
}
If ( ProcName = "_Total" or ProcName = "Idle" )
%ProcName% := ProcVal
}
Used := _Total - Idle ; should be what is used
ToolTip, % "CPU Used: " Used "%`nIdle: " Idle "%`n_Total: " _Total "%"
Return
Esc::
ExitSub:
COM_Term()
ExitApp
Return
;####################################################################
;####################################################################
GetCPUTime(ReqType="used")
{
; Returns various values about CPU usage.
; default is to return the percent used = ( _Total - Idle )
; possible values are "used", "idle" or "all"
; the first 2 will return a single integer value
; and "all" will return a list of all
; enumerated processed found in the form:
; Name1:Value1`nName2:Value2
Namespace := "root\cimv2"
Class := "Win32_PerfFormattedData_PerfProc_Process"
objWMIService := COM_GetObject("winmgmts:\\.\" . Namespace)
objRefresher := COM_CreateObject("WbemScripting.SWbemRefresher")
colItems := COM_Invoke(COM_Invoke(objRefresher, "AddEnum", "+" objWMIService, Class), "objectSet")
; the need to refresh twice is explained here:
COM_Invoke(objRefresher, "Refresh") ; have to refresh first, only get values on the second refresh.
Sleep, 500 ; for some reason, values come back strangely if there is no sleep here, I found 500-1000ms seems to be best...
sMsgTxt := "", IdleTime := "", TotalTime := ""
COM_Invoke(objRefresher, "Refresh")
oEnum := COM_Invoke(colItems, "_NewEnum")
While( COM_Enumerate(oEnum, pItm) = 0 )
{
ItemName := COM_Invoke(pItm, "Name")
ItemVal := COM_Invoke(pItm, "PercentProcessorTime")
If ( ItemName = "Idle" )
IdleTime := ItemVal
Else If ( ItemName = "_Total" )
TotalTime := ItemVal
AllTime .= ItemName . ":" . ItemVal . "`n"
}
COM_Release(oEnum), oEnum := 0
If ( ReqType = "used" )
ReturnVal := TotalTime - IdleTime ; used cpu time
Else If ( ReqType = "idle" )
ReturnVal := IdleTime
Else If ( ReqType = "all" )
ReturnVal := AllTime
COM_Release(objWMIService), objWMIService := 0
COM_Release(objRefresher), objRefresher := 0
COM_Release(colItems), colItems := 0
Return IdleTime != "" ? ReturnVal : -1 ; -1 means there was a problem
} |
|
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|