目的:經過vc++讀取和寫入excel
環境:vs2012 office2010
1.建立一個新的工程,選擇mfc application,選擇dialog,在advanced features選擇automation(這一項我不肯定有沒有必要,查資料說要選上,我就選上了)
2.建立完工程後,在dialog對話框上右擊,選擇class wizard(或是ctrl+shift+x)
3.在add class下拉框內選擇add class from typelib
4.在add class from下面選擇file,而後你的office安裝目錄下的EXCEL.EXE(個人目錄是C:\Program Files (x86)\Microsoft Office\Office14\EXCEL.EXE)
5.在下面添加6個類到咱們的工程,(_Application, Worksheets, _Worksheet, Workbooks, _Workbook, Range)注意有的有下劃線,別添加錯了
6.這個時候若是直接編譯程序會提示錯誤,大致錯誤的信息以下
大致錯誤的信息以下
[plain] view plain copy
Error 1 error C1083: Cannot open compiler generated file: ‘d:\code\vc\exceltojson\exceltojson\debug\excel.tlh’: Permission denied d:\code\vc\exceltojson\exceltojson\capplication.h 3 1 EXCELToJSON c++
[plain] view plain copy
2 IntelliSense: declaration modifiers are incompatible with previous declaration d:\code\VC\EXCELToJSON\EXCELToJSON\Debug\excel.tlh 573 19 EXCELToJSON json
出現不少錯誤,幾乎都與excel.tlh這個文件相關。
解決方法就是把導入的6個類對應的頭文件最開始的一句話
[cpp] view plain copymarkdown
註釋掉,也就是刪掉。具體緣由不明,估計是這個已經更新不用了,可是模版裏面沒有改。因此引用了沒有的東西出的錯
7.作完上面的操做,再編譯一下,可能還有錯誤,錯誤提示以下:
[plain] view plain copy
Error 2 error C2059: syntax error : ‘,’ d:\code\vc\exceltojson\exceltojson\crange.h 336 1 EXCELToJSON app
[plain] view plain copy
3 IntelliSense: expected a type specifier d:\code\VC\EXCELToJSON\EXCELToJSON\CRange.h 336 10 EXCELToJSON 函數
解決方法,把Range這個類自動生成的頭文件(我這是CRage.h)裏面的
[cpp] view plain copy
VARIANT DialogBox()
{
VARIANT result;
InvokeHelper(0xf5, DISPATCH_METHOD, VT_VARIANT, (void*)&result, NULL);
return result;
} ui
改爲
[cpp] view plain copy
VARIANT _DialogBox()
{
VARIANT result;
InvokeHelper(0xf5, DISPATCH_METHOD, VT_VARIANT, (void*)&result, NULL);
return result;
} spa
也就是前面加一個下劃線。具體緣由不明,估計是新版本後有同名的函數
(PS: 汗,話說ms也真夠坑爹,本身的各類不兼容)
8.這個時候編譯一下,估計沒什麼問題了,那麼咱們就須要寫代碼操做excel了。網上找的代碼都差很少,不過裏面有幾句初始化com的
[cpp] view plain copy
::CoInitialize(NULL);
if(!AfxOleInit())
{
AfxMessageBox(L」cannot initialize com」);
return 0;
}
::CoUninitialize(); debug
在新版本的vs上會引發這個錯誤
Debug Assertion Failed!
Program: D:\code\VC\EXCELToJSON\Debug\EXCELToJSON.exe
File: f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\oleinit.cpp
Line: 49
For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)
這個錯誤提示更是個坑,主要緣由是你的com組件初始化了兩次。是由AfxOleInit這個函數致使的。(PS:你說我初始化兩次不行,直說不就好了,整得跟真事似的,我哪來的f盤。真是無語。再說,這麼常見的問題,爲何不能有一個準確的解釋)
解決方法就是把這一段初始化的程序刪掉,不用了。爲何?你能夠全局匹配一下AfxOleInit,你會發如今app class內(就是和你的dlg class同名,僅僅差了Dlg的一個建立工程是系統自建的類,好比個人EXCELToJSONDlg.cpp,咱們的代碼大部分都是寫到這裏面,而後會有一個EXCELToJSON.cpp類。就是在這個類裏面),系統自建的代碼有了這個初始化的程序:excel
[cpp] view plain copy
// Initialize OLE libraries
if (!AfxOleInit())
{
AfxMessageBox(IDP_OLE_INIT_FAILED);
return FALSE;
} code
9.這樣應該沒什麼問題了,在你的程序內引入上面6個類的頭文件,而後就能夠操做了。實例以下:
[cpp] view plain copy
void CEXCELToJSONDlg::OnBnClickedButtonConvert()
{
// TODO: Add your control notification handler code here
CApplication app;
CRange range;
CWorkbook book;
CWorkbooks books;
CWorksheet sheet;
CWorksheets sheets;
LPDISPATCH lpdisp;
COleVariant vresult;
COleVariant covtrue((short)TRUE);
COleVariant covfalse((short)FALSE);
COleVariant covoptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
//create the server if(!app.CreateDispatch(L"Excel.Application")) { AfxMessageBox(L"Cannot start Excel server"); return; } app.put_Visible(FALSE); books.AttachDispatch(app.get_Workbooks()); //open file lpdisp = books.Open( ExcelFile, covoptional, covfalse, covoptional, covoptional, covoptional, covoptional, covoptional, covoptional, covoptional, covoptional, covoptional, covoptional, covoptional, covoptional); //get workbook book.AttachDispatch(lpdisp); //get worksheets sheets.AttachDispatch(book.get_Worksheets()); lpdisp = book.get_ActiveSheet(); sheet.AttachDispatch(lpdisp); //get the used range CRange usedrange; usedrange.AttachDispatch(sheet.get_UsedRange()); //get used row range.AttachDispatch(usedrange.get_Rows()); long irownum = range.get_Count(); long istartrow = usedrange.get_Row(); //get used column range.AttachDispatch(usedrange.get_Columns()); long icolnum = range.get_Count(); long istartcol = usedrange.get_Column(); CString skey = L""; CString svalue = L""; for(int j=2; j<icolnum+1; j++) { JSON JSONObject; range.AttachDispatch(usedrange.get_Item(COleVariant((long)1), COleVariant((long)j)).pdispVal); vresult = range.get_Text(); JSONObject.LanguageTag = vresult.bstrVal; for(int i=2; i<irownum+1; i++) { range.AttachDispatch(usedrange.get_Item(COleVariant((long)i), COleVariant((long)1)).pdispVal); vresult = range.get_Text(); skey = vresult.bstrVal; range.AttachDispatch(usedrange.get_Item(COleVariant((long)i), COleVariant((long)j)).pdispVal); vresult = range.get_Text(); svalue = vresult.bstrVal; } } double dvalue = 3; usedrange.put_Item(COleVariant((long)2), COleVariant((long)2), COleVariant((double)dvalue));//write to excel book.Save(); book.Close(covoptional, COleVariant(ExcelFile), covoptional); books.Close(); app.Quit();
}
上面代碼是打開一個指定路徑的excel,而後得到使用的sheet(也就是你最後一次保存退出的那個sheet,這個你也能夠經過裏面的其餘方法得到excel裏面的其餘sheet),而後得到這個sheet內使用過的區域,並遍歷獲取其數據,後面一點是向指定的地方插入一個數據。在vs2012下,裏面的一些函數名字變了,setItem 改爲put_Item等,你能夠在提示的函數內找一下,看名字,應該能猜出來
xlsx文件實際上是一個zip的壓縮包,你能夠改其後綴名而後解壓,裏面都是一些xml文件和一些圖片等配置文件。若是你有時間,能夠本身解碼excel文件。 頂 0 踩