web與本地應用程序(exe)的通信示例


            接到一個需求,要求web能夠喚起本地應用並執行功能。有點類似web打開QQ的對應的聯系人的會話。

            具體為:如果本地應用(xx.exe) 不存在,則打開它;如果已經存在,則調用它的某方法(如打開聯系人會話)。

 

            web與exe的通信,在5年前用過ocx的技術。那時chrome還沒那么流行,在ie上安裝下ocx控件,有些用戶也能接受。

            如今用戶的首選瀏覽器都是chrome(比如我)了,只能在ie上跑的技術肯定用不了了。

 

            還好有url-protocol技術。

            大概的流程,是預先寫好注冊表信息,web調用的時候會導航到注冊表的具體信息調用程序。簡單理解就是web版的shellexecute功能。

            可以打開exe並傳入命名行參數。

            光這個技術實現不了“如果已經存在,則調用它的某方法(如打開聯系人會話)。”,還得加上進程間通訊功能。

            打開的第二個exe,發現已經存在exe的實例時,得與第一個exe通信,並把參數傳遞給他執行相應的方法。(我們這里采用WM_COPYDATA)。

 

            接下來,上完整代碼過程。

            一、exe程序實現下檢查單例、發送WM_COPYDATA邏輯,接收WM_COPYDATA邏輯。

           

//增加單實例檢測
    HANDLE mutex = ::CreateMutex(NULL, TRUE, _T("url_protocol_demo"));
    if (mutex == NULL || ERROR_ALREADY_EXISTS == ::GetLastError())
    {
        //如果已經存在實例,則把命名行參數傳遞給第一個進程
        if (lpCmdLine)
        {
            HWND hwnd = FindWindow(szWindowClass, szTitle);  //這里查找主窗口句柄以發送WM_COPYDATA
            if (hwnd)
            {
                COPYDATASTRUCT   cpd;
                cpd.dwData = 0;
                cpd.cbData = (_tcslen(lpCmdLine)+1)*sizeof(TCHAR);
                cpd.lpData = (void*)lpCmdLine;
                SendMessage(hwnd, WM_COPYDATA, NULL, (LPARAM)&cpd);
            }
        }

        //假設只允許單實例
        return 0;
    }

 

 

case WM_COPYDATA:
    {
        //這里我們只是單純的把參數打印出來
        COPYDATASTRUCT* data = (COPYDATASTRUCT*)lParam;
        LPCTSTR cmdline = (LPCTSTR)(data->lpData);
        MessageBox(NULL, cmdline, _T("Params"), 0);
    }
break;

 

   二、寫注冊表

          一般在安裝包中寫注冊表(一般安裝包以管理員權限運行,可以寫注冊表)

         當然如果是demo的話,也可以自己手動寫注冊表。         

         這里給出程序寫注冊表的方法。

         

std::string wholepath = "E:\\代碼\\個人測試代碼\\My\\Debug\\url_protocol_demo.exe";
        std::string protocol = "protocol";
        std::string runpath = "\"E:\\代碼\\個人測試代碼\\My\\Debug\\url_protocol_demo.exe\" \"%1\"";

        char regname[] = ("URLDEMO\\");
        HKEY hkResult;
        DWORD dwDisposition;
        LONG re= RegCreateKeyExA(HKEY_CLASSES_ROOT, regname, 0,NULL,REG_OPTION_NON_VOLATILE,
            KEY_ALL_ACCESS, NULL, &hkResult, &dwDisposition);//創建注冊表
        RegSetValueExA(hkResult, (""), 0, REG_SZ, (unsigned char*)protocol.c_str(), protocol.length()+1);//寫注冊表
        RegSetValueExA(hkResult, ("URL Protocol"), 0, REG_SZ, (unsigned char*)wholepath.c_str(), wholepath.length()+1);
        RegCloseKey(hkResult);    //一定要記得關上注冊表

        char regname2[] = ("URLDEMO\\shell\\open\\command");
        RegCreateKeyA(HKEY_CLASSES_ROOT, regname2, &hkResult);//創建注冊表
        RegSetValueExA(hkResult, (""), 0, REG_SZ, (unsigned char*)runpath.c_str(), runpath.length() + 1);//寫注冊表
        RegCloseKey(hkResult);    //一定要記得關上注冊表

 

最后寫個web調用下,測試下

<!DOCTYPEHTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
 <head>
     <meta http-equiv="Content-Type"content="text/html; charset=utf-8" />
 </head>
   <body>
       <div>
           <a href="URLDEMO://xxxx">
          打開客戶端軟件
           </a>
       </div>
   </body>
</html>

 


免責聲明!

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



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