除了IE支持OCX可以直接在浏览器内部,其他所有现代浏览器都不支持内嵌exe执行并交互返回内容了
采用的是本地HttpListener监听端口,然后前端轮询jsonp的方式实现浏览器和本地exe通信,浏览器兼容性高,只要是支持xhr的浏览器都行,
exe程序启动可以依靠自定义协议在浏览器打开或者将exe打包成window服务持久化运行即可
以下是基础Http类
using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using System.Text;
namespace XXX
{
public class Http
{
private static HttpListener httpobj;
private static readonly string serverUrl = ConfigurationManager.AppSettings["serverUrl"]; //url
private static readonly string accessControlAllowOrigin = ConfigurationManager.AppSettings["accessControlAllowOrigin"]; //跨域设置
private static readonly string responseContentType = ConfigurationManager.AppSettings["responseContentType"]; //返回字符集和格式
private static readonly string accessControlAllowMethod = ConfigurationManager.AppSettings["accessControlAllowMethod"]; //允许跨域的方法
public void Start()
{
httpobj = new HttpListener();
httpobj.Prefixes.Add(serverUrl);
httpobj.Start();
httpobj.BeginGetContext(Result, null);
}
private void Result(IAsyncResult ar)
{
httpobj.BeginGetContext(Result, null);
var guid = Guid.NewGuid().ToString();
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine($"接到新的请求:{guid},时间:{DateTime.Now}");
//获得context对象
var context = httpobj.EndGetContext(ar);
var request = context.Request;
var response = context.Response;
if (accessControlAllowOrigin == "*" || accessControlAllowOrigin==null)
{
context.Response.AppendHeader("Access-Control-Allow-Origin", "*");
}
else
{
//获取源地址
var origin = request.Headers.Get("Origin");
Console.WriteLine($"源域地址:{origin}");
string[] domains = accessControlAllowOrigin.Split(',');
if(((IList)domains).Contains(origin))
{
context.Response.AppendHeader("Access-Control-Allow-Origin", origin);
}
}
context.Response.AppendHeader("Access-Control-Allow-Method", accessControlAllowMethod!=null? accessControlAllowMethod:"GET,POST");//后台跨域请求设置,通常设置为配置文件
context.Response.ContentType = responseContentType!=null?responseContentType:"text/plain;charset=UTF-8";//告诉客户端返回的ContentType类型为纯文本格式,编码为UTF-8
context.Response.ContentEncoding = Encoding.UTF8;
string returnObj = null;//定义返回客户端的信息
if (request.HttpMethod == "POST" && request.InputStream != null)
{
//处理客户端发送的请求并返回处理信息
returnObj = HandlePostRequest(request, response);
}
else if (request.HttpMethod == "GET")
{
returnObj = HandleGetRequest(request, response);
}
else
{
return;
}
var returnByteArr = Encoding.UTF8.GetBytes(returnObj);//设置客户端返回信息的编码
try
{
using (var stream = response.OutputStream)
{
//把处理信息返回到客户端
stream.Write(returnByteArr, 0, returnByteArr.Length);
}
}
catch (Exception ex)
{
}
}
private string HandleGetRequest(HttpListenerRequest request, HttpListenerResponse response)
{
string res = "";
try
{
//解析url
string queryString = request.Url.Query;
Dictionary<string, string> queryMap = new Dictionary<string, string>();
if (queryString.StartsWith("?"))
{
queryString = queryString.Substring(1);
string[] queryStrings = queryString.Split('&');
for (int i = 0; i < queryStrings.Length; i++)
{
string[] queryKeyValue = queryStrings[i].Split('=');
queryMap.Add(queryKeyValue[0], queryKeyValue[1]);
}
}
string query = request.Url.LocalPath;
string[] querys = query.Split('/');
res = DoMethods(querys[querys.Length - 1], queryMap);
response.StatusDescription = "200";
response.StatusCode = 200;
}
catch (Exception e)
{
Program.WriteLog(e.ToString());
response.StatusDescription = "500";
response.StatusCode = 500;
}
return res;
}
private string HandlePostRequest(HttpListenerRequest request, HttpListenerResponse response)
{
string data;
string res="";
try
{
var byteList = new List<byte>();
var byteArr = new byte[2048];
int readLen = 0;
int len = 0;
do
{
readLen = request.InputStream.Read(byteArr, 0, byteArr.Length);
len += readLen;
byteList.AddRange(byteArr);
} while (readLen != 0);
data = Encoding.UTF8.GetString(byteList.ToArray(), 0, len);
string query = request.Url.LocalPath;
string[] querys = query.Split('/');
//获取得到数据data可以进行其他操作
res = DoMethods(querys[querys.Length - 1],data);
response.StatusDescription = "200";
response.StatusCode = 200;
}
catch (Exception ex)
{
response.StatusDescription = "500";
response.StatusCode = 500;
}
return res;
}
public virtual string DoMethods(string control, Dictionary<string, string> queryMap)
{
return "";
}
public virtual string DoMethods(string control, string data)
{
return "";
}
}
}
使用方式为,新建类,继承Http类,重写两个DoMethods方法(分别代表的是get和post)返回的字符串就是请求返回值
例如
using System.Collections.Generic;
namespace XXX
{
sealed class HttpMaker : Http
{
private static HttpMaker http = new HttpMaker();
private static object f;
//单例模式,多种初始化方式
private HttpMaker(object o)
{
f = o;
}
private HttpMaker() { }
public static HttpMaker getHttp()
{
return http;
}
public static HttpMaker getHttp(object f)
{
return new HttpMaker(f);
}
public override string DoMethods(string control, Dictionary<string, string> queryMap)
{
//除了winform对象,任何对象都支持
Form1 form1 = (Form1)f;
switch (control)
{
//建议加一个心跳检测,用于检测服务是否在运行,如果不在运行那就用浏览器自定义协议打开
case "test":{
return "window.$" + (queryMap["f"] != null ? queryMap["f"] : "test") + "={\"msg\":1}";
}
case "stop":
{
form1.quit();
return "";
}
default:
{
form1.test();
return "window.$" + (queryMap["f"] != null ? queryMap["f"] : "test") + "=" + form1.msg + "";
}
}
}
public override string DoMethods(string control, string data)
{
return "I am children";
}
}
}
以上以winform程序为例,form1来自winform程序
样例如下
public partial class Form1 : Form
{
public void quit()
{
Environment.Exit(0);
}
//这儿代表exe里面具体的方法
public void test(){
this.msg="haha";
}
public string msg = "";
public Form1()
{
InitializeComponent();
HttpMaker hm = HttpMaker.getHttp(this);
hm.Start();
}
}
然后就是前端浏览器jsonp轮询
具体在这
jsonp实现轮询超时,前端代码