最近發現很多人都在研究OFFICE方面的編程,當然,偶也是一個啦:)
可是這方面的資料卻很難找,而且大部分(幾乎全部)都是英文的。
于是,便有了寫這篇文章的念頭(好了,言歸正傳)。
本來OFFICE已經為大家提供了很好用的COM組件,但我發現我怎么用怎么不順手(估計是本人太菜了)。
于是便絞盡腦汁想用純 C++ 代碼來實現,終于,哈哈,嘿嘿,嚯嚯……
好了,下面是我的步驟(偶用的VC++ 6.0):
1. 先新建一個“Win32 控制臺應用/Win32 Console Application”工程,工程名不妨叫做“createXLS”。
2. 工程向導里選擇“A "Hello,World!" application”,新建完畢(廢話)。
3. 打開“createXLS.cpp”文件,添加代碼(本不想貼代碼的,想做個工程讓大家下載,因為太簡單,不好意思興師動眾了):
#include <ole2.h> // 這個頭文件一定要包含,否則就不能自動化了
// 接著修改我們添加一個函數,這個函數是整個程序的基礎
// 若以后寫別的程序而想用純 C++ 來實現自動化,這個函數是可以復用的
HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...);
// 修改主函數
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() 函數調用失敗!", "錯誤", 0x10010);
return -1;
}
// 創建實例
IDispatch *pXlApp;
hr = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, IID_IDispatch, (void **)&pXlApp);
if(FAILED(hr)) {
::MessageBox(NULL, "請檢查是否已經安裝EXCEL!", "錯誤", 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;
}
// 調用Workbooks.Add()方法,創建一個新的Workbook
IDispatch *pXlBook;
{
VARIANT result;
VariantInit(&result);
AutoWrap(DISPATCH_PROPERTYGET, &result, pXlBooks, L"Add", 0);
pXlBook = result.pdispVal;
}
// 創建一個15x15的數組,用于填充表格
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);
// 初始化數組內容
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);
// 添加數據到數組中
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;
}
// 選擇一個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, "我要填充數據了哈!", "通知", 0x10000);
// 用我們的數組填充這個Range
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, arr);
pXlRange->Release();
// 另外再選擇一個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);
// 用我們的數組再次填充這個Range
AutoWrap(DISPATCH_PROPERTYPUT, NULL, pXlRange, L"Value", 1, arr);
::MessageBox(NULL, "好了,我們該保存文件了!", "通知", 0x10000);
// 接下來我們該保存文件了,利用Worksheet.SaveAs()方法(我這里忽略了其他所有參數,除了文件名)
{
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);
// 退出,調用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 函數的正體(真身,哈哈)
// 先聲明:這個函數不是偶寫的哈(別問是誰寫的,偶也不知道)
// 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環境下運行良好,呵呵
收工,手都酸了(看來得弄個C++轉HTML的軟件用用了,手工著色真的很辛苦啊)。
我的代碼都是貼過來的啊,怎么沒見自動著色啊?
難道是我菜?怪了?!
謝謝大哥哈~```
可以查閱 OFFICE 聯機幫助,找 RANGE、CELL、SELECTION 等對象的屬性以及方法。
不過本人不推薦使用這種方式來對 EXCEL 進行比較復雜的操作。
其實這個范例也是一個COM后綁定操作的示范,關鍵就在 AutoWrap 函數了,這個函數雖然具有通用性,但是大量使用這個函數會影響程序的效率。
等清閑點,我再貼篇教程~```
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("創建對象實例失敗!");
return false;
}
按以上步驟進行com對象的創建卻老是提示創建對象失敗。各位指導一下,謝謝
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");//選中一個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表格中有效范圍的數據?
操作一個6萬行100列的需要多長時間
操作一個6萬行100列的需要多長時間
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