1 (изменено: vo1ty, 2012-11-13 23:03:12)

Тема: PHP: Ссылки, указатели, WINAPI и DynamicWrapperX

Доброго времени суток! Думал написать на PHP приложение, использующее Windows API. Сначала решил узнать, как оно вообще, можно ли вообще это сделать.

Проблема здесь не одна, а целых две. Первая заключается в том, что некоторые функции требуют им передать ссылку на какую-нибудь структуру.
Структура? А что такое структура?

struct S { int x; int y; }

Памяти, насколько мне известно, эта структура занимает 8 байт (если, конечно, int занимает 4 байта). Первые 4 для переменной x, последние - для y.
Есть ли подобные конструкции в PHP? Вот вопрос.
Вот страничка официального сайта PHP:
http://www.php.net/manual/ru/spl.datastructures.php
Здесь есть несколько видов структур данных, но, кажется, ни один из них не подходит, кроме, казалось бы, "Массивов". Описание:

структуры, которые хранят данные в непрерывном виде, доступные через индексы

Может показаться, будто это то, что нужно, но на деле, наверное, это обычный массив, как в C/C++.

Вторая проблема. Структуры явно не передаются параметрами функции Win32API, они передаются по ссылкам. PHP умеет принимать аргументы пользовательских функций "по ссылке", но передаются они при этом самым обычным способом, так, будто это и не ссылка.

function a ($s)
{
// ...
  $s = 1; // $s - копия переменной $b
}
$b = 10;
a($b); // передаём копию переменной $b
echo $b; // выведет 10


function c (&$lnk) // принимаем ссылку
{
// ...
  $lnk = 30 // устанавливаем значение $d в 30
}
$d = 15;
c($d); // ПЕРЕДАЁМ ТАК, КАК ОБЫЧНУЮ ПЕРЕМЕННУЮ
echo $d; // 30

Поэтому я совсем не уверен, что вообще можно передать именно ссылку. Но надеюсь, что ошибаюсь.

В любом случае, хотя бы одна из этих проблем существует, потому что, казалось бы, верный код:

<?php
$com = new COM("DynamicWrapperX");
$com->Register("user32", "GetCursorPos", "i=h", "r=l");

$c = new SplFixedArray(2);
$com->GetCursorPos($c);
?>

Выдаёт такую ошибку:

PHP Fatal error:  Uncaught exception 'com_exception' with message 'Error [0x80070057] Параметр задан неверно.
' in D:\CODE\php\dynwrap.php:4
Stack trace:
#0 D:\CODE\php\dynwrap.php(4): com->GetCursorPos(Object(SplFixedArray))
#1 {main}
  thrown in D:\CODE\php\dynwrap.php on line 4

Надеюсь, кто-нибудь знает, как решить такую проблему.

2

Re: PHP: Ссылки, указатели, WINAPI и DynamicWrapperX

Уточните, о чём всё-таки речь: DynamicWrapper или DynamicWrapperX. Если последний, то можно зарегистрировать API, выделяющую память, — например, GlobalAlloc — и запросить нужное количество байт под структуру. Так и получите указатель на структуру. Писать туда значения её членов можно методом NumPut, а читать методом NumGet. Тип параметра в GetCursorPos обозначить как "i=p".

3 (изменено: vo1ty, 2012-11-14 16:59:02)

Re: PHP: Ссылки, указатели, WINAPI и DynamicWrapperX

YMP пишет:

Уточните, о чём всё-таки речь: DynamicWrapper или DynamicWrapperX. Если последний, то можно зарегистрировать API, выделяющую память, — например, GlobalAlloc — и запросить нужное количество байт под структуру. Так и получите указатель на структуру. Писать туда значения её членов можно методом NumPut, а читать методом NumGet. Тип параметра в GetCursorPos обозначить как "i=p".

Это трудно назвать нормальным способом, скорее костыль какой-то, но, к сожалению, в PHP, видимо, нет другого способа, поэтому только так. Тем не менее, он работает, и вот рабочий код, который пишет позицию курсора:

<?php
$com = new COM("DynamicWrapperX"); // 
$com->Register("user32", "GetCursorPos", "i=p", "r=l"); // регистрируем GetCursorPos
$com->Register("kernel32", "GlobalAlloc", "i=ll", "r=p"); // и GlobalAlloc

$addr = $com->GlobalAlloc(0, 8); // выделяем 8 байт под структуру POINT
// и присваиваем переменной $addr её адрес.
$com->GetCursorPos($addr); // вызываем GetCursorPos
$x = $com->NumGet($addr, 0, "l"); // выдёргиваем первые 4 байта в $x
$y = $com->NumGet($addr, 4, "l"); // и последние в переменную $y
echo "$x $y";
?>

Спасибо, YMP. Спасибо за библиотеку и подсказку, как её использовать в PHP.