How to suspend an application for a specific interval
There have been reports the SalPause function creates instability in some TD versions.
Use the WinApi function Sleep instead.
This is the declaration
Library name: KERNEL32.DLL Function: Sleep Export Ordinal: 0 Returns Parameters Number: DWORD
The interval is set to milliseconds (1000 = 1 second)
! Suspend the application for 5 seconds Call Sleep( 5000 )
Get the time which has elapsed since the system was started
Use the WinApi function GetTickCount.
This is the declaration
Library name: KERNEL32.DLL Function: GetTickCount Export Ordinal: 0 Returns Number: DWORD Parameters
It returns the time in milliseconds.
You can use this function to measure the duration of specific parts in your application
Set nStartTime = GetTickCount( ) ! ! Here specific code to measure its performance Call ExecuteAVeryHeavyFunction( ) ! Set nEndTime = GetTickCount( ) ! ! Now calculate the measured time in milliseconds Set nExecutionTime = nEndTime - nStartTime
Open an empty email in the default email client
Here an easy way to open an empty email using your default email client (eg Outlook) and having filled in the fields
for "mailto", "CC", "BCC", "Subject" and body.
Use the WinApi function ShellExecuteA.
This is the declaration
Library name: SHELL32.DLL Function: ShellExecuteA Export Ordinal: 0 Returns Parameters Window Handle: HWND String: LPCSTR String: LPCSTR String: LPCSTR String: LPCSTR Number: INT
Use the "Open" command for "Mailto:".
Below a sample
Set sMailTo = "mailto:John.Doe@somewhere.com" Set sCC = "email@example.com" Set sBCC = "firstname.lastname@example.org" Set sSubject= "subject=Request for some info" Set sBody = "body=Here my request for some info. Best regards" ! Set sEmail = sMailTo || "?" || sCC || "&" || sBCC || "&" ||sSubject || "&" ||sBody ! ! Call ShellExecuteA( hWndForm, "open", sEmail, STRING_Null, STRING_Null, 1 ) !
Beware that the email will be only text based. No formatting is possible or adding HTML tags.
When you need a newline or TAB in the body text, use the next codes
Newline -> %0D%0A Tab -> %09
So if you want a newline in the bodytext of the sample above
Set sBody = "body=Here my request for some info.%0D%0ABest regards"
Here you can download a sample (created with TD 5.1, using the UNICODE function ShellExecuteW):
Creating process tree using ToolHelp32 to get parent and child processes
Using Toolhelp32 API, you can create a snapshot of all current running processes in the system.
Such a snapshot holds the tree of processes, where information of the processes and their relationships are gathered.
For instance, it holds which process is the parent of another process and which descendants (child) processes it started.
Having this information you are able to determine which process started your application. For instance if your app is started from a batch or is running as a service or was started from another TD application. You can also determine which processes are started from your app. For instance Internet Explorer, or another TD application.
By traversing the snapshot (linking the parent/child relationships) you are able to create a tree of processes. Just like [ProcessExplorer] does.
ToolHelp32 is part of Kernel32.dll and to get a process snapshot these API functions are used:
- CreateToolhelp32Snapshot : Takes a snapshot of the specified processes
- Process32First : Retrieves information about the first process encountered in a system snapshot.
- Process32Next : Retrieves information about the next process recorded in a system snapshot.
The first and next functions retrieve a PROCESSENTRY32 structure describing an entry from a list of the processes residing in the system address space when a snapshot was taken.
It contains process information such as the name of the executable file, the process identifier, and the process identifier of the parent process.
A ready to go implementation can be downloaded from the Sample Vault.
It contains a library with needed classes to create a snapshot.
The main application shows an outlinelistbox with the tree of processes. The red colored process is the current process.
Here you can download a sample:
How to set the value of environment variables
These are the declarations (both ANSI and UNICODE)
Library name: KERNEL32.DLL Function: SetEnvironmentVariableA Export Ordinal: 0 Returns Boolean: BOOL Parameters String: LPCSTR String: LPCSTR Function: SetEnvironmentVariableW Export Ordinal: 0 Returns Boolean: BOOL Parameters String: LPWSTR String: LPWSTR
And here a sample how to set the PATH variable
Set bOk = SetEnvironmentVariableA( "PATH", "C:\\TEST" )
Be aware that if you set a environment variable from within your application, the value is only available in the current process and
in the child processes started from your TD application. When the application ends, the set variables are back to their initial values.
So using this function, you are unable to set the overall variable values for all other applications.
A nice usage of this is setting the PATH variable at startup of your application to the needed paths which then are only known by the current running application. The PATH setting will be reverted back when the application ends, which does drop the need to set global environment variables for your complete system.
Here you can download a sample:
To get the variable value, See How to get the value of environment variables
Format date and time using GetDateFormat and GetTimeFormat
One drawback of function SalFmtFormatDateTime is that you cannot format a date(time) using a specific locale (language).
Also the Sal function has a limited set of formats to be used.
For example, here some LONGDATE formatted strings in their locales:
Dutch maandag 23 november 2009 French lundi 23 novembre 2009 English Monday, November 23, 2009 German Montag, 23. November 2009 Spanish lunes, 23 de noviembre de 2009 Estonian Esmaspäev, 23. november 2009
You can find the specific locale ID's to be used here:
Below the possible format options for date and time
d Day of the month as digits without leading zeros for single-digit days. dd Day of the month as digits with leading zeros for single-digit days. ddd Abbreviated day of the week as specified by a LOCALE_SABBREVDAYNAME* value dddd Day of the week as specified by a LOCALE_SDAYNAME* value. M Month as digits without leading zeros for single-digit months. MM Month as digits with leading zeros for single-digit months. MMM Abbreviated month as specified by a LOCALE_SABBREVMONTHNAME* value MMMM Month as specified by a LOCALE_SMONTHNAME* value y Year represented only by the last digit. yy Year represented only by the last two digits. A leading zero is added for single-digit years. yyyy Year represented by a full four or five digits, depending on the calendar used. yyyyy Behaves identically to "yyyy". g, gg Period/era string formatted as specified by the CAL_SERASTRING value. h Hours with no leading zero for single-digit hours; 12-hour clock hh Hours with leading zero for single-digit hours; 12-hour clock H Hours with no leading zero for single-digit hours; 24-hour clock HH Hours with leading zero for single-digit hours; 24-hour clock m Minutes with no leading zero for single-digit minutes mm Minutes with leading zero for single-digit minutes s Seconds with no leading zero for single-digit seconds ss Seconds with leading zero for single-digit seconds t One character time marker string, such as A or P tt Multi-character time marker string, such as AM or PM
It is also possible to mix text along with the available formats.
sFormat = "'This is day' dd 'of month' MM '(' MMMM ')'" Output = "This is day 23 of month 11 ( November )"
Here you can download a sample (both ANSI and UNICODE versions):
How to enumerate environment variables using GetEnvironmentStrings
Using the WinAPI function GetEnvironmentStrings (ANSI and UNICODE)
you can get the list of environment variables in the current process.
Here you can download a sample:
Query and set Data Execution Prevention (DEP Policy)
What is Data Execution Prevention (DEP)?
Data Execution Prevention (DEP) is a security feature that can help prevent damage to your computer from viruses and other security threats. Harmful programs can try to attack Windows by attempting to run (also known as execute) code from system memory locations reserved for Windows and other authorized programs. These types of attacks can harm your programs and files.
DEP can help protect your computer by monitoring your programs to make sure that they use system memory safely.
If DEP notices a program on your computer using memory incorrectly, it closes the program and notifies you.
This feature is part of Windows starting from XP SP2 and higher.
Though this feature can help getting your applications be more secure, not all applications are compatible with DEP.
Depending on the actions taken by applications, DEP can stop applications performing specific features and could then result
in a crashing application. There are several examples to be found of reports of crashing applications when DEP is enabled.
The DEP policy is a system and application wide setting and can also affect your TD build applications. I have seen TD build applications crash
when DEP was enabled and after disabling it no issues arose afterwards with the same application on the same system.
DEP can be enabled for essential Windows programs and services (OptIn) or can be enabled for all applications (OptOut).
When the setting is OptOut, applications can be excluded from DEP.
For more info on DEP read this:
When your application needs to be excluded from DEP, you are able to programmatically check the DEP policy and change it
to the wanted policy, for instance to disable it.
Having this set of WinAPI functions, you can query and set the DEP policy:
GetCurrentProcess GetProcessDEPPolicy GetSystemDEPPolicy SetProcessDEPPolicy
For example, when you need to be sure DEP is turned off for your application, you can do this at application startup:
If GetProcessDEPPolicy( GetCurrentProcess( ), nFlags, bPermanent ) If nFlags = PROCESS_DEP_ENABLE AND NOT bPermanent Call SetProcessDEPPolicy( PROCESS_DEP_DISABLE )
After this, the current application is excluded from the DEP policy which prevents the crashes.
The implementation of the WinAPI and a sample how to use it can be downloaded here:
Is application running on Windows 64 bit?
At this point, Team Developer build applications (win32) are always 32Bit.
It could be needed to know from your application if it is running on a 32Bit or 64Bit Windows version.
There are some differences between 32 and 64 bit Windows versions and you might want to do certain actions differently
when running on 32 or 64 bit.
This API function can be used to determine if the current application (32Bit) is running on a 64 bit system:
Though beware, this API function could be not present on the system the application is running.
This means you have to check first if this function is present before calling it.
A specific WIKI article can be found here to show how to check for existence of DLL functions:
So, to combine things, the sample of this article shows how to implement the 64 bit check.
The function PALIsWindows64Bit is ready to use in your own projects. Example:
If PALIsWindows64Bit( ) > 0 ! Execute specific actions needed on 64 bit windows systems Else ! Execute specific actions needed on 32 bit windows systems
Here you can download the sample which contains PALIsWindows64Bit function:
Get memory information of the system
To retrieve the current memory information of the system, Kernel32.dll API offers these functions:
Looking at the definition of these functions on MSDN:
It shows that the datatypes used are 64 bit datatypes.
Example for GetPhysicallyInstalledSystemMemory
BOOL WINAPI GetPhysicallyInstalledSystemMemory( _Out_ PULONGLONG TotalMemoryInKilobytes );
The 32bit TD versions do not support the use of 64bit datatype definitions in external functions like ULONGLONG.
When calling the function with ULONG, the values are truncated at the 32 bit boundary.
This means that on systems having more than 4Gb of memory, this function will only report up to 4Gb.
64Bit versions of TD (starting with TD7.0 and up) do have support for 64bit datatypes like ULONGLONG.
This means that here the returned values are correct.
Fortunately, a solution for 32bit TD versions is available.
Looking at the function GetPhysicallyInstalledSystemMemory, it has an OUT parameter having type PULONGLONG.
This datatype is 64bit.
This value can be split into two 32bit values.
The first 32 bits are called the low part and the last 32 bits are called the high part of the value.
A trick is then to define the function in TD not having one 64bit parameter, but two 32Bit parameters.
Function: GetPhysicallyInstalledSystemMemory Export Ordinal: 0 Returns Boolean: BOOL Parameters Receive Number: LPULONG Receive Number: LPULONG
When calling this function, the first parameter will receive the low part of the value and the second parameter receives the high part.
Then these low and high part values (32bit each) should be combined into one number value (64bit).
This is done by adding the low value and a bitshifted high value to a single number value, like this:
Call GetPhysicallyInstalledSystemMemory( nValue32Low, nValue32High ) ! Set nValue64 = nValue32Low + SalNumberPower( 2, 32 ) * nValue32High
The resulting number is the 64bit number.
The supplied sample shows the implementation for 32Bit and 64Bit TD versions.
Here you can download the sample from here: