最近發(fā)現(xiàn)很多人都在研究OFFICE方面的編程,當(dāng)然,偶也是一個(gè)啦:)
可是這方面的資料卻很難找,而且大部分(幾乎全部)都是英文的。
于是,便有了寫這篇文章的念頭(好了,言歸正傳)。
本來OFFICE已經(jīng)為大家提供了很好用的COM組件,但我發(fā)現(xiàn)我怎么用怎么不順手(估計(jì)是本人太菜了)。
于是便絞盡腦汁想用純 C++ 代碼來實(shí)現(xiàn),終于,哈哈,嘿嘿,嚯嚯……
好了,下面是我的步驟(偶用的VC++ 6.0):
1. 先新建一個(gè)“Win32 控制臺(tái)應(yīng)用/Win32 Console Application”工程,工程名不妨叫做“createXLS”。
2. 工程向?qū)Ю镞x擇“A "Hello,World!" application”,新建完畢(廢話)。
3. 打開“createXLS.cpp”文件,添加代碼(本不想貼代碼的,想做個(gè)工程讓大家下載,因?yàn)樘唵危缓靡馑寂d師動(dòng)眾了):
#include <ole2.h> // 這個(gè)頭文件一定要包含,否則就不能自動(dòng)化了
// 接著修改我們添加一個(gè)函數(shù),這個(gè)函數(shù)是整個(gè)程序的基礎(chǔ)
// 若以后寫別的程序而想用純 C++ 來實(shí)現(xiàn)自動(dòng)化,這個(gè)函數(shù)是可以復(fù)用的
HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...);
// 修改主函數(shù)
int main(int argc, char* argv[])
{
// printf("Hello World!\n"); // 注釋掉這一句
// 初始化COM庫
CoInitialize(NULL);
// 獲得EXCEL的CLSID
CLSID clsid;
HRESULT hr = CLSIDFromProgID(L"Excel.Application", &clsid);
if(FAILED(hr)) {
::MessageBox(NULL, "CLSIDFromProgID() 函數(shù)調(diào)用失敗!", "錯(cuò)誤", 0x10010);
return -1;
}
// 創(chuàng)建實(shí)例
IDispatch *pXlApp;
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);
if(FAILED(hr)) {
::MessageBox(NULL, "請檢查是否已經(jīng)安裝EXCEL!", "錯(cuò)誤", 0x10010);
return -2;
}
// 顯示,將Application.Visible屬性置1
VARIANT x;
x.vt = VT_I4;
x.lVal = 1;
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlApp, L"Visible", 1, x);
// 獲取Workbooks集合
IDispatch *pXlBooks;
{
VARIANT result;
VariantInit(&result);
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"Workbooks", 0);
pXlBooks = result.pdispVal;
}
// 調(diào)用Workbooks.Add()方法,創(chuàng)建一個(gè)新的Workbook
IDispatch *pXlBook;
{
VARIANT result;
VariantInit(&result);
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Add", 0);
pXlBook = result.pdispVal;
}
// 創(chuàng)建一個(gè)15x15的數(shù)組,用于填充表格
VARIANT arr;
WCHAR szTmp[32];
arr.vt = VT_ARRAY | VT_VARIANT;
SAFEARRAYBOUND sab[2];
sab[0].lLbound = 1; sab[0].cElements = 15;
sab[1].lLbound = 1; sab[1].cElements = 15;
arr.parray = SafeArrayCreate(VT_VARIANT, 2, sab);
// 初始化數(shù)組內(nèi)容
for(int i=1; i<=15; i++) {
for(int j=1; j<=15; j++) {
VARIANT tmp;
tmp.vt = VT_BSTR;
wsprintfW(szTmp,L"%i,%i",i,j);
tmp.bstrVal = SysAllocString(szTmp);
// 添加數(shù)據(jù)到數(shù)組中
long indices[] = {i,j};
SafeArrayPutElement(arr.parray, indices, (void *)&tmp);
}
}
// 從Application.ActiveSheet屬性獲得Worksheet對象
IDispatch *pXlSheet;
{
VARIANT result;
VariantInit(&result);
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlApp, L"ActiveSheet", 0);
pXlSheet = result.pdispVal;
}
// 選擇一個(gè)15x15大小的Range
IDispatch *pXlRange;
{
VARIANT parm;
parm.vt = VT_BSTR;
parm.bstrVal = ::SysAllocString(L"A1:O15");
VARIANT result;
VariantInit(&result);
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);
VariantClear(&parm);
pXlRange = result.pdispVal;
}
::MessageBox(NULL, "我要填充數(shù)據(jù)了哈!", "通知", 0x10000);
// 用我們的數(shù)組填充這個(gè)Range
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, arr);
pXlRange->Release();
// 另外再選擇一個(gè)Range
{
VARIANT parm;
parm.vt = VT_BSTR;
parm.bstrVal = ::SysAllocString(L"A11:O25");
VARIANT result;
VariantInit(&result);
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);
VariantClear(&parm);
pXlRange = result.pdispVal;
}
::MessageBox(NULL, "我還要填充一次哈!", "通知", 0x10000);
// 用我們的數(shù)組再次填充這個(gè)Range
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, arr);
::MessageBox(NULL, "好了,我們該保存文件了!", "通知", 0x10000);
// 接下來我們該保存文件了,利用Worksheet.SaveAs()方法(我這里忽略了其他所有參數(shù),除了文件名)
{
VARIANT filename;
filename.vt = VT_BSTR;
filename.bstrVal = SysAllocString(L"c:\\test.xls");
AutoWrap(DISPATCH_METHOD, NULL, pXlSheet, L"SaveAs", 1, filename);
}
::MessageBox(NULL, "哈哈,收工了!", "通知", 0x10000);
// 退出,調(diào)用Application.Quit()方法
AutoWrap(DISPATCH_METHOD, NULL, pXlApp, L"Quit", 0);
// 釋放所有的接口以及變量
pXlRange->Release();
pXlSheet->Release();
pXlBook->Release();
pXlBooks->Release();
pXlApp->Release();
VariantClear(&arr);
// 注銷COM庫
CoUninitialize();
return 0;
}
// AutoWrap 函數(shù)的正體(真身,哈哈)
// 先聲明:這個(gè)函數(shù)不是偶寫的哈(別問是誰寫的,偶也不知道)
// AutoWrap() - Automation helper function...
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, "NULL IDispatch passed to AutoWrap()", "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, "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;
}
程序在WINDOWS2000+EXCEL2000環(huán)境下運(yùn)行良好,呵呵
收工,手都酸了(看來得弄個(gè)C++轉(zhuǎn)HTML的軟件用用了,手工著色真的很辛苦啊)。
我的代碼都是貼過來的啊,怎么沒見自動(dòng)著色啊?
難道是我菜?怪了?!
謝謝大哥哈~```
可以查閱 OFFICE 聯(lián)機(jī)幫助,找 RANGE、CELL、SELECTION 等對象的屬性以及方法。
不過本人不推薦使用這種方式來對 EXCEL 進(jìn)行比較復(fù)雜的操作。
其實(shí)這個(gè)范例也是一個(gè)COM后綁定操作的示范,關(guān)鍵就在 AutoWrap 函數(shù)了,這個(gè)函數(shù)雖然具有通用性,但是大量使用這個(gè)函數(shù)會(huì)影響程序的效率。
等清閑點(diǎn),我再貼篇教程~```
if(FAILED(hr))
{MessageBox("組件初始化失敗!");
return false;
}
hr = CoInitializeSecurity(NULL,-1, NULL, NULL,RPC_C_AUTHN_LEVEL_DEFAULT,RPC_C_IMP_LEVEL_IDENTIFY, NULL, 0,NULL);
COSERVERINFO ServerInfo={0,L"administator",NULL,0};
MULTI_QI MultiQi={&IID_IUnknown,NULL,NOERROR};
hr=CoCreateInstanceEx(CLSID_Account,NULL,CLSCTX_REMOTE_SERVER,&ServerInfo,1,&MultiQi);
if(FAILED(hr))
{
MessageBox("創(chuàng)建對象實(shí)例失敗!");
return false;
}
按以上步驟進(jìn)行com對象的創(chuàng)建卻老是提示創(chuàng)建對象失敗。各位指導(dǎo)一下,謝謝
http://support.microsoft.com/kb/216686
http://www.codeproject.com/useritems/BasicExcel.asp
IDispatch *pXlRange;
{
VARIANT parm;
parm.vt = VT_BSTR;
parm.bstrVal = ::SysAllocString(L"A1:O15");
// 15x15的Range定義就在這了。
// 如果你要修改成20x20就是這樣了:
// parm.bstrVal = ::SysAllocString(L"A1:T20");
.
.
.
D:\pugangccs\Source\createExcel\createExcel.cpp(7) : error C2146: syntax error : missing ';' before identifier 'AutoWrap'
D:\pugangccs\Source\createExcel\createExcel.cpp(7) : error C2501: 'HRESULT' : missing storage-class or type specifiers
D:\pugangccs\Source\createExcel\createExcel.cpp(7) : fatal error C1004: unexpected end of file found
Error executing cl.exe.
比如說 我要 10*15的 做得到嗎
IDispatch *pXlRange;
{
VARIANT parm;
parm.vt = VT_BSTR;
parm.bstrVal = ::SysAllocString(L"A1:P3");//選中一個(gè)Range
VARIANT result;
VariantInit(&result);
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlSheet, L"Range", 1, parm);
VariantClear(&parm);
pXlRange = result.pdispVal;
}
VARIANT test;
VariantInit(&test);
AutoWrap(DISPATCH_PROPERTYGET, &arr, pXlRange, L"Value", 1, 0);
可是如何選擇Excel表格中有效范圍的數(shù)據(jù)?
操作一個(gè)6萬行100列的需要多長時(shí)間
操作一個(gè)6萬行100列的需要多長時(shí)間
I am so glad to hear that practical activities about water issues, environment friendly agriculture and many other matters will be set.
Thanks for this Post. am very glad to see this post. Actually i have-been searching this kind of post.It contains lots of information for me.
Thank you, allow me to experience such a good article
stacy@listfreewebdirectories.com
stacy@momsindianrecipes.com