最近發(fā)現(xiàn)很多人都在研究OFFICE方面的編程,當(dāng)然,偶也是一個(gè)啦:)
可是這方面的資料卻很難找,而且大部分(幾乎全部)都是英文的。
于是,便有了寫這篇文章的念頭(好了,言歸正傳)。
本來(lái)OFFICE已經(jīng)為大家提供了很好用的COM組件,但我發(fā)現(xiàn)我怎么用怎么不順手(估計(jì)是本人太菜了)。
于是便絞盡腦汁想用純 C++ 代碼來(lái)實(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. 打開(kāi)“createXLS.cpp”文件,添加代碼(本不想貼代碼的,想做個(gè)工程讓大家下載,因?yàn)樘?jiǎn)單,不好意思興師動(dòng)眾了):
#include <ole2.h> // 這個(gè)頭文件一定要包含,否則就不能自動(dòng)化了
// 接著修改我們添加一個(gè)函數(shù),這個(gè)函數(shù)是整個(gè)程序的基礎(chǔ)
// 若以后寫別的程序而想用純 C++ 來(lái)實(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庫(kù)
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, "請(qǐng)檢查是否已經(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對(duì)象
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, "好了,我們?cè)摫4嫖募耍?, "通知", 0x10000);
// 接下來(lái)我們?cè)摫4嫖募耍肳orksheet.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庫(kù)
CoUninitialize();
return 0;
}
// AutoWrap 函數(shù)的正體(真身,哈哈)
// 先聲明:這個(gè)函數(shù)不是偶寫的哈(別問(wèn)是誰(shuí)寫的,偶也不知道)
// 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)行良好,呵呵
收工,手都酸了(看來(lái)得弄個(gè)C++轉(zhuǎn)HTML的軟件用用了,手工著色真的很辛苦啊)。