Pull to refresh

COM-автоматизация OpenOffice: Чтение содержимого буфера обмена

Reading time5 min
Views3.1K

Часть первая (надеюсь, что не последняя)


Долгое время для меня OpenOffice оставался вещью-в-себе. Я знал, что он прекрасно автоматизируется питонами и бейсиками, но, вот, для PHP никак не мог найти подходящего инструмента. Совершенно случайно обнаружил такую интересную возможность OpenOffice: получение доступа к содержимому буфера обмена Windows. Тогда мне очень не хватало возможности писать простые CLI-скрипты, обрабатывающие текст в буфере на языке PHP. Поэтому я решил основательно разобраться, как можно рулить опен-офисом с помощью рнр из-под винды.


Вот, собственно, решение


<?php
// PHP OpenOffice: работа с COM-объектами
$oo = new COM("com.sun.star.ServiceManager");
$clipboard = $oo->CreateInstance(
 "com.sun.star.datatransfer.clipboard.SystemClipboard");
$converter = $oo->CreateInstance("com.sun.star.script.Converter");
$contents = $clipboard->getContents();
$flavors = $contents->getTransferDataFlavors();
$result = false;
foreach ($flavors as $mm)
  {
  $mime = $mm->MimeType;
  // echo "$mime\r\n"; // DEBUG
  if ($mime=="text/plain;charset=utf-16")
    {
    $data = $contents->getTransferData($mm);
    // "com.sun.star.uno.TypeClass.STRING" ==> 12
    $result = $converter->convertToSimpleType($data, 12);
    break;
    }
  }
echo $result;


Как это все работает


Сначала создается компонент служебного менеджера, "com.sun.star.ServiceManager", который нужен для подключения компонентов буфера и конвертера, поскольку, напрямую создать компонент буфера "com.sun.star.datatransfer.clipboard.SystemClipboard" не получится. Менеждер занимается диспетчеризацией вызовов функций UNO-интерфейса. В результате, в ответ на запросы CreateInstance() в высшую «инстанцию», получаются полноценные экземпляры нужных нам COM-компонентов.
Содержимое буфера извлекается методом getContents(). Это содержимое очень хитро устроено, представлено в нескольких различных форматах (на вкус и цвет). Полный набор ароматов форматов выдает метод getTransferDataFlavors(). В результате имеем составной объект, элементы которого можно перебрать в цикле foreach (..as..).

Каждый элемент сам по себе тоже не менее хитрый. С помощью свойства MimeType определяется тип содержимого. Этот тип содержимого возвращается в виде обычной строки. Нас будет интересовать только "text/plain;charset=utf-16".

Для получения же самих переносимых данных буфера, понадобится метод getTransferData().

И, тут нас ожидает первый облом:


В отличие от MimeType, который представляет собой простое текстовое значение, результат метода выдается не строкой, (которую можно было бы потом просто перекодировать функцией iconv() в нужную кодировку), а, вариантным типом, с которым не так-то просто подружиться в PHP.

Вероятнее всего это сделано так, потому что кроме текстового содержимого, в буфере могут лежать, картинки, музыка и прочая мультимедия, и выдавать ее в виде строки не всегда кошерно.

Конверсия


Эту проблему решает специальный компонент-конвертер "com.sun.star.script.Converter", который так же создается менеджером.

У конвертера есть метод, преобразующий вариантные значения в простые типы convertToSimpleType(), которому нужно скормить сам вариант, и передать «магическую» константу 12 ("com.sun.star.uno.TypeClass.STRING"), соответствующую обычным строкам.

Но, тут — второй облом:


В результате получается строка в кодировке Windows-1251, что может привести к искажению или потере исходных символов (в кодировке Unicode) не вписывающихся в прокрустово ложе виндовой кодовой таблицы.

Дисклеймер


На мой вздляд, решение получилось весьма изящным, однако я ожидаю получить и противоположную реакцию со стороны настоящих гуру программирования, что, типа, опять, мол, в Хабре появляется новое поколение школоло PHP-Быдлокодеров, сидящих в Виндузовой командной строке, и пишущих Хэлловорды для офисной COM-автоматизации чтобы всего-то, прочитать текст из буфера.

В общем-то, место для данного топика должно быть в блоге «Q&A», и его содержание было искусственно раздуто до размера «полновесной» статьи.

К сожалению в интерфейсе Хабра-Песочницы нет возможности указать предпочитаемый блог для публикации поста.
Так же из Read-Only аккаунта нет возможности написать письмо кому-нибудь из Хабраюзеров напрямую, с просьбой запостить вопрос в блог Q&A.

Вот, собственно, сами вопросы:


1. Есть ли еще какие-нибудь альтернативные способы получения доступа к содержимому буфера обмена Windows, аналогичные OpenOffice, без подключения дополнительных php-расширений через COM-автоматизацию, например, какого-нибудь MS-Office или даже Internet Explorer? Статья получилась бы более интересной, если бы читателю было предложено на выбор несколько различных способов решения проблемы, и возможность автоматически получить доступ к содержимому буфера, любым доступным способом, в зависимости от того, какое конкретное дополнительное программное обеспечение в системе было установлено. То есть, обеспечить некую кроссплатформенность (ну, или же «кросс-офисность», если хотите).

2. Ну, читать буфер мы кое-как научились, а, как в этот буфер теперь что-то записать? Сразу вынужден предупредить, что решение по записи в буфер будет выглядеть не столь изящно и прозрачно. По крайненй мере, самостоятельно «навелосипедить» решение этой задачи мне так и не удалось. И, разумеется, в полноценной статье описание обратной операции просто обязано присутствовать. Хотя, еще раз, повторю, что мне самому было в первую очередь нужно именно прочитать содержимое текстового буфера, и кодировка Windows-1251 полностью соответствовала моим аппетитам.

3. Ну, если, с текстовым содержимым буфера, все понятно, то, как быть с графикой? Очень бы хотелось бы получить графическое содержимое буфера, например в виде GD2-объекта, и, еще, чтоб можно было «рисовать» прямо-в-буфере, то есть, иметь возможность синхронизировать содержимое буфера с состоянием GD2-объекта. Помню, как, еще, во времена 98 Windows, один мой друган произвел на меня неизгладимое впечатление, вставив в MsPaint из буфера обмена ФИЛЬМ, скопированный из Медиаплейера в режиме воспроизведения. Я был тогда просто в шоке, когда увидел движущееся изображение на фоне открытого рисунка. В то время я еще плохо понимал, как устроена винда, и мною это воспринималось, как настоящая магия.

P.S.


Статья, конечно же, была бы более полезной, если бы описывала универсальный доступ на чтение-запись к любому типу содержимого, чтобы можно было, например, экспортировать содержимое конкретного типа в файлы соответствующего формата.

Очень надеюсь, найти в комментариях к статье ответы на все эти вопросы, или, хотя бы сами эти вопросы, любезно перенесенные заинтересованными читателями этой статьи в блог «Q&A» в случае, если этому топику так и не удастся покинуть пределы Хабрапесочницы.

Каюсь, ссылок на авторитетные источники вдохновения не дал, надеюсь, в комментариях этот недостаток будет скомпенсирован.
Tags:
Hubs:
Total votes 27: ↑19 and ↓8+11
Comments5

Articles