zoukankan      html  css  js  c++  java
  • 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>
  • 相关阅读:
    docker 打包镜像并传输
    bytes函数——字节
    python——多线程
    Golang基础——随机数rand.Seed
    Golang基础——数据类型:数组
    property 和 setter 装饰器
    qrc文件使用
    SQL优化——索引
    mysql结构及存储引擎
    css样式重置以及定位
  • 原文地址:https://www.cnblogs.com/xuhuajie/p/12759313.html
Copyright © 2011-2022 走看看