Fork me on GitHub

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>

 

posted @ 2020-04-23 15:37  烟波--钓徒  阅读(4979)  评论(0编辑  收藏  举报