GUI – DLL

A fundamental principle of this executable is to reuse capabilities that are readily available in the Windows environment.

You could argue that it is the very reason for OLE.

As a long term “C” programmer I know that there is a lot of functionality in the Dynamic Link Libraries. These libraries provide functionality that can be accessed by other programs.

I set myself the goal of making it possible to access some of these libraries by implementing some general purpose code in this executable (written in “C”).

The nice (?) thing about “C” is the way that parameters are passed from a calling module to a called module.  All that matters is the number of parameters, each parameter is treated as a simple 32 bit value (on 32 bit machines) or as a 64 bit value (on 64 bit machines).

In the 32 bit Windows world it does not even matter what type of value is returned, it was always placed in the same register.

64 bit Windows however does not handle return values in the same way as 32 bit Windows.

In 64 bit Windows there are 2 different locations for return values, one for floating point values, and one for everything else.

That meant that when calling a DLL function from this executable we need to know the type of the return value, so that the executable can fetch it and transfer the value correctly to the invoker.

So armed with that knowledge I have implemented 3 functions to handle a DLL and 1 function (strictly internal) to handle the call to the targetted DLL function.

  • “FLOAT” a floating point number, referred to in “C” as a DOUBLE
  • “BSTR” a data structure used extensively in “automation”
  • “SIGNED” a signed integer
  • “UNSIGNED” an unsigned integer
  • “CSTR” a zero terminated 8bit character string
  • “NONE” nothing, compare with void myfunction ( …. )

work in progress

dll.open

dll.link

dll.close


DLL call needing a simple value parameter, and returning a “float”

' Uses the DLL msvcrt to get access to a square root function
'
newscript
dim myDLL = dll.open ("msvcrt")
if ( myDLL == 0 ) THEN
Message ="Could not open the DLL file"
stop
end IF
dim sqrt = dll.link(myDLL, "sqrt",1,"float" )
if ( ! sqrt ) THEN ' Sorry, do NOT use IF ( sqrt = 0) THEN
Message ="Could not find the named procedure"
stop
end IF
message = "The square root of 625 is = " & sqrt(625.000)
dll.close ( myDLL)
' Finished

 

 

 

The use of DLLs means that we need to pass values to the DLL procedure.  For numerical values this is easy, but for text strings and pointers to values/structures required some special commands.


DLL call needing pointers to “C” strings

newscript
dim myDLL = dll.open ("user32")
if ( myDLL == 0 ) THEN
Message ="Could not open the DLL file"
stop
end IF
dim mbA = dll.link( myDLL, "MessageBoxA",4,"unsigned" )
if (! mbA ) THEN ' Sorry, do NOT use IF ( mbA = 0) THEN
Message ="Could not find the named procedure"
stop
end IF
dim returnBtn = mbA ( 0, @ TextToByteArray("hello from a DLL", 0) , @ TextToByteArray("MessageBox (ANSI) called via DLL",0), 0x031)
if ( returnBtn == 1 ) THEN
Message = "ok"
ELSE
Message = "cancel"
end IF
dll.close ( myDLL)
' Finished

 


DLL call needing pointers to bstr structures.

newscript
dim myDLL = dll.open ("user32")
if ( myDLL == 0 ) THEN
Message ="Could not open the DLL file"
stop
end IF
dim mbW = dll.link( myDLL, "MessageBoxW",4,"unsigned" )
if (! mbW ) THEN ' Sorry, do NOT use IF ( mbW = 0) THEN
Message ="Could not find the named procedure"
stop
end IF
mbW ( 0,@ "hello from a DLL", @ "MessageBox (WideChar) called via DLL", 0)
dll.close ( myDLL)
' Finished

 

 

 


DLL call needing pointers to VARIANT structures.

(Internally this executable makes extensive use of VARIANTs. All user defined variable and constants are stored in VARIANTs.

 

newscript
dim myDLL = dll.open ("OleAut32")
if ( myDLL == 0 ) THEN
Message ="Could not open the DLL file"
stop
end IF
dim varPow = dll.link(myDLL, "VarPow",3,"unsigned" )
' WARNING: the formal definition of VarPow wants the ADDRESSES of 3 VARIANTs
' HRESULT VarPow(LPVARIANT pvarLeft, LPVARIANT pvarRight, LPVARIANT pvarResult)
if (! varPow ) THEN
Message ="Could not find the named procedure"
stop
end IF
dim X = 2 , Y = 8 , res
varPow ( @var X ,@var Y , @var res )
Message = X & " to the power of " & Y & " = " & res
dll.close ( myDLL)
' Finished