2016-02-07 2 views
1

Я пытаюсь вызвать функцию Win32 API из Perl с помощью Win32 :: API и передать массив массивов. Конкретная функция - WaitForMultipleObjects, и мне не нравится, как я ее подаю. Вот как это определено в Perl:Невозможно передать массив массивов дескрипторов Win32 :: API в Perl

# DWORD WaitForMultipleObjects(DWORD nCount, HANDLE* handles, BOOL, DWORD) 
$WaitForMultipleObjects = new Win32::API::More('kernel32', 
               'WaitForMultipleObjects', 'NPNN', 'N'); 

Тогда есть массив ручек. Все они подтверждены действительными, и все они работают, когда передаются по отдельности WaitForSingleObject. Вот как я упаковываю параметры:

my @handles; 
    ... 
    my $n = scalar(@handles); 
    my $handlePack = pack "L*", @handles; # also tried 'L1', 'L2', etc. 
    $rc = $WaitForMultipleObjects->Call($n, $handlePack, 0, 0xffffffff); # fails 

Это терпит неудачу, и GetLastError() сообщает об ошибке 6 (недопустимый дескриптор). Однако, если я прохожу только одну ручку, он работает:

my $handlePack = pack "L", $handles[0]; 
    $rc = $WaitForMultipleObjects->Call(1, $handlePack, 0, 0xffffffff); # works 

Очевидно Win32 :: API не может передать массив дескрипторов правильно во втором параметре, но, насколько я понимаю, в документации (https://metacpan.org/pod/Win32::API), вот как это должно быть. Или мое использование pack() неправильно? Я на 64-битном Perl, если это имеет значение.

ответ

2

Проблема 64 бит. В 64-разрядной версии Windows (и в 64-разрядном Perl) sizeof (HANDLE) = 8 байт. Таким образом, если программа работает в 64-битном Perl, она загружает 64-разрядные библиотеки DLL, и вам приходится обрабатывать дескрипторы с использованием Q (то есть 64-разрядных целых чисел). Использование L не будет работать, потому что оно содержит 32-битные int. Следующие исправляет проблему:

use Config qw(%Config); 

my $ptr_size = $Config{ptrsize}; 
my $ptr_format = 
    $ptr_size == 4 ? "L" : 
    $ptr_size == 8 ? "Q" : 
    die("Unsupported pointer size $ptr_size\n"); 

my $handlePack = pack $ptr_format."*", @handles; 

$rc = $WaitForMultipleObjects->Call($n, $handlePack, 0, 0xffffffff); 

Обратите внимание, что даже в 64-битный Perl, pack('I') все еще может производить 32 бит (в зависимости от компилятора). pack('J') (внутренний int Perl) также непригоден, поскольку, хотя он по крайней мере такой же большой, как указатель, он может быть больше (например, 32-разрядный Perl, построенный с использованием -Duse64bitint).

Смежные вопросы