1

システムトレイのすべてのアイコンを読み取り、それらの座標を取得して、誰がそれらを所有しているかを調べるスクリプトをPerlで作成しようとしています。私はこのコードをここで翻訳しようとしています。

これまでの私のコードは次のとおりです。

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";

システム トレイ ハンドルを取得するために autoit COM DLL を使用しています。トレイ ハンドルを取得したら、そのプロセス ID を取得し、プロセス メモリを読み取って、次のように定義されているTBBUTTON 構造体を取得しようとします。

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";

私が間違っていることについて何か提案はありますか?ありがとう。

4

1 に答える 1

0

プルしているさまざまなものによってもたらされる不確実性の量を最小限に抑え、Win32::GuiTestによって提供される機能を使用することにしました。また、32 ビットの WinXP SP3 ラップトップで何かを実行するために、ビット数と構造体に関して不正を行いました。実行して出力を生成するものを次に示します。

これが正しい出力かどうかはわかりませんが、少なくともより単純な方向に向けられるはずです。

#!/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関数や構造体などを 1 か所で 1 回だけ定義する必要があるわけではありません。

出力例:

655544
393294
---
プロセス: 1920
ポイント: 28835840
トライボタン=19

TB_GETBUTTON ステータス = 1
---
- 7
- 9
- C
- 0
- 0
- 0
-1DA23C8
- 2B70590
于 2012-06-26T11:12:38.517 に答える