国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

MFC加載EXCEL代碼

2019-11-08 02:23:38
字體:
供稿:網(wǎng)友
1。首先按照常規(guī)的方式建立對話框的MFC應(yīng)用程序,然后添加類,也就是我們需要進行數(shù)據(jù)處理的類。由于只涉及到字符轉(zhuǎn)換和數(shù)字提取,我建的是常規(guī)類,沒有基類。2。既然要使用Excel的各種功能,那么就必須包含EXCEL的類文件(excel.h, excel.cpp)。晚上有大把教程告訴我們?nèi)绾螐膃xcel的OBJ文件或者EXE文件提取源文件。這里不再敘述,反正我很早以前提取過office 2003的,就一直在用。3。如果我們看Excel的頭文件(excel.h)會發(fā)現(xiàn)里面有大量的數(shù)據(jù)類型是我們不常使用的。因此如果要直接套用這些函數(shù),就必須做數(shù)據(jù)類型轉(zhuǎn)換,我這里使用了com庫的接口,至于原理什么的不清楚。4。首先我們需要特別說明一個數(shù)據(jù)類型,這一個數(shù)據(jù)類型在Excel操作中反復(fù)用到,就是 VARIANT 類型。這是一個結(jié)構(gòu)體,里面包含了大量的數(shù)據(jù)類型,其定義如下:struct tagVARIANT {    union {        struct __tagVARIANT {            VARTYPE vt;            Word    wReserved1;            WORD    wReserved2;            WORD    wReserved3;            union {                ULONGLONG     ullVal;       /* VT_UI8               */                LONGLONG       llVal;         /* VT_I8                */                LONG                 lVal;          /* VT_I4                */                BYTE                  bVal;        /* VT_UI1               */                SHORT               iVal;         /* VT_I2                */                FLOAT         fltVal;       /* VT_R4                */                DOUBLE        dblVal;       /* VT_R8                */                VARIANT_BOOL  boolVal;      /* VT_BOOL              */                _VARIANT_BOOL bool;         /* (obsolete)           */                SCODE         scode;        /* VT_ERROR             */                CY            cyVal;        /* VT_CY                */                DATE          date;         /* VT_DATE              */                BSTR          bstrVal;      /* VT_BSTR              */                IUnknown *    punkVal;      /* VT_UNKNOWN           */                IDispatch *   pdispVal;     /* VT_DISPATCH          */                SAFEARRAY *   parray;       /* VT_ARRAY             */                BYTE *        pbVal;        /* VT_BYREF|VT_UI1      */                SHORT *       piVal;        /* VT_BYREF|VT_I2       */                LONG *        plVal;        /* VT_BYREF|VT_I4       */                LONGLONG *    pllVal;       /* VT_BYREF|VT_I8       */                FLOAT *       pfltVal;      /* VT_BYREF|VT_R4       */                DOUBLE *      pdblVal;      /* VT_BYREF|VT_R8       */                VARIANT_BOOL *pboolVal;     /* VT_BYREF|VT_BOOL     */                _VARIANT_BOOL *pbool;       /* (obsolete)           */                SCODE *       pscode;       /* VT_BYREF|VT_ERROR    */                CY *          pcyVal;       /* VT_BYREF|VT_CY       */                DATE *        pdate;        /* VT_BYREF|VT_DATE     */                BSTR *        pbstrVal;     /* VT_BYREF|VT_BSTR     */                IUnknown **   ppunkVal;     /* VT_BYREF|VT_UNKNOWN  */                IDispatch **  ppdispVal;    /* VT_BYREF|VT_DISPATCH */                SAFEARRAY **  pparray;      /* VT_BYREF|VT_ARRAY    */                VARIANT *     pvarVal;      /* VT_BYREF|VT_VARIANT  */                PVOID         byref;        /* Generic ByRef        */                CHAR          cVal;         /* VT_I1                */                USHORT        uiVal;        /* VT_UI2               */                ULONG         ulVal;        /* VT_UI4               */                INT           intVal;       /* VT_INT               */                UINT          uintVal;      /* VT_UINT              */                DECIMAL *     pdecVal;      /* VT_BYREF|VT_DECIMAL  */                CHAR *        pcVal;        /* VT_BYREF|VT_I1       */                USHORT *      puiVal;       /* VT_BYREF|VT_UI2      */                ULONG *       pulVal;       /* VT_BYREF|VT_UI4      */                ULONGLONG *   pullVal;      /* VT_BYREF|VT_UI8      */                INT *         pintVal;      /* VT_BYREF|VT_INT      */                UINT *        puintVal;     /* VT_BYREF|VT_UINT     */                struct __tagBRECORD {                    PVOID         pvRecord;                    IRecordInfo * PRecInfo;                } __VARIANT_NAME_4;         /* VT_RECORD            */            } __VARIANT_NAME_3;        } __VARIANT_NAME_2;        DECIMAL decVal;    } __VARIANT_NAME_1;};VARIANT數(shù)據(jù)結(jié)構(gòu)包含兩個域(如果不考慮保留的域)。vt域描述了第二個域的數(shù)據(jù)類型。為了使多種類型能夠在第二個域中出現(xiàn),我們定義了一個聯(lián)合結(jié)構(gòu)。所以,第二個域的名稱隨著vt域中輸入值的不同而改變。用于指定vt域值情況的常量在聯(lián)合的定義中以每一行的注釋形式給出。使用VARIANT和VARIANTARG數(shù)據(jù)結(jié)構(gòu)要分兩步完全。舉一個例子,讓我們考慮如下代碼:long lValue = 999;VARIANT vParam;vParam.vt = VT_I4;vParam.lVal = lValue;在第一行中指定數(shù)據(jù)類型。常量VT_I4表明在第二個域中將出現(xiàn)一個long型的數(shù)據(jù)。根據(jù)類型VARIANT的定義,可以得知,當(dāng)一個long型數(shù)據(jù)存入VARIANT類型時,其第二個域使用的名稱是lVal。5。了解了VARIANT數(shù)據(jù)類型,我們還需要了解一個函數(shù),我實在微軟的官網(wǎng)查到這個函數(shù)的,網(wǎng)上講解的不是很全面,我大概說下,基本上是照貓畫虎,原理什么的都不懂的。這個函數(shù)就是AutoWrap()函數(shù)。可能很多人都在網(wǎng)上查到過這個函數(shù),但是其工作原理不是很清楚,我覺得沒必要全懂,只要理解兩句就足夠了。HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...){    // Begin variable-argument list...    va_list marker;    va_start(marker, cArgs);    if(!pDisp) {        MessageBox(NULL, _T("NULL IDispatch passed to AutoWrap()"), _T("Error"), 0x10010);        _exit(0);    }    // Variables used...    DISPPARAMS dp = { NULL, NULL, 0, 0 };    DISPID dispidNamed = DISPID_PROPERTYPUT;    DISPID dispID;    HRESULT hr;    char buf[200];    char szName[200];    // Convert down to ANSI    WideCharToMultiByte(CP_ACP, 0, ptName, -1, szName, 256, NULL, NULL);    // Get DISPID for name passed...    hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID);    if(FAILED(hr)) {        sprintf(buf, "IDispatch::GetIDsOfNames(/"%s/") failed w/err 0x%08lx", szName, hr);        MessageBox(NULL, buf, L"AutoWrap()", 0x10010);        _exit(0);        return hr;    }    // Allocate memory for arguments...    VARIANT *pArgs = new VARIANT[cArgs+1];    // Extract arguments...    for(int i=0; i<cArgs; i++) {        pArgs[i] = va_arg(marker, VARIANT);    }    // Build DISPPARAMS    dp.cArgs = cArgs;    dp.rgvarg = pArgs;    // Handle special-case for property-puts!    if(autoType & DISPATCH_PROPERTYPUT) {        dp.cNamedArgs = 1;        dp.rgdispidNamedArgs = &dispidNamed;    }    // Make the call!    hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);    if(FAILED(hr)) {        sprintf(buf, "IDispatch::Invoke(/"%s/"=%08lx) failed w/err 0x%08lx", szName, dispID, hr);        MessageBox(NULL, buf, "AutoWrap()", 0x10010);        _exit(0);        return hr;    }    // End variable-argument section...    va_end(marker);    delete [] pArgs;    return hr;}其實這個函數(shù)的作用,就是將特定字符串轉(zhuǎn)換成Excel命令,然后調(diào)用Invoke函數(shù)對相應(yīng)數(shù)據(jù)進行處理。詳細(xì)說來:(1)。int autoType:這里只能有4個值,表示Invoke如何處理相關(guān)數(shù)據(jù)。在OLEAUTO.h文件中定義如下:/* Flags for IDispatch::Invoke */#define DISPATCH_METHOD         0x1#define DISPATCH_PROPERTYGET    0x2#define DISPATCH_PROPERTYPUT    0x4#define DISPATCH_PROPERTYPUTREF 0x8這里面我用了前面三個,主要的是中間的兩個。(2)。VARIANT *pvResult:Invoke處理完數(shù)據(jù)后的返回指針,指向處理結(jié)果,后面我們看到就是子函數(shù)的返回值(3)。 IDispatch *pDisp:一個指針,用于調(diào)用DISPID方法,其實就是只調(diào)用個兩個方法,即在特定層次下,將特定字符串轉(zhuǎn)換成命令值,然后執(zhí)行命令(4)。LPOLESTR ptName:就是一直在說的特定字符串(5)。int cArgs...:命令參數(shù)個數(shù),由于是模板函數(shù),所以后面可跟更多的參數(shù)。好的,我們把參數(shù)都解釋了一下,那么函數(shù)中有兩個特殊語句我們再說一下:(1)。hr = pDisp->GetIDsOfNames(IID_NULL, &ptName, 1, LOCALE_USER_DEFAULT, &dispID)這個函數(shù)在微軟官網(wǎng)上面有,但是我相信很多人沒看懂。如果我們把后面的一個語句放到一塊,就比較輕松了:hr = pDisp->Invoke(dispID, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);我們可以打開我們的工程中的excel.cpp文件,隨便找一個函數(shù):LPDISPATCH CalloutFormat::GetParent(){LPDISPATCH result;InvokeHelper(0x1, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result, NULL);return result;}這里面的InvokeHelper()可以看做與Invoke()相同。所以第一個參數(shù)是一個十六進制的數(shù),每個函數(shù)這個十六進制的數(shù)都不同,所以簡單來說,GetIDsOfNames函數(shù)就是將我們的特殊字符串轉(zhuǎn)換成命令值。我們后面可知,這個特殊字符串實際上只能是Excel相關(guān)的函數(shù)名或者部分函數(shù)名(這個比較難理解,可以先放下,后面會舉例)。所以GetIDsOfNames最后只得到了一個int類型的值dispID,用以Invoke()函數(shù)的執(zhí)行。(2)。hr = pDisp->Invoke(disipD, IID_NULL, LOCALE_SYSTEM_DEFAULT, autoType, &dp, pvResult, NULL, NULL);這個函數(shù)就解釋一句話:根據(jù)定義的運行類型(autotype),特定的參數(shù)(dp),運行特定的命令值(disIpD),得到運行結(jié)果(pvResult)和運行狀態(tài)(hr )。如果hr不等于0,就說明運行失敗。其實這個語句跟函數(shù)的意思是相同的,只是方式改變了而已。所以這個函數(shù):HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...)的意思就是,我們可以直接通過直接寫一個函數(shù)名稱(或者部分函數(shù)名稱),添加相關(guān)參數(shù)(實參)后,就可以實現(xiàn)通常語法的函數(shù)功能,比如如下程序段:例 1://select LineNum x RowNum rangeIDispatch *pXlRange;{VARIANT parm;parm.vt = VT_BSTR;parm.bstrVal = ::SysAllocString(bstr_Range_Str);VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);VariantClear(&parm);pXlRange = result.pdispVal;}這個語句段是調(diào)用pXlSheet.GetRange(Range)這個函數(shù)里面的Invokehelper(),實際我們可以理解為就是在調(diào)用pXlSheet.GetRange(Range)函數(shù)。可能有人會問:里面的字符串是"Range",為什么函數(shù)本體是GetRange()哪?我們看第一個參數(shù):DISPATCH_PROPERTYGET,這表示我們需要Get相關(guān)的命令值(輸出),所以就是GetRange()了如果是DISPATCH_PROPERTYPUT, 就表示此時命令值作為輸入要去改變部分參數(shù),所以就是SetRange()了如果是DISPATCH_METHOD,則在寫字符串時,需要寫函數(shù)的完整名稱。我們只要一個完整的函數(shù)包括形參和返回值,那在AutoWrap()中實參怎么傳遞給形參哪?這個就是int cArgs...的妙處,cArgs是一個int類型,表示需要傳遞的實參的數(shù)目,而cArgs后面的參數(shù)就都是要傳遞給函數(shù)的實參了。我們可以看看Excel.h文件,里面的函數(shù)傳遞的參數(shù)各不相同,有的沒有參數(shù),有的有十幾個參數(shù)。那我們要使用一個函數(shù)解決這所有的問題,就要使用如此的函數(shù)模板了。.如上面的例1。特別需要說明的一點:如果你需要傳遞多個參數(shù),參數(shù)的順序是反向的:SetItem(parm1, parm2, parm3, parm4)。則在AutoWrap(。。。。。。,L"Item", 4, parm4, parm3, parm2, parm1)。6。如果以上內(nèi)容都理解了(我說的可能有不對的地方,不過你們看了下面的例子應(yīng)該就會明白),我們就開始正式些程序了:(1)在我們剛才建好的工程中添加文件:excel.h,excel.cpp(2)在我們新建的那個類DatalogConvertor的cpp文件中添加:#include <ole2.h>       //需要調(diào)用OLE方法#include <comutil.h>   //需要調(diào)用com接口#pragma once#pragma comment(lib,   "comsupp.lib ")  //調(diào)用Com庫添加 HRESULT CDatalogConvertor::AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...)函數(shù),就把上面的代碼黏貼進去即可。(3)在你的excel操作函數(shù)中開始啟動Excel進程,Excel采用層次化編程,如果我們要在Excel的一個sheet上寫數(shù)據(jù),就要先開啟進程,建立工作薄,在工作薄中添加一個工作頁,激活此工作頁(Sheet),之后才可以進行寫入操作。//initial COM libCoInitialize(NULL);CLSID clsid;HRESULT hr = CLSIDFromProgID(L"Excel.application", &clsid);if(FAILED(hr)) {::MessageBox(NULL, "CLSIDFromProgID() function error/nEXCEL Not Be Installed!", "error", 0x10010);//::MessageBox(NULL, "CLSIDFromProgID() function error!", "error", 0x10010);return -1;}// creat instanceIDispatch *pXlApp;hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);if(FAILED(hr)) {::MessageBox(NULL, "Pls check whether setuped EXCEL!", "error", 0x10010);return -2;}// Application.Visible is tureVARIANT IsVisible;IsVisible.vt = VT_I4;IsVisible.lVal = 0; //0=not visible, 1=visibleAutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, IsVisible);//get WorkBooksIDispatch *pXlBooks;{VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);pXlBooks = result.pdispVal;}//create new Workbook using Workbook.Add() methodIDispatch *pXlBook;{VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Add", 0);pXlBook = result.pdispVal;}//get Worksheet object from Application.ActiveSheet attributeIDispatch *pXlSheet;{VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"ActiveSheet", 0);pXlSheet = result.pdispVal;}到這里我們順利啟動了Excel并且創(chuàng)建了工作薄,得到了當(dāng)前的工作頁。我們要寫數(shù)據(jù)進去,就有兩種方法:一個是一個單元一個單元的寫(Cell),還有一個就是選定一個范圍(Range),然后一個特定格式的數(shù)組進行添加。我這里面選取的是Range。//fill excel file functionint CDatalogConvertor::FillExcel(IDispatch *pXlSheet, int LineStart, int LineNum, int RowStart, int RowNum, CString Data[], int flag){int i, j;int data_flag;//***create a LineNum x RowNum arrary to fill excel format***//VARIANT arr;WCHAR szTmp[128];arr.vt = VT_ARRAY | VT_VARIANT;SAFEARRAYBOUND sab[2];sab[0].lLbound = 1; sab[0].cElements = LineNum;sab[1].lLbound = 1; sab[1].cElements = RowNum;arr.parray = SafeArrayCreate(VT_VARIANT, 2, sab);//***Convert string to BSTR and fill the data into the array***//BSTR bstrData[128][64]={0};for(i=0;i<LineNum;i++){for(j=0;j<RowNum;j++){//Convert string to BSTRbstrData[i][j]=_com_util::ConvertStringToBSTR(Data[i+j]);VARIANT tmp;tmp.vt = VT_BSTR;wsprintfW(szTmp,bstrData[i][j],i,j);tmp.bstrVal = SysAllocString(szTmp);//fill the data into the arraylong indices[]={i+1,j+1};SafeArrayPutElement(arr.parray,indices,(void *)&tmp);}}//Math Line Number and Row Number for excel range and arraychar Row_Start = (char) (RowStart+64); //convert 1 to Achar Row_Stop  = Row_Start+RowNum-1;CString Range_Str, LineStart_Str, LineStop_Str;BSTR bstr_Range_Str;LineStart_Str.Format("%d", LineStart);LineStop_Str.Format("%d", LineStart+LineNum-1);Range_Str = _T(Row_Start)+LineStart_Str+_T(":")+_T(Row_Stop)+LineStop_Str;bstr_Range_Str = _com_util::ConvertStringToBSTR(Range_Str);//select LineNum x RowNum rangeIDispatch *pXlRange;{VARIANT parm;parm.vt = VT_BSTR;parm.bstrVal = ::SysAllocString(bstr_Range_Str);VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);VariantClear(&parm);pXlRange = result.pdispVal;}//fill the Range by our arrayAutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, arr);pXlRange->Release();return 0;}這個函數(shù)里面最后的AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, arr);就是將數(shù)組填寫進相關(guān)的Range中。(4)寫完了數(shù)據(jù)后就要保存文件退出Excel進程:  //*****************************************************//save Excel file and quit excel.exe//*****************************************************//save excel file through Worksheet.SaveAs(), ignore all parameter expect filemname.VARIANT filename;filename.vt = VT_BSTR;filename.bstrVal = SysAllocString(_com_util::ConvertStringToBSTR(FileSaveName)); AutoWrap(DISPATCH_METHOD, NULL, pXlSheet, L"SaveAs", 1, filename);SysFreeString(filename.bstrVal);// exit EXCEL app through Application.Quit()AutoWrap(DISPATCH_METHOD, NULL, pXlApp, L"Quit", 0);//release all parameter//pXlRange->Release();pXlSheet->Release();pXlBook->Release();pXlBooks->Release();pXlApp->Release();//VariantClear(&arr);//*********************************************************//close files//*********************************************************//close COM libCoUninitialize();(5)如果我們除了寫數(shù)據(jù)意外還想做點其他的操作,如改變字體格式,顏色,填充顏色,設(shè)置寬度,甚至更高階的功能,不用著急,AutoWrap()的功能弄清楚之后就很容易:CString cstr_Line, cstr_Range;BSTR    bstr_Range;cstr_Line.Format("%d",data_line);cstr_Range = _T("A")+cstr_Line+_T(":")+_T("A")+cstr_Line;bstr_Range = _com_util::ConvertStringToBSTR(cstr_Range);//select LineNum x RowNum range 得到RangeIDispatch *pXlRange;{VARIANT parm;parm.vt = VT_BSTR;parm.bstrVal = ::SysAllocString(bstr_Range);VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);VariantClear(&parm);pXlRange = result.pdispVal;}//Set Column Width object form Range.SetColumnWidth() attribute//設(shè)置此部分Range的列寬度{VARIANT parm;parm.vt = VT_I4;parm.lVal = 40.0;AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"ColumnWidth", 1, parm);}//get Font object from Range.GetFont() attribute//得到相應(yīng)Range內(nèi)默認(rèn)的字體屬性IDispatch *pXlFonts;{VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlRange, L"Font", 0);pXlFonts = result.pdispVal;}//Set Font object from Range.SetColor() attribute//設(shè)定字體顏色I(xiàn)Dispatch *pXlFont;{VARIANT result;VariantInit(&result);VARIANT parm;parm.vt = VT_I4;parm.lVal = RGB(255,0,0); //red colorAutoWrap(DISPATCH_PROPERTYPUT, &result, pXlFonts, L"Color", 1,parm);pXlFont = result.pdispVal;}//get Interior object from Range.GetInterior() attribute//得到相應(yīng)Range內(nèi)的框體默認(rèn)屬性IDispatch *pXlInterior;{VARIANT result;VariantInit(&result);AutoWrap(DISPATCH_PROPERTYGET, &result, pXlRange, L"Interior", 0);pXlInterior = result.pdispVal;}//Set Back Color object from Interior.SetColor() attribute//設(shè)定框體背景顏色I(xiàn)Dispatch *pXlBackColor;{VARIANT result;VariantInit(&result);VARIANT parm;parm.vt = VT_I4;parm.lVal = RGB(140,227,190); //blue back colorAutoWrap(DISPATCH_PROPERTYPUT, &result, pXlInterior, L"Color", 1,parm);pXlBackColor = result.pdispVal;}所以只要想添加什么功能,在Excel.h文件中找到相關(guān)的函數(shù),根據(jù)函數(shù)名和參數(shù)類型,定制AutoWrap()函數(shù),代碼會變得很清晰整潔。同時據(jù)微軟官網(wǎng)說,這也會是代碼執(zhí)行效率提高很多(不知是真是假。。)
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 凤凰县| 大冶市| 阿勒泰市| 永济市| 黄龙县| 儋州市| 洛川县| 仲巴县| 贞丰县| 太和县| 塔河县| 藁城市| 衡阳县| 墨玉县| 罗城| 勃利县| 秭归县| 元江| 杂多县| 金塔县| 长武县| 苏尼特左旗| 罗源县| 额敏县| 徐水县| 紫金县| 浠水县| 布拖县| 聂荣县| 湄潭县| 来凤县| 措勤县| 高雄市| 永胜县| 宁城县| 温宿县| 治县。| 江门市| 安吉县| 霸州市| 玉屏|