Here's little and dirty example of OLE automation done in raw WinAPI
program oletest;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, ActiveX, Ole2;
var
unkXl: IUnknown;
dispXl: IDispatch;
clsidXl: TCLSID;
did: TDispID;
name: POleStr;
dps: DISPPARAMS;
didNamed: TDispID;
param: VARIANTARG;
hres: HRESULT;
begin
// initialize COM
CoInitialize(nil);
// get CLSID of Excel
CLSIDFromProgID('Excel.Application', clsidXl);
// create Excel instance
CoCreateInstance(clsidXl, nil, CLSCTX_LOCAL_SERVER, IID_IUnknown, unkXl);
// get IDispatch interface of received object
unkXl.QueryInterface(IID_IDispatch, dispXl);
// DO SOME STUFF WITH EXCEL HERE
// for example, we'll just show it ;)
name:= 'Visible';
param.vt:= VT_BOOL;
param.vbool:= true;
dps.cArgs:= 1;
dps.rgvarg:= @param;
didNamed:= DISPID_PROPERTYPUT;
dps.cNamedArgs:= 1;
dps.rgdispidNamedArgs:= @didNamed;
dispXl.GetIDsOfNames(GUID_NULL, @name, 1, LOCALE_SYSTEM_DEFAULT, @did);
hres:= dispXl.Invoke(did, GUID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT,
dps, nil, nil, nil);
MessageBox(0, 'Hit OK to end the app', 'Test', MB_OK or MB_ICONINFORMATION);
// release unused objects
dispXl.Release;
unkXl.Release;
// deinitialize COM
CoUninitialize;
end.