您的位置:首页 > 网络编程 > PHP

php调用dll

日期:2007-12-20 08:15:16 点击: 来自: 作者:

  最近做一个网站,需要频繁使用远程数据,数据接口已经做好。在做转换的时候遇到了性能上的问题:开始打算用php来实现转换,苦苦查了数天,都没有找到直接操作字节的方法。虽然可以使用 pack() 方法将各个数据压入结构中,但是在解压的时候却不能通过 unpack() 简单的解出来,需要通过

//php
for( $i = 0; $i <$length; $i+=2 ){
$tempstr = $tempstr.chr( hexdec(substr($array["data"], $i, 2)) );
}
$array["data"] = $tempstr;
code

这类方法进行解码。频繁的使用各种字符串操作,无疑将对性能造成很大的影响。经过研究,发现有以下方法可以实现对字节的操作:

  • 使用stream进行读写
  • 使用socket进行读写
  • 使用COM dll,将数据在C++ dll中进行转换

由于网上找不到相关的文档(其实是没好好找),stream和socket先后被PASS掉了。为了编译COM的dll,还专门下载了VC++ 6.0(为啥不装2005?硬盘太小,装不下,没办法啊)。经过无穷无尽的Google(全是php调用VB写的dll的信息,没多大帮助)和编译/调试,终于成功的把结果传递到php中。
下面简单介绍一下步骤和注意事项

  1. 在VC++ 6.0中,File -> New... 选择Projects中的"ATL COM AppWizard",填写工程名称等。本例中,工程名为"ATLtest"。
  2. 在"ATL COM AppWizard - Step 1 on 1"对话框中,"Server Type" 选择"Dynamic Link Library (DLL)",之后Finish。
  3. 在"ClassView"中,右击"ATLtest",选择"New ATL Object...",在"ATL Object Wizard"中,选择默认的"Simple Object",之后"Next"。
  4. 在"ATL Object Wizard 属性"中,在"Short Name"输入接口的名称。本例中,接口名称为"test"。之后,"Names"选项卡中的所有textBox都自动填好了默认的值。注意两个地方:一个"Prog ID"(本例中为"ATLtest.test"),一个"Interface"(本例中为"Itest")。
  5. 完成之后,在"ClassView"中,"ATLtest classes"下生成了"Ctest"类,并且实现了"Itest"接口。
  6. 右击"Itest"接口,选择"Add Method..."。
  7. 在"Add Method to Interface"中,填写方法的名称和参数。注意:返回值一定是HRESULT型,真正的返回值是最后一个参数。比如
    //C++ code
    BSTR Encode(unsigned int msgType, unsigned int msgLength, BSTR message)

    这个函数,要写成
    //C++ code
    STDMETHODIMP Ctest::Encode(
    unsigned int
    msgType,
    unsigned int
    msgLength,
    BSTR message,
    BSTR *result
    )

    这样的形式。还有就是返回值只接受简单的类型(不知道为什么,char**不能用)和指针,BSTR没法直接使用。
  8. 完成这个函数。当然,为了简单起见,这里就是给结果随便赋了一个值,用来说明参数成功的传递出来了。没有考虑任何内存泄漏问题。
    //C++ code
    STDMETHODIMP Ctest::Encode(
    unsigned int
    msgType,
    unsigned int
    msgLength,
    BSTR message,
    BSTR *result
    )
    {
    BSTR temp = ::SysAllocString(L"asdfasdf");
    *result = temp;
    returnS_OK;
    }
  9. 编译,将得到的ATLtest.dll使用regsvr32进行注册,之后才能使用COM进行调用。
  10. 之后书写这样的php代码:
    //php
    $com = new COM("ATLtest.test") ordie("无法建立COM组件");
    $result = "未处理的字符串";
    echo'$result = "'.$result.'"<br />';
    $result = $com->Encode(1,1,"11");
    echo'$result = "'.$result.'"<br />';
    $com = null;
    code
  11. 注意这里的"ATLtest.test"是刚才(4)中的"Prog ID",并且使用Encode() 的方法和声明的也不一样。没有关系!
    当然,由于完全没有用到三个输入参数,这里的1,1,"11"只是为了满足输入参数的数量。
  12. 这个php的输出是什么样的呢?
    //HTML 结果
    $result = "未处理的字符串"
    $result = "asdfasdf"

    可见,$result 成功的改变成了dll中赋的值,说明 Encode() 方法成功的返回了值。

几点疑问

  1. 为什么 Encode() 中返回的是 BSTR* ,但是到了php中,就变成了字符串(BSTR) 呢?这个自动的转换是ATL进行的,还是php进行的呢?
  2. C++代码中通过SysAllocString()为BSTR分配的空间在何时进行垃圾收集?收集工作由哪里负责?会不会导致内存泄漏?
  3. 完恶的C++ 6.0 编译器,为什么返回值不支持 char** 这种简单的类型呢(使用char**直接编译出无数错误)? BSTR本质上就是指针嘛,也不支持(提示说只支持简单类型和指针),只好用一个不伦不类的BSTR*来写。嗯,下一步尝试改用CCOMBSTR或者_bstr_t,试试哪个更好用。
  4. 对于传入的BSTR* result,需要使用 SysFreeString() 进行处理么?在C++中看来,无疑是需要释放的;但是php在背后做了哪些工作呢?有没有对未被引用的常量"未处理的字符串"进行垃圾收集呢?

参考资料
以下资料比较有参考价值:

More..素材图片 Picture Navigation
  •  彩云之南
  • 《超宽屏壁纸》带你体验大自然的魅力
  • 18张最美丽的北京风光 1600X1200 像素
  • 2ADVANCED 2006 壁纸系列
PHP热门 Class Hot
PHP推荐 Class Commend
版权所有:中国网站资源 2005- 未经授权禁止复制或建立镜像 This Site Tech:XHTML+DIV+CSS+Javascript
CopyRight ® 2005- www.Chinaddv.com online services. all rights reserved. ICP06016627
Optimized to 1024x768 to Firefox,Netscape,Opera,MS-IE6+.