The Windows API provides a rich set of functionalities for applications. The entire Windows API is directly accessible from D. Here, we'll demonstrate this by popping up an information message box and a file chooser dialog box using the standard Win32 API functions.
First, make sure you have correctly installed the DMD compiler for Windows. If you want to build 64-bit applications, you must download and install Visual Studio (any version that supports C++ development, including Express) first because dmd
on 64-bit Windows uses the Microsoft linker and libraries for better cross-language compatibility.
You'll also want to create or download the Windows API bindings since the Windows bindings that come with dmd
are quite incomplete. You can create your own, as required, by copying and pasting the function and struct prototypes from MSDN.
If you are on 32 bit, you might also want to get the newer .lib
files from Microsoft and convert them to the OMF format that the 32-bit dmd uses. This often isn't necessary, but if you want to use features from Windows Vista and newer versions, it likely will be. To do this, first download the Windows SDK from http://www.microsoft.com/en-us/download/details.aspx?id=8279, and then get the Basic Utilities Package (BUP) from http://digitalmars.com/ (you can purchase it for $15). Use coffimplib
from the BUP on the .lib
files from the SDK to generate the OMF-format libraries for dmd
.
Let's call the Windows API functions by executing the following steps:
core.sys.windows.windows
.OPENFILENAME
structure and fill in the required fields.GetOpenFileName
to pop up the file dialog.MessageBox
function to give feedback to the user.comdlg32.lib
by adding it to the dmd
command line.The code is as follows:
import core.sys.windows.window; void main() { wchar[256] filenameBuffer; filenameBuffer[0] = 0; OPENFILENAMEW info; info.lStructSize = OPENFILENAMEW.sizeof; info.lpstrFilter = "Text Files *.txt ImageFiles *.png;*.jpg "w.ptr; info.lpstrFile = filenameBuffer.ptr; info.nMaxFile = filenameBuffer.length; if(GetOpenFileNameW(&info)) { MessageBoxW(null, info.lpstrFile, "You picked"w.ptr, 0); } }
D understands the Windows calling convention. Calling any Windows function is possible by simply declaring the function prototype with extern(Windows)
.
Windows functions that deal with strings come in two variants: ASCII and Unicode. These are denoted by the suffix A
or W
on the function names. In C and some D bindings, a UNICODE
macro aliases the names to the appropriate suffix as needed. Here, we called the W
functions explicitly for maximum compatibility and demonstration purposes.
MSDN often references TCHAR
, TSTR
, and so on. Like with the function prototypes, the meaning of TCHAR
is different if you are using Unicode or ASCII macros. With ASCII, it should be char
in D, whereas with Unicode, it should be wchar
.
As D strings are Unicode, it is best to use the W
versions of functions (it will let you pass strings to the A
function, and it will work if the strings are all ASCII; however, if they include any non-ASCII characters, the string will be corrupted.) D has built-in support for wide-character strings (UTF-16) that can be used on Windows. The UTF-16 character type is wchar
. An immutable array of wchar
types is also called wstring
, analogously to how arrays of UTF-8 characters are called string
literals. The wstring
literals are denoted with the w
suffix, for example, this is a wstring
literal, w
. The wstring
literals, like the string literals, are zero terminated. However, unlike string
literals, they do not automatically convert to pointers; so, to pass a wstring
literal to a Windows function, use the .ptr
property. To pass a non-literal string to a Windows function, use std.utf.toUTFz!(wchar*)(your_string)
. This works both for wstring
literals and UTF-8 strings—it appends the zero, converting the format only if necessary.
The GetOpenFileName
uses a common pattern in Windows programming; it takes a struct, which knows its own size, as an argument. In C or C++, declaring these structs would typically be followed with a call to memset
or ZeroMemory
. This is not normally necessary in D because D, unlike C, initializes variables automatically. However, it is still important to initialize any static char
/wchar
array or float
members since D initializes them by default to invalid values instead of zero (it does this in such a way that the use of an uninitialized value triggers an error as soon as possible). This is why we set filenameBuffer[0] = 0
to ensure it is properly terminated as an empty string. Pointers to strings and floats are by default initialized to null
and may not have to be explicitly set.
core.sys.windows.windows
can be found at http://dsource.org/projects/bindings/wiki/WindowsApi18.220.187.223