#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <windows.h>
#include <combaseapi.h>
VARIANT invoke(IDispatch *disp, const OLECHAR *name, WORD wFlags, size_t count, ...) {
VARIANT result = {0};
DISPID dispIdMember;
HRESULT hr = disp->lpVtbl->GetIDsOfNames(disp, &IID_NULL, (LPOLESTR *)&name, 1, LOCALE_USER_DEFAULT, &dispIdMember);
if(hr != S_OK) return result;
DISPPARAMS dp = {0};
VARIANT *rgvarg = NULL;
if(count) {
rgvarg = malloc(sizeof(VARIANT) * count);
va_list ap; va_start(ap, count);
for(size_t i = 0; i < count; ++i) {
rgvarg[i] = *va_arg(ap, VARIANT *);
}
va_end(ap);
dp.rgvarg = rgvarg;
dp.cArgs = count;
}
DISPID dispIdNamed = DISPID_PROPERTYPUT;
if(wFlags & DISPATCH_PROPERTYPUT) {
dp.rgdispidNamedArgs = &dispIdNamed;
dp.cNamedArgs = 1;
}
disp->lpVtbl->Invoke(disp, dispIdMember, &IID_NULL, LOCALE_USER_DEFAULT, wFlags, &dp, &result, NULL, NULL);
if(count) {
va_list ap; va_start(ap, count);
for(size_t i = 0; i < count; ++i) {
*va_arg(ap, VARIANT *) = rgvarg[i];
}
va_end(ap);
free(rgvarg);
}
return result;
}
VARIANT get_column(IDispatch *range) {
VARIANT columns = invoke(range, L"Columns", DISPATCH_PROPERTYGET, 0);
VARIANT count = invoke(columns.pdispVal, L"Count", DISPATCH_PROPERTYGET, 0);
VariantClear(&columns);
return count;
}
VARIANT get_row(IDispatch *range) {
VARIANT rows = invoke(range, L"Rows", DISPATCH_PROPERTYGET, 0);
VARIANT count = invoke(rows.pdispVal, L"Count", DISPATCH_PROPERTYGET, 0);
VariantClear(&rows);
return count;
}
int main(void) {
CoInitialize(NULL);
CLSID id;
CLSIDFromProgID(L"Excel.Application", &id);
IDispatch *Application;
CoCreateInstance(&id, NULL, CLSCTX_LOCAL_SERVER, &IID_IDispatch, (LPVOID *)&Application);
{
VARIANT boolean = {.vt = VT_BOOL, .boolVal = true};
invoke(Application, L"Visible", DISPATCH_PROPERTYPUT, 1, &boolean);
VariantClear(&boolean);
}
VARIANT wbs = invoke(Application, L"Workbooks", DISPATCH_PROPERTYGET, 0);
VARIANT filename = {.vt = VT_BSTR, .bstrVal = SysAllocString(L"C:\\cygwin64\\tmp\\test.xlsx")};
VARIANT wb = invoke(wbs.pdispVal, L"Open", DISPATCH_METHOD, 1, &filename);
VariantClear(&filename);
VARIANT wss = invoke(wb.pdispVal, L"Worksheets", DISPATCH_PROPERTYGET, 0);
VARIANT index = {.vt = VT_BSTR, .bstrVal = SysAllocString(L"Sheet1")};
VARIANT ws = invoke(wss.pdispVal, L"Item", DISPATCH_PROPERTYGET, 1, &index);
VariantClear(&index);
VARIANT range = invoke(ws.pdispVal, L"UsedRange", DISPATCH_PROPERTYGET, 0);
VARIANT column = get_column(range.pdispVal);
VARIANT row = get_row(range.pdispVal);
for(size_t y = 0; y < row.lVal; ++y) {
for(size_t x = 0; x < column.lVal; ++x) {
VARIANT vx = {.vt = VT_I4, .lVal = x + 1};
VARIANT vy = {.vt = VT_I4, .lVal = y + 1};
VARIANT cell = invoke(range.pdispVal, L"Item", DISPATCH_PROPERTYGET, 2, &vx, &vy);
VARIANT value = invoke(cell.pdispVal, L"Value", DISPATCH_PROPERTYGET, 0);
switch(value.vt) {
case VT_BSTR:
{
int size = WideCharToMultiByte(CP_UTF8, 0, value.bstrVal, -1, NULL, 0, NULL, NULL);
char *str = malloc(size);
WideCharToMultiByte(CP_UTF8, 0, value.bstrVal, -1, str, size, NULL, NULL);
printf("'%s' ", str);
free(str);
}
break;
case VT_R8:
printf("'%.3lf' ", value.dblVal);
break;
default:
printf("'null' ");
}
VariantClear(&value);
VariantClear(&cell);
VariantClear(&vy);
VariantClear(&vx);
}
puts("");
}
VariantClear(&row);
VariantClear(&column);
VariantClear(&range);
VariantClear(&ws);
VariantClear(&wss);
{
VARIANT boolean = {.vt = VT_BOOL, .boolVal = false};
invoke(wb.pdispVal, L"Close", DISPATCH_METHOD, 1, &boolean);
VariantClear(&boolean);
}
VariantClear(&wb);
VariantClear(&wbs);
invoke(Application, L"Quit", DISPATCH_METHOD, 0);
Application->lpVtbl->Release(Application);
CoUninitialize();
return 0;
}