• 纯C++代码创建并保存Excel文件


    本文转载于http://blog.sina.com.cn/s/blog_4c79cc450100ll43.html
    最近发现很多人都在研究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++ 来实现自动化,这个函数是可以复用的</span>
    HRESULT AutoWrap(int autoType, VARIANT *pvResult, IDispatch *pDisp, LPOLESTR ptName, int cArgs...);
    
    // 修改主函数
    int main(int argc, char* argv[])
    {
     // printf("Hello World!
    "); // 注释掉这一句
    
     // 初始化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 0xlx", 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"=lx) failed w/err 0xlx", 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环境下运行良好,呵呵

  • 相关阅读:
    字符串转换整数
    list、tuple、dict加*星号
    字符串
    整数反转
    字符串分割函数
    核密度图(直方图的拟合曲线)
    不同缺失值的删除方法
    Z字形变换
    最长回文字串
    寻找两个有序数组的中位数
  • 原文地址:https://www.cnblogs.com/zztong/p/6695279.html
Copyright © 2020-2023  润新知