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

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

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

  • 使用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;

    return S_OK;
    }

  9. 编译,将得到的ATLtest.dll使用regsvr32进行注册,之后才能使用COM进行调用。
  10. 之后书写这样的php代码:
    //php code
    $com = new COM("ATLtest.test") or die("无法建立COM组件");
    $result = "未处理的字符串";
    echo '$result = "'.$result.'"
    ';

    $result = $com->Encode(1,1,"11");
    echo '$result = "'.$result.'"
    ';

    $com = null;

  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在背后做了哪些工作呢?有没有对未被引用的常量"未处理的字符串"进行垃圾收集呢?

//////////////////////////////////////////////////////////////////////////

php调用dll

项目需要用到php调用dll,论坛发帖得到思路,用DynamicWrapper方法调用。下载DynamicWrapper.dll到php
ext下与windows system32下, $dw = new COM("DynamicWrapper");
$dw->Register("EbUsbApi.dll", "EbCreateDataFile", 'i=sls', "f=s",
"r=l"); $ch = $dw->EbCreateDataFile("222",11,"22"); dll其中一个函数 HANDLE
EbCreateDataFile(LPCTSTR lpFileName, DWORD dwCreationDisposition,
LPCTSTR lpPassword) 得到结果0.成功
///////////////////////////////////////////////////
1。查看CPU荷载:

CODE:

$wmi = new COM('winmgmts://');

$processor = $wmi->ExecQuery("SELECT * FROM Win32_Processor");

foreach($processor as $obj){

$cpu_load_time = $obj->LoadPercentage;

}

echo $cpu_load_time;

?>2。调用自定的dll组件:
1) 创建ActiveX dll组件 --

CODE:

Public Function hello() As String
    hello = "Hello World!"
End Function并存为"test.dll" 文件

2) 用regsvr32.exe注册此组件
regsvr32 test.dll

3) 在PHP内调用此dll组件:

CODE:

$obj = new COM("test.dll");
$output=$obj->hello(); // Call the "hello()" 方法
echo $output; // 显示Hello World! (so this comes from the dll!)
?>

/////////////////////////////////

今天要用工商银的接口做一个在线支付,提供的是两个dll文件和一个说明文档,另外还电子证书。
PHP调用COM组件,从网上找了半天也没找到个说得明白的,是不是用这个的人太少了又或是太简单所

以没有人写。

什么是COM?

COM(Component Object Model)组件对象模型,是一种跨应用和语言共享二进制代码的方法。是

位于DCE RPC上部的对象指向层(关联服务)定义公共的调用协定以允许用不同语言编写的代码调用,

并允许其它语言代码进行交互操作(前题是代码是COM明白的),COM可以作为DLL被本机程序载入也可

以通过DCOM被远程进程调用。

准备工作

比如我作了一个COM组件,新建一个VB6工程,ActiveX Dll将工程命名为P_test,类名为c_test ,类的文件内容如下:

Option Explicit
Private MyScriptingContext As ScriptingContext
Private MyApplication As Application
Private MyRequest As Request Private MyResponse As Response
Private MyServer As Server
Private MySession As Session Public

Sub OnStartPage(PassedScriptingContext As ScriptingContext)
Set MyScriptingContext = PassedScriptingContext
Set MyApplication = MyScriptingContext.Application
Set MyRequest = MyScriptingContext.Request
Set MyResponse = MyScriptingContext.Response
Set MyServer = MyScriptingContext.Server
Set MySession = MyScriptingContext.Session
End Sub

Public Sub OnEndPage()
Set MyScriptingContext = Nothing
Set MyApplication = Nothing
Set MyRequest = Nothing
Set MyResponse = Nothing
Set MyServer = Nothing
Set MySession = Nothing
End Sub

Public Function Test_Number(num) As Variant
If num < 0 Then Get_Number_Attrib = -1
If num > 0 Then Get_Number_Attrib = 1
If num = 0 Then Get_Number_Attrib = 0
End Function

编译生成p_test.dll文件

第一步,做为一个COM组件,这个DLL要被系统识别就要先到系统来报到

regsvr32 [路径]/[组件文件名]

regsvr32 C:/WINDOWS/system32/p_test.dll  
   放在系统文件夹system32下不容易出现权限问题

这时候这个文件就不能移动位置了,系统会在用到它时到这个目录来找,如果改目录就得先删除注册

再重新注册

regsvr32 /u [路径]/[组件文件名]

系统会显示窗口表示成功,大意是 组件Dllregister成功或是Dllunregister成功

第二步就可以直接调用它了
<?
$b=new COM("p_test.c_test");  //一般前边是它的主文件名后边是它的类名从注册表里找这个文

件可以找到

