浏览器调用本地DLL的方法

要在浏览器中调用本地DLL,常见的方法是使用插件。但是为了安全,现在有的浏览器对插件开发做了限制,不让插件调用外部DLL。比如说Chrome,为了调用外部的DLL,我们只能使用早期的chrome版本。
还有一种方法就是在电脑上安装一个助手程序,浏览器通过HTTP GET请求调用助手程序,助手程序再调用本地DLL,并把调用结果反馈到浏览器中。今天我们就来讨论这种方法。
首先助手程序应该是一个WEB服务器,因为只有WEB服务器才能处理浏览器发过来的HTTP GET请求。
第二个问题:浏览器怎么发送HTTP GET请求?答案是JavaScript。如果您熟悉JQuery, 那么让浏览器发送HTTP GET请求只需要几行代码:

$.get("http://localhost/",function(data,status){ 
alert("数据: " + data + "\n状态: " + status); 
});

如果您不了解JQuery,使用的代码会多一些,如下所示:

        //创建XMLHttpRequest对象       
        var httpRequest
		try{ // Firefox, Opera 8.0+, Safari
			httpRequest=new XMLHttpRequest();
		}
		catch (e){
			try{// Internet Explorer
				httpRequest=new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (e){
				try{
					httpRequest=new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch (e){}
			}
		}
		

        httpRequest.open('GET',
		'http://localhost/',
		true);
        httpRequest.send();//发送请求
        
         // 获取数据后的处理程序
         httpRequest.onreadystatechange = function () {
            if (httpRequest.readyState == 4 && httpRequest.status == 200) {
                var str = httpRequest.responseText;//获取到助手程序返回的字符串
               	alert(str);				
            }
        };

因为浏览器和助手程序都在同一台电脑上,所以代码中HTTP GET的url就是http://localhost

第三个问题:其实浏览器不仅可以用HTTP GET请求调用助手程序,还可以使用HTTP POST,WebSocket协议。
下面我们来看一看流程图:

流程图很简单。这里最麻烦的地方就在于我们要自己写助手程序,还要安装在每一台电脑上。所以我觉得这个方法比较适合企业内部信息管理系统。助手程序可以用来在网页中操作控制本地的读卡器、打印机、扫描仪、高拍仪、U盾等各种硬件设备。
好,原理部分讲完了,如果您看不太懂,问题也不大,现在我们写几个助手程序的实例,估计写完实例大家就会理解了。每个人会的编程语言是不同的,所以我们写的实例,有JAVA版,PHP版和C++版。
所有实例都提供了源代码,源代码放在github上:https://github.com/Dengxd/SimpleDllHelper
DllHelperCpp目录是C++版
DllHelperJava目录是JAVA版
DllHelperPhp目录是PHP版,comATL目录是C++写的com组件,专门给PHP版使用的
TestDll目录是测试用的DLL
test.html文件是浏览器使用的网页JavaScript代码 

编写一个测试用的DLL

既然要调用DLL,我们就先写一个测试用的DLL,JAVA和PHP写不了DLL,所以只能用C++
我的开发环境:
Windows 7 旗舰版 SP1 x64
Microsoft Visual Studio Community 2022 (64 位)
主要代码解读:
主要代码就一个函数

__declspec(dllexport) int __stdcall sum(int a, int b)
{
    return a + b;
}

这是个求和函数,两个输入参数a和b, 返回a+b
我们的助手程序要调用的就是这个函数
这个项目可以编译出x64和Win32(x86)版本的DLL。Visual Studio自动生成的项目也是奇葩,在主界面上Win32程序叫做x86:

但是到了项目属性配置页面,又变成了Win32:

 

很容易把初学者搞得无所适从。其实在这两个地方x86和Win32是一回事。一般我们都是编译成Release版本的,如果要编译成64位的,就在主界面选择x64,如果要编译成32位的,就在主界面选择x86
如果您不会C++和Microsoft Visual Studio, 不知道怎么编译出DLL, 源码里面提供了编译好的DLL,Release x64版的TestDll.dll在文件夹TestDll\x64\Release中,Debug x64版的TestDll.dll在文件夹TestDll\x64\Debug中, Release Win32版的TestDll.dll在文件夹TestDll\Release中,Debug Win32版的TestDll.dll在文件夹TestDll\Debug中,一般情况下我们会使用Release版本的DLL,如果操作系统是64位的,最好使用x64版,如果操作系统是32位的,只能使用Win32版。如果您手痒很想自己编译的话,可以参考一下这篇文章:https://www.freesion.com/article/6443438938/ 。声明一下,这篇文章不是我写的,只是我搜索到的文章。 

编写JavaScript代码

我们建立一个文件,文件名text.html, 内容如下:

<!doctype html>
<html>
  <head>
	<meta http-equiv="Content-Type" content="text/html;charset=utf-8">

  </head>
  <body>
     <form action="" enctype="application/x-www-form-urlencoded">
          <input type="button" name="ok" id="ok" value="HTTP GET">
      </form>
  </body>
  <script type="text/javascript" >
	window.onload = function () {
		document.getElementById("ok").onclick = function () {
        
        //创建XMLHttpRequest对象       
        var httpRequest
		try{ // Firefox, Opera 8.0+, Safari
			httpRequest=new XMLHttpRequest();
		}
		catch (e){
			try{// Internet Explorer
				httpRequest=new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (e){
				try{
					httpRequest=new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch (e){}
			}
		}
		

        httpRequest.open('GET',
		//'http://localhost/cgi-bin/dllhelpercpp.cgi',
		'http://localhost/',
		true);
        httpRequest.send();//发送请求
        
         // 获取数据后的处理程序
         
        httpRequest.onreadystatechange = function () {
            if (httpRequest.readyState == 4 && httpRequest.status == 200) {
                var str = httpRequest.responseText;//获取到助手程序返回的字符串
               	alert(str);				
            }
        };

    }
	
}		
  </script>
</html>

这代码熟悉JavaScript的同学都能看得懂,我就不解释了。
我们用浏览器打开这个文件,会显示一个按钮“HTTP GET”,点击这个按钮,浏览器就会向助手程序发送HTTP GET请求

编写JAVA版的助手程序

我的开发环境:
Windows 7 旗舰版 SP1 x64
IntelliJ IDEA 2021.2.1(Ultimate Edition)
java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
我们使用JNA来调用DLL,关于JNA,网络上文章很多了,大家可以自己去搜一搜,我就不献丑了。大家可以参考一下这篇文章:https://www.freesion.com/article/6443438938/
前面我们说过,助手程序应该是一个WEB服务器,所以我们就使用spring boot框架,这货自带了一个TOMCAT,省了不少麻烦
主要代码解读:

public interface Mydll extends Library {
   Mydll instance = Native.load("C:\\TestDll.dll", Mydll.class);

   int sum(int a,int b);

}
@RequestMapping("/")
@ResponseBody
public int dll(HttpServletResponse resp) {

   int ret=Mydll.instance.sum(1,2);
   resp.setHeader("Access-Control-Allow-Origin","*");
   return ret;
}

"C:\\TestDll.dll" 是DLL文件所在的路径,要改成您相应的文件路径
int sum(int a,int b);声明了DLL中对应的函数
int ret=Mydll.instance.sum(1,2); 就是调用DLL中的sum函数
resp.setHeader("Access-Control-Allow-Origin","*"); 这句是为了解决跨域问题的

修改application.yml
把端口改为80
server:
  port: 80

特别注意:如果您的WINDOWS是32位的,只能使用Win32版的DLL和32位的JDK。如果您的WINDOWS是64位的,可以使用x64版的DLL和64位的JDK,也可以使用Win32版的DLL和32位的JDK。归纳为一句话: DLL和JDK位数要一致。

现在我们运行这个JAVA程序,然后在浏览器中打开前面写的test.html文件,点击“HTTP GET”按钮:

成功调用DLL

编写PHP版的助手程序 

我的开发环境:

Windows 7 旗舰版 SP1 x64

PHPStudy 8.1.1.3 ,  Nginx 1.15.11, PHP 7.3.4nts

Microsoft Visual Studio Community 2022 (64 位)

PHP调用普通的DLL有两种方法,一种是开发一个PHP扩展,再由PHP扩展调用DLL,第二种是开发一个com组件,php先调用com组件,再由com组件调用DLL。我们采用的是第二种方法。

Php是写不了com组件的,所以我们用C++来写一个com组件。

开发com组件

可以参考这个网页:https://blog.csdn.net/weixin_33507838/article/details/115411281

主要代码解读:

STDMETHODIMP CATLSimpleObject::atlsum(LONG a, LONG b, LONG* c)
{
    // TODO: 在此处添加实现代码
	HINSTANCE hinstLib;
	hinstLib = LoadLibrary(TEXT("c:\\TestDll.dll"));
	if (hinstLib != NULL)
	{
		typedef int(__stdcall* SUM)(int, int);
		SUM sum;
		sum = (SUM)GetProcAddress(hinstLib, "sum"); //这是获取dll里面的sum函数

		if (NULL != sum)
		{
			int ret = sum(a, b);  //调用dll的sum函数
			* c = ret;  //这是设置返回值
		}
		FreeLibrary(hinstLib);
	}
    return S_OK;
}

"C:\\TestDll.dll" 是DLL文件所在的路径,要改成您相应的文件路径
特别注意:TestDll.dll 和 com组件的位数要一致。要么都是x64 ,要么都是Win32(x86)。千万不能一个x64,另一个Win32(x86)
Com组件编译出来之后,需要注册,注册需要使用命令行:regsvr32 D:\doc\code\SimpleDllHelper\comATL\x64\Release\comATL.dll
这里D:\doc\code\SimpleDllHelper\comATL\x64\Release\comATL.dll是com组件所在的路径,应该改成您本机上实际的文件路径

开发php代码

总共三行代码:

header('Access-Control-Allow-Origin:*'); //这句是为了解决跨域问题的
$com = new COM("ComATL.ATLSimpleObject") or die("无法调用ComTest");  //初始化com组件
echo $com->atlsum(1, 2);  //调用com组件的接口

如果说程序代码是美女们的超短裙,那么我最喜欢的就是PHP了,因为越短越好!
还有一点很重要,修改php配置文件,加上一行extension=php_com_dotnet.dll

如果没有这一行, PHP无法调用com组件
最后我们在浏览器中打开前面写的test.html文件,点击“HTTP GET”按钮,将会看到和java助手程序一样的结果

编写C++版的助手程序

我的开发环境:
Windows 7 旗舰版 SP1 x64
Microsoft Visual Studio Community 2022 (64 位)

介绍一下我们的思路:先安装一个APACHE HTTPD服务器,然后写一个CGI的程序,由这个CGI程序来调用DLL,最后把CGI程序部署到APACHE HTTPD服务器里面

安装一个APACHE HTTPD服务器

官网下载地址:https://archive.apache.org/dist/httpd/binaries/win32/ 这里面有很多版本,我下载的是这个:httpd-2.2.18-win32-x86-no_ssl.msi

安装的时候,就按照缺省的设置安装,安装完会自动启动apache2.2服务,系统托盘区也会多一个apache的图标:

 

 打开浏览器,输入网址http://localhost/,显示如下:

 出现It works! 就说明已经安装成功。

写一个CGI的程序

由这个CGI程序来调用DLL
主要代码如下:

#include <windows.h> 
#include <stdio.h> 

int main()
{
	HINSTANCE hinstLib;

	printf("Access-Control-Allow-Origin:*\n");
	printf("Content-type: text/html\n\n");

	hinstLib = LoadLibrary(TEXT("c:\\TestDll.dll"));



	if (hinstLib != NULL)
	{
		typedef int(__stdcall* SUM)(int, int);
		SUM sum;
		sum = (SUM)GetProcAddress(hinstLib, "sum");

		if (NULL != sum)
		{
			int ret = sum(1,2);
			printf("%d", ret);
		}
		else
		{
			printf("can not find function sum ");
		}

		FreeLibrary(hinstLib);
	}
	else
	{
		printf("load library fail!");
	}
	return 0;
}

"C:\\TestDll.dll" 是DLL文件所在的路径,要改成您相应的文件路径
printf("Access-Control-Allow-Origin:*\n");这句是为了解决跨域问题的
printf("Content-type: text/html\n\n");  \n\n这个说明HTTP响应头部结束

printf("%d", ret); 这句是真正在网页上显示的内容

注意事项,因为我们安装的APACHE HTTPD是Win32版本的,所以我们使用的TestDll.dll也必须是Win32(x86)版的,这个CGI程序在编译的时候也要选择Win32(x86)版的。

把CGI程序部署到APACHE HTTPD服务器

我们把编译好的exe文件改名为dllhelpercpp.cgi, 复制到APACHE HTTPD的CGI-BIN目录里面。
打开浏览器,打开网址http://localhost/cgi-bin/dllhelpercpp.cgi,如果出现一个数字3,就说明部署成功了。

测试

现在我们修改test.html文件,
把httpRequest.open('GET',    'http://localhost/',true); 
改成httpRequest.open('GET',    'http://localhost/cgi-bin/dllhelpercpp.cgi',true);
用浏览器打开test.html文件,点击“HTTP GET”看看得到的结果是不是和JAVA版本的一样?

CGI程序更进一步的开发

可以参考下面两个网页:
https://blog.csdn.net/u010105970/article/details/41278489
https://blog.csdn.net/weixin_39652658/article/details/116873261

猜你喜欢

转载自blog.csdn.net/dengxiaodai/article/details/128770811