Accessing Windows API
API is an abbreviation for application programming interface. This means it is a way to access another app, a web service, an OS, a library etc. from your code. It does not specify how to do this: APIs can be based on HTTPRequests (e.g. web services), exchanging text files, window messages, DLLs (dynamic link libraries), which will be covered in this chapter, or COM (which will be covered later). So the way we’re looking at here does of course not work for all APIs.
The way we look at here does not only work for Windows, but for a lot of other code packaged in a DLL. Custom Gui controls often use this. But it is important to know you can’t even cover all of them: the DLLs must be native code (e.g. not a .NET library), and it must be organized in functions (not classes).
Using the Windows built-in
As you know, AutoHotkey has the
MsgBox command. So actually theres no need for calling the Windows API function most of the time. But we’re doing so because it’s a good example.
Note: This is, of course, Windows-only code. So it will not work for IronAHK users on other systems.
First, we look on the msdn page for the MessageBox function we’re going to call. It tells us what it is supposed to do:
Displays a modal dialog box that contains a system icon, a set of buttons, and a brief application-specific message, such as status or error information. The message box returns an integer value that indicates which button the user clicked.
Then we see a Syntax box:
int WINAPI MessageBox( __in_opt HWND hWnd, __in_opt LPCTSTR lpText, __in_opt LPCTSTR lpCaption, __in UINT uType );
We can’t use this as it’s not AutoHotkey code. In AutoHotkey, to call a function in a DLL, we use the built-in
DllCall() function. As the manual tells us, it’s first parameter is the DLL file and the function to call.
In case of the MessageBox function, we needn’t specify the DLL file:
DllFile may be omitted when calling a function that resides in User32.dll, Kernel32.dll, ComCtl32.dll, or Gdi32.dll.
And happily MessageBox is in User32.dll as msdn tells us.
So we have the following code:
1 DllCall("MessageBox", ...) ; yet to be done
The rest of the parameters is a list of parameter types and values to be passed to the function. We look at the parameter descriptions on msdn now:
hWnd [in, optional]
A handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window.
Now we need to take the parameter type from this. This is not “HWND”, as AutoHotkey does not “support” this type. We’ll later take a closer look on type mappings, for now believe me the AutoHotkey type is
UInt for AutoHotkey classic / IronAHK users). As in our example, we don’t need any parent window, we’ll just pass 0 to this.
The next two parameters are as easy: their type
LPCTSTR maps to the AutoHotkey
str type. As values, we pass the text we want the box to show:
lpText [in, optional]
The message to be displayed. If the string consists of more than one line, you can separate the lines using a carriage return and/or linefeed character between each line.
lpCaption [in, optional]
The dialog box title. If this parameter is NULL, the default title is Error.
Now our code is as follows:
1 ; AutoHotkey classic and IronAHK 2 DllCall("MessageBox", "UInt", 0, "Str", "This is my first DllCall()!", "Str", "The caption", "UInt", 0)
1 ; AutoHotkey_L and similarly newer versions 2 DllCall("MessageBox", "UPtr", 0, "Str", "This is my first DllCall()!", "Str", "The caption", "UInt", 0)
For the last parameter, we just passed 0, but now we will have a closer look at it:
The contents and behavior of the dialog box. This parameter can be a combination of flags from the following groups of flags.
This is followed by a bunch of flag lists including explanations. We will add “OK” and “Cancel” buttons to our box, an error icon, and we’ll make it topmost:
1 ; any AutoHotkey version 2 3 ; the constants need to be defined in AutoHotkey first: 4 MB_OKCANCEL := 0x00000001 ; remove the trailing L from the value 5 MB_ICONERROR := 0x00000010 6 MB_TOPMOST := 0x00040000 7 8 flags := MB_OKCANCEL | MB_ICONERROR | MB_TOPMOST ; combine the flags. 9 ; This will be explained in detail in the chapter "Working with bits". 10 11 ptr := A_PtrSize ? "UPtr" : "UInt" ; if AHK_L or similar: use "UPtr", else "UInt" 12 result := DllCall("MessageBox", ptr, 0, "Str", "This is my first DllCall()!", "Str", "The caption", "UInt", flags)
One thing we didn’t yet look at is the return value. In the example above, we saved it in the variable “result”. Msdn tells us that we receive an integer and what each integer means. For example, we could check if the user cancelled:
1 ; any AutoHotkey version 2 IDCANCEL := 2 ; define the constant as pointed out on msdn 3 if (result == IDCANCEL) 4 MsgBox You canceled.
Rarely, DLLs may export variables in addition to functions; for example, the Raydium Game Engine DLL. Although it is not possible to retrieve or store values to this variable directly using DllCall(), it is possible to use the GetProcAddress() WinAPI function to do so:
1 ; any AutoHotkey version 2 3 ;compatibility types 4 UPtr := A_PtrSize ? "UPtr" : "UInt" 5 AStr := A_IsUnicode ? "AStr" : "Str" 6 7 ;load the library that contains the exported variable 8 hModule := DllCall("LoadLibrary","Str","Raydium.dll",UPtr) 9 10 ;obtain the address of the variable "raydium_joy_x" 11 pJoystickX := DllCall("GetProcAddress",UPtr,hModule,AStr,"raydium_joy_x",UPtr) 12 13 ;retrieve a float value from the address 14 JoyStickX := NumGet(pJoystickX + 0,0,"Float") 15 MsgBox, The joystick position in the x-axis is currently %JoystickX%. 16 17 ;store a float value in the memory location pointed to by the address 18 NumPut(0.8,pJoystickX + 0,0,"Float") ;store 0.8 as the value