--这篇文章饿内容是写得,在做一些项目,客户要求web版本,但是我们的现有的框架式桌面程序,为满足这个要求做的一个临时的解决方案,已经基本实现,当然还有一些小的瑕疵。在此通过博客备忘下。
1,基本原理
WinForm不能运行在网页中,但是ActiveX控件作为IE的插件,可以嵌在网页中运行。如果我们将winform装在这个ActiveX插件中,似乎就可以实现将winform程序转换为“B/S”程序,在IE下运行了。因此我们首先实现一个ActiveX形式的Form容器用来装在WinForm。
2,WinForm的ActiveX容器
基本功能是加载指定的Winform窗体。
指定程序集和窗口名称,使用反射技术可以动态加载窗体。
3,依赖的程序集的加载
一个复杂的程序可能有很多程序集,包括系统的程序集和自定义的程序集。在运行时,系统会自动加载用到的程序集。系统在加载程序及时,首先从GAC、系统目录、宿主程序所在的目录下查找程序集。若要顺利加载程序集,可以将程序集放在以上的位置。但是如果在IE下运行的话,宿主程序(IE)所在的目录就是IE安装的目录,一般是:C:\Program Files\Internet Explorer。很显然,将程序集放在IE安装目录不是很好的选择。
3.1,将程序集放在IE安装目录的子目录中
这个方法比直接放在IE目录下稍微好点,至少不会显得太乱。通过指定程序运行的私有目录可以使得加载程序查找该目录,一边从该目录下加载所需的程序集。
3.2,将程序集放在IE安装目录之外的指定目录中。
这样最好,不与IE混在一块。但是问题是,如何指定程序集所在的位置呢,因为,私有目录只能是宿主程序的基础目录的下级目录,也就是说,只能是IE安装目录的下级目录。
有两个方法:
(1)在配置文件中指定程序集所在的位置:
<runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="ClassLibrary1" publicKeyToken="2af6181c6a13eff6" culture="neutral"/> <codeBase version="1.0.0.0" href="D:\ TestCodeBase\ClassLibrary1.dll"/> </dependentAssembly> </assemblyBinding> </runtime> |
MSDN:“对于大多数 .NET Framework 应用程序而言,您可以在以下位置找到构成该应用程序的程序集,这些位置包括:该应用程序的目录中,该应用程序目录的子目录中,或全局程序集缓存中(如果该程序集是共享的话)。可以通过在配置文件中使用 <codeBase> 元素重写公共语言运行库查找某一程序集的位置。如果该程序集没有强名称,则使用 <codeBase> 元素指定的位置将被限制在应用程序目录或子目录中。如果程序集具有强名称,则 <codeBase> 元素能够指定计算机或网络上的任意位置。”
(2)在AppDomain.CurrentDomain的事件AssemblyResolve中处理。如果找不到程序集的话,从指定的目录加载。这种方法,有一点要注意,加载时,不能使用Assembly.LoadFrom(程序集文件)方法加载,因为这个方法,加载失败后,不触发AssemblyResolve事件。要使用Assembly.Load或者Assembly.LoadFile。这3种加载搜索程序集的方式略有不同,不同之处请msdn或者谷歌。与本文无关,不细说。
(3)指定程序运行的私有目录。不知道这个方法可不可以指定运行目录之外的目录位置。测试是不行的,但是参考上面MSDN的说法,是不是程序有了强名称就可以了呢?有识之士可以验证一下。
4,系统配置文件
对.NET开发的winform应用来说,系统默认的配置文件是:[可执行程序文件名].exe.config。如果运行在IE下的话,程序会查找配置文件:iexplore.exe.config。并且也要放在IE的安装目录下,这显然是不合适的。好在.NET提供了个性化配置文件名称和存放位置的方法。通过这个方法可以修改配置文件为特定的文件,比如可以将配置文件放在软件安装目录下。但是如果是已经开发完的系统的话,必须修改源码。
5,系统自动安装
大型网络应用要实现自动部署和自动更新。B/S应用当然也是,这是长久以来B/S程序一直引以为豪的特点之一。当然现在格局变了,一些非B/S程序,比如胖客户端程序也能实现自动部署和自动更新。
5.1 Activex控件本身的安装
IE可以自动下载本地没有安装过的控件,通过指定版本号,还可以实现控件的自动更新。(没有验证)。如果可以的话,控件本身的安装和更新不用做太多的工作。
5.2 程序文件的下载与更新
Activex控件只是应用程序的容器和代理。程序要运行,还需要把需要的程序文件以及配置文件下载到本地,必要时,还需要执行特定的安装程序,比如注册报表组件。除了初次下载安装外,最好还要支持自动更新,当有了更高的版本后,能自动下载并安装之。这个可以考虑由activeX控件来实现。因此ActiveX控件就不仅仅是容器了,应该赋予它更大的使命,可以作为本地程序的管理器,负责程序的下载、安装、自动更新。
6,本地程序管理器
那我们来仔细讨论和设计下本地管理器-增强的activeX包装器,看看它的功能要怎么来实现。
6.1,管理器本身的安装
管理器是个activeX控件,可以通过指定安装程序,由IE自动安装。并通过指定最新的版本号,实现自己的版本更新。
当然也可以提供客户端安装工具,该安装工具可以安装该控件,并能注册控件,优点是可以避免前一种方式可能回由于浏览器设置不当导致安装失败。
6.2,本地程序的管理
应该支持多个应用程序,比如条码系统,进销存系统都可能使用同一个管理器来管理。
(1)首次下载程序
根据指定的本地安装目录,检查是否安装过,如果没有,则根据指定的服务器目录,下载要安装的文件到本地安装目录。本地安装目录:<panwebapp>\<app_id>。
下载完后,执行指定的程序。比如注册报表组件等等。
(2)检查更新
如果本地已经安装过了,则检查服务器上是否有更高版本的程序,如果有,则下载覆盖本地的程序。
(3)装载程序
加载指定的程序集,实例化指定的主窗口。
6.3 管理器的参数
(1)app_id,唯一标识一个应用。管理器可以管理多个应用,通过app_id来区分之。
通过app_id还可以区分本地安装目录,同时本地安装目录还是程序集、配置文件等本地资源文件的加载地址。
(2)app_name,应用名称。
(3)更新服务器地址。管理器在该地址上检查是否有更新版本的程序。如果有,则下载之。
(4)入口程序集的名称和入口窗体名称。
管理器通过这两个参数来加载程序入口界面。
(6)配置文件名称。如果不指定,默认为“入口程序集名称.config”。
(7)应用的logo和图片。在管理器加载应用之前(初始化,检查更新,下载更新)显示在屏幕上。
6.4 管理器与网页的交互功能
(1)修改网页标题。
修改网页标题为主窗体的标题。
这个从技术上可以实现,通过实现一些接口,可以得到浏览器以及网页模型的一些信息,通过这些信息可以修改网页上的某些元素,当然包括网页的标题(Title)。
(2)网页关闭时得到通知
以便通知每个打开的窗口是否关闭,是否保存数据。
一个简单的方式是,ActiveX实现一个关闭方法,由页面JS在网页关闭的时候来调用。要区分是刷新还是关闭两种情况。
另外有个问题,IE在关闭页面或者刷新页面的时候,不会通知ActiveX吗?如果会的话,调用其什么方法呢?
当网页关闭情况下,是否关闭提示窗口不可以有“取消”按钮,因为IE的网页关闭是不可取消的。功能窗口通过判断EAFC的“系统关闭可中止”标志,以及关闭事件是否是由EAFC发出的来确定是否显示“取消”按钮。EAFC需要增加两个标志:“系统关闭可中止”以及“EAFC正在关闭”。
7,一些问题
理论上讲,这种方法可以将任何的winform应用包装运行在IE中,但是也有一些不足。
(1) 文件打开位置
当应用打开一些文件,比如配置文件,图片,图标等资源文件时,一般会假设这些文件存放在应用安装的目录下及其子目录中,在定位时,使用“运行目录”+附加目录+文件名的形式来定位,比如要打开一个图片,希望会是c:\program file\安装目录\imags\logo.gif(其中“c:\program file\安装目录\”是传统winform应用的运行目录)。独立运行的话,这没问题,但是当把应用包装在IE中运行时,取得的应用运行目录是IE的安装路径:“c:\program file\internet explorer\”,合成的图片路径就变成了c:\program file\internet explorer\imags\logo.gif,显然是找不到的,除非你把这些文件复制到IE的安装目录下。这当然不是个好的做法。
一个替代方案是,应用在查找文件时,不要取应用的运行目录(baseDirectory),而要用主窗体程序集的所在目录。因为一般来讲,主窗体会和这些文件位于同样的目录中。这个方案的缺点是,一般程序不会这么做(除非它预先知道将来会被包装在IE下运行),需要修改应用程序的实现,在没有源码的情况下,这比较难以实现。
再一个方案就是,截获本应用对某些文件的打开,进行重定向,这有点木马的做法了。但也许是有效的。
(2)资源文件定位的问题
网上有人反映打开语言资源文件时,会有问题。没有得到验证。
(3)其他问题
比我,我们呢目前的一个些系统中,有些功能使用浮动窗口显示额外的信息,比如新增资产转资申请用浮动窗口显示资产图片。当在IE中切换标签页时,浮动窗口并不消失。导致即便你离开了应用的页面去浏览新浪新闻,浮动窗口依然可见。显然是windows的消息通知出了问题。