Using the Windows COM in PHP


Occasionally, when developing a desktop application or service in PHP, you’ll need to delegate tasks to components of Windows. This is where COM comes in. Luckily, PHP has had working COM support for several years.

What is COM?

The best description of COM, in this context, comes from the PHP documentation:

“COM is an acronym for Component Object Model; it is an object orientated layer (and associated services) on top of DCE RPC (an open standard) and defines a common calling convention that enables code written in any language to call and interoperate with code written in any other language (provided those languages are COM aware). Not only can the code be written in any language, but it need not even be part of the same executable; the code can be loaded from a DLL, be found in another process running on the same machine, or, with DCOM (Distributed COM), be found in another process on a remote machine, all without your code even needing to know where a component resides.”

For the purposes of this post, I’d simplify that to the following:

COM defines a means of manipulating Windows applications and services which is independent of any programming language. As well, it provides a means to expose an interface to other applications to allow them to manipulate your application or service.

What Can I Do?

COM is especially useful for dealing with Microsoft-developed applications such as the Windows Registry, Internet Explorer, Office applications, and so on. Without COM, it is nearly impossible to elegantly interface with these applications in any meaningful way.

In this post, I’ll detail a few use-cases, with some example code, and provide some tools that will make developing your own applications easier.

Important Resources

OLE/COM Object Explorer:

OLE/COM Object Explorer provides detailed information about every “Object Class”, “Application ID”, “Type Library” and “Interface” exposed by COM on the Windows system. It is essential for COM application development.

MSDN Library:

MSDN Library provides (somewhat poor) documentation for a number of important COM objects, such as InternetExplorer, Word, etc. It’s not essential that you use this, but it can augment your understanding that you would otherwise gain from inspecting the Object signature.

com_print_typeinfo:

The com_print_typeinfo function in PHP will output a skeleton class of a COM Object, which can provide some useful information regarding the signature of that Object. This is the primary way that you will want to inspect COM Objects.

Wikipedia’s COM Article:

This article does a decent job of explaining some of the fundamentals of dealing with COM. Specifically, the Technical Details section is of particular help.

Terminology

COM is very-much-so designed in Object-Oriented style, so the terminology is all fairly straightforward if you are familiar with PHP’s OOP style.

Class

Each application is referred to as a class. This is similar to a Class in PHP, where the Object is an instance of a particular Class. It is a wrapper of sorts for all of the various methods that are exposed.

Interface

An interface defines what methods a particular class implements. Knowing which interfaces a class implements, you can know which methods are available and how they’re invoked.

Type Library

A type library defines a set of interfaces which a class implements.

GUID / Application ID

A GUID is a unique identifier that can be used to refer to an application or interface, rather than by object or interface name.

Useful Application Classes

InternetExplorer.Application

This COM Object provides an interface to Internet Explorer, which can be used to spawn a browser window, cause it to navigate, and trigger any number of events that the browser provides, such as printing.

Previously, I’ve used Internet Explorer as a quick and dirty rendering engine for report generation and printing. I’ll detail that process in one of the examples.

WScript.Shell

This COM Object provides an interface to a number of integral mid-level functions in Windows, such as registry access, shortcut creation and accessing system folders.

I’ll detail how to get and set registry values in one of the examples.

Excel.Application

This COM Object provides an interface to Microsoft Excel, which can be used to create Excel spreadsheets without having to rely on a third-party library.

The Basics in PHP

Before we get to any examples, let’s cover some of the basics of working with COM in PHP.

In the vast majority of situations, all you will need to do to access a COM Object is instantiate the COM class, with the name of the COM Object Class as the single parameter. Doing so should create an overloaded object with all of the methods of the Class.

If you would like to see what methods are exposed by the object, you can simply use com_print_typeinfo as mentioned earlier. This will output a signature for the class.

Lastly, you may wish to “sink” an events interface for the application you’re interfacing with. What this means is that you can create a class with methods that will be called when certain events occur (are dispatched) in the application. For instance, you may wish to sink the “ProgressChange” event in Internet Explorer’s DWebBrowserEvents2 interface, which will call your specified class method every time a download’s progress changes.

Examples (finally)

Here are a few examples of things you can do with COM.

Rendering and Printing a Report Using Internet Explorer

<?php
$report = array(
"file" => sys_get_temp_dir()."report.html",
"data" => array(
"title" => "Example Report",
"date" => date("F j, Y, g:i a"),
"employees" => array(
"Jim" => true,
"Rick" => false,
"Jane" => false,
"John" => true,
"Amy" => true,
"Don" => true
)
)
);

ob_start();
?>
<html>
<head>
<title><?php echo $report["data"]["title"]; ?></title>
</head>
<body>
<h1><?php echo $report["data"]["title"]; ?></h1>
<h2><?php echo $report["data"]["date"]; ?></h2>
<table>
<caption>Employee Attendance</caption>
<thead>
<tr>
<th>Name</th>
<th>Attended</th>
</tr>
</thead>
<tbody>
<?php
foreach($report["data"]["employees"] as $name => $attended) {
?>
<tr>
<td><?php echo $name; ?></td>
<td><?php echo $attended?"Yes":"No"; ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
</body>
</html>
<?php
file_put_contents($report["file"], ob_get_clean());

class IESink {
public $ie;
public $done = false;

public function __construct(&$ie) {
$this->ie = $ie;
}

public function DocumentComplete(&$dom, $url) {
// Print page on default printer
$this->ie->ExecWB(6, 2);
sleep(4); // Slightly inelegant way of waiting for the printer. There's probably an event we could use.
$this->ie->Quit();
}

public function OnQuit() {
$this->done = true;
}
}

$ie = new COM("InternetExplorer.Application");
$ie->Visible = true;
com_event_sink($ie, $sink = new IESink($ie), "DWebBrowserEvents2");
$ie->Navigate("file://{$report["file"]}");

while(!$sink->done) com_message_pump(4000);
?>

Change Your Windows Wallpaper Using the Registry

<?php
$registry = new COM("WScript.Shell");
$currentWallpaper = $registry->RegRead('HKEY_CURRENT_USER\Control Panel\Desktop\Wallpaper');
echo "{$currentWallpaper}\n";

$registry->RegWrite('HKEY_CURRENT_USER\Control Panel\Desktop\Wallpaper', 'C:\Documents and Settings\YourUser\Local Settings\Application Data\Microsoft\YourWallpaper.bmp');
?>

          
  1. No comments yet.
(will not be published)