WinApi Miscellaneous
From TeamDeveloperWiki
This page covers miscellaneous Windows API tips & tricks.
Where to get WinAPI declarations, constant values and structure layouts
The common place to get info for WinAPI is Microsoft's MSDN library MSDN library. There you will find all info concerning WinAPI programming.
What is missing there are the actual values of WinAPI constants.
You might find them already defined in the WinApi32.apl which can be downloaded from the Wiki main page.
You can also use these very handy tools, named ApiViewer and ApiGuide.
With this tools you can search all WinApi constants.
You can download it here : ApiViewer and here ApiGuide.
The constants found there are in VB or C syntax. You will have to define the constants in TD by changing &H to 0x.
For instance : &H202 -> 0x202
How to detect memory or GDI leaks
If you use Windows API functions to draw custom stuff on your GUI's for example it is very important to release or destroy created handles.
Without this, the resources can diminish up until severe (painting) errors occur.
An easy way to detect those memory leaks is using tools to monitor the amount of opened handles.
Great recommendations (free ones) are:
Process Explorer.
GDIView.
How to determine a window exists
Having a window handle, use the WinApi function IsWindow to determine if it is present in the system and corresponds to a valid window.
This is the declaration
Library name: USER32.DLL
Function: IsWindow
Export Ordinal: 0
Returns
Boolean: BOOL
Parameters
Window Handle: HWND
hWndMain = SalCreateWindow( frmMain, hWndNULL )
...
If IsWindow( hWndMain )
! Window exists
Else
! Does not exist
Beware : this function checks if the window handle is valid, but it does not mean the window handle is the one you have created earlier. Window handles are reused in Windows, so the window handle could correspond to another window.
How to fill strings with a specific character
To get high performance while filling a string with a specific character, use RtlFillMemory.
With large data, this function is significantly faster than any SAL implementation.
This is the declaration
Library name: KERNEL32.DLL
Function: RtlFillMemory
Export Ordinal: 0
Returns
Parameters
Receive String: LPVOID
Number: DWORD
Number: BYTE
The next sample creates a very large string variable and is completely filled with spaces
! Create a string buffer size of 512K Call SalStrSetBufferLength( sData, 1024 * 512 ) ! Now fill the string with spaces (ASCII value 32) Call RtlFillMemory( sData, 1024 * 512, 32 )
How to disable Windows themes on your application
Applications build with Team Developer (prior to version 5.1) are not 100% compatible with the Windows themes (available from Win XP).
Some GUI objects are painted using the selected theme and some are not. This could look ugly and not very consistent.
In some cases it could be better to force the application to disable themes all the way.
Beware : only the special painting of objects are disabled, not the sizes and colors of the GUI objects.
First, use the following declaration of SetThemeAppProperties
Library name: UxTheme.dll
Function: SetThemeAppProperties
Export Ordinal: 0
Returns
Parameters
Number: DWORD
Now call the function at the start of the application
Application Actions
On SAM_AppStartup
Call SetThemeAppProperties( 0 )
This will disable all custom theme painting by Windows within the application.
Beware that this approach disables an application from running on OS < WinXP due to the absence of uxtheme.dll on these OS. Perhaps it is an option to have a faked uxtheme.dll to be installed with the application.
Another way is to determine which Windows OS the application is running on and based on the OS call the API function or not.
How to format a number of bytes to a formatted string
The WinApi function StrFormatByteSize can be used to display
a formatted string presenting a number of bytes as bytes, kilobytes, megabytes and gigabytes.
532 -> 532 bytes
1340 -> 1.3KB
23506 -> 23.5KB
2400016 -> 2.4MB
2400000000 -> 2.4GB
This is the declaration
Library name: SHLSWAPI.DLL
Function: StrFormatByteSizeA
Export Ordinal: 0
Returns
String: LPSTR
Parameters
Number: DWORD
Receive String: LPSTR
Number: UINT
Here a sample to display a number of bytes
Call SalStrSetBufferLength( sBuf, 1024 ) Call StrFormatByteSizeA( 23506, sBuf, 1024 ) ! ! sBuf = "22,9 kB"
Here you can download a sample:
How to format a number of milliseconds to a formatted string
The WinApi function StrFromTimeIntervalA can be used to display
a formatted string presenting a number of milliseconds as seconds, minutes and hours.
It will be formatted against the current locale. For instance English will be "hour", Dutch will be "uur".
34000 -> 34 sec 74000 -> 1 min 14 sec
This is the declaration
Library name: SHLSWAPI.DLL
Function: StrFromTimeIntervalA
Export Ordinal: 0
Returns
Number: INT
Parameters
Receive String: LPSTR
Number: UINT
Number: DWORD
Number: INT
Here a sample to display a number of milliseconds
Call SalStrSetBufferLength( sBuf, 1024 ) Call StrFromTimeIntervalA( sBuf, 1024, 74000, 3 ) ! ! sBuf = "1 min 14 sec"
Here you can download a sample:
How to get the current Windows user
The WinApi function GetUserName can be used to get the current Windows logon user.
(Implemented as GetUserNameW (Unicode) and GetUserNameA (ANSI)).
This is the declaration
Library name: ADVAPI32.DLL
Function: GetUserNameA
Export Ordinal: 0
Returns
Boolean: BOOL
Parameters
Receive String: LPSTR
Receive Number: LPDWORD
Here a sample
Function: GetWindowsUser
Returns
String:
Parameters
Local variables
String: sUser
Number: nLen
Actions
! Set nLen to the correct length (max size of the username + 1)
Set nLen = 64
Call SalStrSetBufferLength( sUser, nLen )
Call GetUserNameA( sUser, nLen )
Return sUser
Here you can download a sample:
Useful path functions
We all have done file and path handling in one way or another, putting backslashes to folders or stripping extensions for example.
Windows API gives us quite nice prebuild functionality, so that could save us reinventing the wheel in SAL.
Below a list of handy functions. They are all put together in two TD libraries for both ANSI and UNICODE.
(UNICODE version is for TD5.x and higher, the ANSI version is for pre TD 5.x versions).
You can download the library and a small test application from the sample vault.
Here -> WIKI_PathFunctions.zip
Click on the function names to get more information and requirements.
| PathAddBackslash | Adds a backslash to the end of a path string when not present This results in correct syntax for a path. | INPUT: C:\dir_name\dir_name\file_name OUTPUT: C:\dir_name\dir_name\file_name\ |
| PathAddExtension | Adds a file extension to a path string If there is already a file extension present, no extension will be added. | INPUT: C:\dir_name\test .txt OUTPUT: C:\dir_name\test.txt |
| PathAppend | Appends one path to the end of another This function automatically inserts a backslash between the two strings. | INPUT: name_1\name_2 name_3 OUTPUT: name_1\name_2\name_3 |
| PathCanonicalize | Removes elements of a file path according to special strings inserted into that path This function allows the user to specify what to remove from a path by inserting special character sequences into the path. | INPUT: A:\name_1\.\name_2\..\name_3 OUTPUT: A:\name_1\name_3 |
| PathCommonPrefix | Compares two paths to determine if they share a common prefix A prefix is one of these types: "C:\\", ".", "..", "..\\". | INPUT: C:\win\desktop\temp.txt c:\win\tray\sample.txt OUTPUT: C:\win |
| PathCompactPathEx | Truncates a path to fit within a certain number of characters by replacing path components with ellipses The '/' separator will be used instead of '\' if the original string used it. | INPUT: "c:/program files/My SuperProgram/skins/sample.txt" Max length 30 characters OUTPUT: "c:/program files/.../sample.txt" |
| PathIsDirectoryEmpty | Determines whether a specified path is an empty directory "C:\" is considered a directory. | Obvious functionality ;) |
| PathIsNetworkPath | Determines whether a path string represents a network resource PathIsNetworkPath interprets the following two types of paths as network paths.
Note The function does not verify that the specified network resource exists, is currently accessible, or that the user has sufficient permissions to access it. | INPUT: "c:\" OUTPUT: FALSE -> no network drive INPUT: "\\Server\Folder" OUTPUT: TRUE -> a network drive |
| PathIsRelative | Searches a path and determines if it is relative | INPUT: "c:\Test.txt" OUTPUT: FALSE -> path is absolute INPUT: "Folder\Test.txt" OUTPUT: TRUE -> path is relative |
| PathIsRoot | Parses a path to determine if it is a directory root Returns TRUE for paths such as "\", "X:\", "\\server\share", or "\\server\". | INPUT: "c:\" OUTPUT: TRUE -> path contains a root INPUT: "Folder\Test.txt" OUTPUT: FALSE -> path does not contain a root |
| PathIsSameRoot | Compares two paths to determine if they have a common root component Returns TRUE if both strings have the same root component, or FALSE otherwise. | INPUT: C:\path1\one C:\path2\two OUTPUT: TRUE -> These both have the same root part |
| PathIsUNC | Determines if the string is a valid Universal Naming Convention (UNC) for a server and share path Returns TRUE if the string is a valid UNC path, or FALSE otherwise. | INPUT: \\path1\path2 OUTPUT: TRUE -> is a valid UNC INPUT: path1\path2 OUTPUT: FALSE -> is not a valid UNC |
| PathIsURL | Tests a given string to determine if it conforms to a valid URL format This function does not verify that the path points to an existing site—only that it has a valid URL format. | INPUT: http://tdwiki.daverabelink.net OUTPUT: TRUE -> is a valid URL INPUT: microsoft.com OUTPUT: FALSE -> is not a valid URL |
| PathQuoteSpaces | Searches a path for spaces. If spaces are found, the entire path is enclosed in quotation marks TRUE if spaces were found; otherwise, FALSE. | INPUT: c:\program files\MyApp\test.txt OUTPUT: "c:\program files\MyApp\test.txt" |
| PathRemoveArgs | Removes any arguments from a given path This function should not be used on generic command path templates (from users or the registry), but rather it should be used only on templates that the application knows to be well formed. | INPUT: MyApp.exe Arg1 Arg2 Arg3 OUTPUT: MyApp.exe |
| PathRemoveBackslash | Removes the trailing backslash from a given path when present Eh, the opposite of PathAddBackslash. | INPUT: c:\Folder1\Folder2\ OUTPUT: c:\Folder1\Folder2 |
| PathRemoveExtension | Removes the file extension from a path, if one is present | INPUT: c:\Test.txt OUTPUT: c:\Test |
| PathRemoveFileSpec | Removes the trailing file name and backslash from a path, if they are present | INPUT: c:\Folder1\Test.txt OUTPUT: c:\Folder1 |
| PathRenameExtension | Replaces the extension of a file name with a new extension If the file name does not contain an extension, the extension will be attached to the end of the string. | INPUT: c:\Folder1\Test.txt .doc OUTPUT: c:\Folder1\Test.doc |
| PathStripPath | Removes the path portion of a fully qualified path and file | INPUT: c:\Folder1\Test.txt OUTPUT: Test.txt INPUT: c:\Folder1\Folder2\ OUTPUT: Folder2\ |
| PathUnquoteSpaces | Removes quotes from the beginning and end of a path Yes, the opposite of PathQuoteSpaces. | INPUT: "c:\program files\MyApp\test.txt" OUTPUT: c:\program files\MyApp\test.txt |
How to get the elapsed time since the application was started
A gimmick, but a simple one.
The CRT function Clock returns the time since the process (application) was started.
The time is presented as clock-ticks, which is in milliseconds.
Declare this external function:
Library name: MSVCRT.dll
Function: clock
Export Ordinal: 0
Returns
Number: LONG
Parameters
Here a sample to get the elapsed time
Set nElapsedTime = clock( )
When running the application from IDE, the time returned by clock is the elapsed time since Team Developer IDE started.
When running the application as executable (EXE), the time returned is the elapsed time since the executable was started.
Here you can download a sample:
How to use the Windows Timer (instead of SalTimer)
The good old SalTimerSet (SalTimerKill) function has one major drawback, it only supports timers up to 65535 milliseconds (65 seconds).
When you need larger timeframes, you can use the WinAPI functions TimerSet and KillTimer
The TimerSet function supports elapse times of 24.8 days (2.147.483.647 milliseconds).
The usage is nearly similar to the SalTimer functions.
Declare these external functions:
Library name: USER32.dll
Function: SetTimer
Export Ordinal: 0
Returns
Number: UINT
Parameters
Window Handle: HWND
Number: UINT
Number: UINT
Number: LPVOID
Function: KillTimer
Export Ordinal: 0
Returns
Boolean: BOOL
Parameters
Window Handle: HWND
Number: UINT
Also declare these constants
Number: WM_TIMER = 0x0113 Number: USER_TIMER_MAXIMUM = 0x7FFFFFFF Number: USER_TIMER_MINIMUM = 0x0000000A
Now trap the WM_Timer message:
On WM_TIMER
! wParam holds the timer ID
To set a timer do this:
! Set timer ID 1 to 30 minutes Call SetTimer( hWndForm, 1, 1800000, NUMBER_Null )
To kill the timer:
! Kill timer ID 1 Call KillTimer( hWndForm, 1 )
Here you can download a sample:

