Logo

Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.

Declare-DLL

This command offers a very cool method for integrating commands from external DLLs directly into Visual FoxPro.

Usage

DECLARE [ SHORT | INTEGER | SINGLE | DOUBLE |
          LONG | STRING | OBJECT ]
        APIFunctionName IN DLLName [ AS YourFunctionName ]
        [ SHORT | INTEGER | SINGLE | DOUBLE | LONG | STRING
          [ @ ] [ Param1Name ]
        [, SHORT | INTEGER | SINGLE | DOUBLE | LONG | STRING
          [ @ ] [ Param2Name ]
        [, ... ]
        [, SHORT | INTEGER | SINGLE | DOUBLE | LONG | STRING
          [ @ ] [ ParamnName ] ] ] ]

Parameter

Value

Meaning

APIFunctionName

Name

The case-sensitive name of the function within the DLL.

DLLName

Name

The DLL within which the function is located. If the function is one of the standard Win32 functions, you may specify WIN32API instead of needing to determine the version-correct name for the DLL.

YourFunctionName

Name

Optionally, you may alias the function to a name more easily remembered or more in keeping with your naming standards. Another reason for aliasing is that the function name conflicts with another function in your environment.

@

Literal

Specifies that this parameter is passed by reference and not by value, the default.

ParamnName

Name

Optional parameter name—we strongly suggest you always use this as a bit of in-line documentation: What is this value and why is it here?

Dynamic Link Libraries (DLLs for short) are the Windows equivalent of procedure files—collections of useful functions compiled into a single file. It is through DLLs that we can access most of the functionality available to programmers within the Windows Application Programming Interface (commonly referred to as the Win32 API), as well as access functions provided by third-party vendors. Before you can use a function in a DLL, you must tell FoxPro about it—providing the function’s name, the library that contains it and a list of the parameter types it expects.

Note that the VFP documentation is a bit misleading in not showing the parameter name as an optional element, but we think it should always be added anyway.

This is the preferred method of accessing DLLs, and we recommend it over using FoxTools or FLL manipulation whenever possible, just because it involves fewer intermediaries, and hence is less likely to go wrong. However, the DECLARE method is only available for 32-bit DLLs; older DLLs will have to settle for either the RegFn() function built into FoxTools, or a 32-bit FLL wrapper.

Unlike almost everything in Visual FoxPro, the mechanism for registering API calls is case-sensitive. Make sure you type the name as it appears in your documentation. If you get the message "Cannot find entry point BlahBlahBlah in the DLL," check your use of case. This isn't VFP's fault; API functions are case-sensitive no matter where they're used.

A common complaint we hear is that VFP is limited in the types of parameters it can pass and is therefore unable to use DLL functions that require pointers or structures to be passed to them. In a great many cases, this is untrue. Most functions that require a pointer to a string will be just as happy if passed the string itself. Rather than declaring the function as requiring a DOUBLE to point to the string, modify your declaration to STRING and the function is likely to work fine. As for structures, it is true that Visual FoxPro does not support the idea of structures internally, as a memory type, but structures can be created programmatically and passed to the functions that require them. The second example below illustrates the technique required. If you don’t want to puzzle out what you need to do for a particular structure, take a look at the Struct library placed in the public domain by our friend, Christof Lange. It lets you work with structures as objects and handles all the messy conversion details internally.

There is a 32-bit version of RegFn(), cleverly called RegFn32(), built into FoxTools as well. We haven’t run into a case where using that function is preferable over the DECLARE method.

Example

* Display the Windows System Directory:
DECLARE INTEGER GetSystemDirectory ;
        in Win32api ;
        STRING @cWinDir, ;
        INTEGER nWinDirLength
lcWinDir = SPACE(255)
nWinDirLength = GetSystemDirectory(@lcWinDir,len(lcWinDir))
? LEFT(lcWindir,nWinDirLength)

* This excerpt from a routine uses WinAPI calls
* to create a memory space ("heap"), and copy
* a string to it, then pass a pointer to that
* memory location to a function.
Declare Integer StartDoc in Win32Api ;
       Integer, String
Declare Integer HeapCreate in Win32Api ;
       Integer, Integer, Integer
Declare Integer HeapAlloc in Win32Api ;
       Integer, Integer, Integer
Declare lstrcpy in Win32Api Integer, String

* The GetVersionEx API function fills a structure with version
* information. Since VFP can't create structures, we'll use
* a string instead. Here are the official declarations for this
* function and the structure it uses:

*!* Public Declare Function GetVersionEx Lib "kernel32" ;
*!*     Alias "GetVersionExA" ;
*!*     (lpVersionInformation As OSVERSIONINFO) As Long

*!* Public Type OSVERSIONINFO
*!*     dwOSVersionInfoSize As Long
*!*     dwMajorVersion As Long
*!*     dwMinorVersion As Long
*!*     dwBuildNumber As Long
*!*     dwPlatformId As Long
*!*     szCSDVersion As String * 128
*!* End Type

declare integer GetVersionEx in Win32API ;
    string @lpVersionInformation
lcStruct       = chr(148) + replicate(chr(0), 147)
  && Initialize the structure as the length of the entire
  && structure followed by nulls.
lnResult       = GetVersionEx(@lcStruct)
lnMajorVersion = Hex2Decimal(substr(lcStruct, 5, 4))
lnMinorVersion = Hex2Decimal(substr(lcStruct, 9, 4))
? lnMajorVersion, lnMinorVersion
function Hex2Decimal
lparameters tcValue
local lnDecimal, ;
    lnLen, ;
    lnI
lnDecimal = 0
lnLen     = len(tcValue)
for lnI = 1 to lnLen
    lnDecimal = lnDecimal + ;
        asc(substr(tcValue, lnI, 1)) * 256 ^ (lnI - 1)
next lnI
return lnDecimal

See Also

FoxTools, Set Library