• 网页打开客户端本机程序,未安装则提示要求安装


    很多应用都使用到啦。例如飞速土豆,迅雷,QQ,等等。。

    1、 需求描述:项目由网页部分及客户端大厅程序部分组成,网页上有一个进入大厅按钮,如果客户端安装了,点击按钮直接打开客户端程序,如果未安装则提示消息提醒安装客户端程序。

    类似于QQ游戏大厅、联众游戏大厅的打开,QQ的强制聊天功能。

    2、首先要实现如果客户端安装了,就打开客户端,网上大多给出的是通过js调用activex控件的方式实现,因为这样IE会弹出安全提示,感觉不好。

    <SCRIPT language=javascript>
    function Run() {
    var o = new ActiveXObject("WScript.Shell");
    o.exec("D:\\Program Files\\Ulead Systems\\Ulead VideoStudio 9.0\\vstudio.exe");
    }
    </SCRIPT>

    其实我们只需要通过注册协议方式就可以成功实现。

    在客户端安装时我们只需要写如下注册表信息:

    [HKEY_CLASSES_ROOT\test]
    @="testProtocol"
    "URL Protocol"="\"C:\\Program Files\\test.Setup\\test.exe\""

    [HKEY_CLASSES_ROOT\Ustcori\DefaultIcon]
    @="\"C:\\Program Files\\test.Setup\\test.exe,1\""

    [HKEY_CLASSES_ROOT\test\shell]

    [HKEY_CLASSES_ROOT\test\shell\open]

    [HKEY_CLASSES_ROOT\test\shell\open\command]
    @="\"C:\\Program Files\\test.Setup\\Driver.exe\""

    这样就注册了一个新协议test,之后直接通过在浏览器中输入test:\\\ ,就会自动从注册表中查找该协议程序的地址,打开客户端程序。

    3、然后就要实现客户端未安装时,提示消息了。

    这个颇费周折,网上没有找到相关的方式,大多的实现方式也是通过js调用WScript.Shell控件。

    后来找到了网上有很多QQ的实现方式:

    function   IsInstallQQ(){    
      try{//支持  
      var   xmlhttp=new   ActiveXObject("TimwpDll.TimwpCheck");  
          return   true;  
      }catch(e){//不支持  
      location.href='http://is.qq.com/webpresence/up_alarm.shtml';  
      //window.open('http://is.qq.com/webpresence/up_alarm.htm','','toolbar=no,location=no,directories=no,status=no,menubar=no,   scrollbars=yes,resizable=no,copyhistory=no,width=410,   height=410,top=0,left=0')  
      return   false;  
      }  
      return   false;  
      }  

    对于红色那段activex的调用是怎么回事却没有说明,搜索一下发现msn,迅雷等其实是通过类似的方式实现的,制作一个自定义控件后,并对它进行安全授权,连同客户端程序一起安装,该自定义控件会往注册表中写值,然后通过js实例化该控件,如果异常说明客户端程序未安装。

    看一下QQ如何写值的:

    [HKEY_CLASSES_ROOT\TimwpDll.TimwpCheck]
    @="TimwpDll.TimwpCheck"

    [HKEY_CLASSES_ROOT\TimwpDll.TimwpCheck\CLSID]
    @="ED4CA2E5-0EEA-44C1-AD7E-74A07A7507A4"

    认准的实现方向,那么下面就展开对于自定义activex控件的调查。

    4、利用VS2008制作自定义activex控件

        a、首先在解决方案下建一个Windows控件库项目(windows from control library),然后增加一个控件UstcOriWebLab.cs。

        b、打开AssemblyInfo.cs修改程序集信息。引用System.Security命名空间,并添加[assembly : AllowPartiallyTrustedCallers()]安全声明,修改[assembly: ComVisible(false)]为[assembly: ComVisible(true)]使程序集Com可见。

        c、为Com Interop注册。右键demoActiveX项目属性,在“生成”选项卡里将“为Com Interop注册”打上勾即可。

        d、选择菜单工具->创建 Guid工具生成一个新的Guid{E5FD041B-8250-4cbc-B662-A73FC7988FB5},copy下来,加在类头上

    [Guid("F325140B-90E3-42d7-8F27-F1E68E1BD92E"), ProgId("UstcOriWebLabActivex.UstcOriWebLab"), ComVisible(true)]

    F325140B-90E3-42d7-8F27-F1E68E1BD92E就是写入注册表的CLSID,UstcOriWebLabActivex.UstcOriWebLab为键名。

       e、实现IObjectSafety接口,把ActiveX控件标记为安全的。

    ActiveX危险,那么为什么QQ以及MediaPlayer等都是用ActiveX的方式创建的,却没有问题?原来,这是因为这些ActiveX组件都声明自己是脚本安全的,而IE的中级安全设置上,是允许脚本安全的ActiveX创建,并且不予警告的。

    IE怎么知道一个插件是脚本安全的?它是通过以下两个办法。一是查询ActiveX组件是否实现了IObjectSafety接口,并且返回脚本安全;二是查询ActiveX组件是否在注册表的Component Category Manager里表明自己实现了CATID_SafeForInitializing和CATID_SafeForScripting。(参考http://blog.csdn.net/optman/archive/2007/07/18/1698070.aspx

    那么我们就通过实现IObjectSafety接口

    建一个接口文件IObjectSafety.cs,内容如下:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;

    namespace UstcOriWebLabActivex
    {
        [ComImport, GuidAttribute("CB5BDC81-93C1-11CF-8F20-00805F2CD064")]
        [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
        public interface IObjectSafety
        {
            [PreserveSig]
            int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);

            [PreserveSig()]
            int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
        }
    }

    在UstcOriWebLab.cs中实现接口

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Data;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Runtime.InteropServices;

    namespace UstcOriWebLabActivex
    {
        [Guid("F325140B-90E3-42d7-8F27-F1E68E1BD92E"), ProgId("UstcOriWebLabActivex.UstcOriWebLab"), ComVisible(true)]
        public partial class UstcOriWebLab : UserControl, IObjectSafety
        {
            public UstcOriWebLab()
            {
                InitializeComponent();
            }

             private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
            private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
            private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
            private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
            private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";

            private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
            private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
            private const int S_OK = 0;
            private const int E_FAIL = unchecked((int)0x80004005);
            private const int E_NOINTERFACE = unchecked((int)0x80004002);

            private bool _fSafeForScripting = true;
            private bool _fSafeForInitializing = true;

            public int GetInterfaceSafetyOptions(ref Guid riid,
                                 ref int pdwSupportedOptions,
                                 ref int pdwEnabledOptions)
            {
                int Rslt = E_FAIL;

                string strGUID = riid.ToString("B");
                pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
                switch (strGUID)
                {
                    case _IID_IDispatch:
                    case _IID_IDispatchEx:
                        Rslt = S_OK;
                        pdwEnabledOptions = 0;
                        if (_fSafeForScripting == true)
                            pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                        break;
                    case _IID_IPersistStorage:
                    case _IID_IPersistStream:
                    case _IID_IPersistPropertyBag:
                        Rslt = S_OK;
                        pdwEnabledOptions = 0;
                        if (_fSafeForInitializing == true)
                            pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                        break;
                    default:
                        Rslt = E_NOINTERFACE;
                        break;
                }

                return Rslt;
            }

            public int SetInterfaceSafetyOptions(ref Guid riid,
                                 int dwOptionSetMask,
                                 int dwEnabledOptions)
            {
                int Rslt = E_FAIL;

                string strGUID = riid.ToString("B");
                switch (strGUID)
                {
                    case _IID_IDispatch:
                    case _IID_IDispatchEx:
                        if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) &&
                             (_fSafeForScripting == true))
                            Rslt = S_OK;
                        break;
                    case _IID_IPersistStorage:
                    case _IID_IPersistStream:
                    case _IID_IPersistPropertyBag:
                        if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) &&
                             (_fSafeForInitializing == true))
                            Rslt = S_OK;
                        break;
                    default:
                        Rslt = E_NOINTERFACE;
                        break;
                }

                return Rslt;
            }
        }
    }

    f、开始制作安装包

    新建一个安装项目,在项目上点右键,【添加】->【项目输出】,添加刚才的项目,生成项目,这样我们的activex控件就会和客户端程序一起安装到用户的机器上了。会生成两个文件,一个exe文件和一个msi文件。

    安装后,就是自动写入注册表键UstcOriWebLabActivex.UstcOriWebLab。

    客户端通过js检查:

    function   IsInstall(){    
      try{//支持  
            var   xmlhttp=new   ActiveXObject("UstcOriWebLabActivex.UstcOriWebLab");  
           window.navigate('Ustcori:///');  //打开客户端
      }catch(e){//不支持  
    alert("您未安装大厅程序!");

      return   false;  
      }  
      return   false;  
      }  

    OK搞定!!!!!!

    总结一下思路:

    通过写注册表自定义协议,然后通过协议地址打开客户端;

    自定义activex控件,并对控件进行安全授权,然后将该控件和客户端程序一起安装,写入注册表;

    最后通过js实例化自定义activex控件来检查控件是否安装,从而判断客户端程序是否安装。

    作者:达奇
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    设计模式六大原则之单例模式
    SpringCloud Alibaba Seata---处理分布式事务
    SpringCloud Alibaba Sentinel---实现熔断与限流
    Linux下Nacos集群与持久化配置
    SpringCloud Alibaba Nacos---服务注册与配置中心
    SpringCloud(H版)学习---分布式请求链路追踪
    Markdown主要语法及使用
    project read error(项目读取错误)
    详解C3P0(数据库连接池)
    Java一般命名规范
  • 原文地址:https://www.cnblogs.com/dachie/p/1822303.html
Copyright © 2020-2023  润新知