前言

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):

  1. 执行"dcomcnfg"
  2. 打开组件服务>计算机>我的计算机>DCOM配置
  3. 搜索Microsoft Office Word 97-2003文档
  4. 右键单击并打开属性,选择"身份"选项卡
  5. 通常情况下设置为"启动用户",将其更改为"交互式用户"或您选择的管理用户

实例化时的异常捕捉

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

处理办法:

  1. 首先在windows的"服务"里面检查COM+服务是否已经启动,如果未启动,请启动它
  2. 检查php目录ext下是否有php_com_dotnet.dll文件
  3. 在php.ini中开启配置:com.allow_dcom = true 和 extension=php_com_dotnet.dll

调用com组件之权限问题

如果出现"拒绝访问"错误,需要配置DCOM权限:

  1. 运行dcomcnfg打开组件服务
  2. 找到对应的COM组件
  3. 在属性中设置合适的身份验证和权限

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部