WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

DllCall Information

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

More DllCall Info

Keywords: DllCall third party DLL

Check out the following article created by a user: http://www.p6c.com/TechnicalArticles/WBHowTo_Call_Windows_API_Functions.html


The DllCall function is unlike all other WIL functions. It is designed to allow sophisticated users to either write their own extensions to the WIL language (using the Windows SDK), to call third party Dlls, or to access Windows APIs directly.

In order to use this function properly, a little background is necessary. There are a number of very specific reasons one would want to call an external DLL to process some code. Examples may include calling Dlls to interface with certain hardware devices, to perform special compute-intensive algorithms, or to perform a series of functions not possible using the WIL language. In many cases, the user has no control over the DLLs to be called, so that the WIL DllCall statement must be able to call a wide variety of Dlls, to be able to pass an assortment of different parameter types, and to be able to process a number of different return values.

For this reason, the DllCall syntax is complicated and initially confusing. Use of the DllCall requires detailed understanding of Windows programming and complete documentation for the Dll and the Dll entry point being called. If you need tech support help with the DllCall statement, you must send us relevant documentation before calling for help.

To call an external Dll, the user must first determine the following information:


	1)	Name of the DLL.
	2)	Entry point name of the desired function within the Dll.
	3)	Type of the return value from the Dll.
	4)	Number of passed parameters the Entry point requires.
	5)	Type of each of the passed parameters.
WIL supports the following types of return types from a Dll:

	1)	word		16 bit integer
	2)	long		32 bit integer
	3)	lpstr		32 bit pointer to a string
	4)	void		no return value
WIL supports the following parameter types to pass data to a Dll:

1)	word	16 bit integer
2)	long	32 bit integer
3)	lpstr	32 bit pointer to a string
4)	lpnull	32 bit NULL pointer
5)	lpbinary	32 bit pointer to a memory block allocated with the BinaryAlloc function.  See section on Binary Operations.
Note: If lpbinary is used to pass information from a Dll back to a WIL script via a DllCall, then be sure to use BinaryEodSet to manually set the end of data point so that the other binary functions can reference the returned data.

The DllCall parameters are as follows:



Syntax:

DllCall(dllname, returntype:epname, paramtype:parameter [paramtype:parameter ...] )

The first parameter can either be a dllname or a dllhandle. A dllname may be used for "oneshot" types of calls where a single call to the Dll is all that is required, or when each call to the Dll is independent of all other calls. A dllhandle is used for multiple calls to a Dll, where the calls are interrelated -- perhaps the first call to initialize the Dll, other calls use it, and a final call to terminate processing. In such cases the Dll must first be loaded with the DllLoad function, and freed with the DllFree function. The dllname parameter must be one of the following:

(1) Simply the filename of the Dll that contains the desired entry point name. A single Dll may contain one to many separate entry points. Each entry point may have its own unique return type and parameter list; or (2) dllhandle: A handle do a Dll obtained from the DllLoad function.

The second parameter consists of two parts: the first part is the return type of the entry point desired, followed by a colon (:), and the second part is the entry point name itself.

Note: Only use the lpstr return type for text strings. Even though some other documentation might suggest using a lpstr as a return type for its structures, don't. Use long instead.

For each parameter the entry point requires, an additional parameter is added to the DllCall parameter list. If the entry point has no parameters, then the DllCall function uses only the first and second parameters as described above.

Additional: For each parameter that the entry point in the Dll requires, additional DllCall parameters are added. Each additional parameter consists of two parts, the first part is the parameter type of the required parameter, followed by a colon (:), and the second part is the parameter itself.

Example:


; DllCall example.  
; This example calls the CharUpperA API in the Windows User module.
; The CharUpperA function requires a 32 bit pointer to a string (lpstr).
; It converts the string to uppercase and passes back a 32 bit
; pointer (also lpstr)  to the uppercased string.
; The CharUpperA function is found in the Windows USER32.Dll.
; Note: Dll Name, being a normal string is in quotes.
;       Entry point name, also being a string, is also in quotes
;       Parameter a0, being a normal variable is not in quotes.

a0="Hello Dolly"
dllname=strcat(dirwindows(1),"USER32.DLL")
a1=DllCall(dllname, lpstr:"CharUpperA", lpstr:a0)
Message(a0,a1)
A number of third party DLL's like to write to an address passed in a DLLCall. Oftentimes the third-party documentation uses LPSTR's to do this (a LPSTR is a null-terminated string). WinBatch does not detect if a LPSTR was modified, and consequently does not capture the changed data. In order to do this type of operation, you must use a Binary buffer. In addition, you must use the BinaryEODSet function to alter the BinaryBuffer EOD point.

Example:


DaBinBuf=BinaryAllocate(1024)
BinaryEODSet(DaBinBuf,1024)
flag = DllCall("party3.dll",word:"DaEntryPoint",lpBinary:DaBinBuf)
if flag == 1
    NewData=BinaryPeekStr(DaBinBuf,0,1024)
else
    NewData=""
endif
Message("The New Data is", NewData)
DLLCall will only call standard Windows API functions designed to be called via such a process. None of the C runtime functions, for example, can be called with DLLCall. Only the Windows API functions.

Making a call to a DLL is the same as making a call to an EXE, except the entry point is different. All API functions live inside the DLL. For example, in the KERNEL32.DLL, there are 1000+ functions. DLLs are basically a library of subroutines.

What you need to get is the pointer to, and address of, the function in that DLL that you want to call.

There are primarily two different type of "calling conventions" which specify how an area of memory, "the stack", is to be set up for a call. They are:

  1. The "FAR PASCAL" or "WINDOWS API" or "STDAPI" method which nearly all windows DLLs use.

  2. The "C" method that most of the C runtime uses.
The DLLCall statement can only do the first one (#1):

You can DllCall: USER32.DLL GUI32.DLL KERNEL32.DLL and practically all DLL's that come with Windows or Windows programs, with the exception of the C runtime DLL's.

Getting the name of the DLL is fairly easy. Knowing what to pass them is the tricky part and tends to require massive documentation. It a little like a combination lock. It is unlikely that you can get in without knowing the combination.

16-bit versus 32-bit DllCalls

In 16 bit versions of Windows, functions that are called using DllCall must use the _pascal calling convention (declared as FAR PASCAL or WINAPI).

In 32 bit versions of Windows, they must use the __stdcall calling convention (declared as WINAPI). Otherwise, DllCall will return a "Bad Entrypoint" or "Bad Parameter List" error message, even though you have specified the correct function name and parameter types; this would likely indicate that the function is using an unsupported calling convention.

Question:

How do I pass a variable to a DLL by reference?

Here's my DllCall to ATMAPI.DLL details:

I'm trying assign a string value to a string variable, inside a DLL. After the DLL is called, the string should contain the contents of a screen.


***********************************************************
cScreen = BINARYALLOC( 1920 )
; - Already tried using cScreen = STRFILL( " ", 1920 ) - 


GOSUB LOGINTOTSO
RETURN

:LOGINTOTSO
hWnd = DLLHWND( "" )
hDll = DLLLOAD( "ATMAPI.DLL" )
xResult = DLLCALL( hDll, word:"ATMRESETSYSTEM", word:hWnd )
xResult = DLLCALL( hDll, word:"ATMSETPARAMETER", word:hWnd, word:3, word:2, lpstr:"@" )

xResult = DLLCALL( hDll, word:"ATMCONNECTSESSION", word:hWnd, lpstr:"A" )

GOSUB ISCMDSHELL
...
...
RETURN

; - Here's the line with the problem.
xResult = DLLCALL( hDll, word:"ATMGETSTRING", word:hWnd, word:0, word:0, lpstr:cScreen,
word:1921 )
...
...
RETURN
***********************************************************
These are the parameters:

hWnd Handle to app.
Row Starting row position of string to 
copy from host session.

Col Starting column position ""
Buffer String provided by the caller 
used as destination when copying a string from the
target session.

BufferLength An integer defining the number 
of characters to copy plus one extra character.
The function returns a 65534, which I believe is equivalent to a -2. This represents an invalid parameter. The problem, obviously, is that I don't know how to pass a variable to a DLL by reference. Is there a way to do this?

Answer:

  1. Use LPBINARY to pass binary buffer.

  2. Add BinaryEODSet(cScreen,1920) after BinaryAlloc.

  3. Is this a 32 bit DLL (are you using 32 bit WinBatch) If so, change all WORD: to LONG:

    Here's the line with the problem:

    
    xResult = DLLCALL( hDll, word:"ATMGETSTRING", word:hWnd, word:0,word:0, LPBINARY:cScreen, word:1921 )
    

Article ID:   W12863
Filename:   DllCall additional info.txt
File Created: 2004:09:14:10:31:30
Last Updated: 2004:09:14:10:31:30