Windows系统服务+C#WebSocket服务+C#调用ActiveX实现多种浏览器调用ActiveX插件

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服务

新建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

启动服务

如建控制台应用测试

websocket-sharp.dll

using WebSocketSharp.Server;
        static void Main(string[] args)
        {
            WebSocketServer webSocketServer = new WebSocketServer(23981);
            webSocketServer.AddWebSocketService<EL100ActiveXMessageHandler>("/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测试

<html>
<head >
    <title>测试WebSocket</title>
</head>
<body >
<div id="messages"></div>
<div>内容:<input type="text" id="content" value=""/><button onclick="Send()">发送</button></div>
</body>
<script language="javascript">
    var websocket;
    function initWebSocket() {
        if ('WebSocket' in window) {
            websocket = new WebSocket("ws://127.0.0.1:23981/el100activex");
            //连接成功建立的回调方法
            websocket.onopen = function (e) {
                console.log("WebSocket连接成功");
                console.log(e);
            };
            //连接关闭的回调方法
            websocket.onclose = function () {
                console.log("WebSocket连接关闭");
                // 断线重连
                initWebSocket();
            }
            //连接发生错误的回调方法
            websocket.onerror = function () {
                console.log("WebSocket连接发生错误");
            };

            //接收到消息的回调方法
            websocket.onmessage = function (e) {
                console.log("收到",e.data);
				var oldvalue = document.getElementById("messages").innerHTML;
				document.getElementById("messages").innerHTML = oldvalue + e.data + "<br/>";
            }
        }
        else {
            console.info("当前浏览器 Not support websocket");
            alert('当前浏览器 Not support websocket')
        }
    }

    initWebSocket();
    function sendMsg(msg){
        console.info("msg="+msg);
        websocket.send(msg);
    }
    function Send(){
        if(websocket==null || websocket.readyState!=1){
            alert('请先连接成功')
        }
        else{
            var text = document.getElementById("content").value;
            sendMsg(text);
        }
    }
</script>
</html>

三、C#调用ActiveX

可建控制台应用测试

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<string> operateparameterList = new List<string>();

                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; }
    }

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值