System Functions
DLL( ) / DLX( ) Call External function
   
Formats 1. Load Library: lib_num = DLL(ADDR lib_string$[,ERR=stmtref]) 
2.
Unload Library: DLL(DROP lib_num[,ERR=stmtref])
3.
Get Function Address: fnc_addr = DLL(FIND lib_num,fnc_name$ [,ERR=stmtref])
4.
Call Using String: DLL( [FLOATING POINT] lib_string$,fnc_name$,arg[ ,arg,arg...][,ERR=stmtref])
5.
Call by Library Number: DLL( [FLOATING POINT] lib_num,fnc_name$,arg[ ,arg,arg...][,ERR=stmtref])
6.
Call Using Function Address: DLL( [FLOATING POINT] *,fnc_address,arg[ ,arg,arg...][,ERR=stmtref])
7.
Define Callback routine: DLL (CALL OBJECT obj_id EVENT "event_name" [,ERR=stmtref]) (ver 10)
8.
Free Callback routine: DLL (CLEAR routine_addr [,ERR=stmtref]) (ver 10)

Where:

arg, arg... Parameters or arguments to pass to the function. The number and type of arguments you use vary from function to function. See DLL( ) Parameters.
event_name Name of the Event that will be passed to the referenced obj_id to handle Callbacks.
fnc_addr Address of the desired function. Numeric expression.
fnc_name Name of the function. The function name is the case-sensitive entry point in the DLL. Some API functions have an appended letter A for ASCII, others have an appended W for wide character UNICODE. String expression.
lib_num Internal library identifier used to reference a loaded library. Numeric expression.
lib_string$ Name of the .dll, . exe orother shared libary that contains the function to be used. String expression.
obj_id Object handle for an object that contains the Callback logic.
stmtref Program line number or statement label to which to transfer control.
FLOATING POINT The FLOATING POINT keyword is used to declare that the value being returned or passed is a floating point (double) value.

If the keyword occurs immediately following the open parenthesis of the DLL function then the function is assumed to return a floating point number.

Example: DLL(FLOATING POINT... ) )

If the keyword preceeds any passed-in numeric arg value then the value will be passed as a floating point value.

Example: DLL("MyDll", "MyFunc", FLOATING POINT x1, FLOATING POINT y1, ... ) )

Use of the FLOATING POINT keyword is +PxPlus Exclusive (build 9200)

   
Returns Calls external function or returns DLL identifiers and addresses.


*Note* DLL( ) and DLX( ) functions are only available under MS Windowsas well as most UNIX/Linux environments -- TCB(196) will return 1 if the function is supported. DLLs do not need to be registered to be used in ProvideX. Under WindX, remember that DLLs run on the host. Use a call to a WindX program to invoke a DLL.


   
Description Use the ProvideX DLL( ) function to access functions within DLLs that are external to ProvideX. It's similar to a call to execute external DLL functions from inside ProvideX applications. The ProvideX DLL( ) function will also return any function identifiers and addresses, as defined by the DLL routine.

In 32-bit environments, the DLX( ) function is unnecessary, since both DLX( ) and DLL( ) functions return 32-bit values. In 16-bit environments, DLL( ) returns 16-bit values while the DLX( ) function returns 32-bit values.

A DLL is a free-standing library of 'C'-style functions commonly used in the Microsoft Windows and/or various Unix/Linux systemst. In Windows, all functions controlling the environment are done through DLL calls with function names as the entry points in the DLL. Most Windows API functions reside in the following DLLs:

32-bit DLL Purpose
USER32.DLL USER32.DLL User interface
KERNEL32.DLL System interface
GDI32.DLL Graphics interface


*Warning* You can use third-party DLLs, but make sure you have good documentation on what you're passing and getting back. We can provide assistance on how to call a DLL, but we do not provide support for third-party DLLs. There is no validation on what you pass. Bad pointers can cause memory corruption and potential GPFs.


   
Format 1 Load Library

lib_num = DLL(ADDR lib_string$[,ERR=stmtref])

Use the DLL(ADDR ...) format to addresses or load the DLL. This lets you load and lock a library into memory and obtain the addresses of its functions and the internal identifier. You can then use this identifier on subsequent DLL( ) functions to avoid having to reload the DLL. Note that the return value is the handle to the DLL and should be used in all subsequent DLL( ) calls.



*Note* In some instances (e.g., when the DLL maintains internal data structures) it is mandatory to keep the DLL loaded in order to use or call the function. When in doubt, load the DLL (not needed for Windows API DLLs). Keeping the DLL loaded has memory consequences, but commonly lets you gain access speed.


   
Format 2 Unload Library

DLL(DROP lib_num[,ERR=stmtref])

Use the DLL(DROP ...) format to unload a loaded DLL when you no longer need it. Note that if you LOAD a DLL, you must DROP or unload it to free up the memory that was allocated to it.

   
Format 3 Get Function Address

fnc_address=DLL(FIND lib_num,fnc_name$[,ERR=stmtref])

You can obtain the address of a DLL( ) function in an addressed (loaded) library by using the FIND format. This format asks the DLL( ) function to return its current address, which you can then use in subsequent calls. The address is only valid while the library is loaded.

In some cases, you may need to use the return value as a memory pointer. The MEM( ) function can be used to obtain memory information (address, contents, etc.). If you need a 32-bit result from a DLL( ) call, use the function DLX( ) instead.

When you call an external function and pass arguments to it, you can identify it using a string, a library number, or a function address. For more information, refer to DLL( ) Parameters and MEM( ) Return Memory Value.

   
Format 4 Call Using String

DLL(lib_string$,fnc_name$,arg[,arg,arg...][,ERR=stmtref])

Use this format to call the DLL( ) function using strings to identify the library and function by name.

   
Format 5 Call by Library Number

DLL(lib_num,fnc_name$,arg[,arg,arg...][,ERR=stmtref])

Use this format to call the DLL( ) function using a numeric to identify the library by its internal identifier and the function name.

   
Format 6 CALLs Using Function Address:

DLL(*,fnc_address,arg[,arg,arg...][,ERR=stmtref])

Use this format to call a DLL( ) function in a loaded library using the internal function address as a memory pointer.



*Note* The address is only valid while the library is loaded.


Formats 7 & 8 CALLBACK (Windows only):

As of version 10, PxPlus/PxBasic supports a single active callback which can have up to five parameters. It has been implemented as part of the DLL function with two options:

DLL(CALL ...) ! To define the callback function and get its address
DLL(CLEAR ...) ! To free the callback address

All callback functions MUST be defined within an Object so they can return a value to the caller. The callback is internally processed as an Event and processed by a event handler within the object. To obtain a reference to the Callback routine the DLL(CALL ...) function is called to return the callback address for the event handler within the object specified. When finished with the CALLBACK, the entry must be freed using the CLEAR option of the DLL function.

For example, to get the callback address for "NameOfEvent" in obj_id:

CB_valu = DLL (CALL OBJECT obj_id EVENT "NameOfEvent")

You can then pass CB_valu to the external DLL. When finished either drop the object or issue the following to free the Callback.

Junk = DLL(CLEAR CB_valu)

Here is a sample Callback Object:

0010 DEF CLASS "cb"
0020 FUNCTION EnumWindow(hwnd,lparam) FOR EVENT "EnumWindows"
0030 ENTER hwnd,lparam
0040 PRINT "Lparam=",lparam," hwnd=",hwnd
0050 RETURN 1
0060 END DEF

And here is a test program which uses the Callback functionality to spin through all the WIndows.

0010 LET cb=NEW("cb")
0020 LET proc=DLL(CALL OBJECT cb EVENT "EnumWindows")
0030 LET x=DLL("USER32.DLL","EnumWindows",proc,123)
0040 PRINT DLL(CLEAR proc)
0050 DROP OBJECT cb

   
DLL( ) Parameters DLLs normally expect one of two types of parameters: integers and pointers. The arguments/parameters you use when you call the DLL( ) function are passed to the function in the following ways:
Example Type 32-Bit Data Format Passed 16-Bit Data Format Passed
X$ Strings Address of string Address of string
X Numeric Variables Double word value (32-bit) Double word value (32-bit)
X% Integer Variables 16-bit value passed as 32-bit Single word value (16bit)
INT(X+1) INT( ) Function Standard 32 bit Single word value (16 bit)
X+Y Numeric Expression 32-bit value 32-bit value
   
Examples Example 1. The following example swaps the left and right mouse buttons:

0010 A=DLL("USER.EXE",""SwapMouseButton",1) ! Passes 32-bit value
or
0010 A=DLL("USER.EXE","SwapMouseButton",INT(1)) ! Passes 16-bit value
0020 IF A<>0 THEN PRINT "Could not swap button"

An integer value of zero swaps the mouse buttons back.

Example 2. Pointers are commonly used to pass string values, usually terminating with a null byte. This passes a pointer to a DLL to return the handle of a window with the title Notepad:

0030 A=DLL("USER.EXE",""FindWindowA","Notepad"+$00$,0)

Example 3. Sometimes a pointer refers to a region of memory or a structure to receive information from a DLL. You must pre-allocate a string variable to receive the data. The example below returns the window title, given the handle. The returned string terminates with a null byte ($00$):

DIM X$(256)
0030 A=DLL("USER.EXE",""GetWindowTextA",Hndl,X$,LEN(X$))

Example 4. To pass a pointer to a number, define a two- or four-byte string and read the value after swapping the bytes, as follows:

DIM X$(256) A=DLL("SOME.DLL",""GetSomething",Hndl,X$) X=DEC($00$+SWP(X$)

Example 5. Program DLLS1in this example starts Notepad, locates the handle and closes the window handle:

0010 !dlls1 Start Notepad and Close It
0020 INVOKE "NOTEPAD"
0030 INPUT "Press enter after Notepad has started ",X$
0040 LET HWND%=DLL("USER32.DLL","FindWindowA","Notepad"+$00$,0)
0050 IF HWND%<=0 THEN PRINT "Notepad not found!"; STOP
0060 LET WM_CLOSE=DEC($0010$),WPARAM%=0,LPARAM=0
0070 LET X=DLL("USER32.DLL","SendMessageA",HWND%,
0070:INT(WM_CLOSE),WPARAM%,LPARAM)

   
Inter-Task Communication The Version 4.10 DireXions example which follows illustrates inter-task communication. The program DLLS3 starts a second PVXWIN32session, finds its Window handle, sends CTL values 101 through 103, defines an atom (pointing to a string variable in a global string table) and passes the atom reference to the second session. Then it waits for the second session to terminate.

0010 ! DLLS3 - Inter-task communication - Send CTLs & a string
0020 MAX_COL=MXC(0)+1,MAX_ROW=MXL(0)+1
0030 PRINT 'SHOW'(-1),'DIALOGUE'(0,0,MAX_COL,INT(MAX_ROW/2)-1,"Inter-task com
0030:munication",'MODE'($000F$)+'CS'),
0040 IF ARG(1,ERR=*NEXT)="Receiver" THEN GOTO RECEIVER
1000 ! ^1000
1010 LOOP=0
1100 ! ^100 - Find Receiver & start if necessary
1110 IF LOOP++>1 THEN PRINT "Cannot start/find the Receiver!"; STOP
1120 HWND%=DLL("USER32.DLL","FindWindowA",0,"PVXWIN32 - Receiver"+$00$)
1130 IF HWND%>0 THEN GOTO 1200
1140 INVOKE ARG(0)+" "+PGN+" -ARG Receiver"
1150 WAIT 1
1160 GOTO 1100
1200 ! ^100 - Send CTL 101 to 103 to Receiver
1210 WM_USER=DEC($0400$),WPARAM%=0,LPARAM=0
1220 FOR WPARAM%=101 TO 103
1230 PRINT "Sending CTL value of",WPARAM%," to Receiver"
1240 X=DLL("USER32.DLL","SendMessageA",HWND%,INT(WM_USER),WPARAM%,LPARAM)
1250 NEXT
1300 ! ^100 - Send CTL 104 & the address of a String
1310 WM_USER=DEC($0400$),WPARAM%=104,LPARAM=0
1320 ATOM$="Message to Send ",LPARAM=DLL("KERNEL32.DLL","GlobalAddAtomA",ATOM$
1320:+$00$)
1330 PRINT " Sending CTL Value ",WPARAM%,"to Receiver with message:",'BR',ATOM
1330:$,'ER'
1340 X=DLL("USER32.DLL","SendMessageA",HWND%,INT(WM_USER),WPARAM%,LPARAM)
2000 ! ^1000
2010 LOOP=0; PRINT "Waiting for Receiver to shutdown",
2020 HWND%=DLL("USER32.DLL","FindWindowA",0,"PVXWIN32 - Receiver"+$00$)
2030 IF HWND%<=0 THEN GOTO 2100
2040 PRINT ".",; IF LOOP++<30 THEN WAIT 1; GOTO 2020
2100 ! ^100
2110 X=DLL("KERNEL32.DLL","GlobalDeleteAtom")
2120 PRINT 'DROP'(-1),'SHOW'(2),
2130 STOP
3000 ! ^1000 - Receive CTL values from Sender
3010 RECEIVER:
3020 PRINT 'CAPTION'("PVXWIN32 - Receiver"),'MOVE'(0,INT(MAX_ROW/2)+1),
3030 INPUT "Press F4 when finished ",*; PRINT @(0),'BR',"Received CTL =",CTL,'E
3030:R','CL'
3040 IF CTL=4 THEN GOTO 3200
3050 IF CTL<>104 THEN GOTO 3030
3060 ATOM=TCB(81) ! Atom identifier
3070 DIM ATOM$(512)
3080 X=DLL("KERNEL32.DLL","GlobalGetAtomNameA",ATOM,ATOM$,LEN(ATOM$))
3090 X=DLL("KERNEL32.DLL","GlobalDeleteAtom") ! Release Atom
3100 X=POS($00$=ATOM$); IF X THEN ATOM$=ATOM$(1,X-1)
3110 PRINT "Received: ",'BR',ATOM$,'ER'
3120 GOTO 3030
3200 ! ^100
3210 STOP