為完成網頁自動下載並安裝控件的功能,需要通過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 CustomI
...{
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文件。
當然,這種方法寫的東西比較多點,只是提供一種思路,為其他可能的項目准備。