前言
PHP可以在Win32平台中访问COM和DCOM对象。本文详细介绍PHP调用COM组件的方法,包括COM配置、COM类、DOTNET类、VARIANT类的使用,以及com_event_sink事件处理。
前提配置
需要手动在php.ini中开启COM扩展:
[COM_DOT_NET]
extension=php_com_dotnet.dll
COM配置项
| 名字 | 默认 | 可修改范围 | 说明 |
|---|---|---|---|
| com.allow_dcom | "0" | PHP_INI_SYSTEM | 如果打开此选项,PHP将被允许以D-COM(Distributed COM)客户方式操作,允许PHP脚本在远程服务器上实例化COM对象 |
| com.autoregister_typelib | "0" | PHP_INI_ALL | 当打开这个时,PHP将尝试从它实例化的对象类型库中注册常量 |
| com.autoregister_verbose | "0" | PHP_INI_ALL | 在对象实例化过程中加载类型库的任何问题都将使用PHP错误机制来报告 |
| com.autoregister_casesensitive | "1" | PHP_INI_ALL | 当打开这个(默认值)时,在自动加载的类型库中发现的常量将会大小写敏感地注册 |
| com.code_page | "" | PHP_INI_ALL | 控制在从COM对象传递字符串时使用的默认字符集代码页 |
| com.typelib_file | "" | PHP_INI_SYSTEM | 设置时,该文件应该包含一个文件,该文件包含应该在启动时加载的类型库列表 |
The COM class
COM类允许实例化一个OLE兼容的COM对象并调用其方法并访问其属性。
$obj = new COM("Application.ID");构造函数
COM::__construct ( string $module_name [, mixed $server_name [, int $codepage [, string $typelib ]]] )
参数说明:
- module_name:可以用一个ProgID、类ID或Moniker进行加载组件。ProgID通常是应用程序或DLL名称,然后是一个句点,然后是对象名称,类似:Word.Application
- server_name:应该加载和运行组件的DCOM服务器的名称。如果为NULL,则使用本地机器
- codepage:指定用于将字符串转换为unicode字符串的代码页,反之亦然
注意:函数参数问题
很多实例化的COM对象的方法参数,不能直接是字符串。如果您在遇到类似Error [0x80004002] ...,您正在通过COM调用类方法,它期望char作为一个参数,您不应该使用单字符串来调用该方法。
调用这种方法的正确方法是使用带有VT_UI1类型的变体:
$com = new COM('Some.Class.Name');
// This will fail
$var = 'a';
$com->DoSomething($var);
// This works correctly
$var = new VARIANT(ord('a'), VT_UI1);
$com->DoSomething($var);权限问题
如果你有权限问题比如不能打开或保存文档,试试这个(如果你正在运行IIS):
- 执行"dcomcnfg"
- 打开组件服务>计算机>我的计算机>DCOM配置
- 搜索Microsoft Office Word 97-2003文档
- 右键单击并打开属性,选择"身份"选项卡
- 通常情况下设置为"启动用户",将其更改为"交互式用户"或您选择的管理用户
实例化时的异常捕捉
try {
$var = new COM('Whatever.Something');
} catch (com_exception $e) {
//couldn't load, do something else like register
exec('regsvr32 /s whatever.dll');
}The DOTNET class
DOTNET类允许您从.NET程序集实例化一个类并调用其方法并访问其属性。
$obj = new DOTNET("assembly", "classname");构造函数
DOTNET::__construct ( string $assembly_name , string $class_name [, int $codepage ] )
assembly_name指定应该装载哪个程序集,class_name指定在该程序集中实例化的类。一旦创建了DOTNET对象,PHP就将其与其他COM对象进行完全相同的处理。
VARIANT class
The VARIANT是COM的等价于PHP zval的一种结构,可以包含有一系列不同类型的值。
$vVar = new VARIANT($var);
构造函数
VARIANT::__construct ([ mixed $value [, int $type [, int $codepage ]]] )
参数:
- value:初始值。如果省略了,或者设置为NULL,则创建一个VT_EMPTY对象
- type:指定变量对象的内容类型。可能的值是VT_XXX预定义常量
- codepage:指定用于将字符串转换为unicode的代码页
在PHP 5中,当返回一个值或获取一个变量属性时,只在不导致信息丢失的类型之间进行直接映射时,才将变量转换为PHP值。在所有其他情况下,结果返回为变量类的实例。
COM 函数
- com_create_guid — 生成一个全局唯一标识符(GUID)
- com_event_sink — 将事件从COM对象连接到PHP对象
- com_get_active_object — 返回一个已经运行的COM对象的实例句柄
- com_load_typelib — 装载一个 Typelib
- com_message_pump — 处理COM消息,睡眠时间超过毫秒
- com_print_typeinfo — 为dispatchable接口打印一个PHP类定义
- variant_abs — 返回变量的绝对值
- variant_add — 将两个变量值加在一起并返回结果
- variant_and — 在两个变量之间执行一个位and操作
- variant_cast — 将一个变量转换为另一个类型的新变量对象
- variant_cat — 将两个变量值连接在一起并返回结果
- variant_cmp — 比较两个变量
- variant_date_from_timestamp — 返回一个Unix时间戳的变量日期表示
- variant_date_to_timestamp — 将一个变量日期/时间值转换为Unix时间戳
- variant_div — 返回划分两个变量的结果
- variant_eqv — 在两个变量上执行一个位等价
- variant_fix — 返回变量的整数部分
- variant_get_type — 返回变量对象的类型
- variant_idiv — 将变量转换成整数,然后通过将其分隔返回结果
- variant_imp — 对两个变量执行一个位暗示
- variant_int — 返回变量的整数部分
- variant_mod — 划分两个变量并只返回剩余部分
- variant_mul — 将这两个变量的值相乘
- variant_neg — 对变量执行逻辑上的否定
- variant_not — 对变量执行不否定
- variant_or — 在两个变量上执行逻辑or
- variant_pow — 返回使用两个变量执行功能函数的结果
- variant_round — 将一个变量转到指定的小数位数
- variant_set_type — 将一种变量转换为另一种类型的"in-place"
- variant_set — 为变量对象分配一个新值
- variant_sub — 从左变值减去右变量的值
- variant_xor — 对两个变量执行逻辑亦或
com_event_sink 详细说明
函数原型:
bool com_event_sink ( variant $comobject , object $sinkobject [, mixed $sinkinterface ] )
指示COM将comobject生成的事件放入PHP对象sinkobject中。
参数:
- comobject:实例化的COM对象
- sinkobject:应该是一个类的实例,其方法是以期望的不接口的方式命名的
- sinkinterface:PHP将尝试使用与comobject相关联的typelibrary指定的默认的消息接口类型
com_event_sink 使用示例
function pr() {
$args = func_get_args();
if (!empty($args)) {
echo '';
foreach ($args as $arr) {
print_r($arr);
echo '
';
}
echo '
';
}
}
class ComTestSinkClass {
var $flag = false;
public function eventMsg($a) {
pr($a);
}
public function quit(){
$this->flag = true;
}
}
try {
$MyCom = new COM('MyCom.MyClass');
$sink = new ComTestSinkClass();
com_event_sink($MyCom, $sink, 'MyCom.MyClassEvent');
while (!$sink->flag) {
com_message_pump(2000);
}
} catch (Exception $e) {
pr($e);
}ComTestSinkClass类中的方法名和事件中的方法名应一致,在事件被调用的时候触发方法时,php中可以获取,并进行相应的操作。
常见问题解决
Fatal error: Class 'COM' not found
处理办法:
- 首先在windows的"服务"里面检查COM+服务是否已经启动,如果未启动,请启动它
- 检查php目录ext下是否有php_com_dotnet.dll文件
- 在php.ini中开启配置:com.allow_dcom = true 和 extension=php_com_dotnet.dll
调用com组件之权限问题
如果出现"拒绝访问"错误,需要配置DCOM权限:
- 运行dcomcnfg打开组件服务
- 找到对应的COM组件
- 在属性中设置合适的身份验证和权限

发表评论 取消回复