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>