【問題記錄】— 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判斷自定義協議是否存在,有好到方法也希望能得到大家的解答。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM