转载自http://blog.chinaunix.net/uid-20787846-id-3530180.html
编译com的dll
下面简单介绍一下步骤和注意事项:
- 在VC++ 6.0中,File -> New... 选择Projects中的"ATL COM AppWizard",填写工程名称等。本例中,工程名为"ATLtest"。
- 在"ATL COM AppWizard - Step 1 on 1"对话框中,"Server Type" 选择"Dynamic Link Library (DLL)",之后Finish。
- 在"ClassView"中,右击"ATLtest",选择"New ATL Object...",在"ATL Object Wizard"中,选择默认的"Simple Object",之后"Next"。
- 在"ATL Object Wizard 属性"中,在"Short Name"输入接口的名称。本例中,接口名称为"test"。之后,"Names"选项卡中的所有textBox都自动填好了默认的值。注意两个地方:一个"Prog ID"(本例中为"ATLtest.test"),一个"Interface"(本例中为"Itest")。
- 完成之后,在"ClassView"中,"ATLtest classes"下生成了"Ctest"类,并且实现了"Itest"接口。
- 右击"Itest"接口,选择"Add Method..."。
- 在"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没法直接使用。
- 完成这个函数。当然,为了简单起见,这里就是给结果随便赋了一个值,用来说明参数成功的传递出来了。没有考虑任何内存泄漏问题。
//C++ code
STDMETHODIMP Ctest::Encode(
unsigned int msgType,
unsigned int msgLength,
BSTR message,
BSTR *result
)
{
BSTR temp = ::SysAllocString(L"asdfasdf");
*result = temp;returnS_OK;
} - 编译,将得到的ATLtest.dll使用regsvr32进行注册,之后才能使用COM进行调用。
- 之后书写这样的php代码:
//php code
$com = new COM("ATLtest.test") ordie("无法建立COM组件");
$result = "未处理的字符串";
echo‘$result = "‘.$result.‘"
‘;$result = $com->Encode(1,1,"11");
echo‘$result = "‘.$result.‘"
‘;$com = null;
- 注意这里的"ATLtest.test"是刚才(4)中的"Prog ID",并且使用Encode() 的方法和声明的也不一样。没有关系!
当然,由于完全没有用到三个输入参数,这里的1,1,"11"只是为了满足输入参数的数量。 - 这个php的输出是什么样的呢?
//HTML 结果
$result = "未处理的字符串"
$result = "asdfasdf"可见,$result 成功的改变成了dll中赋的值,说明 Encode() 方法成功的返回了值。
几点疑问
- 为什么 Encode() 中返回的是 BSTR* ,但是到了php中,就变成了字符串(BSTR) 呢?这个自动的转换是ATL进行的,还是php进行的呢?
- C++代码中通过SysAllocString()为BSTR分配的空间在何时进行垃圾收集?收集工作由哪里负责?会不会导致内存泄漏?
- 完恶的C++ 6.0 编译器,为什么返回值不支持 char** 这种简单的类型呢(使用char**直接编译出无数错误)? BSTR本质上就是指针嘛,也不支持(提示说只支持简单类型和指针),只好用一个不伦不类的BSTR*来写。嗯,下一步尝试改用CCOMBSTR或者_bstr_t,试试哪个更好用。
- 对于传入的BSTR* result,需要使用 SysFreeString() 进行处理么?在C++中看来,无疑是需要释放的;但是php在背后做了哪些工作呢?有没有对未被引用的常量"未处理的字符串"进行垃圾收集呢?
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)
查看CPU荷载:
$wmi = new COM(‘winmgmts://‘); $processor = $wmi->ExecQuery("SELECT * FROM Win32_Processor"); foreach($processor as $obj){ $cpu_load_time = $obj->LoadPercentage; } echo $cpu_load_time;
调用自定的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组件:
$obj = new COM("test.dll"); $output=$obj->hello(); // Call the "hello()" 方法 echo $output; // 显示Hello World! (so this comes from the dll!)
准备工作
比如我作了一个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" br style=‘font-size:16px;font-style:normal;font-weight:400;font-family:Verdana;color:rgb(102, 102, 102);‘ />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"找到改库,并勾上 。