OLE – Low level

The functionality described on this Web page is: esoteric, specialized, and hardy every used.

First a bit of techie talk.

This executable uses the Windows APIs:  CoCreateInstance / IDispatch / Invoke to achieve much of its OLE capabilities.

The outer interpreter of this executable (the inner interpreter handles the SQLite commands) handles all OLE related commands.

When analyzing a command line, the outer interpreter breaks the line in to a sequence of tokens, and then checks some internal tables to see if a token is a keyword, a numerical value, a user defined variable/constant/function or subroutine. Anything that it can not identify is treated as an unknown name.

Once the input has been tokenised and identified, the token sequence is passed to the line execution code.

Each token sequence is examined in sequence.

Assume that we have

dim myExl = createObject ("excel.application")
myExcel.visible = 1

The first line is not actually OLE, it is just standard interpreter work.

But the second line is OLE. The token visible is unknown to the interpreter, but it appears just after a period (dot) so it is assumed that visible is a method or property of the object that is immediately before the period (in this case the myExcel object).

The interpreter now decides if visible if a property or a method. The next token is an equal ( = ) so it assumes that visible is a property. It executes the token sequence after the equal to get the value, and then constructs  an internal OLE property set command for the object myExcel, on the property visible, with a value of 1 .

Since this executable does not refer to an Excel type library, then the whole interpretation process for OLE command lines is based on this type of look-back/look-forward analysis.

What surprises me, is that I do not know of a single case where it has failed!

However! In 1979 I joined a telecommunications manufacturer as an ISDN design engineer. All of my training / experience has told me that ISDN engineers are belt and braces engineers.

By that I mean they try to design / create / implement systems with inbuilt safety. For example,  large ISDN telephone exchanges were powered by a mains power system, with a (massive) battery back-up, with a emergency diesel power electrical generator on the premises. Even a small exchange had mains power and 8 hours of battery for emergencies. ISDN equipment was created for 99.999 % availability, whereas Internet Protocol equipment is usually designed to a lower level. Internet Protocol engineers were not brought up as belt and braces engineers. ( All of this is of course only my opinion!)

Anyway, from a belt and braces point of view the normal OLE handling done by the executable might be wrong in some weird or wonderful case.


Belt and braces: Methods and Properties

This executable has a number of built-in functions that map directly to a pre-defined OLE API:  olePut , oleGet, oleFunction

So the line   myExcel.visible = 1 can be replaced by:

olePut ( myExcel, "visible", 1 )

——————-

And reading the visible property would be:

message = oleGet ( myExcel, "visible")

——————-

And setting the value of a cell on the active worksheet:

myExcel.cells(1,2).value = 3

could be written as:

olePut (    oleGet ( myExcel, "cells" , 1,2 )   , "value" , 3)

This is certainly more difficult to read, but it is predictable.


Belt and braces: oleENUM  and oleNextEnum

There are two other low level OLE commands, and they focus on handling  enumerated objects.

Sounds tricky, but a simple example is:

newscript
dim fso = createobject ("Scripting.FileSystemObject")
If ( ! fso ) THEN
Message ="Could not create object"
stop
End IF
dim objFolder = fso.getFolder( dir() )
freestring = ""
dim myEnum = objFolder.files
dim myFile
freestring = ""
For each myFile in myEnum
freestring = freestring & myFile.name & chr(0x0a)
Next myFile
message = freestring

It displays the names of all the files in the current default folder.

The File System Object is used to get a folder object for the default folder. We then get a collection of file objects from the folder object and display the name property for each file object.

The executable has a  For each ..   Next object construct that handles enumerated collections.

But some applications have a unusual implementation and then For each ..   Next object does not work.

So, belts and braces, there are the two functions oleENUM  and oleNextEnum which are wrappers around low level OLE APIs in Windows.

We can rewrite the original enumerated based script:

dim myEnum = objFolder.files
dim myFile
freestring = ""
For each myFile in myEnum
freestring = freestring & myFile.name & chr(0x0a)
Next myFile
message = freestring

with the low level commands as:

dim myEnum = oleENUM ( objFolder.files )
dim myEnumItem = oleNextEnum ( myEnum )
Do while ( istype(myEnumItem) == "Dispatch")
freestring = freestring & myEnumItem.name & chr(0x0a)
myEnumItem = oleNextEnum ( myEnum)
loop
message = freestring


oleMAP

As already stated, this executable does not use type library files which is the standard way to find out methods, properties and values an application make visible to third parties.

Sorry.

But there is a limited look in to what a object has, using the oleMAP command, refer to help("oleMAP") or look here for the oleMAP section.


Here are a few examples of the high/low level OLE programming approaches:

xlopen ()
' -----------------------------------------------------------------------
' Simple Excel access
'
' "Traditional" approach
'
' exl.cells(1,1).value = "Hello"
' exl.cells(1,2).value =
' exl.cells(1,3).value = "World"
'
' Functional approach

olePut ( oleGet ( exl, "cells" , 1, 1 ) , "value" , "Hello")
olePut ( oleGet ( exl, "cells" , 1, 2 ) , "value" , 2)
olePut ( oleGet ( exl, "cells" , 1, 3 ) , "value" , "the World")


' Write the current EDIT panel to Excel as an OLE embedded file
'
' "Traditional" approach
'
' exl.ActiveSheet.OLEObjects.Add( , ScriptAsFile,,,,,, exl.range("E4").left, exl.range("E4").top ).select
'
' Functional approach
' Note how I have intentionally mixed both approaches here, the last parameter is given in the traditional way

oleFunction ( oleGet ( oleGet(exl, "Activesheet") , "OLEObjects" ) , "ADD", , ScriptAsFile, , , , , , oleGet ( oleGet ( exl, "range" , "E4") , "left") , exl.range("E4").top )


' FOR EACH item in OBJECT
'
' Starts the Scripting.FileSystemObject
' Lists the files in the default directory
' first part of the code is common to both approaches
'
newscript
dim fso = createobject ("Scripting.FileSystemObject")
If ( ! fso ) THEN
Message ="Could not create object"
stop
End IF
dim objFolder = fso.getFolder( dir() )
freestring = ""

'
' "Traditional" approach
'
' dim myEnum = objFolder.files
' dim myFile
' For each myFile in myEnum
' freestring = freestring & & myFile.name & chr(0x0a)
' Next myFile
' message = freestring
'
' Functional approach
'

dim myEnum = oleEnum ( objFolder.files)
dim myEnumItem = oleNextEnum ( myEnum)
Do while ( istype(myEnumItem) == "Dispatch4")
freestring = freestring & myEnumItem.name & chr(0x0a)
myEnumItem = oleNextEnum ( myEnum)
loop
message = freestring