接到一個需求,要求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>