在用C#操作Excel作报表的时候,你可能遇到这样的困扰(用其他COM时也存在类似的问题):引用的组件是哪个版本的Office提供的;想使用tlbimp得到excel.dll,却不知道对哪个文件执行tlbimp(Excel9.olb或Excel.exe)。对于前者我自己深有体会:Office XP以后的版本比Office 2000提供的一些方法的参数要多(比如Excel.Workbooks.Open方法),而且引用Office XP以后版本的dll的.NET应用程序在安装Office 2000的系统上可能会出问题(我遇到过由Excel._Worksheet CurSheet = (Excel._Worksheet)WorkBook.Sheets[1];引发的null值问题),另外,不同版本的Excel引发的客户操作也可能是不同的,如果引用Office 2000下的dll后使用Excel.Workbooks[0].Worksheets[0].Delete()方法删除一个sheet时,会弹出以下对话框:
而引用Office XP以后版本的dll就不会出现这个对话框。
我们在C# Project中添加引用时,可以看到下面这个对话框:
这个对话框列举了当前系统中所有的COM组件,但是它提供的关于类型库的信息并不详细,而且没有搜索功能,用起来不是很方便。
其实,类型库的信息存储在注册表的HKEY_CLASSES_ROOT->TypeLib下:
我们可以使用Microsoft.Win32.RegistryKey类来获取这些信息:
搜索:
类型库详细信息:
代码下载:Down
下载内容包括:
TypeLibs的详细内容:
2
3namespace TypeLibBrowser
4{
5 /**////
6 /// TypeLibs 的摘要说明。
7 ///
8 public class TypeLibs : System.Collections.CollectionBase
9 {
10 public TypeLibs()
11 {
12 //
13 // TODO: 在此处添加构造函数逻辑
14 //
15 }
16
17 private string Obj2Str(object pObj)
18 {
19 if (pObj == null)
20 return String.Empty;
21 else
22 return pObj.ToString();
23 }
24
25 public void GetTL()
26 {
27 const string ROOT_TLB = "TypeLib";
28
29 Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot;
30 Microsoft.Win32.RegistryKey regTLibRoot = regKey.OpenSubKey(ROOT_TLB);
31
32 foreach(string strTypeLib in regTLibRoot.GetSubKeyNames())
33 {
34 Microsoft.Win32.RegistryKey regTL = regTLibRoot.OpenSubKey(strTypeLib);
35 foreach(string strVersion in regTL.GetSubKeyNames())
36 {
37 Microsoft.Win32.RegistryKey regVersion = regTL.OpenSubKey(strVersion);
38 TypeLibBrowser.TypeLib typeLib = new TypeLib();
39 typeLib.GUID = strTypeLib;
40 typeLib.Version = strVersion;
41 foreach(string strValueName in regVersion.GetValueNames())
42 {
43 switch (strValueName)
44 {
45 case "PrimaryInteropAssemblyName" :
46 typeLib.PrimaryInteropAssemblyName = this.Obj2Str(regVersion.GetValue(strValueName));
47 break;
48 default :
49 typeLib.FullName = this.Obj2Str(regVersion.GetValue(strValueName));
50 break;
51 }
52 }
53 foreach(string strSubKey in regVersion.GetSubKeyNames())
54 {
55 Microsoft.Win32.RegistryKey regSubKey = regVersion.OpenSubKey(strSubKey);
56 switch (strSubKey)
57 {
58 case "FLAGS" :
59 typeLib.Flags = this.Obj2Str(regSubKey.GetValue(""));
60 break;
61 case "HELPDIR" :
62 typeLib.HelpDir = this.Obj2Str(regSubKey.GetValue(""));
63 break;
64 default :
65 TypeLibBrowser.TLBFiles typeLibFiles = new TLBFiles();
66 foreach(string strPlatform in regSubKey.GetSubKeyNames())
67 {
68 TypeLibBrowser.TLBFile tlbFile = new TLBFile();
69 tlbFile.Number = strSubKey;
70 switch (strPlatform.Trim().ToUpper())
71 {
72 case "WIN16" :
73 tlbFile.Platform = TypeLibBrowser.TypeLibraryPlatformType.Win16;
74 break;
75 case "WIN32" :
76 tlbFile.Platform = TypeLibBrowser.TypeLibraryPlatformType.Win32;
77 break;
78 case "WIN64" :
79 tlbFile.Platform = TypeLibBrowser.TypeLibraryPlatformType.Win64;
80 break;
81 default :
82 tlbFile.Platform = TypeLibBrowser.TypeLibraryPlatformType.未知;
83 break;
84 }
85 tlbFile.File = this.Obj2Str(regSubKey.OpenSubKey(strPlatform).GetValue(""));
86 typeLibFiles.Add(tlbFile);
87 }
88 typeLib.Files = typeLibFiles;
89 break;
90 }
91 }
92 List.Add(typeLib);
93 }
94 }
95 }
96
97 /**////
98 /// 根据GUID和Version搜索Type Library
99 ///
100 ///
101 ///
102 ///
103 public TypeLibBrowser.TypeLib GetTLDetail(string pGUID, string pVersion)
104 {
105 if (this.InnerList.Count == 0)
106 this.GetTL();
107
108 foreach (TypeLibBrowser.TypeLib t in this.InnerList)
109 if (pGUID == t.GUID && pVersion == t.Version)
110 return t;
111
112 return null;
113 }
114 }
115}
116
再回到本文开头提出的两个问题,我们可以发现在“详细信息”中包含了我们想知道的答案。
BTW:微软为Excel VBA提供的帮助本身就包含两个版本:2000和2002的,2003的应该与2002的相同,需要这个帮助(包括VBA For Access 2000、Excel 2000 、Excel 2002、Outlook 2000、Outlook 2002、Word 2000、Word 2002的资料)的朋友可以留下自己的Email,文件有点大,我无法上传,这些帮助对我们使用C#操作Office大有裨益!