C#是微软的产物,所以其生成的COM组件目前只能提供给IE使用。
实现网页和本地系统双向调用的方法IE使用ActiveX控件,而在Chrome、FireFox等浏览器有类似的NPAPI插件技术。
开发ActiveX较为简单,开发NPAPI教程较少。
微软新生代浏览器Edge不再支持ActiveX控件,且除了IE其他浏览器基本不兼容ActiveX。
采用Windows系统服务启动WebSocket服务,接收网页客户端发送的指令信息完成相关操作,实现多种浏览器调用ActiveX插件。
C#ActiveX插件制作https://blog.csdn.net/qq_25189723/article/details/101544749
所有测试都支持.Net3.5
Windows系统服务_C#WebSocket服务_C#调用ActiveX实现多种浏览器调用ActiveX插件例子下载
新建Windows服务项目
设计视图中切换到代码视图
重写OnStart和OnStop方法
public partial class EL100Service : ServiceBase
{
public EL100Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
WriteMessage("服务启动");
}
protected override void OnStop()
{
WriteMessage("服务停止");
}
//写文件验证启动
public void WriteMessage(string msg)
{
StreamWriter dout = new StreamWriter(@"D:\" + "EL100WindowsServiceLog.txt", true);
dout.Write("\r\n" + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + msg);
dout.Close();
}
}
设计视图上右键 点 添加安装程序
系统会自动生成“ProjectInstaller.cs”文件,在该文件的设计视图界面会有两个控件,一个是serviceProcessInstaller1,一个是serviceInstaller1
serviceInstaller1属性中设置:
Description(系统服务的描述)
DisplayName (系统服务中显示的名称)
ServiceName(系统事件查看器里的应用程序事件中来源名称)
StartType(启动服务的方式,分为手动、自动和禁用)
serviceProcessInstaller1属性设置:
Account 下拉设置成 LocalSystem
生成服务程序之后,使用InstallUtil.exe进行服务的安装(该文件可能在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\)
安装使用命令 InstallUtil EL100WindowsService.exe
卸载使用命令 InstallUtil -u EL100WindowsService.exe
启动服务或手动启动
NET START EL100ActiveXService
启动服务
如建控制台应用测试
websocket-sharp.dll
using WebSocketSharp.Server;
static void Main(string[] args)
{
WebSocketServer webSocketServer = new WebSocketServer(23981);
webSocketServer.AddWebSocketService("/el100activex");
webSocketServer.Start();
Console.WriteLine("服务启动");
Console.ReadKey();
}
消息处理
using WebSocketSharp;
using WebSocketSharp.Server;
public class EL100ActiveXMessageHandler : WebSocketBehavior
{
protected override void OnOpen()
{
Console.WriteLine("建立连接" + ID);
Broadcast(string.Format("{0}上线了,共有{1}人在线", ID, Sessions.Count));
}
protected override void OnClose(CloseEventArgs e)
{
Console.WriteLine("连接关闭" + ID);
Broadcast(string.Format("{0}下线,共有{1}人在线", ID, Sessions.Count));
}
protected override void OnError(WebSocketSharp.ErrorEventArgs e)
{
Console.WriteLine("错误!");
}
protected override void OnMessage(MessageEventArgs e)
{
Console.WriteLine("收到消息:" + e.Data);
Send(ID+":" +e.Data);
}
private void Broadcast(string msg)
{
Sessions.Broadcast(msg);
}
}
HTML测试
测试WebSocket
内容:
可建控制台应用测试
using System;
using System.Reflection;
private static Type type;
private static object activexobj;
static void Main(string[] args)
{
try {
if (type == null) {
Console.WriteLine("查找插件");
//根据classId获取ActiveX类
type = Type.GetTypeFromCLSID(new Guid("881BF978-EE89-4D08-9396-D5BE3F253615"));
if (type == null)
{
Console.WriteLine("插件不存在");
return;
}
Console.WriteLine("插件存在");
}
if (activexobj == null) {
Console.WriteLine("初始化插件");
//创建类的实例,第二个参数是object数组,就是你的构造方法里面的参数,
//null即为无参构造方法,也可以这么写:
//activexobj = Activator.CreateInstance(type);
activexobj = Activator.CreateInstance(type, null);
if (activexobj == null)
{
Console.WriteLine("插件初始化失败");
return;
}
Console.WriteLine("插件初始化成功");
}
//获取实例的指定方法,根据方法名,还有其他重载,也可以根据参数找
MethodInfo methodInfo = type.GetMethod("GetStr");
if (methodInfo == null) {
Console.WriteLine("方法错误");
return;
}
Console.WriteLine("方法正确");
//调用该方法的参数,按顺序
object[] GetComPortStr_para = new object[] { "测试参数" };
//调用方法,返回值是object
String operate_result = (String)methodInfo.Invoke(activexobj, GetComPortStr_para);
operate_result = operate_result.Replace("\"", "\\\"");
Console.WriteLine(operate_result);
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
Console.ReadKey();
}
常见错误
System.Runtime.InteropServices.COMException (0x80040154): 检索 COM 类工厂中 CLSID 为 {881BF978-EE89-4D08-9396-D5BE3F253615} 的组件时失败,原因是出现以下错误: 80040154。
-->
不存在插件。
或项目右键属性-生成-平台目标x86。
将websocket服务和调用ActiveX插件集成到Windows服务里就可以实现多种浏览器网页调用ActiveX插件了。
ActiveX插件实现的功能也可以直接在Windows服务里实现,只是已经开发完ActiveX只是为了适应其他浏览器就直接调用了。
四、通配传参调用
以参数及返回类型都为字符串为例。
特殊的可以switch。
网页发送方法和参数(可多个参数)的json字符串
function sendMsg(operatemethod, operateparameter){
console.info("operatemethod="+operatemethod +" operateparameter="+operateparameter);
var send_object = {};
$(send_object).attr("operatemethod", operatemethod);
var operateparameter_object = {};
if(operateparameter!=null && operateparameter!=""){
$(operateparameter_object).attr("arg0", operateparameter);
}
$(send_object).attr("operateparameter", operateparameter_object);
websocket.send(JSON.stringify(send_object));
}
C#使用 Json.Net35和Newtonsoft.Json(之前用的Json.Net35文件小,但实现不了嵌套JSON的解析,换Newtonsoft之前实现的序列化也没改。)
JObject rece_JObj = JObject.Parse(e.Data);
operatemethod_str = rece_JObj["operatemethod"].ToString();
methodInfo = type.GetMethod(operatemethod_str);
if (methodInfo == null)
{
SendErrorMsg(operatemethod_str, "方法错误");
isTesting = false; return;
}
//调用该方法的参数,按顺序
//object[] GetComPortStr_para = new object[] { };
List operateparameterList = new List();
var operateparameter_obj = rece_JObj["operateparameter"];
if (operateparameter_obj == null)
{
//SendDebugMsg(operatemethod_str, "无参");
}
else
{
JObject operateparameter = JObject.Parse(operateparameter_obj.ToString());
foreach (JProperty jProperty in operateparameter.Properties())
{
SendDebugMsg(operatemethod_str, "key:" + jProperty.Name + " value:" + jProperty.Value);
operateparameterList.Add(jProperty.Value.ToString());
}
}
//调用方法,返回值是object,我的方法返回void,所以不写
String operate_result = (String)methodInfo.Invoke(activexobj, operateparameterList.ToArray());
operate_result = operate_result.Replace("\"", "\\\"");
SendSuccMsg(operatemethod_str, operate_result);
private void SendMsg(string code, string operatemethod, string msg)
{
fileOperate.WriteMessage("发送消息:" + msg);
var data = new JsonDto() { code = code, msg = msg, operatemethod = operatemethod };
Send(Json.JsonParser.Serialize(data));
}
private void SendSuccMsg(string operatemethod, string msg)
{
SendMsg("1", operatemethod, msg);
}
class JsonDto
{
public string code { get; set; }
public string msg { get; set; }
public string operatemethod { get; set; }
public object operateparameter { get; set; }
}