From Team Developer SqlWindows Wiki
Revision as of 12:22, 25 July 2018 by DaveRabelink (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Windows Kernel


Pointer2.png How to suspend an application for a specific interval Pointer.png

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
         Number: DWORD

The interval is set to milliseconds (1000 = 1 second)

   ! Suspend the application for 5 seconds
   Call Sleep( 5000 )

Pointer2.png Get the time which has elapsed since the system was started Pointer.png

Use the WinApi function GetTickCount.
This is the declaration

Library name: KERNEL32.DLL
   Function: GetTickCount
      Export Ordinal: 0
         Number: DWORD

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

Pointer2.png Open an empty email in the default email client Pointer.png

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
         Window Handle: HWND
         String: LPCSTR
         String: LPCSTR
         String: LPCSTR
         String: LPCSTR
         Number: INT

Use the "Open" command for "Mailto:".
Below a sample

   Set sMailTo = ""
   Set sCC     = ""
   Set sBCC    = ""
   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):
Down.png WIKI_OpenNewEmptyMail_(TD51).zip

Pointer2.png Creating process tree using ToolHelp32 to get parent and child processes Pointer.png

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:

Pointer2.png How to set the value of environment variables Pointer.png

Using the WinAPI functions SetEnvironmentVariableA (ANSI) and SetEnvironmentVariableW (UNICODE)
you can set and delete environment variables in the current process.

These are the declarations (both ANSI and UNICODE)

Library name: KERNEL32.DLL
   Function: SetEnvironmentVariableA
      Export Ordinal: 0
         Boolean: BOOL
         String: LPCSTR
         String: LPCSTR

   Function: SetEnvironmentVariableW
      Export Ordinal: 0
         Boolean: BOOL
         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

Pointer2.png Format date and time using GetDateFormat and GetTimeFormat Pointer.png

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.

You can also use the WinApi functions GetDateFormat and GetTimeFormat.
Based on the default (user or system) locale you can get the names of days and months in the specific language.

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 )"

Date Time Format.png

Here you can download a sample (both ANSI and UNICODE versions):

Pointer2.png How to enumerate environment variables using GetEnvironmentStrings Pointer.png

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:

Pointer2.png Query and set Data Execution Prevention (DEP Policy) Pointer.png

What is Data Execution Prevention (DEP)?

From Microsoft:

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:


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:

Pointer2.png Is application running on Windows 64 bit? Pointer.png

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
      ! Execute specific actions needed on 32 bit windows systems

Here you can download the sample which contains PALIsWindows64Bit function:

Pointer2.png Get memory information of the system Pointer.png

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
      Boolean: BOOL
      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: