c# 开发的OCX的部署

相对于开发工作,部署显得不是那么重要,但却是最困难的一步,也是最后一步。
控件的部门总的说来要完成以下几件事,或者说实现以下几个功能:

1、客户端第一次访问页面时自动安装(自动提示用户下载).
2、有新版本发布时自动下载最新版并安装。
经测试还发现,我的2.0框架下开发的控件,不能直接在客户机上进行注册(regAsm.exe:C#开发的ActiveX控件只能用此程序注册,而不能使用RegSvr32),不知道是不是框架版本的问题,只能做成安装文件。
打包成安装文件具体的就不说了,和打包其他项目一样的步骤,但需要注意以下几点:
1、针对控件生成的DLL中有一个Register属性,该属性一定要设置为vsdraCOM,否则安装包只会将DLL文件简单拷到你的目标目录下,设置该值后,安装包才会进行注册表的写入,相当于进行regasm注册。
2、还有一个属性Permanent,看该属性的描述说明是说指定该DLL文件在卸载程序时是否移除,一般性的惯性思维都是设置为true时表示在卸载程序时要移除该dll文件,但经过测试发现设置为flase时才会进行移除操作。如果不移除老版本的文件,新版本安装时不会覆盖原有的文件。所以此属性显得很重要了。
一般说来发布OCX最常用的就是打成CAB包,该方式最简单但也最麻烦,需要搞证书。所以我就自己实现了一种不需要证书的发布方式(前提是要生成安装包:XXXX.msi)。
为了实现自动下载并安装,我把MSI包又制作为自解压包,之后文件名就变成了XXXXXXX.EXE了(这个包的制作就不多说了,用RAR直接可以进行压缩,网上也有很多介绍),这样当用户通过IE下载到本地后,IE会针对EXE类型的文件提示用户是否要现在运行,如果用户选择运行,就会进行自动安装了。整个实现原理就是如此的简单,但在简单的过程中却有比较麻烦的步骤,让页面通知客房端IE下载控件的步骤就较麻烦了。
在控件所在的页面(我用的是JSP页面)只能使用JS脚本进行判断是否需要安装控件或者开载新版本进行安装。
下面我说说通过JS来判断控件的问题。需要判断以下2个内容:
1、判断是否需要新安装。
2、是否发布了新版本的判断。
   需要通过JS读取注册表(有这个东东注定该项目不能移植到非WINDOWS操作系统上了)下的控件的相关项或者键值。如果没找到相应的键则表示没有进行安装,需要新安装。具体判断逻辑直接上代码:
主函数:
   var lastModiDatetime = "<%=lastModiDatetime%>";//读取的服务器上的控件文件的最后修改日期
   //判断当前本地计算机上是否已注册了控件。
   //如果已注册了控件,再次判断是否是最新版本(JAVA现在没有直接提供对文件版本的获取,通过获取文件最后修改日期来变相对比文件新旧)
   //要实现此功能,要求每一次发布新版本控件时必须在应用服务器上安装并注册最新的控件。
   //并把安装路径下的最新RuntimeData.dll及RunData.dll和最新的安装包:
   //wellalarmruntimedata.exe(根据RuntimeDataSetup.msi制作的自解压RAR安装包)拷到WEB应用程序下的petrol/cab下,拷RuntimeData.dll及RunData.dll是为了让JAVA能够获取控件的最新修改日期,拷wellalarmruntimedata.exe是为了让客户端IE在服务器上能找到下载路径及文件。

window.onload=function()
{
           //在系统提示用户是否允许交互前判断当前控件是否加载,通过此属性判断当前是否注册了COM组件
         var isReg = true;
         //通过获取注册表属性得到安装路径
         var hkey_root,hkey_path,hkey_key,path;
         hkey_root="HKEY_CLASSES_ROOT"
         hkey_file://\\CLSID\\{80C07FCA-841C-43C9-BD34-E9F3A6E87A85}\\InprocServer32\\">\\CLSID\\{80C07FCA-841C-43C9-BD34-E9F3A6E87A85}\\InprocServer32\\";  //80C07FCA-841C-43C9-BD34-E9F3A6E87A85就是开发篇强调的控件的GUID
         try
         {
             var RegWsh = new ActiveXObject("WScript.Shell");
             hkey_key="CodeBase" ;  
             path = RegWsh.RegRead(hkey_root+hkey_path+hkey_key);    
             //获取本地机器上的组件版本号  
             var assembly = RegWsh.RegRead(hkey_root+hkey_path+"Assembly");              
             if(assembly!=null)
             {
                 //获取版本号
                 var versionNos = assembly.split("Version=")[1];                
                 var versionNo = versionNos.substring(0,versionNos.indexOf(","));                
                 //查找是否注册此版本号.找到最新版本的就采用此版本的安装路径
                 try
                 {                    
                     var path = RegWsh.RegRead(hkey_root+hkey_path+ versionNo + "\\" + hkey_key);
                 }
                 catch(ex)
                 {
                     isReg = false;
                 }
             }    
         }
         catch(e){}    
         //注意,当用户不允许脚本运行时path也是为NULL值,但只要安装注册了控件,不放管用户是否同意脚本运行,
         //MWellAlm控件都会被创建成object
         if((path==null && document.getElementById("MWellAlm")==null) || !isReg)
         {
             //没有注册此控件或者此控件已被卸载
             msg.style.display = '';
             ctlload.style.display = 'none';
             msg.innerHTML = '本地计算机上未安装“井场预警及实时数据显示控件”或此控件已被卸载,不能正确显示此页面,需要下载最新的控件!<br>';
             msg.innerHTML += "请[运行]自动下载的文件  或者    <a id='loadctl' href='<%=context%>/petrol/cab/wellalarmruntimedata.exe'>点击下载最新显示控件</a>";        
             document.getElementById("loadctl").click();
             return;            
         }
         if(path!=null && document.getElementById("MWellAlm")==null)  
         {
             alert("当前控件已安装注册但不能正确显示,请关闭所有的IE浏览器后重试!");
             return;    
         }    
         document.getElementById("MWellAlm").stop(); //调用控件的方法之一

         //以下就是判断是否发布了新版本
         if(path!=null && path!="")
         {
                var fso = new ActiveXObject("Scripting.FileSystemObject");  
                var f1 = fso.GetFile(path);
                //FSO获取的文件最后修改日期是UTC格式的,JAVASCRIPT还没有对此日期格式操作对象.所以只有转换成字符来处理
                //而且此UTC日期串与从北京时间转换来的UTC串格式不相同
                var lastDate = ""+f1.DateLastModified; //转换成字符串
                var v = new Date();
                v.setTime(lastModiDatetime);                
                //直接通过toUTCString()的格式:Thu, 18 Dec 2008 06:46:04 UTC
                //获取的文件最后修改时间的UTC格式:Thu Dec 18 14:46:04 UTC+0800 2008
                //经测试,这2个UTC时间之前除格式不同外,在小时上还不相同。前者比后者少了8小时
                //在小时上+上8小时,因为这个UTC时间是从北京时间转换来的
                v.setHours(v.getHours()+8);
                //把从北京时间转换来的UTC时间转换成数组,在后者中逐个匹配,都匹配上就说明时间相等
                var ds = v.toUTCString().replace(",","").split(" ");
                //为了保证不出现左右滑动匹配的情况(18不能与118、181匹配),在匹配项与被匹配项左右都加上一个空格
                var baseUtc = " "+lastDate.replace("+0800","")+" ";
                var isEqual = true;
                for(var i=0; i<ds.length; i++)
                {
                    var temp = " "+ds+" ";
                    if(baseUtc.indexOf(temp)==-1)
                    {
                        isEqual = false;
                        break;
                    }
                }
                if(!isEqual)
                {
                    document.getElementById("MWellAlm").click();
                    document.getElementById("MWellAlm").clearAll();  
                    msg.style.display = '';
                    ctlload.style.display = 'none';                    
                    msg.innerHTML = '本地计算机上安装的“井场预警及实时数据显示控件”不是最新版本,不能正确显示此页面,需要下载最新的控件!<br>';
                    msg.innerHTML += "请[运行]自动下载的文件  或者    <a id='loadctl' href='<%=context%>/petrol/cab/wellalarmruntimedata.exe'>点击下载最新显示控件</a>";                    
                    msg.innerHTML += '<br>注意:在安装最新控件之前请保证已通过[控制面板->添加或者删除程序]卸载了旧版本的控件!';
                    document.getElementById("loadctl").click();
                    return;
                }
             msg.style.display = 'none';
             ctlload.style.display = '';            
             document.getElementById("MWellAlm").click();
             document.getElementById("MWellAlm").start();
        }

}
以上就是我实现的控件发布的全部内容。为了保证能顺利发布,要求客户端IE最好把控件所在的站点加为信任站点,并调低安全限制,否则容易发生控件能显示,但不能进行用户交互的情况。
以上功能全部测试通过,而且现在项目中也在正常使用。
OCX技术现在不被人们所看好,也不被推广,但在实际项目中很多时候却不得不运用这些鸡肋技术来解决实际问题,或者实现特定功能,所以很多问题还要参考实际问题找到合适的解决办法。

你可能感兴趣的:(C#)