C#下OCX控件的完美使用
在上一篇C#下COM組件調用篇中,我當時沒有把OCX的使用方法說清楚,主要原因是我那時有一個核心問題沒有解決好,后來在CodeProject中看到一篇文章,一下解開了心中多年的疑惑,豁然開朗。在這里分享一下最新的研究成果。
OCX使用的關鍵問題點
其實OCX使用中,有兩個關鍵點需要解決:
- 1、如何獲取到AxInterop文件
- 2、Visual Studio 設計Form時,可以在工具箱位置找到OCX控件,且使用我們自己的Axinterop。
只要大家親身使用過OCX控件就會有體會,以前我都是直接在工具箱里面點擊添加項,然后選COM頁簽,找到我想要的控件,最后選中確認。此時VS會進行一連串的TlbImp和AxImp操作,然后給你自動生成一大堆的Interop和AxInterop,簡直是自動的不要不要的。但是以前文章中說過的COM Interop 拖家帶口問題和ADODB問題,會造成你的項目引用非常混亂,2008系統會各種報錯。
加之U8的COM組件和OCX控件引用關鍵錯終復雜,搞得我最后一聽說要畫控件在Form上就惡心。我也在網絡上找了很多資料,不管是國內的還是國外的論壇,基本回答都是手工使用AxImp加上rcw參數,解決引用問題。然后都不說怎么在VS的工具箱里增加控件。后來我測試發現,rcw參數也解決不了ADODB錯誤。我也就沒有在深入研究下去。有興趣的可以看看我之前的文章,rcw參數和TlbImp的reference參數差不多。
OCX止吐關鍵技術
AxInterop引用關系解決
第一個問題,AxInterop引用錯誤問題,還是建議使用IL工具進行編譯修改。如果不會或者不明白看我之前的COM使用技巧第二章。換言之,我們必須先得到一個已經解決了引用關系的Axinterop。
VS工具箱引用解決
VS工具箱引用問題,其實並不難,這里僅僅需要使用到AxImp工具的一個參數,直接給大家看一下命令行
C:\ax>aximp /source "c:\u8soft\ufcomsql\vsflex8u.ocx"
生成的源: C:\ax\AxVSFlex8U.cs
生成的程序集: C:\ax\VSFlex8U.dll
生成的程序集: C:\ax\AxVSFlex8U.dll
簡單說,我們這里利用aximp的一個叫做srource的參數,搞出來一個C#版本的源碼文件,引入項目,並通過修改這個文件的代碼就可以讓控件顯示在工具箱里面了。
這里有一點,需格外強調一下,我們雖然這里使用了aximp,但是他生成的其他文件我們都不用,比如后面兩個DLL文件,或者說,就唯獨使用那個cs源碼文件。下面看看這個剛剛生成出來的CS文件,熱乎的時候是什么樣子,記住此時他是不正確的,需要進行下一步修改才可以。
//------------------------------------------------------------------------------
// <auto-generated>
// 此代碼由工具生成。
// 運行時版本:4.0.30319.42000
//
// 對此文件的更改可能會導致不正確的行為,並且如果
// 重新生成代碼,這些更改將會丟失。
// </auto-generated>
//------------------------------------------------------------------------------
[assembly: System.Reflection.AssemblyVersion("1.0.0.0")]
[assembly: System.Windows.Forms.AxHost.TypeLibraryTimeStamp("09/30/2011 10:57:06")]
namespace AxVSFlex8U {
[System.Windows.Forms.AxHost.ClsidAttribute("{3705b4e2-8fcb-4a21-8cce-5d6a98c32456}")]
[System.ComponentModel.DesignTimeVisibleAttribute(true)]
[System.ComponentModel.DefaultEvent("SelChange")]
[System.ComponentModel.DefaultProperty("Text")]
public class AxVSFlexGrid : System.Windows.Forms.AxHost {
private VSFlex8U.IVSFlexGrid ocx;
private AxVSFlexGridEventMulticaster eventMulticaster;
private System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
private msdatasrc.DataSource axDataSource;
public AxVSFlexGrid() :
base("3705b4e2-8fcb-4a21-8cce-5d6a98c32456") {
this.SetAboutBoxDelegate(new AboutBoxDelegate(About));
}
'后面代碼一律省略,毛用沒有,沒必要看!!!
代碼修改1
注意看這個文件的幾個地方,第一個就是版本號,在上文的11行
[assembly: System.Reflection.AssemblyVersion("1.0.0.0")]
這行代碼必須刪除,放在這里就是報錯用的。
代碼修改2
namespace AxVSFlex8U {
命名空間必須修改成你的項目中的命名空間
代碼修改3
'必須增加ToolboxItem參數
[System.ComponentModel.ToolboxItem(true)]
public class AxVSFlexGrid : System.Windows.Forms.AxHost {
這個非常非常重要,就因為有了這個才真正讓VS識別出來是控件類。
代碼修改4
最后添加 MSACAL.dll 和 Stdole.dll 兩個引用,一般情況下VS會提示你的。
最后我們看一下完美解決后的文件
'刪除垃圾代碼
[assembly: System.Windows.Forms.AxHost.TypeLibraryTimeStamp("09/30/2011 10:57:06")]
namespace WindowsFormsApp1 '命名空間修改
{
[System.Windows.Forms.AxHost.ClsidAttribute("{3705b4e2-8fcb-4a21-8cce-5d6a98c32456}")]
[System.ComponentModel.DesignTimeVisibleAttribute(true)]
[System.ComponentModel.DefaultEvent("SelChange")]
[System.ComponentModel.DefaultProperty("Text")]
[System.ComponentModel.ToolboxItem(true)] '屬性增加
public class AxVSFlexGrid : System.Windows.Forms.AxHost {
然后試着編譯一下程序,用X86編譯你的項目,64的編譯后不能拖拽控件,去設計一下窗體,看看工具箱里面是不是出現了一個叫做AxVSFlexGrid的控件了,然后拖拽控件進入Form,版權提示后,就有一個美麗的控件嵌入Form中了。是不是很神奇!
勞動成果的復用
到此OCX問題完美解決了。如果你想讓勞動成果最大化復用,並為后期的項目使用,完全可以把這個項目編譯成類庫,然后供給其他項目引用。我測試后發現是好用的,關鍵點在於需要到工具箱里面增加引用,如圖
然后就可以正常拖拽控件進入Form了,使用過程非常簡單,記住你的項目必須X86。
也就是說如果你願意,可以把所有常用的控件都封裝到一個DLL中,然后引用后直接使用,這操作簡直666,比VB6引用控件方便太多了。
大家有任何問題,可以在博客中留言,我會在平時進行回復。