訪問智能文檔內容 為了能起到作用,你的智能文檔操作DLL一般需要訪問(並且可能修改)下層的Office文檔。在例子中,它是Excel項目進程表電子表格。為了這個目的,ISmartDocument的幾個方法為你下層文檔提供了一個IDispatch COM接口指針。在Office上編寫COM的人知道,Idispatch提供了進入Office對象模型的通道。在Visual Basic中,使用Idispatch和類型庫是相當自動化的,但是在C++中稍微復雜一些。
起先我預備使用#import指令,它答應Visual C++為類型庫中的所有接口生成ATL智能指針包裝。但是要讓它正確的編譯需要做大量的工作,它經常提示有東西出錯了。果真,我找到了知識庫文章“Office Application Remains in Memory After Program Finishes”,它描述了在Office類型庫中使用#import指令所碰到的知名的問題以及相應的建議。
最後,我決定建立自己的類CexcelWorkbook來包裝需要的Excel方法。這個類繼續自ATL模版CcomDispatchDriver,這使它相對輕易通過IDispatch調用Excel對象模型上的方法。使用CcomDispatchDriver的方法GetIDOfName,你可以得到一個給定的屬性或方法(例如,Excel對象模型中的ActiveSheet的范圍)的DISPID。你一旦有了DISPID(為了效率更高,我在類中對它進行了緩沖處理),就可以使用某個其它的CcomDispatch方法(例如GetProperty或InvokeN,此處的N是參數的數量)訪問對象模型中的屬性和方法。注重Exce Range值是作為VBA屬性(而不是方法)暴露的,但是它也需要一個參數(范圍地址)。因為CcomDispatchDriver沒有提供為GetProperty調用傳遞的參數的途徑,我在自定義類(CExcelWorkbook)中實現了一個新的方法(GetProperty1),它用於處理這種情況。
調試智能文檔DLL
一切都在預料之中,在我嘗試建立智能文檔操作DLL的時候也沒有出現異常。我試圖在Excel中附加一個XML大綱的時候,收到了一個錯誤信息“XML擴展包邏輯丟失或無效”。為了調試這個錯誤,我首先使用ListDLLs(http://www.sysinternals.com上的一個方便的工具)確定Excel是否載入了我的庫,這樣清單才能看起來足夠好,它可以讓Excel找到該DLL的。我退出Excel,接著修改了項目的Debugging屬性(右鍵點擊解決方案並選擇“屬性”)告訴Visual Studio使用Excel作為該DLL的EXE容器。我浏覽Excel.exe並選擇它作為Command值。
接著,我按下Ctrl-B打開“New Breakpoints”對話框,在Function字段中輸入DllMain,當出現“disambiguate symbol”窗口(顯然有兩個重載的DllMain函數)的時候選擇了它們兩個,通過這些操作在DllMain中設置了一個斷點。我的目的是當Excel第一次調用該DLL的時候得到控制權。接著我按下F5,Excel啟動了。Visual Studio警告沒有Excel符號,但是我早就知道了。我打開智能文檔,使用Data XML XML EXPansion Packs試圖再次附加XML大綱。Visual Studio同ATL生成的DllMain中的斷點一起出現了。
這個時候我的目標是確定DLL中是否有方法、哪些方法被調用了。我在自己的IsmartDocument接口實現中的所有方法上設置了斷點,以確定它們其中的哪些被調用了。實際上,有幾個方法被調用了,並且通過逐步運行我找到了一個普通的索引問題,傳遞到get_SmartDocXmlTypeName的控件索引是從1開始的,但是C++代碼把它處理為從0開始的,因此對最後一個元素的調用返回了E_INVALIDARG。後來我給所有的接口方法的入口點添加了ATLTRACE2宏,使自己更輕易知道正在調用什麼、什麼時候調用。
改變通知
對於示例解決方案,我需要知道用戶什麼時候選擇了電子表格的數據項區域中的某行,這意味著他希望編輯該事務的相關信息。接著我從當前行中抓取信息並填充事務面板,答應他輸入本周的工作和下一周的計劃工作的相關信息。當他改變了事務面板中的某些東西的時候,我將使用Excel對象模型把新的信息復制回原工作表行。但是我如何知道什麼時候選擇了新的行?有一種比較復雜的解決方案,即使用Excel事件(在Visual Basic中輕易,但是在C++中不是太輕易),但是我發現這是沒有必要的。在Excel中無論選擇什麼時候發生了改變,都會調用IsmartDocument接口方法,因此無論什麼事情,你僅僅需要改變通知。通過更新每次改變後的進度表事務內部視圖,我能夠忽略行選擇的變化。
安全性
因為宏病毒和其它的腳本技術的惡意使用變得很普遍,Office在兩個途徑做了修改:通過提高默認的安全性設置,防止運行大多數沒有簽名的、潛在的惡意代碼;通過增加安全性設置的數量,為即使沒有數字簽名的解決方案的運行提供了更多的治理權限。這考慮了現實情況:很多Office解決方案(嵌入Word或Excel文檔中的宏)都已經廣泛的布署在大型組織中,要讓它們完全安全將花費一定時間。假如新版本Office忽然要求所有的解決方案必須有數組簽名(理想的解決方案),這將給很多組織帶來布署方面的障礙。但是,Office安全性設置的增加也使安全性更加復雜,在本文中我沒有談到這個主題。
應用於宏和插件程序的相同的Office安全性設置也可應用於智能文檔。這些設置包括:
·用戶宏的安全性設置(高、中或低,在Tools Macro Security中設置;默認的是高)。
·智能文檔是否從可信(trusted)位置載入:可信的文件系統目錄(例如每個用戶的或工作組模版目錄)、公司局域網上的Web服務器或可信的Internet站點。
·智能文檔組件是否是數字簽名的,假如是,發行人是否在Tools Macro Security Trusted Publishers設置為可信發行人。
·是否在Tools Macro Security Trusted Publishers中選擇了“相信所有安裝了的插件程序和模版”。
默認情況下,Tools Macro Security中的安全性層次被設置高,Office阻止任何沒有數字簽名的插件程序DLL(包含智能文檔操作DLL)的載入。上面列舉的安全性設置的其它組合可以答應智能文檔被載入(可能給用戶顯示一個安全性提示),但是保證組織中的安全性的最好途徑仍然是使用從VeriSign或GTE CyberTrust得到的數字證書對所有的已布署的解決方案(包括智能文檔組件)進行數字簽名。微軟2003 智能文檔SDK中的XMLSign.exe工具可以用於對XML智能文檔清單文件進行數字簽名。
此外,假如某個Office智能文檔解決方案是從Web服務器上運行的,微軟Internet Explorer和Office安全性設置都會影響解決方案是否能運行。假如服務器上的XML擴展包清單文件既不在Internet Explorer可信站點中,也不在局域網區域,就不會試圖檢索它,也不會給用戶提示把該站點添加到Internet Explorer可信列表站點列表中。假如XML擴展包清單文件位於可信的服務器或局域網上,清單是否被載入依靠於它是否簽名了。假如它是簽名了的,並答應運行,它仍然受到用戶Office安全性設置的約束。
在智能文檔解決方案開發過程中,你可以通過編輯注冊表的下述鍵下面的REG_DWORD值“DisableManifestSecurityCheck”激活或禁止XML擴展包清單文件安全性檢查:
HKEY_LOCAL_MACHINESoftwareMicrosoftOfficeCommonSmart Tag 假如它的值為1將禁止XML擴展包清單文件安全性檢查,假如值為0就激活了它。當你試圖引用某個XML擴展包清單文件的時候,假如這個注冊表設置是1(禁止安全性檢查),將出現一個對話框警告用戶禁止安全性是危險的。它同時提供一個“確定”按鈕,這個按鈕答應你立即重新激活XML擴展包安全性檢查。你應該僅僅在開發解決方案的時候把開發計算機的注冊表的這個值設置為1(這個時候每次編譯每個組件後進行數字簽名可能不方便),但是要確保在簽名後的組件的最後測試中激活它。在用戶計算機上禁止XML擴展包清單文件安全性檢查是非常不可取的。
盡管本文討論了在C++中智能文檔操作DLL的建立,但是用Visual Basic .NET或C#建立受控操作DLL也是可行的。在那種情況下,將應用.NET框架組件安全性模型,但是這超出了本文討論的范圍。
生成狀態報告
我的示例依據Excel對象模型使用Idispatch訪問來自進度表智能文檔工作表的信息以生成狀態報告。我也可以選擇開發一些C++代碼來驅動Word對象模型建立狀態文檔,但是我選擇了另一種途徑,它也利用了Word 2003中的新XML特性的優點。我把狀態報告生成為XML文件,並使用XSLT在Word中打開它以提供良好的格式化。這種方法利用了使用XSLT很輕易把幾個XML文件(可能是整個小組的狀態報告)合並成一個大的報告的優點,假如它們作為Word文檔保存就很難合並了。
在花費一段時間研究如何實現XML保存後,我決定定義一個類來治理將顯示在狀態報告上的數據項列表。當開發者更新進度表中的信息的時候,智能文檔操作DLL中的代碼就會建立並更新這個事務列表,這與文檔操作工作面板中放置的控件對應。最後,開發者點擊工作面板中的控件生成XML狀態報告。每個類負責使用MSXML DOM正確地保持存儲在XML中的信息。處理這種情行的處理方法是CScheduleTaskList和CScheduleTask。我用於格式化它的Word XSL樣式表是ScheduleReport.xsl,它在示例代碼中提供了。當你安裝智能文檔解決方案的時候,這個XLST文件就會被安裝好,並讓Word知道它,這樣當你在Word中打開XML狀態報告的時候,它將自動應用這個樣式表。你也可以使用Word中的XML數據視圖事務面板來選擇這個樣式表。
在我生成的XML中有一個指令值得提起: