一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

MFC對EXCEL的操作

 VoidOc 2013-10-14

MFC對EXCEL的操作

要說做OLE Automation容器,我還是喜歡VB,簡單死了。用VC,TMD能麻煩死你,

不過使用起來“麻煩”也正是說明它相當(dāng)靈話。其實用VC實現(xiàn)自

動化容器也只是麻煩,并不難。我們一起來試試看怎么樣?

要做Excel的OLE自動化,前提當(dāng)然是你得對Excel的可編程對象十分了解,

了解它的最好方法就是使用VBA。為了讓大家有個比較,我們將首先用一

段VB代碼來實現(xiàn)一個最簡單的Excel功能,再償試用VC來實現(xiàn)同樣的功能,

看看工作量的差別有多大。

用VB實現(xiàn)自動化容器的好處是你根本不用知道什么是自動化,這就是我最

喜歡的傻瓜用法。真的嗎?真的!不信我信就試試看!各位,請打開筆記

本,啟動VB6,建立一個標(biāo)準(zhǔn)工程,然后選擇“工程”->“引用”,再選

中“Microsoft Excel 8.0 Object Library”點OK,Excel對像庫就裝載

進(jìn)來了,就這么簡單!然后在窗體建立一個命令按鈕并輸入如下代碼:

 Private Sub Command1_Click()

     Dim xlsApp As Application

     Dim xlsWorkSheet As Worksheet

     Dim xlsRange As Range

     ' 第一段

     Set xlsApp = CreateObject("Excel.Application.8")

     xlsApp.Visible = True

     '第二段

     xlsApp.SheetsInNewWorkbook = 1

     '第三段

     With xlsApp.Workbooks

    If (.Count = 0) Then

    .Add

    End If

     End With

     '第四段

     Set xlsWorkSheet = xlsApp.Worksheets.Item(1)

     xlsWorkSheet.Range("A1").Value = "用VB做,多簡單!"

 End Sub

上述代碼啟動Excel并在A1單元格中輸入了幾個字,這可能是做這

個操作所用的最少代碼(省略了錯誤處理)。第一段建立了一個

Excel對象并將Excel程序的窗口顯示出來;第二段設(shè)置在一個新工

作簿中的工作表數(shù)為1;第三段檢查如果沒有可用的工作簿則添加一

個;第四段則向A1單元格里寫入了一句話。

快運行一遍程序看看,是不是很簡單?哈哈!別高興得太早,我們

要接觸VC做OLE自動化了!心臟不好的朋友請把速效救心丹放在身邊!

如果你接觸過OLE自動化,那一定知道IDispatch接口了,它是OLE自

動化的核心接口,恐怕這是至今為止最慢的一個接口了,呵呵!

 微軟的軟件工程師們就是熱心腸,他們怕用MFC的廣大程序員累著,

 專門做了一個類來封裝IDispatch接口,這個類就是COleDispatchDriver,

 它包裝了IDispatch接口的復(fù)雜性,然而IDispatch復(fù)雜在什么地方

 呢?到MSDN上查一下,也許你會注意到它的Invoke接口函數(shù)了?該

 函數(shù)應(yīng)該算是IDispatch的核心函數(shù),因為它將負(fù)責(zé)所有從自動化對

 象中調(diào)用方法、設(shè)置屬性值以及取得屬性值的所有操作。

也許你看到該函數(shù)的原型以后會很softly的說:“TNND!這參數(shù)也TMD

太多了!”是呀!要不然怎么說VC程序員的眼神兒要好呢!光對齊

參數(shù)就得要求你8.6的好眼睛,至于老花眼,干脆就不能做OLE程序,

更別提COM接口了!嘻嘻!下面我們仔細(xì)研究一下該函數(shù)吧:

dispIdMember:該參數(shù)是一個DISPID類型。它唯一地指定了待調(diào)用

的函數(shù)或?qū)傩浴R?,Invoke可不像我們這樣按名稱來確定一個

函數(shù)或一個屬性,它是拿這個參數(shù)做為函數(shù)指針數(shù)組的索引。如果

你只知道該函數(shù)的名字而不知道這個索引值怎么辦呢?不要緊,你

可以用IDispatch::GetIDsOfNames從函數(shù)名稱得到DISPID。怎么樣?

這個參數(shù)是不是很好填?

請注意Invoke的wFlags參數(shù),它可以是

DISPATCH_METHOD、

DISPATCH_PROPERTYGET、

DISPATCH_PROPERTYPUT

分別表示Invoke函數(shù)的工作性質(zhì)為:調(diào)用方法、取得屬性值、設(shè)置

屬性值。COleDispatchDriver將上述三個操作分成了三個函數(shù):

InvokeHelper、GetProperty和SetProperty,分解了Invoke函數(shù)的

功能。

另外,請注意pDispParams

參數(shù),為了支持有不同參數(shù)個數(shù)的不同方法,Invoke使用了參數(shù)數(shù)

組來批量的接受參數(shù),這個很苯的方法卻很實用,你覺得呢?

哇塞!要是這么詳細(xì)地說下去,我不得寫一本書?!得!我們還是

啟動VC玩兒點實用的吧!用向?qū)梢粋€Dialog base的框架,并畫

一個按鈕。接下來就是一堆復(fù)雜的工作了!

 首先在stdafx.h里加入對IDispatch接口提供支持的頭文件:

 #include 《afxDisp.h》

 再在應(yīng)用程序類的InitInstance()函數(shù)里加入:

 AfxOleInit(); // 初始化OLE Automation庫

 我們應(yīng)該怎么引用Excel對象庫呢?按Ctrl+W啟動Class Wizard,

 再選擇“Add Class...”->“From a type library...”,然后

 選擇“c:\program files\microsoft office\office”目錄下的

 “Excel8.olb”,隨后在“confirm classes”對話框的List box

 中將列出所有Excel8對象庫中可用的對象。按住ctrl鍵再用箭頭

 選中Sheets、_Application、_Worksheet、_Workbook、Workbooks、

 Range幾個對象,按確定。哈!你看到在ClassView窗口中多出的

 幾個類嗎?現(xiàn)在Excel就可以任由我們擺布啦!

 好了,VC的靈話性在這兒將會體現(xiàn)出來了,我們生成的幾個Excel

 對象有很多已定義好的函數(shù),但它們可能并不完全適合我們,哈!

 我們可以跟據(jù)需要來修改這些函數(shù)!!當(dāng)然不能亂改,前提是我

 們必須對Excel VBA有詳細(xì)的了解!

比如Workbooks類中的Add函數(shù)有一個Template參數(shù)用于指定模板文

件,但大多數(shù)情況我們用不著模板文件,怎么辦呢?你是否記得在

VBA中這個參數(shù)是一個可選項?那就改唄!我們可以用C++的特性,

重載這個函數(shù)!在左邊的Workbooks上右鍵->“Add member

function...”,然后在function type中輸入“LPDISPATCH”,在

fucntion declaration輸入“Add()”然后按OK。然后按如下方法

編輯該函數(shù),大家看到,我們只是將Template參數(shù)去掉了,然而

繼續(xù)保留對InvokeHelper的調(diào)用,請別忘記,MFC自動化類通常都

是從COleDispatchDriver派生的。

 LPDISPATCH Workbooks::Add()

 {

    LPDISPATCH result;

    InvokeHelper(0xb5, DISPATCH_METHOD, VT_DISPATCH,

    (void*)&result, NULL);

    return result;

 }

為對話框上的按鈕生成一個函數(shù)吧,我們要寫VC代碼了!別忘了在

對話框的實現(xiàn)文件中加入#include"excel8.h"呀!

準(zhǔn)備好了嗎?代碼如下?。。。?!

 void CExcelOleDlg::OnButton1()

 {

    LPDISPATCH      pDispatch = NULL;

    LPUNKNOWN       pUnknown = NULL;

    CLSID      clsid;

    _Application    appExcel;

    LPDISPATCH      pWorkbooks = NULL;

    Workbooks       Workbooks;

    LPDISPATCH      pWorkbook = NULL;

    LPDISPATCH      pWorksheets = NULL;

    Sheets     Worksheets;

    LPDISPATCH      pWorksheet = NULL;

    _Worksheet      Worksheet;

    LPDISPATCH      pWorkRange = NULL;

    Range      WorkRange;

    CLSIDFromProgID( L"Excel.Application.8", &clsid );

    // 看指定的對象是否已經(jīng)運行

    if ( SUCCEEDED(GetActiveObject(

         clsid, NULL, &pUnknown )) )

    {

        VERIFY( SUCCEEDED(pUnknown->QueryInterface(

            IID_IDispatch, (void**)&pDispatch )) );

        ASSERT( pDispatch );

        appExcel.AttachDispatch( pDispatch );

        pUnknown->Release();

    }

    else

    {

        // 沒運行。那就建立Excel.Application.8對象

        if ( ! appExcel.CreateDispatch(

            (LPCTSTR)"Excel.Application.8") )

        {

           MessageBox(

           "can not found the Excel.Application.8 object!");

           return;

        }

    }

    // 顯示并激活Excel窗口

    // XLMAIN 是用Spy++查到的

    HWND hWndExcelMain = ::FindWindow( "XLMAIN", NULL );

    ASSERT( hWndExcelMain );

    ::ShowWindow( hWndExcelMain, SW_SHOW );

    ::UpdateWindow( hWndExcelMain );

    ::BringWindowToTop( hWndExcelMain );

    // 設(shè)置在一個新工作簿中的工作表數(shù)為1

    appExcel.SetSheetsInNewWorkbook( 1 );

    // 得到工作簿集的IDispatch,并綁定到Workbooks對象

    pWorkbooks = appExcel.GetWorkbooks();

    ASSERT( pWorkbooks );

    Workbooks.AttachDispatch( pWorkbooks );

    // 如果工作簿集是空的,那就添加一個工作簿

    if ( Workbooks.GetCount() == (long)0 )

    {

        pWorkbook = Workbooks.Add();

        ASSERT( pWorkbook );

    }

    // 得到工作表集(同上)

    pWorksheets = appExcel.GetWorksheets();

    ASSERT( pWorksheets );

    Worksheets.AttachDispatch( pWorksheets );

    // 激活第一個工作表

    pWorksheet = Worksheets.GetItem(

        COleVariant((short)1) );

    ASSERT( pWorksheet );

    Worksheet.AttachDispatch( pWorksheet );

    Worksheet.Select( COleVariant((short)TRUE) );

    // 得到A1區(qū)域的引用

    pWorkRange = Worksheet.GetRange(

        COleVariant("A1"), COleVariant("A1"));

    WorkRange.AttachDispatch( pWorkRange );

    WorkRange.SetValue(

        COleVariant("多簡單!就是麻煩一點兒!") );

    if ( pWorkbook )

        pWorkbook->Release();

 }

請注意,上述代碼中除了了加入錯誤檢查之外,還判斷指定的對象是否已經(jīng)

運行,如果已經(jīng)運行則直接引用該對象,否則才建立新對象,其它的和上面

VB程序的功能相同!?。【谷欢嗔诉@么多代碼,真讓人不可思議!

快累死我了!我是實在沒力氣解釋這段VC程序了,感興趣的朋友可以拿它和

上面的VB程序?qū)φ找幌?,回頭再討論這個問題吧!?。」?--依呀累死我了?。?/p>

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产欧美一区二区另类精品| 国产美女精品人人做人人爽| 免费福利午夜在线观看| 国产欧美日韩精品成人专区| 国产又长又粗又爽免费视频| 亚洲午夜精品视频在线| 国产欧美日韩精品一区二区| 欧美在线观看视频三区| 久久免费精品拍拍一区二区| 国产精品日韩精品最新| 老富婆找帅哥按摩抠逼视频| 在线免费观看一二区视频 | 国产户外勾引精品露出一区| 亚洲av熟女一区二区三区蜜桃| 亚洲最新中文字幕在线视频| 成人午夜爽爽爽免费视频| 亚洲伦片免费偷拍一区| 精品伊人久久大香线蕉综合| 午夜亚洲少妇福利诱惑| 美女被后入福利在线观看| 俄罗斯胖女人性生活视频| 少妇被粗大进猛进出处故事| 日本一本在线免费福利| 麻豆视传媒短视频在线看| 欧美激情中文字幕综合八区| 国产成人精品99在线观看| 国产精品欧美在线观看| 亚洲视频偷拍福利来袭| 国产精品激情在线观看| 五月婷婷六月丁香亚洲| 综合久综合久综合久久| 国产精品一区二区香蕉视频| 日韩人妻欧美一区二区久久| 国产精品免费视频视频| 国产午夜福利一区二区| 国产精品免费无遮挡不卡视频| 久久精品亚洲精品一区| 欧美大胆美女a级视频| 亚洲欧美视频欧美视频| 中文字幕日韩无套内射| 国产又猛又大又长又粗|