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_