Excel writing and reading with pure c API

Reading and Writing Excel file with pure C api in windows system. tested on windows 2000, hope it can help you:


#ifndef _WINXLS_H_
#define _WINXLS_H_

/*============================================================================*
*      Include Files
*============================================================================*/
#include <windows.h>
#include <Oleauto.h>    /* SysAllocString */
#include <objbase.h>    /* CoCreateInstance, ... */
#pragma comment(lib, "ole32.lib")

#include "mytypes.h"    /* tInt32, ...        */
#include "mydll.h"    /* define EXPORT     */

/*============================================================================*
*    define/typedef/struct
*============================================================================*/

#define DISP_CELL    170

/* XLS file handle */
typedef struct
{
    tChar*        filepath;
    IDispatch*    bookhandle;
    IDispatch*    sheetshandle;
    IDispatch**    sheethandles;    // Array of IDispatch*
    IDispatch**    rangehandles;    // Array of IDispatch*
    tUInt32        sheet_count;
}XLSFILE;

/*============================================================================*
*    Const variables
*============================================================================*/

/*============================================================================*
*    Global variables
*============================================================================*/

/*============================================================================*
*    Prototypes
*============================================================================*/
 
#ifdef __cplusplus
extern "C" {
#endif
    /* Functions used to manipunate excel file */

    /** /brief Initialize enviroment for using Windows excel component
    *
    * Return                        : boolean
    * Details                        : Initialization for com, and try to get IDispatch to
    *                                  Excel and Books                                    */
    EXPORT tBool winxls_init(void);

    /** /brief Open a specific excel file
    * [ in ] file_path    : Indicates the excel file to create
    * [ in ] open_mode    : open mode
    * Return            :    File handle if succeeded or NULL                            */
    EXPORT XLSFILE* winxls_open(tChar* file_path, tChar* open_mode);

    /** /brief Open a specific excel file
    * [ in ] xlsfile    : Indicates the excel file handle
    * [ in ] sheet_name    : Sheet to add, defaults to 'Sheetn'
    * Return            : True if succeeded or false                                    */
    EXPORT tBool winxls_addsheet(XLSFILE* xlsfile, tChar* sheet_name);

    /** /brief Delete a specific sheet from excel file
    * [ in ] xlsfile            : the excel file handle
    * [ in ] open_name/index    : indicates which seet to delete, defaults to the last sheet
    * Return                    : True if succeeded or false                            */
    //EXPORT tBool winxls_deletesheet(XLSFILE* xlsfile, tChar* sheet_name = NULL);
    //EXPORT tBool winxls_deletesheet(XLSFILE* xlsfile, tChar* sheet_index = 0);

    /** /brief Rename a given sheet's name of the Excel
    * [ in ] xlsfile            : Indicates the excel file handle
    * [ in ] sheet_name/index    : The specific sheet to rename
    * [ in ] new_name            : The new name
    * Return                    : File handle if succeeded or NULL                */
    //EXPORT tBool winxls_rename_sheet(XLSFILE* xlsfile, tChar* sheet_name,  tChar* new_name);
    //EXPORT tBool winxls_rename_sheet(XLSFILE* xlsfile, tChar* sheet_index, tChar* new_name);

    /** /brief Write into specific cell of a excel file's given sheet
    * [ in ] xmlfile                : Indicates the xmlfile handle to write into
    * [ in ] sheet_(name/index)        : Indicates which page to write into
    * [ in ] value                    : The value string to write
    * [ in ] col                    : The X coordinate of the cell to write into
    * [ in ] row                    : The Y coordinate of the cell to write into
    * Return                        : Size written                */
    EXPORT tUInt32 winxls_write(XLSFILE* xlsfile, tUInt32 sheet_index, tChar* value, tUInt32 col, tUInt32 row);
    //EXPORT tUInt32 winxls_write(XLSFILE* xlsfile, tChar*  sheet_name,  tChar* value, tUInt32 col, tUInt32 row);

    /** /brief Close the xls file handle
    * [ in ] XLSFILE        : Indicates the excel file to close
    * Return                : Indicates whether sucessfully closed the file                */
    EXPORT tBool winxls_close(XLSFILE* xlsfile);

    /** /brief Uninitialization for use of Windows excel component
    *
    * Return            : boolean indicates whether successfully or not
    * Details            : Coupled with winxls_init                                    */
    EXPORT tBool winxls_uninit(void);

#ifdef __cplusplus
}        /* extern "C"    */
#endif

#endif /*  _WINXLS_H_ */


#define _WINXLS_C_

/* ==========================================================================
*  Header files
* ========================================================================== */
#include <stdio.h>
#include <stdlib.h>        /* malloc, ... */
#include <assert.h>        /* assert, ... */
#include <string.h>        /* strcmp, ... */

//
//#pragma comment(lib, "comsupp.lib")

#include "winxls.h"

/* ==========================================================================
*  Typedef
* ========================================================================== */

/* ==========================================================================
*  Global Variables
* ========================================================================== */
static IDispatch* g_pDispExcel = NULL;
static IDispatch* g_pDispBooks = NULL;

/* ==========================================================================
*  Private functions
* ========================================================================== */
static tUInt16* MString2WString(tChar* string)
{
    tUInt16* pwstring = NULL;
    tUInt32 wcharLength = 0;

    /* Calculate required size in wchars for 'value' */
    wcharLength = MultiByteToWideChar(
        CP_ACP,
        0,
        string,
        strlen(string)+1,
        0,
        0
        );

    pwstring = malloc(sizeof(tUInt16) * wcharLength);
    memset(pwstring, 0x00, sizeof(tUInt16) * wcharLength);

    MultiByteToWideChar(
        CP_ACP,
        0,
        string,
        strlen(string)+1,
        pwstring,
        wcharLength
        );

    return pwstring;
}

