There is a better way. I will provide the code for you, with the following disclaimer:
The following code has been tested with Windows XP SP2. It lacks comprehensive error checking and due to differences between systems, and especially between versions of Windows, may cause the Windows shell (i.e., Explorer) to crash.
If you're willing to run the code and report back the information presented in each dialog -- especially that in the "button information" dialog -- then I can help you further.
Code:
WM_USER = 0x400
hw_notification_area := FindWindow( "Shell_TrayWnd|TrayNotifyWnd|SysPager|ToolbarWindow32,Notification Area" )
MsgBox, hw_notification_area = %hw_notification_area%
VarSetCapacity( pid_explorer, 4 )
WinGet, pid_explorer, PID, ahk_id %hw_notification_area%
MsgBox, pid_explorer: %pid_explorer%
hp_explorer := DllCall( "OpenProcess", "uint", 0x8|0x10, "int", true, "uint", pid_explorer )
MsgBox, openprocess: %ErrorLevel% - %hp_explorer%
remote_buffer := DllCall( "VirtualAllocEx"
, "uint", hp_explorer
, "uint", 0
, "uint", 0x1000
, "uint", 0x1000
, "uint", 0x4 )
MsgBox, virtualallocex: %ErrorLevel% - %remote_buffer%
TB_BUTTONCOUNT := WM_USER+24
SendMessage, TB_BUTTONCOUNT, 0, 0,, ahk_id %hw_notification_area%
MsgBox, button count = %ErrorLevel%
TB_GETBUTTON := WM_USER+23
SendMessage, TB_GETBUTTON, 0, remote_buffer,, ahk_id %hw_notification_area%
MsgBox, TB_GETBUTTON: %ErrorLevel%
remote_buffer2 := remote_buffer+200
TB_GETITEMRECT := WM_USER+29
SendMessage, TB_GETITEMRECT, index, remote_buffer2,, ahk_id %hw_notification_area%
MsgBox, TB_GETITEMRECT: %ErrorLevel%
VarSetCapacity( buffer, 1000, 0 )
VarSetCapacity( buffer_actual_size, 4, 0 )
pBuffer2 := &buffer+200
result := DllCall( "ReadProcessMemory"
, "uint", hp_explorer
, "uint", remote_buffer
, "uint", &buffer
, "uint", 1000
, "uint", &buffer_actual_size )
buffer_actual_size := ReadInteger( "uint", &buffer_actual_size, 0 )
MsgBox, readprocessmemory: %ErrorLevel% - %result% ~ %buffer_actual_size%
; -- data --
VarSetCapacity( buffer2, 1000, 0 )
VarSetCapacity( buffer_actual_size, 4, 0 )
result := DllCall( "ReadProcessMemory"
, "uint", hp_explorer
, "uint", ReadInteger( "int", &buffer, 12 )
, "uint", &buffer2
, "uint", 1000
, "uint", &buffer_actual_size )
buffer_actual_size := ReadInteger( "uint", &buffer_actual_size, 0 )
MsgBox, readprocessmemory: %ErrorLevel% - %result% ~ %buffer_actual_size%
; -- string --
VarSetCapacity( buffer3, 1000, 0 )
VarSetCapacity( buffer_actual_size, 4, 0 )
result := DllCall( "ReadProcessMemory"
, "uint", hp_explorer
, "uint", ReadInteger( "int", &buffer, 16 )
, "uint", &buffer3
, "uint", 1000
, "uint", &buffer_actual_size )
buffer_actual_size := ReadInteger( "uint", &buffer_actual_size, 0 )
MsgBox, readprocessmemory: %ErrorLevel% - %result% ~ %buffer_actual_size%
MsgBox, %
( Join
"-- [" A_Index-1 "] button information --"
"`n`ncommand = " ReadInteger( "int", &buffer, 4 )
"`nstate = " ReadInteger( "uchar", &buffer, 8 )
"`ndata = " ReadInteger( "uint", &buffer, 12 )
"`nstring = " ReadInteger( "int", &buffer, 16 )
"`n`nrect = " ReadInteger( "int", pBuffer2, 0, false )
", " ReadInteger( "int", pBuffer2, 4, false )
", " ReadInteger( "int", pBuffer2, 8, false )
", " ReadInteger( "int", pBuffer2, 12, false )
"`n`ndata = " ReadInteger( "uint", &buffer2, 0 )
"`nstring = " ReadStringA( &buffer3, 0, 1000 )
)
ExitApp
TwosComplement( p_value, p_size )
{
return, ( p_value^( 2**( p_size*8 )-1 ) )+1
}
ReadInteger( p_type, p_address, p_offset, p_hex=true )
{
old_FormatInteger := a_FormatInteger
if ( p_hex )
SetFormat, integer, hex
else
SetFormat, integer, dec
if ( p_type = "int" )
{
sign := true
size = 4
}
else if ( p_type = "uint" )
{
sign := false
size = 4
}
else if ( p_type = "short" )
{
sign := true
size = 2
}
else if ( p_type = "ushort" )
{
sign := false
size = 2
}
else if ( p_type = "char" )
{
sign := true
size = 1
}
else if ( p_type = "uchar" )
{
sign := false
size = 1
}
else
MsgBox, [ReadInteger] error: the type %p_type% is undefined!
value = 0
loop, %size%
value := value+( *( ( p_address+p_offset )+( a_Index-1 ) ) << ( 8*( a_Index-1 ) ) )
if ( sign )
{
sign := ( *( p_address+p_offset+( size-1 ) ) ) >> 7
if ( sign )
value := -1*TwosComplement( value, size )
}
SetFormat, integer, %old_FormatInteger%
return, value
}
ReadStringA( p_address, p_offset, p_size )
{
text=
address := p_address+p_offset-2
loop, %p_size%
{
address += 2
if ( *( address ) = 0 )
break
text := text Chr( *( address ) )
}
return, text
}
FindWindow( p_tree )
{
level_total = 0
loop, parse, p_tree, |
{
level_total++
ix := InStr( a_LoopField, "," )
if ( ix )
{
StringMid, tree[%level_total%]?class, a_LoopField, 1, ix-1
StringMid, tree[%level_total%]?title, a_LoopField, ix+1, StrLen( a_LoopField )-ix
}
else
{
tree[%level_total%]?class := a_LoopField
tree[%level_total%]?title = 0
}
}
hw_parent = 0
hw_child = 0
level = 1
loop,
{
hw_child := FindWindowEx( hw_parent, hw_child, tree[%level%]?class, tree[%level%]?title )
if ( hw_child )
{
if ( level = level_total )
return, hw_child
level++
hw_parent_old := hw_parent
hw_parent := hw_child
hw_child_old := hw_child
hw_child = 0
}
else
{
if ( level = 1 )
return, 0
level--
hw_parent := hw_parent_old
hw_child := hw_child_old
}
}
}
FindWindowEx( p_hw_parent, p_hw_child, p_class, p_title=0 )
{
if ( p_title = 0 )
type_title = uint
else
type_title = str
return, DllCall( "FindWindowEx"
, "uint", p_hw_parent
, "uint", p_hw_child
, "str", p_class
, type_title, p_title )
}