Reflector
先尝试
1copy .\*.dll %windir%\System32\
2regsvr32 %windir%\System32\zkemkeeper.dll
我就不吐槽官方的包把system32写成小写了…
然后看看Demo…有P/Invoke的全称是Platform Invoke (平台调用) 它实际上是一种函数调用机制,通过P/Invoke可以调用非托管DLL中的函数.于是里面没有啥对我们有用的代码,核心函数全在那些c++的dll里.不过姑且还算
谷歌了下网上的php调用.net的dll教程.基本上都是dll自己写的或者是有源码的,但是我手头只有一个孤零零的P/Invoke的dll,怎么办呢?
dll
由于用reflector看了下发现assembly中没有ComVisible项,于是用dll
这里需要先给reflector安装Reflexil插件.重启reflector后,先选择需要的dll,然后打开Tools->Reflexil v1.5,在Custom attributes选项卡中右击Create New,在Attributes选项卡中,Constructor找到mscorlib->CommonLanguageRuntimeLibrary->System.Runtime.InteropServices->ComVisibleAttribute,选择.ctor,如图所示:
同理,在Constructor arguments选项卡中,Type找到mscorlib->CommonLanguageRuntimeLibrary->Boolean并选择,Specification选Default,Arg.type选Boolean,Argument手动输入True并确定.
最后在类上右击,找到Reflexil->Save as,就可以导出
强命名签名文件
木有项目文件,只有一个dll,怎么做强命名签名?还是有办法的:
为没有源码的DLL文件添加强名称:
1sn -k Interop.zkemkeeper.snk //创建一个新的随机密钥对
2
3ildasm Interop.zkemkeeper.dll /out=Interop.zkemkeeper.il //反编译目标程序集
4
5ilasm Interop.zkemkeeper.il /dll /resource=Interop.zkemkeeper.res /key=Interop.zkemkeeper.snk /optimize
6//重新编译,附带强命名参数
ok,这个时候的dll就是带
注册.netdll并添加到全局程序集缓存
以管理员身份运行vs的命令提示符工具:(一般在Visual Studio Tools中有个Visual Studio 命令提示)
1sn -v Interop.zkemkeeper.dll
2//验证签名信息(这一步可省略)
3regasm Interop.zkemkeeper.dll
4//注册COM组件
5gacutil /I Interop.zkemkeeper.dll
6//将程序集添加到全局程序集缓存中
如图所示就代表成功了:
1regasm /regfile Interop.zkemkeeper.dll
这步只是为了看我们之前注册组件的时候在注册表的位置.
打开regedit,找到reg文件里记录的{xxxx..}这样的键,展开,找到
php调用.net dll:
首先php需要开启com_dotnet,在php.ini中开启插件:
1[COM_DOT_NET]
2extension=php_com_dotnet.dll
然后php中便可调用了,方法类似如下:
1$r=new Com("刚才获得的ProgID");
2$s=$r->类的方法();
3echo $s;
–悲剧的分割线–
当然,以上是理想状态下,实际情况是,我在前面都成功的情况下,最后调用仍然报错了:
0x80040154 没有注册类
…
(╯‵□′)╯︵┻━┻
谷歌了半天,最后觉得仍然是如果有谁知道请务必告诉我_(:з」∠)_)
于是迫不得已只能用另一种方法了,那就是
使用WinForm监听http
先引用Interop.zkemkeeper.dll,然后写个方法GetData.test()按照Demo的事例抓取需要的数据(此处略);
winform使用端口监听还是蛮方便的,一个后台线程就能搞定:
1private Thread _t;
2private HttpListener _listerner =new HttpListener();
3
4private void StartBackWork( )
5{
6if (!_listerner.IsListening)
7using (_listerner =new HttpListener())
8{
9_listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份验证 Anonymous匿名访问
10try
11{
12_listerner.Prefixes.Add(textBox1.Text.Trim());
13}
14catch (ArgumentException)
15{
16MessageBox.Show("地址不合法!","错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
17return;
18}
19try
20{
21_listerner.Start();
22}
23catch (HttpListenerException e)
24{
25MessageBox.Show("启动失败:\n" + e.Message,"警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
26return;
27}
28string[] ipstr = richTextBox1.Text.Split(',');
29foreach (string sin ipstr)
30{
31if (s.Trim()=="")
32{
33MessageBox.Show("IP不能为空","警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
34return;
35}
36}
37
38
39label2.Text ="已启动";
40richTextBox1.ReadOnly =true;
41textBox1.ReadOnly =true;
42MessageBox.Show("监听启动成功","提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
43while (true)
44{
45//等待请求连接
46//没有请求则GetContext处于阻塞状态
47HttpListenerContext ctx = _listerner.GetContext();
48ctx.Response.StatusCode = 200;//设置返回的http状态代码
49string name = ctx.Request.QueryString["name"];
50
51if (name !=null)
52{
53Console.WriteLine(name);
54}
55
56
57//使用Writer输出http响应代码
58using (StreamWriter writer =new StreamWriter(ctx.Response.OutputStream))
59{
60//writer.Write("aaa");
61
62writer.Write(GetData.test(ipstr));
63
64writer.Close();
65ctx.Response.Close();
66}
67
68}
69}
70}
当然,为了不卡UI,我们要新建一个Thead来运行它:
1if (!_listerner.IsListening)
2{
3_t =new Thread(StartBackWork);
4_t.Start();
5}
这样,当这个程序运行着的时候,就能监听指定的本地http地址(如localhost),如果其他机器或者php访问请求,就可以触发事件,该程序调用那几个COM组件去考勤机上取数据,最终返回给http请求方.
参考文章: