2012-06-26 1 views
1

시스템 트레이에있는 모든 아이콘을 읽으려면 Perl에서 스크립트를 작성하려고합니다. 좌표를 가져와 &을 소유하고있는 사람을 찾습니다. 나는 거의 번역하려고 노력하고있다 this code here. 나는 시스템 트레이 핸들을 얻을하는 AutoIt COM DLL을 사용하고Perl을 사용하면 Windows의 작업 표시 줄 알림 영역에있는 아이콘에 대한 정보를 어떻게 얻을 수 있습니까?

use strict; 
use warnings; 

use Win32::API; 
use Win32::OLE qw(in); 
use Data::Dumper; 

use constant wbemFlagReturnImmediately => 0x10; 
use constant wbemFlagForwardOnly  => 0x20; 

use constant SYNCHRONIZE => 0x00100000; 
use constant STANDARD_RIGHTS_REQUIRED => 0x000F0000; 
use constant PROCESS_ALL_ACCESS => (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF); 

my $TB_BUTTONCOUNT  = 0x0418; 
my $TB_GETBUTTONTEXT = 0x041B; 
my $TB_GETBUTTONINFO = 0x0441; 
my $TB_GETITEMRECT  = 0x041D; 
my $TB_GETBUTTON  = 0x0417; 

sub get_windows_details { 
    my ($self) = @_; 
    my $ret; 

    my $objWMIService = 
     Win32::OLE->GetObject("winmgmts:\\\\localhost\\root\\CIMV2") 
     or die "WMI connection failed.\n"; 
    my $colItems = 
     $objWMIService->ExecQuery("SELECT * FROM Win32_OperatingSystem", 
           "WQL", 
           wbemFlagReturnImmediately | wbemFlagForwardOnly); 

    my $objItem; 
    foreach $objItem (in $colItems) { 
     $ret->{'osname'} = $objItem->{Caption}; 
    } 

    $colItems = 
     $objWMIService->ExecQuery("SELECT * FROM Win32_Processor", 
           "WQL", 
           wbemFlagReturnImmediately | wbemFlagForwardOnly); 

    foreach $objItem (in $colItems) { 
     $ret->{'osbit'} = $objItem->{AddressWidth}; 
    } 

    return $ret; 
} 

sub get_autoit_tray_handle { 
    my $autoit = Win32::OLE->new("AutoItX3.Control") 
     or return 0; 
    my $tray_hwnd = $autoit->ControlGetHandle("[Class:Shell_TrayWnd]", "", "[Class:ToolbarWindow32;Instance:1]"); 
    return hex $tray_hwnd; 
} 

sub get_tray_icon_count { 
    #my $hWnd = get_tray_handle(); 
    my $hWnd = get_autoit_tray_handle(); 
    my $send_message = Win32::API->new("user32", "SendMessage", "NNII", "I"); 
    return $send_message->Call($hWnd, $TB_BUTTONCOUNT, 0, 0); 
} 



# Randomly chosen icon index. 
my $iIndex = 6; 

my $os = get_windows_details(); 
if ($os->{'osbit'} == 64) { 
    Win32::API::Struct->typedef('TBBUTTON', qw { int  iBitmap; 
               int  idCommand; 
               BYTE  fsState; 
               BYTE  fsStyle; 
               BYTE  bReserved[6]; 
               DWORD_PTR dwData; 
               INT_PTR iString; 
               } 
           ) or die "Typedef error $!\n"; 
} else { 
    Win32::API::Struct->typedef('TBBUTTON', qw { int  iBitmap; 
               int  idCommand; 
               BYTE  fsState; 
               BYTE  fsStyle; 
               BYTE  bReserved[2]; 
               DWORD_PTR dwData; 
               INT_PTR iString; 
               } 
           ) or die "Typedef error $!\n"; 
} 

# Get tray handle & it's proc id 
my $tb_button = Win32::API::Struct->new('TBBUTTON'); 
my $tray_hwnd = get_autoit_tray_handle(); 
print "tray hwnd: $tray_hwnd\n"; 
my $window_thread_proc_id = Win32::API->new('user32', "GetWindowThreadProcessId", 'LP', 'N'); 
my $lpdwPID = pack 'L', 0; 
my $pid = $window_thread_proc_id->Call($tray_hwnd, $lpdwPID); 
my $dwPID = unpack 'L', $lpdwPID; 
print "proc id: $dwPID\n"; 

# read the tray process memory to get the tray button info 
my $open_process = Win32::API->new('kernel32', 'OpenProcess', 'NIN', 'N') || die $!; 
my $proc_hwnd = $open_process->Call(PROCESS_ALL_ACCESS, 0, $dwPID); 
print "proc hwnd: $proc_hwnd\n"; 

my $virtual_alloc = Win32::API->new('kernel32', 'VirtualAllocEx', 'NNLNN', 'N'); 
my $lp_data = $virtual_alloc->Call($proc_hwnd, 0, $tb_button->sizeof(), 0x1000, 0x04); 
print "Error allocating memory: $!\n" if $!; 
print "Allocated addresss: $lp_data\n"; 

my $send_message = Win32::API->new('user32', 'SendMessage', 'NNIN','I'); 
my $get_button_status = $send_message->Call($tray_hwnd, $TB_GETBUTTON, $iIndex, $lp_data); 
print "TB_GETBUTTON Status: $get_button_status\n"; 

my $read_process = Win32::API->new('kernel32', 'ReadProcessMemory', 'NNSNP','I'); 
my $bytes_read = pack 'L', 0; 
$read_process->Call($proc_hwnd, $lp_data, $tb_button, $tb_button->sizeof(), $bytes_read); 
print "dwData: $tb_button->{'dwData'} \n"; 

:

여기에 지금까지 내 코드입니다. 나는이 트레이 핸들을 가지고 일단, 나는 그 다음 다음과 같이 정의된다 TBBUTTON structure를 얻을 수있는 프로세스 메모리를 읽을 프로세스 ID &의 얻으려고 :
if ($os->{'osbit'} == 64) { 
    Win32::API::Struct->typedef('TBBUTTON', qw { int  iBitmap; 
               int  idCommand; 
               BYTE  fsState; 
               BYTE  fsStyle; 
               BYTE  bReserved[6]; 
               DWORD_PTR dwData; 
               INT_PTR iString; 
               } 
           ) or die "Typedef error $!\n"; 
} else { 
    Win32::API::Struct->typedef('TBBUTTON', qw { int  iBitmap; 
               int  idCommand; 
               BYTE  fsState; 
               BYTE  fsStyle; 
               BYTE  bReserved[2]; 
               DWORD_PTR dwData; 
               INT_PTR iString; 
               } 
           ) or die "Typedef error $!\n"; 
} 

최소한에, 위의 코드를 실행

내 시스템은 다음과 같습니다.

tray hwnd: 401922 
proc id: 11040 
proc hwnd: 704 
Allocated addresss: 32702464 
TB_GETBUTTON Status: 1 
dwData: 10293610267052867588 

"dwData"는 잘못된 것 같습니다. 여기 내가 뭔가 잘못하고있는 것처럼 보입니다.

my $read_process = Win32::API->new('kernel32', 'ReadProcessMemory', 'NNSNP','I'); 
my $bytes_read = pack 'L', 0; 
$read_process->Call($proc_hwnd, $lp_data, $tb_button, $tb_button->sizeof(), $bytes_read); 
print "dwData: $tb_button->{'dwData'} \n"; 

내가 잘못하고있는 것에 대한 제안 사항이 있습니까? 감사.

+0

하지만 전혀하지 [이] (http://stackoverflow.com/a/1013870/100754) 도움? –

+0

Win32 :: Process :: Memory를 사용할 수 있다고 생각합니다. 그렇다면 Win32 :: API :: Struct를 사용하여 TBBUTTON 구조체를 버리고 전체 구조체를 직접 포장해야합니다. 나는이 옵션을 확실히 탐구 할 것이다. 그러나 관계없이, 나는 트레이 (Tray) 프로세스에서 버퍼로 프로세스를 진행할 때 내 코드에서 어떤 일이 일어나고 있는지를 알고 싶다. 이것이 바로 마지막 코드 블록이 성취하고자하는 단계입니다. –

+0

아무도 대답이 없으면 내일 볼 것입니다. 내가하지 않으면 나를 찌르십시오. 취침. – ikegami

답변

0

나는 여러분이 끌어 당기는 다양한 것들로 인한 불확실성을 최소화하기 위해 노력했으며, 단지 Win32::GuiTest이 제공하는 기능을 사용하기로 결정했습니다. 32 비트 WinXP SP3 랩톱에서 뭔가를 실행하기 위해 bitness와 structs에 대해서도 속임수를 사용했습니다. 실행되고 출력을 생성하는 무언가가 있습니다. 이것이 바로 출력하는 경우

나는 잘 모르겠지만, 그것은 간단 방향으로 이상 지점을해야한다 : 또한

#!/usr/bin/env perl 

use feature 'say'; 
use strict; use warnings; 

use Const::Fast; 
use Devel::CheckOS; 
use Win32::GuiTest qw(
    AllocateVirtualBuffer 
    FreeVirtualBuffer 
    ReadFromVirtualBuffer 
    FindWindowLike 
    SendMessage 
); 

use YAML; 

const my %TB => (
    BUTTONCOUNT => 0x0418, 
    GETBUTTONTEXT => 0x041B, 
    GETBUTTONINFO => 0x0441, 
    GETITEMRECT => 0x041D, 
    GETBUTTON => 0x0417, 
); 

const my %TBUTTON => (
    32 => 'iiCCCCLL', 
    64 => 'iiCCCCCCCCLL', 
); 

my ($tray_handle) = FindWindowLike(undef, undef, 'TrayNotifyWnd'); 

my ($toolbar_handle) = FindWindowLike($tray_handle, undef, 'ToolbarWindow'); 

say for ($tray_handle, $toolbar_handle); 

my $button_count = SendMessage($toolbar_handle, $TB{BUTTONCOUNT}, 0, 0); 

unless (defined($button_count) and $button_count > 0) { 
    die "Can't find buttons\n" 
} 

my $buf = AllocateVirtualBuffer($toolbar_handle, 0x20); 

print Dump $buf; 

my $index = int(rand $button_count); 

say "Trying button = $index\n"; 

my $status = SendMessage(
    $toolbar_handle, 
    $TB{GETBUTTON}, 
    $index, 
    $buf->{ptr} 
); 

say "TB_GETBUTTON status = $status"; 

my $result = ReadFromVirtualBuffer($buf, 0x20); 

FreeVirtualBuffer($buf); 

print Dump [ map sprintf('%X', $_), unpack $TBUTTON{32}, $result ]; 

이 아니라 한 곳에서 Win32::API 함수와 구조체 같은 것들을 정의 갈까요 것을 한 번만

샘플 출력 : 내가 지금 Windows 시스템에 아닙니다

655544 
393294 
--- 
process: 1920 
ptr: 28835840 
Trying button = 19 

TB_GETBUTTON status = 1 
--- 
- 7 
- 9 
- C 
- 0 
- 0 
- 0 
- 1DA23C8 
- 2B70590
+0

이것은 효과가 있습니다. 나는 Win32 :: GuiTest가 이러한 것들을 대부분 제공한다는 것을 알지 못했다. 고맙습니다! –