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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章