这样就生成了一个叫b的对象,我们就可以用它的属性和方法来操作了
$a=$b->Test_Number(-454);
echo $a;
?>
可能遇到的问题是,编译工程时通不过,要将
Microsoft Active Server Pages Object Library 
引用进来,具体实现"Project->References"找到改库,并勾上 。

php调用dll经验小结的更多相关文章

  1. VB6.0调用DLL

    目录 第1章 VB6.0调用DLL    1 1 VC++编写DLL    1 1.1 使用__stdcall    1 1.2 使用 .DEF 文件    1 2 简单数据类型    2 2.1 传 ...

  2. 在ASP中调用DLL的方法

    .net的dll已经不是严格意义上的动态连接库了,而是一个类或者类库.它是不能直接在ASP.VB等其它的应用环境中使用的.   我们可以通过COM包装器(COM callable wrapper (C ...

  3. 在vs2013下手把手创建/调用dll

    body { font: 16px } 参考了大佬的文章 首先,体会一下静态编译: 创建Win32Project,选DLL,添加一个.h和.cpp文件 点击生成解决方案,然后去debug目录下拷贝.l ...

  4. Java调用DLL有多种方式,常用的方式有JNative、JNA、JNI等。

    JNative方式调用dll JNative是一种能够使Java语言使调用DLL的一种技术,对JNI进行了封装,可能有些读者会有这样一个问题,JNative对JNI进行了封装,并且是一种跨语言的使用D ...

  5. war包部署在tomcat下,使用windows service服务方式启动tomcat服务器,在包含调用dll的模块,报dll找不到问题的解决办法

    问题描述: 开发了一个需要调用dll的java web程序,在idea开发环境下运行调试没问题,可以正常运行,在tomcat/bin下,运行批处理startup.bat,启动tomcat服务器,也可以 ...

  6. Windows平台Go调用DLL的坑

    最近的项目中,使用了GO来开发一些服务中转程序.业务比较简单,但是有一些业务需要复用原有C++开发的代码.而在WINDOWS,用CGO方式来集成C/C++代码并不是太方便.所以用DLL把C++的代码封 ...

  7. Java 调用 C++ (Java 调用 dll)康哥手把手教你

    摘要: 本文原创,转载请注明地址 http://www.cnblogs.com/baokang/p/4979243.html 因为要做点图形处理的项目,需要在Java中调用dll库,所以开发的第一步是 ...

  8. 【转】C#调用DLL

    C#中如何调用动态链接库DLL(转)     每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍.首先,您需要了解什么是托管,什么是非托管.一般可以认为:非托管代码主要是基 ...

  9. C#程序实现动态调用DLL的研究(转)

    摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...

随机推荐

  1. Mininet实验 测量路径损耗率

    参照:基于Mininet测量路径的损耗率 在SDN环境中,可以利用控制器来测量特定路径的损耗率,在本实验中,基于Mininet脚本,设置特定的交换机间的路径损耗速率,然后编写POX脚本,实现对路径的损 ...

  2. python 正则匹配字符串里面的字符

    import re x=re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest') print(x)

  3. JAVA-随机生成四则运算

    代码如下: package jiajianchengchu; import java.util.*; public class jisuan { public static String yuefen ...

  4. Java线程池Executor使用

    合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:减少系统对于,外部 服务的响应时间的等待.第三:提高线程的可管理性.线程是稀缺资源,如果 ...

  5. JAVA消息 JMS 很重要

    首先大致讲一下,java 消息模块 消息,个人理解分为两种:1.同步消息(RPC调用) 2.异步消息(本篇讲解部分) 一.同步消息java提供了多种方案: 最新比较常用的方式就是spring Http ...

  6. 使用Bootstrap插件datapicker获取时间

    引入css和js <link rel="stylesheet" href="/${appName}/commons/css/datapicker/datepicke ...

  7. 最小生成树prim和kruskal模板

    prim: int cost[MAX_V][MAX_V]; //cost[u][v]表示边e=(u,v)的权值(不存在的情况下设为INF) int mincost[MAX_V]; //从集合X出发的每 ...

  8. BZOJ2620 [Usaco2012 Mar]Haybale Restacking

    恩,非常好的题...至少思路非常巧妙 首先可以得到性质:对于相邻的两堆A & B,A给B然后B再给A是完全没有意义的...也就是说只能单向传递 然后我们记下每个点要给(被给)多少堆干草a[i] ...

  9. hdu 3682 10 杭州 现场 C - To Be an Dream Architect 简单容斥 难度:1

    C - To Be an Dream Architect Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d &a ...

  10. java远程下载文件到本地

    方法一 ** * 下载远程文件并保存到本地 * * @param remoteFilePath-远程文件路径 * @param localFilePath-本地文件路径(带文件名) */ public ...