为完成网页自动下载并安装控件的功能,需要通过C#创建一个ActiveX控件,然后将该控件置于安装程序中,在打开网页的时候下载、安装并注册该ActiveX控件。本文是采用VS2005创建的,VS2003创建过程与之相似。
首先,创建一个类库,为其命名为CreateActiveXEmail:
删除掉默认生成的类Class1.cs,创建一个接口ActiveXEmailInterface:
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Runtime.InteropServices;
namespace
CreateActiveXEmail
...
{ [Guid( " CB5BDC81-93C1-11CF-8F20-00805F2CD064 " ), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] public interface ActiveXEmailInterface ... { void GetInterfacceSafyOptions( int riid, out int pdwSupportedOptions, out int pdwEnabledOptions); void SetInterfaceSafetyOptions( int riid, int dwOptionsSetMask, int dwEnabledOptions); } }
其中GUID可以通过【工具】-【创建GUID】来产生。
实现该接口的目的就是提高程序的安全性,以便客户端IE在不更改设置的情况下可以预行该ActiveX控件。
然后,用你需要实现某些功能的类来继承上面的接口。
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Drawing;
using
System.Data;
using
System.Text;
using
System.Windows.Forms;
using
System.Runtime.InteropServices;
namespace
CreateActiveXEmail
...
{ [Guid( " 060d1308-f34e-4c9f-8962-0abafe385d33 " ), ComVisible( true )] public class ActiveXEmail : ActiveXEmailInterface ... { public void GetInterfacceSafyOptions( int riid, out int pdwSupportedOptions, out int pdwEnabledOptions) ... { pdwSupportedOptions = 1 ; pdwEnabledOptions = 2 ; } public void SetInterfaceSafetyOptions( int riid, int dwOptionsSetMask, int dwEnabledOptions) ... { } public ActiveXEmail() ... { } } }
注意,上面代码中的类属性“ComVisible(true)”,是必须添加的。
在上面的类中,仅仅是现实了接口的两个方法,至于其他需要的方法,自行添加即可。另外,需要对项目属性进行一点修改:
注意,类属性中的“ComVisible(true)”和上图中的【为 COM Interop 注册】缺一不可!只有这样才能生成tlb文件。
这样,一个可用的ActiveX控件就已经生成。在本机你可以随意调用其中的任何方法,但问题是,当客户端机器需要远程调用时,必须在能在客户端机器上注册该ActiveX控件才行。所以,还必须进行下面的步骤:将该ActiveX打包,在安装后在目标机器进行注册。
创建一个安装包:
然后右键单击项目,点击【添加】-【项目输出】,在【主输出】中选择上面创建的工程“CreateActiveXEmail”。然后,打开安装工程的【属性】页面,对项目的【安装URL】项进行设置:
注意,上图的【安装URL】项中,必须使用绝对路径。另外,上图中的“DllFolder”是一个已发布网站“http://172.16.11.136/TestingAX”下的一个目录,这意味着,当在客户端访问页面时,如果客户端未安装当前ActiveX控件,则从路径http://172.16.11.136/TestingAX/DllFolder ”来下载。
最后,在页面中按如下方法调用即可:
<
object
classid
="clsid:060d1308-f34e-4c9f-8962-0abafe385d33"
codebase
="DllFolder/setup.exe#version=1,0,0,0"
></
object
>
另外,还可以采用其他方法,即上面的类库属性不选择【为 COM Interop 注册】,安装工程属性不为【安装URL】指定路径,类中也不添加“ComVisible(true)”属性,而是创建一个安装类:
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Configuration.Install;
using
System.Reflection;
using
System.IO;
using
Microsoft.Win32;
using
System.Diagnostics;
namespace
CreateActiveXEmail
...
{ [RunInstaller( true )] public partial class CustomInstaller : Installer ... { private string regCommandFile = string .Empty; private string unRegCommandFile = string .Empty; public CustomInstaller() ... { InitializeComponent(); } protected override void OnAfterInstall(System.Collections.IDictionary savedState) ... { base .OnAfterInstall(savedState); try ... { // get the path of the Regasm.exe string regasmPath = string .Empty; // get the path of the current executing assembly string currentAsmDLLFilePath = Assembly.GetExecutingAssembly().Location; string currentAsmPath = currentAsmDLLFilePath.Substring( 0 , currentAsmDLLFilePath.LastIndexOf( ' / ' ) + 1 ); string currentRegasmPath = string .Format( " {0}{1} " , currentAsmPath, " RegAsm.exe " ); if ( ! File.Exists(currentRegasmPath)) ... { try ... { RegistryKey frmReg = Registry.LocalMachine.OpenSubKey( @" SOFTWAREMicrosoft.NETFramework " ); if (frmReg == null ) ... { // the .net framework do not exist in the local machine return ; } string frameworkVersion = Environment.Version.ToString(); frameworkVersion = frameworkVersion.Substring( 0 , frameworkVersion.LastIndexOf( ' . ' )); regasmPath = string .Format( @" {0}v{1}{2} " , frmReg.GetValue( " InstallRoot " ).ToString(), frameworkVersion, " RegAsm.exe " ); if ( ! File.Exists(regasmPath)) ... { // the Regasm.exe do not exist in the local machine return ; } } catch (System.ArgumentException ex) ... { throw new System.ArgumentException(ex.Message); } } else ... { regasmPath = currentRegasmPath; } // create the registration command line string regCommand = string .Format( " {0} "{1}" /{2} /{3} " , regasmPath, currentAsmDLLFilePath, " tlb " , " codebase " ); try ... { regCommandFile = string .Format( " {0}{1} " , currentAsmPath, " Regasm.bat " ); if (File.Exists(regCommandFile)) ... { File.Delete(regCommandFile); } using (StreamWriter swReg = File.CreateText(regCommandFile)) ... { swReg.Write(regCommand); swReg.Flush(); } } catch (UnauthorizedAccessException uaex) ... { throw new UnauthorizedAccessException(uaex.Message); } catch (DirectoryNotFoundException dnex) ... { throw new DirectoryNotFoundException(dnex.Message); } catch (IOException ioex) ... { throw new IOException(ioex.Message); } // create the unregistration command file string unRegCommand = string .Format( " {0} "{1}" /{2} " , regasmPath, currentAsmDLLFilePath, " u " ); try ... { unRegCommandFile = string .Format( " {0}{1} " , currentAsmPath, " UnRegasm.bat " ); if (File.Exists(unRegCommandFile)) ... { File.Delete(unRegCommandFile); } using (StreamWriter swReg = File.CreateText(unRegCommandFile)) ... { swReg.Write(unRegCommand); swReg.Flush(); } } catch (UnauthorizedAccessException uaex) ... { throw new UnauthorizedAccessException(uaex.Message); } catch (DirectoryNotFoundException dnex) ... { throw new DirectoryNotFoundException(dnex.Message); } catch (IOException ioex) ... { throw new IOException(ioex.Message); } // register for the COM Interop Process.Start(regCommandFile); } catch (Exception ex) ... { throw new Exception(ex.Message); } } public override void Uninstall(System.Collections.IDictionary savedState) ... { try ... { Process.Start(unRegCommandFile); } catch (Exception ex) ... { throw new Exception(ex.Message); } base .Uninstall(savedState); } } }
因为没有了“ComVisible(true)”和【为 COM Interop 注册】,工程也就无法生成tlb文件,没有tlb文件也就意味着注册失败,dll文件或ActiveX控件在客户端无法使用。上面的类就是通过代码的方式将dll文件在客户端注册,生成tlb文件。
当然,这种方法写的东西比较多点,只是提供一种思路,为其他可能的项目准备。