MS Excel Flat API

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

MS Excel Flat API

Post by Justin »

Most of the Excel interfaces have to be called through IDispatch wich is a pain so rather than using COMate or vbscript engine i decided to automate the process of creating a flat API using the Excel TypeLibray and ITypeInfo interfaces, it should work with any TypeLibray.

The result: 6077 functions, and all constants up to Office 12.
Source is 1.2MB so is recommended to create a PB Lib, but currently there is a bug in PB that prevents from doing it, you can try it with the file Excel.pb.

Github project:
https://github.com/omegakode/PBExcel

Excel Reference:
https://learn.microsoft.com/en-us/offic ... view/excel

Usage:
All objects are of type IDispatch. When you no longer need an object call Release() on it.
Boolean values are #VARIANT_TRUE / #VARIANT_FALSE
Single is PB float.
Double is PB double.

Function parameters with non VARIANT types are passed directly, otherwise are passed as pointer to VARIANT.
When a function returns a non VARIANT type is returned directly, otherwise you must supply a pointer to a VARIANT as the last paramenter ie *result.VARIANT.

Use the Excel_GetLastError() functions to retrieve error info.

See examples in the example folder. Of course you will need MS Excel installed.
Ecample to create a workbook:

Code: Select all

;ExcelWrite.pb

EnableExplicit

XIncludeFile "..\Excel.pb"

