WinApi Miscellaneous
Miscellaneous Windows API & external functions
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 prevent "Not responding" state on "heavy load" functions 
The operating system defines an application hang as a UI thread that has not processed messages for at least 5 seconds. Obvious bugs cause some hangs, for example, a thread waiting for an event that is never signaled, and two threads each holding a lock and trying to acquire the others. You can fix those bugs without too much effort. However, many hangs are not so clear. Yes, the UI thread is not retrieving messages - but it is equally busy doing other 'important' work and will eventually come back to processing messages.
However, the user perceives this as a bug. The design should match the user's expectations.
If the application's design leads to an unresponsive application, the design will have to change. Finally, and this is important, unresponsiveness cannot be fixed like a code bug; it requires upfront work during the design phase. Trying to retrofit an application's existing code base to make the UI more responsive is often too expensive. The following design guidelines might help.
- Make UI responsiveness a top-level requirement; the user should always feel in control of your application
- Ensure that users can cancel operations that take longer than one second to complete and/or that operations can complete in the background; provide appropriate progress UI if
- Queue long-running or blocking operations as background tasks (this requires a well-thought out messaging mechanism to inform the UI thread when work has been completed)
Keep the code for UI threads simple; remove as many blocking API calls as possible
... but if application still going into "Not responding state" there is an option to switch off that unwanted behaviour with user32.dll function DisableProcessWindowsGhosting() which has no return value and also not any parameter.
(external function) Library name: USER32.DLL ThreadSafe: No Function: DisableProcessWindowsGhosting
Library name: USER32.DLL ThreadSafe: No Function: DisableProcessWindowsGhosting Description: function disables the window ghosting feature for the calling GUI process. Window ghosting is a Windows Manager feature that lets the user minimize, move, or close the main window of an application that is not responding. (http://msdn.microsoft.com/en-us/library/windows/desktop/ms648415(v=vs.85).aspx) Export Ordinal: 0 Returns Parameters
More source:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd744765(v=vs.85).aspx
BUT BE AWARE!!!: There is no function to enable window ghosting in a process once it has been disabled. Once ghosting has been disabled in a process, it remains disabled for the duration of the process. What that means: changed (unwanted)behaviour in GUI - doing so it may seriously mess up the user interface, it depends which messages are used for coding/messaging ... But its worth to try at least if "Not Responding" is issue...
Riho Kukk, Tresoor Tarkvara OÜ, Estonia
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:
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.
Here you can download a sample:
ForceThemesOff.zip
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:
WIKI_ShowBytes.zip
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:
WIKI_ShowTimeInterval.zip
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 Function: GetUserNameW Export Ordinal: 0 Returns Boolean: BOOL Parameters Receive String: LPWSTR 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:
WIKI_GetWindowsUser.zip
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 pre-build 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.
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: https://wiki.tdcommunity.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:
WIKI_ApplicationRunningTime.zip
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:
WIKI_Timer.zip
Special folders 
To get the path to a specific special folder you can use the shell function SHGetSpecialFolderPath.
Examples of special folders are:
CSIDL_SYSTEM -> C:\Windows\system32 CSIDL_PROGRAM_FILES -> C:\Program Files (x86) CSIDL_MY_DOCUMENTS -> C:\Users\Dave en Esther\Documents etc
Declare this external function:
(A = ANSI, W=UNICODE)
Library name: shell32.dll Function: SHGetSpecialFolderPathA Description: Export Ordinal: 0 Returns Boolean: BOOL Parameters Window Handle: HWND Receive String: LPSTR Number: INT Boolean: BOOL Function: SHGetSpecialFolderPathW Description: Export Ordinal: 0 Returns Boolean: BOOL Parameters Window Handle: HWND Receive String: LPWSTR Number: INT Boolean: BOOL
The sample contains a wrapper for this WinApi function.
String PALGetSpecialFolder( pnCSIDL, pbIncTrailingBackslash )
Here a sample to get the Windows Fonts folder:
Set dfFolder = PALGetSpecialFolder( CSIDL_FONTS, FALSE ) ! ! Output here is : C:\Windows\Fonts
Here you can download the sample:
(It contains ANSI and UNICODE versions)
WIKI_SpecialFolders.zip
Detect system idle time 
If your application must react on the fact that the system is not used for a specific time interval, you can use the
user32 function GetLastInputInfo.
Declare the external function:
Library name: user32.dl Function: GetLastInputInfo Description: Export Ordinal: 0 Returns Boolean: BOOL Parameters structPointer Number: UINT Receive Number: DWORD
It returns the tick-count of the last input event (in msecs).
Calculate the difference between the currrent tick count and the one from the function above.
This is the idle time and depending on the value you can logoff or do other automated tasks.
Here you can download a sample:
WIKI_SystemIdleDetect.zip
Convert (binary) buffer to formatted string: CryptBinaryToString 
A string variable in TD can contain "normal" strings or any binary data (eg images, file contents etc).
Using the WinAPI function CryptBinaryToString you can
format the contents of a string variable to readable text depending on the used flags.
For instance, this function can format the data to be viewed as most HEX viewers show data:
0000 4c 69 6e 65 20 31 0d 0a 4c 69 6e 65 20 32 0d 0a Line 1..Line 2.. 0010 4c 69 6e 65 20 33 0d 0a 54 61 62 31 09 54 61 62 Line 3..Tab1.Tab 0020 32 09 54 61 62 33 0d 0a 41 6e 64 20 73 6f 6d 65 2.Tab3..And some 0030 20 6d 6f 72 65 20 74 65 78 74 20 68 65 72 65 20 more text here 0040 21 21 21 21 00 !!!!.
Here the HEX values of the bytes are displayed in blocks and also the ASCII representation of those bytes.
The function also is able to convert data to other encodings like base64 in several flavors.
Below the same data but now formatted to BASE64 HEADER:
-----BEGIN CERTIFICATE----- TABpAG4AZQAgADEADQAKAEwAaQBuAGUAIAAyAA0ACgBMAGkAbgBlACAAMwANAAoA VABhAGIAMQAJAFQAYQBiADIACQBUAGEAYgAzAA0ACgBBAG4AZAAgAHMAbwBtAGUA IABtAG8AcgBlACAAdABlAHgAdAAgAGgAZQByAGUAIAAhACEAIQAhAAAA -----END CERTIFICATE-----
This could come in handy to create your own HEX viewer or to inspect any string byte contents.
A TD wrapper function is created which calls CryptBinaryToString, named PALCryptBinaryToString.
bOk = PALCryptBinaryToString( psBuffer, pnFlags, rpsString ) Converts a buffer to a formatted string. Parameters Type Description psBuffer String Buffer to convert pnFlags Number Formatting flags, see CRYPT_STRING constants rpsString Receive string OUTPUT: Formatted string Return value bOk = TRUE if the function succeeds. Otherwise it returns FALSE
This function is placed in a separate library to be used in your own projects.
This library also contains all WinAPI flag constants to be used in PALCryptBinaryToString.
Here you can download a sample to show how to use PALCryptBinaryToString.
Both ANSI and UNICODE versions are supplied.
WIKI_CryptBinaryToString.zip
Advanced file operations: copy, move, rename and delete 
Team Developer offers several file functions, for instance to copy or delete files.
When you need more advanced features, have a look at the WinAPI function SHFileOperation.
Some of the features are:
- Copy complete folders and subfolders with their files to the destination folder
- Delete folders and subfolders even when they contain files
- Rename multiple files in a single operation
- Move multiple files
- Show confirmation dialogs (eg to overwrite) or abort
- Use the recycle bin when deleting files
- For all operations, specify Standard MS-DOS wildcard characters
- Automatically rename files when collisions are detected
Though most of these operations can be created using the standard Sal and Vis functions, this API function does it out of the box.
A nice sample to show how to use this API function can be found in the sample vault:
SHFileOperation.zip
Check existence of DLL functions at runtime 
When building applications using external functions from Windows API or other third party DLL's, the system you are building on obviously contains
the DLL's and DLL functions. If not, you are not able to compile your application in the first place.
But what about the system your application is running on, at customer sites?
For instance, an application using new Windows 7 API functions on a Windows 7 development environment, but you are not sure
on which Windows OS your application will be used by the customer.
Or you use a third party DLL, which comes in several versions and you are not certain a specific version is installed on the deployment system.
In those cases where at runtime the application calls a non existent exported function, you will get this error message:
After this message, the application closes.
To prevent this, you can check at runtime if a particular API function is present on the running system.
Basically, it is getting a handle to the DLL and then getting the proc address of the function using it's name.
These external API functions are used to do this:
GetModuleHandle (ANSI or UNICODE version) LoadLibraryEx (ANSI or UNICODE version) GetProcAddress FreeLibrary
There are two situations:
- The DLL is already loaded by your application. Most commonly used WinAPI dll's are.
- The DLL is not yet loaded. You application did not call any DLL function from it
In the first case, the DLL is already loaded, the actions are the easiest.
You first get the handle to the DLL by:
Set nHandle = GetModuleHandleA( "kernel32.dll" )
With this handle you can query the functions:
Set nProcAddress = GetProcAddress( nHandle, "GetSystemDefaultUILanguage" )
When nProcAddress is not NULL, the functionname was found.
Beware that the functionname is case sensitive. You must supply the exact case to get the function address.
The other situation, the DLL is not yet loaded by the application. For instance when a third party DLL is not yet called.
Here, you need to load the DLL explicitly to get the handle. After loading and checking the function, you should free the dll afterwards:
Set nHandle = LoadLibraryExA( "MyCustom.dll", NUMBER_Null, DONT_RESOLVE_DLL_REFERENCES ) ... ! Check the functions ... Call FreeLibrary( nHandle )
The LoadLibraryEx function loads the dll from the search PATH. If you specify a full path, only that path is used to search the dll.
The DONT_RESOLVE_DLL_REFERENCES parameter will load the DLL without loading linked DLL's and does not initialise the DLL.
If you are not sure if a DLL is already loaded, combine the GetModuleHandle and LoadLibraryEx.
A ready to use function is present in the sample: PALCheckDLLFunction
This function will first try to get the handle from the requested DLL and if that fails tries to load it.
You can use this function as-is in your own projects to check the existence of DLL functions, like:
If PALCheckDLLFunction( "MyCustom.dll", "MyFunction1" ) > 0 Call MyFunction1( ) Else ! Show error message or perform alternative task
Here you can download the sample which contains PALCheckDLLFunction for both ANSI and UNICODE TD versions:
WIKI_CheckDLLFunctionExists.zip
External datatypes and byte sizes 
The several datatypes used in external functions have a predefined size.
The next table shows the commonly used types and their sizes in bytes.
Type | Size (bytes) |
---|---|
BYTE, CHAR | 1 |
ATOM, WORD, SHORT, USHORT, WCHAR | 2 |
BOOL, DWORD, HANDLE, HWND, INT, LONG, LPARAM, UINT, ULONG, WPARAM | 4 |
LPATOM, LPBOOL, LPBYTE, LPCHAR, LPDOUBLE, LPDWORD, LPFLOAT, LPHANDLE, LPHWND, LPINT, LPLPARAM, LPLONG, LPLPVOID, LPSHORT, LPSTR, LPUINT, LPULONG, LPUSHORT, LPWORD, LPVOID, LPWPARAM, LPWCHAR, LPWSTR | 4 |
DOUBLE, FLOAT | 8 |
File version info: get TD version including build number 
File version details from an executable or DLL can be shown manually in the file properties dialog
The version information can also be retrieved programmatically.
This is especially useful in these situations:
- Need to check if required versions of particular dlls or executables are installed on the system
- Depending on the versions found, your application might need to execute different functionality
- From your application, a need to display the installed versions for debugging or logging purposes
- Display or log the TD runtime version including build numbers
Using Windows API, the version information strings can be retrieved with these functions:
- GetFileVersionInfoA / GetFileVersionInfoW
- GetFileVersionInfoSizeA / GetFileVersionInfoSizeW
- VerQueryValueA / VerQueryValueW
The sample provided here shows how to implement it in TD.
It also offers a global function to retrieve the TD runtime version including the build number.
The archive contains both the ANSI and UNICODE version.
Here you can download the sample:
WIKI_FileVersionInfo.zip
External datatype reference and CStructEx library 
When implementing external function definitions, it is important to adopt the correct datatypes for return values and parameters.
The datatype definition instructs TD to handle the data according to the intended bit/byte sizes and sign.
Incorrect definitions can lead to datatype casting which transforms/cast the data in unexpected ways.
The general rule is that you try to match the datatype definition exactly to the intended definition.
For example, when a parameter expects an INT datatype, the TD definition should be set to Number: INT, obviously.
Though you might come into doubt what to choose when the datatype is not explicitly one of the base datatypes, like INT or LONG.
For example, Windows API functions could define other types, which are aliases or placeholders for the really underlying datatypes.
Look at HBITMAP, which is a Windows API datatype. Team Developer does not have the option to set HBITMAP for exported functions.
Reading the documentation of the function should indicate which base type it represents.
Even then, in most cases it is searching all kinds of docs to find out which TD datatype to take.
Personally, I still struggle to get the correct datatype, which takes time and in some cases, I accidentally use the wrong one.
Therefore, I decided to make it a bit easier. I tried to get all base types and related Windows API datatypes into a list for future reference.
The list offers this info per datatype:
- The TD datatype(s) to use
- The size in bits/bytes of the type
- The maximum value range of the type (e.g. 0..255)
- The sign (+/-)
(Some types are only present in TD70 (32 and 64 bit). This TD version has support for 64bit types.)
The way to use it is: look up the API datatype in the list and determine which TD external function datatype to use.
In addition, which CStruct functions to use to read/write the datatypes from/to buffers.
Here you can access the external function datatype reference (PDF and Excel format):
External datatype reference
Extended CStruct functions (CStructEx library)
Developers in TD are able to access (memory) buffers to read or write data directly.
This is done using the CStruct library (cstructl.apl) which contains several functions for a limited set of API datatypes.
For instance, using CStructGetWord, we can read a WORD value from a buffer. Using CStructPutWord we can write a WORD value to a buffer.
However, looking closely at the CStruct library, it is striking that not all base datatypes have corresponding Get and Put functions.
For instance, CStructGetWord, is defined to get only UNSIGNED values. This means that it only supports types having a maximum value range of 0 to 65535.
A SIGNED value has a different maximum range, in this case -32768 to 32767.
Most of the CStruct functions have this limitation. They are designed to handle UNSIGNED values only.
When an UNSIGNED value is handled using these functions, the values will be truncated at certain values and result in strange values.
To help out with these issues, I created an extension to the CStruct library, called CStructEx library.
It offers many more functions for a wide range of different datatypes.
All extended functions have the function name CStructEx... or CStructExPtr...
The Ptr functions are using memory pointers (number) instead of string buffers.
The API reference list shows which CStruct function to use for the particular datatypes.
The CStructEx library consist of 3 libraries:
- Library to use in ANSI TD versions
- Library to use in UNICODE TD versions
- Library to use in TD70 and up (both 32 and 64 bit versions).
Here you can download the CStructEx library:
CStructEx library archive
Windows Speech API (SAPI): Text to Speech / Speech to Text 
The Speech Application Programming Interface or SAPI is an API developed by Microsoft to allow the use of speech recognition and speech synthesis within Windows applications.
In general the Speech API is a freely re-distributable component which can be shipped with any Windows application that wishes to use speech technology.
Simply said, using this API you are able to convert spoken text (eg audio from a microphone) to text within your application, called Speech to Text.
Also, giving text to the engine creates spoken audio (computer voice) which is played through the speaker or saved to a file, called Text to Speech.
A sample has been created in Team Developer to show how to use the API.
Two versions are present: one for TD versions up to TD6.3 and one starting from TD 7.0.
The sample shows both Speech to Text and Text to Speech implementations.
Here you can download the sample:
WIKI_SpeechAPI.zip
Also a short YouTube video to show the usage of the sample:
Speech API demo