25 April 2021

The gfawinx library

It’s been a while since GFA Software Technologies GmbH released GFA-BASIC 32. At that time (2001) it could not be foreseen how Windows - and PC-use in general - would evolve. Consequently, GB32 misses runtime functions to coop with the latest Windows developments and the introduction of better hardware. To fill that gap gfawinx.lg32 comes with a set of commands and functions to access and use the newer features. The name gfawinx stands for “GFA-BASIC 32 expansion” library, gfawinx contains several categories. When you load the gfawinx.g32 code file in the editor the Procs sidebar shows the current groups:

Screenshot 2021-04-23 112115

Download latest version
Previous gfawinx versions – until and including the version of 16 Feb 2021 - contain an error that may lead to problems when loading the library into a program. If you are planning to use gfawinx make sure you have a version later than 16 Feb 2021. Please check the date of the file in the Include directory.

Download a newer version if necessary here and unzip the file to the Include directory.

What’s the problem? One of the library functions uses a DLL function declared using the Declare command. However, when a lg32 library uses a declared function it must also export that DLL function using an $Export Decl command.The program that is importing the library must be able to add that declared function to the program’s table of DLL functions. Gfawinx used a declared function, but did not export it. The current version of gfawinx doesn’t use Declare anymore, but uses GetProcAddress() to obtain the function’s address and calls it using StdCall()(). Something to remember when you are developing your own libraries.

The String functions
The Wide and Ansi functions are mainly used with Windows API functions that take a UNICODE string. An example of both functions was discussed in Task Dialog as a replacement for Alert, which demonstrates the use of a Windows API taking UNICODE strings as parameters. This blog post also contained an example of StrToArr, which is used to convert a string, containing sub-strings separated with any character, to an array. StrToArr is an addition or replacement for the Array ar$() = $ command.
The Replace string function is a VB(A) compatible function, much easier to use then the Split command of GB32. The Replace function is optimized for speed and takes the string arguments by reference if the arguments are string variables. Only in case a string literal is passed GB32 will pass the string parameter by value (making a copy first and then pass that copy). This is achieved by making Replace a FunctionVar rather than a Function.

FunctionVar and Sub anonymous String and Variant parameters
When a parameter of a FunctionVar or Sub does not explicitly specify ByVal or ByRef the parameter is anonymous. In this case the compiler decides how to pass the parameter to the FunnctionVar or Sub. If possible, the compiler generates code to pass the String or Variant by reference, otherwise the parameter is passed by value. To be able to pass by reference the caller must pass a variable; a literal is always copied to a temporary locally variable which is then passed by reference. Note that a ByVal parameter always gets a copy of the data that is passed, which requires the compiler to insert additional code to create a copy first. Passing by reference is almost always faster. Using anonymous parameters can speed up the execution of a procedure or function considerably.

An example that shows the difference:

$Library "gfawinx"
Dim src$, find$, new$, result$
result$ = Replace(src$, find$, new$)     ' variables, fast
result$ = Replace("GFA-BASIC", "A", "x") ' literals, slower

ErrStr is a convenient function to obtain the relevant Err-properties as a string. Usually, ErrStr will be used in a Try/Catch handler to present information about the trapped error to the user. The problem is to decide which Err-properties contain the relevant error information. ErrStr examines the properties and only returns the properties that contain the actual error information. ErrStr takes one string parameter that is added to the error information. This parameter is perfectly suited for the current proc-name, which is easily inserted using the keyboard short cut App+P. Here App+P inserts “main” into text:

$Library "gfawinx"Screenshot 2021-04-23 131437
  Error 3
  MsgBox ErrStr("main")

The program produces the following message box:

The $ = HexDump(addr%, size%) string function returns a memory dump starting from the specified address addr% and with a length of size%. The result of this debugging aid can easily be displayed in the Debug Output window or a MsgBox.

The Windows functions
Here we find the Windows API and form-windows related commands and functions. Let’s first examine the WinVer function which returns the Windows OS version. In the latest version of gfawinx it returns the value obtained using the RtlGetVersion() API in a hexadecimal format $XXYY, where XX represents the major version and YY the minor version:

$Library "gfawinx"
Print Hex(WinVer())  // A00 (Win 10)

There is a lot of information to be found on how to obtain the Windows version. The method used by WinVer() does not depend on the manifest file as other methods do and should be safe to use with future releases of Windows. (Note - only the latest version of gfawinx - later than 16 Feb 2021- contains this method.)

GetWorkArea is a useful command when using multiple monitors where the Screen.Work* properties don’t work. GetWorkArea returns the work area of the monitor containing the largest area of a given window.
GetProcAddr returns the address of a function from a specified DLL. It works a little different than the GetProcAddress() API, because it first checks if the required DLL is already loaded.
The GetClientSize command returns the size of the client area, useful if _X and _Y are not available (in API windows).
ModifyStyle and ModifyExStyle make it easy to change the windows Style or ExStyle on the fly. They allow to both set and remove a windows-style simultaneously.
The Assoc() function returns system information associated with files, extensions or Prog IDs. For instance to obtain the full path of the default application that is associated with the .txt extension use:

$Library "gfawinx"
Print Assoc(".txt") // full path of default app

SaveFormPos and LoadFormPos save and load the form’s position respectively. For single monitor apps these are simple functions to store and retrieve the form’s current position in and from the registry. They are especially useful when used with multiple displays and DPI-aware applications. For detailed information see the help file.
MemStat is is a helper function to obtain memory statistics. If the argument is omitted (or is 0) it returns the memory used by the application. It is possible to trap a possible memory leak by using MemStat() when the program starts and compare the returned values at each start of the program.

The DPI-related functions
When you want to write DPI-aware applications these helper functions will be very useful. For more information on writing DPI-aware programs please see the English CHM helpfile: in the Contents section see Creating an application. Programming DPI aware programs is beyond the scope of this blog post. The gfawinx library provides the following functions.

WinDpi returns the DPI of the display for a window or form.
DpiAwareness set the DPI mode for the program.
ScaleToDpi(Sng) helps to scale coordinates.
ScaleXYWHToDpi scales ScaleLeft, ScaleTop, ScaleWidth, and ScaleHeight to a form's DPI.

The TimerQ function
The TimerQ function creates a high-resolution timer wrapped in a (minimal) COM object. This is the gfawinx implementation of the discussion in the blog High Resolution Timer . By using a COM object for a resource it can be guaranteed that the resource is freed when the program ends – either normally or through a runtime error.

The gfawinx library provides functions and commands that are not included in the GB32 runtime. The commands and functions are displayed in the GB32 syntax color for statements and GB32 functions. The procedures that implement the additions are optimized for speed, when possible the procedures are Naked. It is recommended that you – sometime - take a look at the code, it contains comments on implementation details you might find interesting. The library will grow over time when more ‘missing’ features will be added.