Procedure main()
	Protected.IDispatch excel, workBooks, workBook, cellsRange
	Protected.VARIANT vRowIndex, vColIndex, vCellRange, vStr, vBool, vNone, vLong
	Protected.l iCol, iRow
	Protected.s file
	
	COM_Init()
	
	COM_VarNone(@vNone)

	;Create Excel application
	excel = Excel_Application()
	If excel = 0
		Debug "Error failed to create Excel application"
		ProcedureReturn
	EndIf
	Excel_Application_Put_Visible(excel, #VARIANT_TRUE)
	Excel_Application_Put_DisplayAlerts(excel, #VARIANT_FALSE)
	
	;Add a workbook
	workBooks = Excel_Application_Get_Workbooks(excel)
	workBook = Excel_Workbooks_Add(workBooks, @vNone)

	;Fill 2 rows of 10 columns
	cellsRange = Excel_Application_Get_Cells(excel)
	For iRow = 1 To 2
		For iCol = 1 To 10
			Excel_Range_Get_Item(cellsRange, COM_VarLong(@vRowIndex, iRow), COM_VarLong(@vColIndex, iCol), @vCellRange)
			If vCellRange\pdispVal = 0 ;Error
				Continue
			EndIf	
			
			Excel_Range_Put_Value2(vCellRange\pdispVal, COM_VarString(@vStr, "Item" + Str(iRow) + "-" + Str(iCol)))

			COM_VarClear(@vStr)
			COM_VarClear(@vCellRange) ; = vCellRange\pdispVal\Release()
		Next
	Next 
	
	file = SaveFileRequester("Save", "", "", 0)
	If file
		Excel_Workbook_SaveAs(workBook, COM_VarString(@vStr, file), @vNone, @vNone, @vNone, @vNone, @vNone, 
			#xlNoChange, @vNone, @vNone, @vNone, @vNone, @vNone)
		COM_VarClear(@vstr)
		
		If Excel_GetLastError() <> 0
			Debug "Failed to save file:"
			Debug Excel_GetLastErrorDescription()
			
		Else
			Debug "File " + file + " saved succesfully"
		EndIf 
	EndIf 
	
	Excel_Workbook_Close(workBook, COM_VarBool(@vBool, #VARIANT_FALSE), @vNone, @vNone)
	workBook\Release()
	workBooks\Release()
	cellsRange\Release()

	Excel_Application_Quit(excel)
	excel\Release()
EndProcedure

main()
Last edited by Justin on Mon Dec 23, 2024 3:16 pm, edited 1 time in total.
User avatar
idle
Always Here
Always Here
Posts: 5896
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: MS Excel Flat API

Post by idle »

that's a great contribution to the community.
User avatar
le_magn
Enthusiast
Enthusiast
Posts: 280
Joined: Wed Aug 24, 2005 12:11 pm
Location: Italia

Re: MS Excel Flat API

Post by le_magn »

Thank you for this great code!!!
Image
Rinzwind
Enthusiast
Enthusiast
Posts: 690
Joined: Wed Mar 11, 2009 4:06 pm
Location: NL

Re: MS Excel Flat API

Post by Rinzwind »

i decided to automate the process of creating a flat API using the Excel TypeLibray and ITypeInfo interfaces, it should work with any TypeLibray.
How did you do that part? What tools/code? I don't see it on github. Only the end result.
Justin
Addict
Addict
Posts: 948
Joined: Sat Apr 26, 2003 2:49 pm

Re: MS Excel Flat API

Post by Justin »

The converter code is way to dirty to post it, i would have to rewrite it from scratch.

But it's not that hard, i just used the ITypeLib and similar interfaces.
https://learn.microsoft.com/en-us/windo ... l-itypelib

Basically you get the function name, return type, params names and params types and build the PB function.
Basic pseudo code:

Code: Select all

xincludefile "oaidl.pbi"

;Get typelib
LoadTypeLibEx_("c:\EXCEL.exe", #REGKIND_NONE, @typeLib.ITypeLib)

;Get type count
typeCount = typeLib\GetTypeInfoCount()

;Loop types
For typeIndex = 0 To typeCount - 1
	;Type name
	typeLib\GetDocumentation(typeIndex, @pTypeName.i, #Null, #Null, #Null)
	
	;Type info
	typeLib\GetTypeInfo(typeIndex, @typeInfo.ITypeInfo)
	
	;Type attributes
	typeInfo\GetTypeAttr(@*tatt.TYPEATTR)
	
	Select *tatt\typekind
		Case #TKIND_DISPATCH
			For iFunc = 0 To *tatt\cFuncs - 1
				;Function description
				typeInfo\GetFuncDesc(iFunc, @*fDesc.FUNCDESC)
				
				;Func name
				typeInfo\GetDocumentation(*fDesc\memid, @pItemName.i, #Null, #Null, #Null)
				;Func return type
				retType.w = *fDesc\elemdescFunc\tdesc\vt
				
				;Param names
				Dim paramNames.i(*fDesc\cParams)
				typeInfo\GetNames(*fDesc\memid, @paramNames(), *fDesc\cParams + 1, @paramCount)

				;Param types
				*elDescArr.ELEMDESC_ARRAY = *fDesc\lprgelemdescParam
				For iParam = 0 To *fDesc\cParams -1
					Select *elDescArr\item[iParam]\tdesc\vt
						Case #VT_I4
						
						;rest of types
					EndSelect
				Next 
			Next 
			
		;do rest of types
		;
	EndSelect
Next 
And the header you will need:

Code: Select all

;oaidl.pbi
	
;- enum CALLCONV
#CC_FASTCALL    = 0
#CC_CDECL       = 1
#CC_MSCPASCAL   = ( #CC_CDECL + 1 )
#CC_PASCAL      = #CC_MSCPASCAL
#CC_MACPASCAL   = ( #CC_PASCAL + 1 )
#CC_STDCALL     = ( #CC_MACPASCAL + 1 )
#CC_FPFASTCALL  = ( #CC_STDCALL + 1 )
#CC_SYSCALL     = ( #CC_FPFASTCALL + 1 )
#CC_MPWCDECL    = ( #CC_SYSCALL + 1 )
#CC_MPWPASCAL   = ( #CC_MPWCDECL + 1 )
#CC_MAX         = ( #CC_MPWPASCAL + 1 )

;- enum DISPID
#DISPID_UNKNOWN	= -1
#DISPID_VALUE	= 0
#DISPID_PROPERTYPUT	= -3
#DISPID_NEWENUM	= -4
#DISPID_EVALUATE = -5
#DISPID_CONSTRUCTOR	= -6
#DISPID_DESTRUCTOR = -7
#DISPID_COLLECT = -8

;- enum TYPEKIND
Enumeration
	#TKIND_ENUM
	#TKIND_RECORD
	#TKIND_MODULE
	#TKIND_INTERFACE
	#TKIND_DISPATCH
	#TKIND_COCLASS
	#TKIND_ALIAS
	#TKIND_UNION
	#TKIND_MAX
EndEnumeration

;- enum TYPEFLAGS
#TYPEFLAG_FAPPOBJECT	= $1
#TYPEFLAG_FCANCREATE	= $2
#TYPEFLAG_FLICENSED	= $4
#TYPEFLAG_FPREDECLID	= $8
#TYPEFLAG_FHIDDEN	= $10
#TYPEFLAG_FCONTROL	= $20
#TYPEFLAG_FDUAL	= $40
#TYPEFLAG_FNONEXTENSIBLE	= $80
#TYPEFLAG_FOLEAUTOMATION	= $100
#TYPEFLAG_FRESTRICTED	= $200
#TYPEFLAG_FAGGREGATABLE	= $400
#TYPEFLAG_FREPLACEABLE	= $800
#TYPEFLAG_FDISPATCHABLE	= $1000
#TYPEFLAG_FREVERSEBIND	= $2000
#TYPEFLAG_FPROXY	= $4000

;- enum VARKIND
Enumeration
	#VAR_PERINSTANCE
	#VAR_STATIC
	#VAR_CONST
	#VAR_DISPATCH
EndEnumeration

;- enum INVOKEKIND
Enumeration
	#INVOKE_FUNC	= 1
	#INVOKE_PROPERTYGET	= 2
	#INVOKE_PROPERTYPUT	= 4
	#INVOKE_PROPERTYPUTREF	= 8
EndEnumeration

;- enum SYSKIND
Enumeration SYSKIND
	#SYS_WIN16
	#SYS_WIN32
	#SYS_MAC
	#SYS_WIN64
EndEnumeration

;- enum PARAMFLAG
#PARAMFLAG_NONE	= 0 
#PARAMFLAG_FIN	= $1
#PARAMFLAG_FOUT	= $2
#PARAMFLAG_FLCID = $4
#PARAMFLAG_FRETVAL = $8
#PARAMFLAG_FOPT = $10
#PARAMFLAG_FHASDEFAULT = $20
#PARAMFLAG_FHASCUSTDATA = $40

;- TYPEDESC
Structure TYPEDESC Align #PB_Structure_AlignC
	StructureUnion
		*lptdesc.TYPEDESC
		lpadesc.i
		hreftype.l
	EndStructureUnion 
  vt.w  
EndStructure

;- IDLDESC
Structure IDLDESC Align #PB_Structure_AlignC
	dwReserved.l
	wIDLFlags.w
EndStructure

;- PARAMDESCEX
Structure PARAMDESCEX
	cBytes.l
	varDefaultValue.VARIANT
EndStructure

;- PARAMDESC
Structure PARAMDESC
	*pparamdescex.PARAMDESCEX
	wParamFlags.w
EndStructure

;- ELEMDESC
Structure ELEMDESC Align #PB_Structure_AlignC
	tdesc.TYPEDESC        
	StructureUnion
		idldesc.IDLDESC     
		paramdesc.PARAMDESC 
	EndStructureUnion
EndStructure

;- ELEMDESC_ARRAY
Structure ELEMDESC_ARRAY
	item.ELEMDESC[0]
EndStructure

;- VARDESC
Structure VARDESC Align #PB_Structure_AlignC
	memid.l
	lpstrSchema.i
	StructureUnion
		oInst.l
		*lpvarValue.VARIANT
	EndStructureUnion
	elemdescVar.ELEMDESC
	wVarFlags.w
	varkind.l
EndStructure

;- FUNCDESC
Structure FUNCDESC Align #PB_Structure_AlignC
	memid.l
	*lprgscode.LONG
	*lprgelemdescParam.ELEMDESC
	funckind.l
	invkind.l
	callconv.l
	cParams.w
	cParamsOpt.w
	oVft.w
	cScodes.w
	elemdescFunc.ELEMDESC
	wFuncFlags.w
EndStructure

;- TYPEATTR
Structure TYPEATTR Align #PB_Structure_AlignC
	guid.GUID               
	lcid.l                                 
	dwReserved.l
	memidConstructor.l                       
	memidDestructor.l                       
	lpstrSchema.i  
	cbSizeInstance.l                     
	typekind.l         
	cFuncs.w      
	cVars.w      
	cImplTypes.w   
	cbSizeVft.w   
	cbAlignment.w   
	wTypeFlags.w
	wMajorVerNum.w  
	wMinorVerNum.w   
	tdescAlias.TYPEDESC                         
	idldescType.IDLDESC
EndStructure 

;- TLIBATTR
Structure TLIBATTR Align #PB_Structure_AlignC
	guid.GUID
	lcid.l
	syskind.l
	wMajorVerNum.w
	wMinorVerNum.w
	wLibFlags.w
EndStructure
Post Reply