我们用文件读写来模拟
先用VS2013新建一个Visual C++语言的ATL-〉ATL项目
给网页用的COM对象,相当于进程内服务器,所以应用类型为DLL,勾上“允许合并代理/存根代码”,对网页用COM对象,避免分开编译代理和存根更方便
在项目中“添加类”,选择类型为:ATL简单对象
给ATL简单对象(一个COM类)进行命名,我们添加简称FileKey,其余自动生成的。注意需要自己添加ProgID(一般命名成:DLL文件名(即工程名).COM类名(即简称))
指定COM对象的一些特性:如线程安全模型用 套间(Apartment,即图中的“单元”),支持“聚合”,双重接口,支持错误信息、连接点、IE对象支持等
因为我们通过COM对象暴露的接口来调用其中的方法、属性,所以,右键选中接口IFileKey,打开“添加方法”的向导
指定方法名GetContent,添加第一个输入性LONG类型参数lFlags
添加第二个输出返回性BSTR*类型的参数pFileContent,注意,[out,retval]参数相当于我们方法被调用时的返回值,BSTR*作为输出性的字符串参数的类型
添加GetContent方法的具体内容:创建文件ttt.txt,可读可写,读取该文件的内容,在该内容后面添加一点后返回给pFileContent,然后写入添加后的内容到文件。注意:如果文件路径为ttt.txt,在Windows 7上,该文件创建在桌面,如果改成.\\ttt.txt,我的情况它生成在apache的安装目录的根下(可能默认文件的读写者就是apache这样的Web服务器)
给我们的FileKey添加安全相关内容:让COM类从IObjectSafetyImpl接口(模板接口)继承,并在接口入口映射中添加IObjectSafety
编译生成DLL,将该DLL放到一定地方(我放到了文档根www),用regsvr32.exe /i UseFileTestATL.dll进行控件的注册,可以在注册表检查FileKey的注册情况,注意ProgID
编写测试用的php文件testcom.php如下:
$obj = new COM("UseFileTestATL.FileKey");
$str = $obj->GetContent(12);
echo $str;
?>
然后输入http://127.0.0.1/testcom.php测试,可以发现不断增长的“在tick=77881330添加值12 在tick=77883795添加值12 在tick=77891377添加值12 ……”
在上述测试中,COM对象是在服务器上测试,php中调用的,这种方式适合在服务端(Windows环境)打开php和COM对象之间的联系,可以用于扩展php难以支持的功能
另外,我们在new COM中使用了ProgID作为参数,但COM对象不一定有ProgID。查看php中COM类的官网说明:
module_name
意思是这个参数除了可以是ProgID外,也可以是COM类的UUID或者Moniker命名对象,后两者未试,但一个COM类肯定有UUID的
要让COM对象工作在客户端,必须要让客户可以下载该对象并进行注册(通常打包成cab),然后在网页进行调用。
查看FileKey.rgs了解UUID:
编写inf文件UseFileTestATL.inf:
[version]
signature="$CHICAGO$"
AdvancedINF=2.0
[Add.Code]
UseFileTestATL.dll=UseFileTestATL.dll
[UseFileTestATL.dll]
file-win32-x86=thiscab
RegisterServer=yes
clsid={F595E720-32BC-4AAC-AA58-806F6359AFF9}
DestDir=11
FileVersion=1,0,0,1
[RegisterFiles]
%11%\UseFileTestATL.dll
打开VS2013 x86本机工具命令提示,输入iexpress运行打包cab的工具程序。(这个程序似乎装了VS就被安装到了系统目录下)
选择“Create new Self Extraction Directive file”,选择“Create compressed files only(ActiveX Installs)”,点Add,添加进去UseFileTestATL.dll和UseFileTestATL.inf这两个文件,输入(或浏览再输入)cab文件存放的位置(提示要求输入8.3格式的cab文件名),如V:\UFTATL.cab,再勾上“Store files using Long File Name inside Package”(即cab内文件名可以用长文件名),SED可以不保存。最后生成cab。如果出现Unable to Open Report File这样的错误,是权限问题,用管理员身份重新运行iexpress即可。
编写testcom.htm如下:
--------------------------------
------------------------------------
在浏览器输入http://127.0.0.1/testcom.htm,将出现如下提示:
这是浏览器为了安全考虑,将未签名的控件进行了拦截。选择允许,就可以试验我们的控件在网页的行为了。这种方式适合在客户端使用COM。
上面的图中,公司名等信息看上去未完善,而且每次要额外点击允许。
VS2013从浏览器对控件进行调试还是比较方便的,例如,在前面的testcom.htm中,去掉codebase部分,然后regsvr32.exe /u UseFileTestATL.dll注销控件,以管理员身份运行VS2013(不是管理员不能实现控件生成后自动注册),设置项目的属性-〉调试属性,将调试器改成Web浏览器调试器,指定url,类似如下:
然后下断点,按F5开始调试即可。
修改控件显示的公司名、文件说明,可以在资源文件的版本信息中修改:
控件签名问题,可以参考以下网址的文章http://www.cnblogs.com/itech/archive/2011/07/21/2110924.html,概括如下:
signtool.exe 数字签名工具
makecert.exe 创建数字证书
cert2spc.exe 将数字证书转化为软件发布者证书格式
pvk2pfx.exe(pvkimprt.exe) 将私有的密匙和软件发布者证书合并为pfx文件,此文件将被signtool.exe使用
makecert -sv mykey.pvk -n "CN=Sjg Software Inc." mycert.cer
会要求密码,作为简单测试我们都输入12345678,生成pvk文件和cer文件
cert2spc mycert.cer mycert.spc
将cer转换成spc
V:\>pvk2pfx -pvk mykey.pvk -pi 12345678 -spc mycert.spc -pfx mycert.pfx -po 12345678
使用pvk、spc生成pfx
V:\>signtool sign /f mycert.pfx /p 12345678 /t http://timestamp.globalsign.com/scripts/timstamp.dll /v UFTATL.CAB
上面这句失败,无法签名
SignTool sign /fd SHA256 /a /f mycert.pfx /p 12345678 UFTATL.CAB 也无法签名
后来发现,VS中,如果是C#的项目,在项目-〉属性-〉签名(VC中没有这个页,而且显示的风格也不一样),有“创建测试证书”的按钮,可以生成pfx(可设密码),用这个生成的pfx,可以通过signtool sign命令,给cab签名。
通过另一机器IE,先将pfx文件导入到IE的证书-〉受信任的根证书列表里,然后以Web方式访问前面的testcom.htm,会出现安装控件的提示,并且会显示签名者信息,安装后,就可以不跳出拦截提示了。(值得注意的是,真实生产环境应该用release版,而且应该将ATL相关的库dll拷贝到cab,当然,证书最好使用正式证书)