static tChar  * WString2MString(tUInt16* wstring)
{
    tChar* pstring = NULL;
    tUInt32 charLength = 0;

    /* Calculate required size in wchars for 'value' */
    charLength = WideCharToMultiByte(
        CP_ACP,
        0,
        wstring,
        wcslen(wstring)+1,
        0,
        0,
        NULL,
        NULL
        );

    pstring = malloc(sizeof(tChar) * charLength);
    memset(pstring, 0x00, sizeof(tChar) * charLength);

    MultiByteToWideChar(
        CP_ACP,
        0,
        wstring,
        wcslen(wstring)+1,
        pstring,
        charLength,
        NULL,
        NULL
        );

    return pstring;
}
static void        ReleaseXLSHandle(XLSFILE* xlsfile)
{
    tUInt32 i = 0;

    if (xlsfile == NULL) {return ;}

    /* Release xlsfile    */
    if (xlsfile->filepath) {free(xlsfile->filepath); xlsfile->filepath=NULL;}

    if (xlsfile->rangehandles)   
    {
        for (i=0; i<xlsfile->sheet_count; i++)
        {
            if (xlsfile->rangehandles[i])
            {
                xlsfile->rangehandles[i]->lpVtbl->Release(xlsfile->rangehandles[i]);
                xlsfile->rangehandles[i]=NULL;
            }
        }

        xlsfile->rangehandles = NULL;
    }

    if (xlsfile->sheethandles)   
    {
        for (i=0; i<xlsfile->sheet_count; i++)
        {
            if (xlsfile->sheethandles[i])
            {
                xlsfile->sheethandles[i]->lpVtbl->Release(xlsfile->sheethandles[i]);
                xlsfile->sheethandles[i]=NULL;
            }
        }
        xlsfile->sheethandles = NULL;
    }

    if (xlsfile->sheetshandle)    {xlsfile->sheetshandle->lpVtbl->Release(xlsfile->sheetshandle); xlsfile->sheetshandle=NULL;}
    if (xlsfile->bookhandle)    {xlsfile->bookhandle->lpVtbl->Release(xlsfile->bookhandle);        xlsfile->bookhandle=NULL;}
}
static HRESULT AutoWrap(tUInt32 autoType, VARIANT *pvResult, IDispatch *pDisp, tChar* ptName, tUInt32 cArgs, ...)
{
    HRESULT hr;
    int i;
    tChar buf[200] = {0};
    tUInt16* pwName = NULL;

    DISPID dispID;
    VARIANT* inArgs = NULL;
    DISPID dispidNamed = DISPID_PROPERTYPUT;
    DISPPARAMS disp_params = {NULL,NULL,0,0};

    EXCEPINFO except;

    va_list marker;
    va_start(marker, cArgs);

    if (pDisp == NULL)
    {
        MessageBox(NULL, "AutoWrap: NULL IDispatch passed in", "Error", MB_SETFOREGROUND);
        return S_FALSE;
    }

    pwName = MString2WString(ptName);
    hr = pDisp->lpVtbl->GetIDsOfNames(pDisp, &IID_NULL, &pwName, 1,LOCALE_USER_DEFAULT, &dispID);
    free(pwName);
    if (FAILED(hr))
    {       
        sprintf(buf, "AutoWrap: GetIDsOfNames( %s ) failed", ptName);
        MessageBox(NULL, buf, "Error", MB_SETFOREGROUND);
        return hr;
    }

    inArgs = malloc(sizeof(VARIANT) * (cArgs+1));

    for (i=0; i<cArgs; i++)
    {
        inArgs[i] = va_arg(marker, VARIANT);
    }

    disp_params.cArgs = cArgs;
    disp_params.rgvarg = inArgs;
    if(autoType & DISPATCH_PROPERTYPUT) {
        disp_params.cNamedArgs = 1;
        disp_params.rgdispidNamedArgs = &dispidNamed;
    }

    hr = pDisp->lpVtbl->Invoke(pDisp,dispID,&IID_NULL,LOCALE_SYSTEM_DEFAULT,autoType,&disp_params,pvResult,&except,NULL);
    if (FAILED(hr))
    {
        sprintf(buf, "AutoWrap: Invoke( %s ) with disp id = %d failed", ptName,dispID);
        MessageBox(NULL, buf, "Error", MB_SETFOREGROUND);
        return hr;
    }

    return S_OK;
}
#ifdef __cplusplus
extern "C" {
#endif

    /* ========================================================================== */
    EXPORT tBool winxls_init(void)
    {       
        CLSID clsidExcel;

        HRESULT hr;
        VARIANT    resParam;

        DISPID dispid_books;

        const tChar* ucstr_books = "Workbooks";
        DISPPARAMS dispParams = { NULL, NULL, 0, 0 };

        // Initialize OLE Libraries.
        OleInitialize(NULL);

        // Get CLSID for Excel.Application from registry.
        hr = CLSIDFromProgID(L"Excel.Application", &clsidExcel);
        if (FAILED(hr))
        {
            MessageBox(NULL, "Excel not registered.", "Error", MB_OK);
            return false;
        }

        ///
        // Start excel and get its IDispatch pointer.
        hr = CoCreateInstance(&clsidExcel, NULL, CLSCTX_LOCAL_SERVER,
            &IID_IDispatch, (void **)&g_pDispExcel);

        /* Excel not successfully initialize */
        if (!g_pDispExcel) {return false;}

        hr = AutoWrap(DISPATCH_PROPERTYGET,&resParam, g_pDispExcel, ucstr_books, 0);
        if(FAILED(hr) || resParam.vt != VT_DISPATCH)
        {
            g_pDispExcel->lpVtbl->Release(g_pDispExcel);
            g_pDispExcel = NULL;
            return false;
        }

        g_pDispBooks = resParam.pdispVal;

        return true;
    }


    /* ========================================================================== */
    EXPORT XLSFILE* winxls_open(tChar* file_path, tChar* open_mode)
    {
        XLSFILE* h_file;

        tUInt16* wFile_path = NULL;

        tChar* ucstr_open = "Open";
        tChar* ucstr_add = "Add";
        tChar* ucstr_sheets = "Worksheets";
        tChar* ucstr_sheet = "Item";
        tChar* ucstr_range = "Cells";
        tChar* ucstr_cell = "Item";
        tChar* ucstr_sheet_count = "Count";

        tUInt32 i =0;

        VARIANT varg;
        HRESULT hr;
        VARIANT resParam;

        EXCEPINFO except;

        /* winxls not successfully initialized */
        if (g_pDispExcel == NULL || g_pDispBooks == NULL) {return NULL;}

        h_file = malloc(sizeof(XLSFILE));
        memset(h_file, 0x00, sizeof(XLSFILE));       

        VariantInit(&resParam);

        /* prepare for IDispatch input arg */
        varg.vt = VT_BSTR;
        wFile_path = MString2WString(file_path);
        varg.bstrVal = SysAllocString(wFile_path);
        free(wFile_path);
        wFile_path = NULL;

        if (strstr(open_mode, "r"))
        {
            hr = AutoWrap(DISPATCH_METHOD,&resParam, g_pDispBooks, ucstr_open, 1, varg);
        }
        else if (strstr(open_mode, "w"))
        {
            hr = AutoWrap(DISPATCH_METHOD,&resParam, g_pDispBooks, ucstr_add, 0);

            /* Keep the file path for saving  */
            h_file->filepath = malloc(strlen(file_path)+1);
            memset(h_file->filepath, 0, strlen(file_path)+1);
            memcpy(h_file->filepath, file_path, strlen(file_path));
        }

        SysFreeString(varg.bstrVal);

        if(FAILED(hr) || resParam.vt != VT_DISPATCH) {return NULL;}

        h_file->bookhandle = resParam.pdispVal;

        /* Get the 'Worksheets' */
        hr = AutoWrap(DISPATCH_PROPERTYGET,&resParam, h_file->bookhandle, ucstr_sheets, 0);
        if(FAILED(hr) || resParam.vt != VT_DISPATCH)
        {
            ReleaseXLSHandle(h_file);
            return NULL;
        }
        h_file->sheetshandle = resParam.pdispVal;

        /* Get Sheet total number */
        hr = AutoWrap(DISPATCH_PROPERTYGET,&resParam, h_file->sheetshandle, ucstr_sheet_count, 0);
        if(FAILED(hr) || resParam.vt != VT_I4)
        {
            ReleaseXLSHandle(h_file);
            return NULL;
        }
        h_file->sheet_count = resParam.intVal;

        /* Get sheethandle, rangehandle */
        h_file->sheethandles = malloc(sizeof(IDispatch*) * h_file->sheet_count);
        h_file->rangehandles = malloc(sizeof(IDispatch*) * h_file->sheet_count);
        memset(h_file->sheethandles, 0x00, sizeof(IDispatch*) * h_file->sheet_count);
        memset(h_file->rangehandles, 0x00, sizeof(IDispatch*) * h_file->sheet_count);
        for (i=1; i<=h_file->sheet_count; i++)
        {
            varg.vt = VT_I4;
            varg.intVal = i;

            hr = AutoWrap(DISPATCH_PROPERTYGET,&resParam, h_file->sheetshandle, ucstr_sheet, 1, varg);
            if(FAILED(hr) || resParam.vt != VT_DISPATCH) {ReleaseXLSHandle(h_file);return NULL;}
            h_file->sheethandles[i-1] = resParam.pdispVal;

            // Get the 'all Range'
            hr = AutoWrap(DISPATCH_PROPERTYGET,&resParam, h_file->sheethandles[i-1], ucstr_range, 0);
            if(FAILED(hr) || resParam.vt != VT_DISPATCH) {ReleaseXLSHandle(h_file);return NULL;}
            h_file->rangehandles[i-1] = resParam.pdispVal;
        }

        return h_file;
    }


    /* ========================================================================== */
    EXPORT tBool winxls_addsheet(XLSFILE* xlsfile, tChar* sheet_name)
    {
        tUInt16* tsheet_name = NULL;
        tUInt16 cBuf[_MAX_PATH] = {0};
        tChar    buf[100] = {0};

        tChar* ucstr_add = "Add";
        DISPID dispid_add = 0;
        DISPPARAMS disp_params_add    = {NULL, NULL, 0, 0};

        VARIANT inArg;
        HRESULT hr;
        VARIANT resParam;

        EXCEPINFO except;


        if (!xlsfile || !xlsfile->sheetshandle)
        {
            return false;
        }

        /* Prepare the new sheet name */
        if (sheet_name) {tsheet_name = MString2WString(sheet_name);}
        else
        {
            swprintf(cBuf, "Sheet%d", xlsfile->sheet_count+1);
            tsheet_name = cBuf;
        }

        VariantInit(&resParam);
        VariantInit(&inArg);
        inArg.vt = VT_BSTR;
        inArg.bstrVal = SysAllocString(tsheet_name);
        disp_params_add.cArgs = 1;
        disp_params_add.cNamedArgs = &inArg;

        hr = xlsfile->sheetshandle->lpVtbl->GetIDsOfNames(xlsfile->sheetshandle,&IID_NULL, ucstr_add, 1,
            LOCALE_USER_DEFAULT, &dispid_add);
        if (FAILED(hr))
        {
            sprintf(buf, "IDispatch::xlsfile->sheetshandle->lpVtbl->GetIDsOfNames(add) failed with %08lx", hr);
            MessageBox(NULL, buf, "Debug Notice", MB_SETFOREGROUND);
            return false;
        }

        hr = xlsfile->sheetshandle->lpVtbl->Invoke(xlsfile->sheetshandle,dispid_add, &IID_NULL, LOCALE_SYSTEM_DEFAULT,
            DISPATCH_PROPERTYPUT | DISPATCH_METHOD,
            &disp_params_add, &resParam, &except, NULL );
        if (FAILED(hr))
        {
            sprintf(buf, "IDispatch::xlsfile->sheetshandle->lpVtbl->Invoke(add) failed with %08lx", hr);
            MessageBox(NULL, buf, "Debug Notice", MB_SETFOREGROUND);
            return false;
        }

        return true;
    }
    /* ========================================================================== */
    EXPORT tUInt32 winxls_write(XLSFILE* xlsfile, tUInt32 sheet_index, tChar* value, tUInt32 col, tUInt32 row)
    {
        HRESULT hr = 0;

        tUInt16* wvalue = NULL;

        VARIANT inVariants[3];

        VARIANT    resParam;

        tChar* ucstr_cell = "Item";

        assert(    xlsfile->bookhandle        &&
            xlsfile->sheetshandle    &&
            xlsfile->sheethandles    &&
            xlsfile->rangehandles);

        if (sheet_index > xlsfile->sheet_count || sheet_index < 1)
        {
            return 0;
        }

        /* The value to write */
        inVariants[0].vt = VT_BSTR;
        wvalue = MString2WString(value);       
        inVariants[0].bstrVal = SysAllocString(wvalue);
        free(wvalue);

        /* The col number */
        inVariants[1].vt = VT_I4;
        inVariants[1].intVal = col;

        /* The row number */
        inVariants[2].vt = VT_I4;
        inVariants[2].intVal = row;

        hr = AutoWrap(DISPATCH_PROPERTYPUT,&resParam,xlsfile->rangehandles[sheet_index-1],ucstr_cell,3,inVariants[0],inVariants[1],inVariants[2]);
        SysFreeString(inVariants[0].bstrVal);

        if(FAILED(hr)) {return 0;}

        return strlen(value);
    }

    /* ========================================================================== */
    EXPORT tBool winxls_close(XLSFILE* xlsfile)
    {
        tUInt16* ucstr_saveas    = "SaveAs";
        tUInt16* ucstr_save        = "Save";
        tUInt16* ucstr_close    = "Close";

        VARIANT resParam;

        VARIANT varg;
        HRESULT hr = 0;
        tUInt16* wfile_path = NULL;

        assert(    xlsfile->bookhandle        &&
            xlsfile->sheetshandle    &&
            xlsfile->sheethandles    &&
            xlsfile->rangehandles
            );

        /* SaveAs    */
        if (xlsfile->filepath)
        {
            DeleteFile(xlsfile->filepath);

            /* prepare for the file path to save as */
            varg.vt = VT_BSTR;
            wfile_path = MString2WString(xlsfile->filepath);
            varg.bstrVal = SysAllocString(wfile_path);
            free(wfile_path);
            wfile_path = NULL;

            hr = AutoWrap(DISPATCH_METHOD,&resParam, xlsfile->bookhandle, ucstr_saveas, 1, varg);
            SysFreeString(varg.bstrVal);
        }
        else /* Save    */
        {
            hr = AutoWrap(DISPATCH_METHOD,&resParam, xlsfile->bookhandle, ucstr_save, 0);
        }

        if (FAILED(hr)) {return false;}

        /* Close    */
        hr = AutoWrap(DISPATCH_METHOD,&resParam, xlsfile->bookhandle, ucstr_close, 0);

        if (FAILED(hr)) {return false;}

        ReleaseXLSHandle(xlsfile);

        return true;
    }



    /* ========================================================================== */
    EXPORT tBool winxls_uninit(void)
    {
        tChar* ucstr_quit        = "Quit";
        DISPID dispid_quit        = 0;
        DISPPARAMS disp_params_quit        = {NULL, NULL, 0, 0};

        HRESULT hr = 0;
        VARIANT    resParam;

        /* Quit    */
        hr = AutoWrap(DISPATCH_METHOD,&resParam, g_pDispExcel, ucstr_quit, 0);
        if (FAILED(hr)) { return false;    }

        if (g_pDispBooks)    {g_pDispBooks->lpVtbl->Release(g_pDispBooks); g_pDispBooks=NULL;}
        if (g_pDispExcel)    {g_pDispExcel->lpVtbl->Release(g_pDispExcel); g_pDispExcel=NULL;}

        return true;
    }
#ifdef __cplusplus
}        /* extern "C" */
#endif

#undef _WINXLS_C_

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值