頁面----呼叫本地程式
web頁面呼叫本地程式
起因:
最近由於專案需要在web頁面中呼叫本地部署的exe程式;進而對該功能實現做了對應瞭解;以及存在的問題進行記錄。
要實現該功能就不得不說瀏覽器自定義協議;解決辦法:那麼它是什麼呢?
瀏覽器自定義協議:
瀏覽器自定義協議,其實是微軟提供Asynchronous Pluggable Protocols;可以用來註冊本地應用程式到URI Scheme
https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa767914(v=vs.85)
實現自定義協議方式—添加註冊表:
Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\協議名稱] @="程式執行地址" "URL Protocol"="" [HKEY_CLASSES_ROOT\calldemo\DefaultIcon] @="程式執行地址,1" [HKEY_CLASSES_ROOT\calldemo\shell] [HKEY_CLASSES_ROOT\calldemo\shell\open] [HKEY_CLASSES_ROOT\calldemo\shell\open\command] @="程式地址" \"%1\""
自定義協議實現示例:
示例實現:實現一個本地Exe,並註冊到登錄檔中;並執行效果。(程式比較簡單,可以檢視github)
程式實現寫入登錄檔主要邏輯:
static class Program { /// <summary> /// 應用程式的主入口點。 /// </summary> [STAThread] static void Main(string[] args) { RegisterUrlProtocol(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); var from = new Form1(); //顯示輸入引數 from.Args = args; Application.Run(from); }
/// <summary> /// 註冊自定義協議 /// </summary> private static void RegisterUrlProtocol() { try { //檢查是否註冊自定義協議:如未註冊則註冊 Register register = new Register("calldemo", RegDomain.ClassesRoot); if (!register.IsSubKeyExist("calldemo")) { //註冊: register.CreateSubKey(); register.WriteRegeditKey("", $"{Application.ExecutablePath}"); register.WriteRegeditKey("URL Protocol", ""); if (!register.IsSubKeyExist(@"calldemo\DefaultIcon")) { register.CreateSubKey(@"calldemo\DefaultIcon"); register.SubKey = @"calldemo\DefaultIcon"; register.WriteRegeditKey("", $"{Application.ExecutablePath},1"); } if (!register.IsSubKeyExist(@"calldemo\shell")) { register.CreateSubKey(@"calldemo\shell"); register.CreateSubKey(@"calldemo\shell\open"); register.CreateSubKey(@"calldemo\shell\open\command"); register.SubKey = @"calldemo\shell\open\command"; //新增預設鍵 register.WriteRegeditKey("", $"\"{Application.ExecutablePath}\" \"%1\""); } } } catch (Exception e) { MessageBox.Show(e.Message); throw; } }
建立檢驗html:
<a href="calldemo:123qwe">UrlProtocolDemo</a>
執行效果:
github地址:https://github.com/cwsheng/URLProtocolDemo.git
問題記錄:
1、關於js中檢驗瀏覽器自定義協議是否存在,現在沒有教好的解決辦法?
開源專案:https://github.com/ismailhabib/custom-protocol-detection(親測無效,且不維護了)
https://github.com/Veryfirefly/custom-protocol-detection(原理同上,也無效)
問題:https://stackoverflow.com/questions/836777/how-to-detect-browsers-protocol-handlers
2、每次呼叫啟動exe,都會新執行一個程式例項;可以通過程式實現判斷該程式是否已經在執行。
#region 確保程式只執行一個例項 private static Process RunningInstance() { Process current = Process.GetCurrentProcess(); Process[] processes = Process.GetProcessesByName(current.ProcessName); //遍歷與當前程序名稱相同的程序列表 foreach (Process process in processes) { //如果例項已經存在則忽略當前程序 if (process.Id != current.Id) { //保證要開啟的程序同已經存在的程序來自同一檔案路徑 if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName) { //返回已經存在的程序 return process; } } } return null; } //3.已經有了就把它啟用,並將其視窗放置最前端 private static void HandleRunningInstance(Process instance) { ShowWindowAsync(instance.MainWindowHandle, 1); //呼叫api函式,正常顯示視窗 SetForegroundWindow(instance.MainWindowHandle); //將視窗放置最前端 } [DllImport("User32.dll")] private static extern bool ShowWindowAsync(System.IntPtr hWnd, int cmdShow); [DllImport("User32.dll")] private static extern bool SetForegroundWindow(System.IntPtr hWnd); #endregion
最後:
當然該方式不一定是唯一實現方式,也可以嘗試使用WebAssembly實現本地執行程式邏輯,本次未進行驗證
如果js判斷自定義協議是否存在,有好到方法也希望能得到大家的解答。