Site hosted by Angelfire.com: Build your free website today!

Home
DelphiZeus
Reading the C code in Win32 API Help

Home



When you are using functions from the Windows API, you will need to have a source of reference for the functions, parameters and stuctures of the API. So you will likely spend alot of time reading your local API Help or looking at the pages of the Microsoft Developers Network Library. There is much helpful information in there, however you will see that the the "C" coding language is used and not Pascal. This can be frustrating for a Delphi programmer, since the C-Code language uses different syntax and methods than Pascal-Code. In a function listing, like CreateWindow( ), the Parameters will be listed with the Type of variable before the variable name not after it, like in Pascal. The Result of a Function is listed before the function not after it as in Pascal. The first HWND in the CreateWindow( ) listing below is the Return Result type for that function. Here is the C-Code definition for that function -
HWND CreateWindow(
    LPCTSTR lpClassName,  // pointer to registered class name
    LPCTSTR lpWindowName, // pointer to window name
    DWORD dwStyle,    // window style
    int x,            // horizontal position of window
    int y,            // vertical position of window
    int nWidth,       // window width
    int nHeight,      // window height
    HWND hWndParent,  // handle to parent or owner window
    HMENU hMenu,      // handle to menu or child-window identifier
    HANDLE hInstance, // handle to application instance
    LPVOID lpParam    // pointer to window-creation data
   );

In thr first parameter the variable name is "lpClassName" and the variable type is "LPCTSTR", a pointer to a C-Code null terminated string See C Strings, a LPSTR below. A variable naming convention called "Hungarian notation" is used for most variables. In the "lpClassName" the first 2 charaters (lp) are Hungarian notation for "long" "pointer". And the LPCTSTR type is a Long Pointer "LP" to an Input "CT", String "STR" - which is a Pascal PChar type. In the variable "dwStyle", the dw tells you it's a "DWORD" type, and in the "nWidth" the n tells you it's a "Short Int" type (acually this "n" is left over from 16 bit windows and is now a 32 bit Integer type). Here is a list of the commonly used Hungarian notation prefixes, remember that the "Types" are C language types not pascal.
Hungarian Notation
 Prefix

b
by
c
cx / cy
dw
fn
h
i
l
n
p
s
sz
w
x, y
  C language Data Type

Boolean
Byte
Char
short Int used as size
DWORD
Function
Handle
Int
Long
Short Int
Pointer to address of variable
string
ASCI null terminated string
Word
Short Int used as coordinates

You may see the "LP" prefix in many API functions, this is to mark the difference between a "Pointer" (16 bit Word type - 2 bytes) and the "Long Pointer" (32 bit DWord type - 4 bytes), however this is "Left Over" from 16-Bit windows and has NO significance in the 32 bit windows systems (windows 95 and newer), since ALL POINTERS are 32 bit (4 byte- DWord, Cardinal types). These prefixes may be more confusing than helpful to a Delphi programmer, since many are incorrect (16-Bit windows types) and others do not correspond to the Pascal data Type acually used in that variable parameter.

Here is a list of some of the C variables as Pascal variables

HANDLE = type LongWord (Cardinal)
HWND = type LongWord (Cardinal)
HMENU = type LongWord
    ALL HANDLE TYPES ARE type LongWord (Cardinal) or THandle
        (HICON, HBITMAP, HFONT, HBRUSH, HPEN)
BYTE = Byte
SHORT = Smallint;
INT = Integer; (LongInt)
WORD = Word
DWORD = LongWord; (Cardinal)
LONG = LongInt (Integer)
LONGLONG = Int64
UINT = LongWord; (Cardinal, see comment below)
ASCI = null terminated string = Array of Char, #0 terminated
LPSTR = PAnsiChar; (PChar)
LPCTSTR = PAnsiChar; (PChar)
ULONG = Cardinal; (see UINT comment below)
BOOLEAN = Boolean
BOOL = LongBool
LPVOID = Pointer
PSID = Pointer
LCID = DWORD, LongWord (Cardinal)
LANGID = Word
UCHAR = Byte

UINT - There is No Delphi Pascal variable type that is the equivalent of a C code Unsigned Integer, UINT. A C code UINT can have a Cardinal value from 0 to 4,294,967,294 AND a single negative value of -1. Delphi declares a UINT as a LongWord (Cardinal), but if this variable has a Value of (hex) $FFFFFFFF (const MAXDWORD), then it is a -1 to the Windows System. So if you see any reference to a -1 value for a UINT, you will need to change it to MAXDWORD ($FFFFFFFF) for Delphi.

It may be confusing understanding the data types in the Win32 API help since there are several "C types" for a Pascal variable type, such as "DWORD, UNIT, HWND, ULONG, and LCID" are all Cardinal types in Pascal. And to add to the confusion, many Delphi code examples use the Pascal types of "LongWord" for "Cardinal", and a "LongInt" for an "Integer" type. If you have trouble with C data types, you usually can use the "C" type to define your variable in your code, since it was nessary to define these types in the windows.pas unit, for instance, in windows.pas it has -

type
DWORD = LongWord;
LONG = Integer;
LCID = DWORD;
SHORT = Smallint;

General CONFUSION
When I first tried to understand the relation and corespondence of Pascal number variables (Byte, Word, Cardinal, Integer) and the C-Code number variables, It somehow seemed Clear (direct corespondence) and Confused to me at the same time. Much of my confusion came from the code variable naming "Traditions" used in both MS C-Code Help and in Borland-Delphi Pascal. I know that I looked at many pascal "Code Examples" to show how to use API functions, with a "Wild Mix" and confusing use of variable type declaration. Like this-
var
 Style: LongWord;
 Parent: HWND;
 uReturn: UINT;
 Insts: DWord;
 hMenu: THandle;
 Param: ULONG;
 dwCap: Cardinal;
From this variable declaration, I somehow thought that all of these variable types were "Different" and need to be "Exactly" like this for the function to work. There are seven different variable types used above, for the Same unsigned 32-bit number variable type, the Delphi-Pascal Cardinal type. The to the delphi code compilier it would be -
var
 Style: Cardinal;
 Parent: Cardinal;
 uReturn: Cardinal;
 Insts: Cardinal;
 hMenu: Cardinal;
 Param: Cardinal;
 dwCap: Cardinal;
You may be helped if you can see that there are MANY diferent variable type names for 32-bit numbers. An Integer type is the same as all of these - LongInt, Long, Int . . Here at Delphi Zeus, I try to use the "Cardinal" and "Integer" for all variable declarations of 32-bit numbers.

Pointer Types
• Since many parameters in a windows API function are declared as a Pointer type, it was nessary to have many pointer types declared in windows.pas, here are some of the more common -
LPSTR = PChar;
PByte = ^Byte;
PLongint = ^Longint;
PInteger = ^Integer;
PINT = ^Integer;
PLongWord = ^LongWord;
PSmallInt = ^Smallint;
PDWORD = ^DWORD;
LPDWORD = PDWORD;
PDouble = ^Double;
PShortInt = ^ShortInt;

Please Note - Because many API functions were used in 16-BIT Windows OS, Usually the C-Code pointer types do not have a "P" in front of them, they Have a "LP" to prefix the Normal type, like "LPDWORD". Not all of the parameter variable types in the "Win32 API Help" Function defintions can be directly "translated" to Delphi Pascal variable types, particulaly the ones with a LP prefix. You will see a LPDWORD type (a pointer type) in the API Help and the Delphi Pascal function will use a Cardinal type (a non-pointer type) for it's parameter. Many times this is due to different Methods that parameters can be passed in Pascal and C-Code. As an Example, let's look at the GetComputerName( ) function. This is how it is defined in the API Help -

BOOL GetComputerName(
    LPTSTR lpBuffer,  // address of name buffer 
    LPDWORD nSize     // address of size of name buffer 
   );
And this is how it is defined in the Delphi Windows.pas unit
function GetComputerName(
    lpBuffer: PChar;  // address of name buffer 
    var nSize: Cardinal // size of name buffer
    ): Boolean;
The nSize variable type is different in the two functions, a pointer type in C-Code and a non-pointer type in Pascal. The C-Code used in the API Help does not have a "var" parameter defintion, like Pascal does, so it uses a pointer type. However, the guys at Delphi did Not always change a "LP" pointer type to a non pointer type for all of the API functions. It may be helpful to you if you have the Delphi Code Editor Options for "Code Completion" turned On (should be On by default). Then it will display the parameters and their types for an API function, so you can see what variable types are used. Otherwize you will need to look at the function defintion in these web pages or the source code of the windows.pas file.

A common variable name "Identifier" for a pointer type in API C-Code is "buffer", as in lpBuffer above. This is used many times for an "Output" variable name, of a memory block that will recieve the information from the function, often a PChar type. The pointer name lpBuffer may also be used for an Input parameter, if the pointer is UnTyped. You must remember that the Delphi compilier does NOT initialize a Pointer type with any memory, so you will need to to get a memory allocation for any pointer type that you pass to an API function as a "Buffer".

  C Strings, a LPSTR Pointer Type
You will see several Pointer to "string" types used in the API Help. These strings are Null terminated character arrays, Usually a Pointer to this string is used, with a type designation, based on a Long Pointer "LP" to a String "STR", a LPSTR API type, which is usually a PChar Delphi Pascal type. However, the LPSTR type is almost never used in the documentation, additional Charaters may be added to LPSTR, between the "LP" and the "STR" to try an give additional information about how this string may be used as the function parameter. A "CT" is added for LPCTSTR, which may indicate that this is an Input string, and not changed by the function (But for Delphi it is still a PChar type). Another is LPTSTR, the " T " may indicate that this is an Output string, and the function does Not read this string, but adds charaters to this string for a function output. In some Structures (Records) a LPCSTR may be used as a pointer to a String type, (Still a Pascal PChar). And you may see a few other letters between the "LP" and "STR", but it will again be a Pascal PChar type.


  VOID,   PVOID,  LPVOID, What is a Void?
You will see the VOID in a parameter or Return (Result) of an API function. There is no Pascal substitute for VOID, it roughly means "Nothing is here". The API says this about it -
The base type VOID indicates a procedure with no arguments or a function that does not return a result value (a procedure in Pascal).
The pointer types of PVOID, LPVOID and LPCVOID are for the C-Code Non-Typed pointers, which is the Delphi Pascal Pointer type (non-typed pointer). Let's look at the API definition for the ZeroMemory( ) function -
VOID ZeroMemory(
   PVOID Destination,
   DWORD Length  
   );
and the windows.pas Pascal definition -
procedure ZeroMemory(
   Destination: Pointer;
   Length: Cardinal
   );
In Pascal this function becomes a Procedure, because the Return in C-Code is VOID. And the "Destination" is a Pascal "Pointer" type.


  BOOLEAN and BOOL, What is a Long Boolean?
In many API functions there is a parameter type of BOOL, a 32-bit "Long" Boolean type (a 4 byte variable to fit a 32-bit memory block). The Delphi compiler will often treat this LongBool as a Normal Boolean type (It is either True or False), and the Windows system will only use a True and False for the value of a Long Boolean. But a Long Boolean type can sometimes have additional information in the other 3 bytes of that variable, although this is not a common practice. Also you will see a reference in the API Help for an Integer (usually a Return value) or Cardinal type as a "True" or "False", this just means that the Integer value will be Zero for False and One for True. (rarely you might see the reverse, a Boolean type refered to as 1 and 0).


  DATA STRUCTURES
In Pascal the term "Record" is used for a collection of data items, in C these collections are called a "Structure". Many API functions will use Pointers to a Structure, like RECT (TRect) or POINT (TPoint) and the API Help will show you what variables are in these structures. Usually the "typedef" and a "struct" precedes the stucture defintion (corresponding roughly to "Type" and "Record" in Pascal). In the API help C structures (records), the variable "Type" is listed before the variable.
// for a POINT

typedef struct tagPOINT {
    LONG x;
    LONG y;
} POINT;

// for a RECT

typedef struct _RECT {
    LONG left;
    LONG top;
    LONG right;
    LONG bottom;
} RECT;
• Some API C Structures and the Pascal Record Types -
MSG = TMsg
WNDCLASS = TWndClass
FINDREPLACE = TFindReplace
MENUITEMINFO = TMenuItemInfo

For most Window API Data Structure Types, you can add a " T " before the C structure data type name, to get the Pascal Record type, an API C-code  " RECT "  type becomes a " TRect " for the Pascal type. . . A " POINT " becomes a " TPoint ". Please notice that for "typedef" names in the helps's  C  code, like RECT and POINT, , they are written in UPPERCASE, this is similar to the way delphi puts a "T" in front of it's Type names, TRect, TPoint. Also Constant names are also Capitalized, but they will have a  _  in them like WM_PAINT.

    Predefined Constants

Many of the API fuction Parameters are numbers (Cardinal, Integer, Word), and to try to make code easier to read, numbers are given Constant Names to reflect what the number will do as the parameter. There are many Predefined values like WM_PAINT, CS_PARENTDC, IDC_ARROW, and COLOR_BTNFACE. The prefix before the  _  can tell you the general catagory of the constant, and what follows the _ will indicate what the contant value will do. Like IDC_ARROW, is a Cursor ID for the Arrow cursor. Here is a list of a few of the prefixes.

WM_
WS_
CS_
CW_
IDC_
IDI_
HKEY_     
FW_
BS_
BM_
ES_
Windows Message
Window Creation Style
Class Style
Create Window
Cursor ID
Icon ID
Registry Key
Font Weight
Window Creation Button Style
Button Message
Window Creation Edit Style



    C Text String and Special Charaters

In Delphi Pascal you can use the   '   Single Quote to singify the begining and end of an Array of Charaters (String, PChar). In C code a   "   Double Quote is used. And in Pascal the   #   with the Charater number , like #9 is used to have special charaters in a string, of course if you need a single Quote in a String you will need to put Two Single Quotes so the compiler will NOT think the Single Quote Ends the String. In C code the   \   is used as an Escape Charater in text strings enclosed in Double Quotes. If you wanted to put a Double Quote in a text string you would put a   \"   to show that the Double Quote is in the String and not the end of the Charater Array (string). To have a backslash   \   in a C string you would put Two backslashes   \\   to show that it is Not an Escape charater. The next example shows how to code the string -
the \ is an "Escape" character
"the \\ is an \"Escape\" character"
Some other escape charaters are
\t   Tab Stop
\'   Single Quote
\"   Double Quote
\?   Question Mark
\\   Backslash
\n   New Line
\r   Carriage Return
\b   Backspace


    PChar and pascal String use in API fuctions

When you use API fuctions and pass your program's PChar output variables as parameters, you need to keep in mind that the memory used by the variables is changed by the OS and NOT by your program, so Variables that are Not a fixed size (usually PChar, or some buffer) will need to be given memory allocations - ( Cardinal, Integer, TRect memory size does not change, -- PChar and String memory allocation will change as the Length of the string changes). If your program changes a PChar ( aPCharVar := 'New text' ) the compiler changes the memory use to fit the number of charaters in the string. But string Variables passed to API are changed without the your program knowing whats changing so it can NOT change the memory allocation to fit the new text from the OS, you have to do it with code OR make sure there is enough string memory to hold the text. Let's look at the GetWindowText( ) function.

procedure GetText;
  var
  Length: Integer;
  Text: PChar;
  Str1: String;

begin
Length := GetWindowTextLength(hEdit1)+1;
if Length < 2 then Exit;
GetMem(Text,Length);
GetWindowText(hEdit1,Text,Length);
Str1 := String(Text);
FreeMem(Text);
end;
The length of the "Text" in hEdit1 is returned by the GetWindowTextLength( ) function, notice that this is increased by 1 (+1). All "Null-terminated" (Pchar) strings end with a #0, which is not part of the text, but it is part of the memory for that variable, so you need to add one to the length for this null #0 charater. Then the GetMem( ) function is used to get a memory block allocated for the PChar variable "Text".


    Reading API Help Example C code
If you try and read some of the examples for coding you will see things like this -

HANDLE hFile;  // variables are listed at the begining
               // there is NO declaration like "var"
 
HANDLE hTempFile; 
 
DWORD  dwBytesRead, dwBytesWritten; 
 
char szTempName[MAX_PATH]; 
    // szTempName would be an Array[0..MAX_PATH] of Char
char buffer[4096]; 
 
// Open the file. 
 
hFile = CreateFile("ORIGINAL.TXT",        // filename 
// double quotes are use like single quote for Text
    GENERIC_READ,                 // open for reading 
    0,                            // do not share 
    NULL,                         // no security 
    OPEN_EXISTING,                // existing file only 
    FILE_ATTRIBUTE_NORMAL,        // normal file 

    NULL);                        // no attr. template 
if (hFile == INVALID_HANDLE_VALUE) { 
    ErrorHandler("Could not open file."); // process error 
} 
 
// Create a temporary file. 
 
GetTempFileName("\\TEMP", // dir. for temp. files 
    "NEW",                // temp. filename prefix 
    0,                    // create unique name 
    szTempName);          // buffer for name 

hTempFile = CreateFile((LPTSTR) szTempName,  // filename
// the (LPTSTR) szTempName is roughly like Typecasting in Pascal
// PChar(szTempName); 
    GENERIC_READ | GENERIC_WRITE, // open for read-write 

    0,                            // do not share 
    NULL,                         // no security 
    CREATE_ALWAYS,                // overwrite existing file
    FILE_ATTRIBUTE_NORMAL,        // normal file 
    NULL);                        // no attr. template 

if (hTempFile == INVALID_HANDLE_VALUE) { 
    ErrorHandler("Could not create temporary file."); 
}  

do 
{
    if (ReadFile(hFile, buffer, 4096, 
        &dwBytesRead, NULL)) { 
// the & above is roughly like the @ in Pascal
        CharUpperBuff(buffer, dwBytesRead); 
 
        WriteFile(hTempFile, buffer, dwBytesRead, 
            &dwBytesWritten, NULL); 
    } 
} while (dwBytesRead == 4096);  
 
CloseHandle(hFile); 
CloseHandle(hTempFile); 
 
// Move the temporary file to the new text file.
 
if (!MoveFile(szTempName, "ALLCAPS.TXT")) { 
    ErrorHandler("Could not move temp. file."); 

}

    In Pascal it would be -
var
hFile, hTempFile: THandle; 
BytesRead, BytesWritten: Cardinal; 
TempName: Array[0..MAX_PATH] of Char; 
buffer: Array[0..4095] of Char;

hFile := CreateFile('ORIGINAL.TXT',        // filename 
    GENERIC_READ,                 // open for reading 
    0,                            // do not share 
    nil,                         // no security 
    OPEN_EXISTING,                // existing file only 
    FILE_ATTRIBUTE_NORMAL,        // normal file 
    0);                        // no attr. template 
if hFile = INVALID_HANDLE_VALUE then
  begin 
  ErrorHandler('Could not open file.'); // process error
  Exit;
  end;

// Create a temporary file. 
 
GetTempFileName('\\TEMP', // dir. for temp. files 
    'NEW',                // temp. filename prefix 
    0,                    // create unique name 
    TempName);          // buffer for name 

hTempFile := CreateFile(TempName,  // filename 
    GENERIC_READ or GENERIC_WRITE, // open for read-write 

    0,                            // do not share 
    nil,                         // no security 
    CREATE_ALWAYS,                // overwrite existing file
    FILE_ATTRIBUTE_NORMAL,        // normal file 
    0);                        // no attr. template 

if hTempFile = INVALID_HANDLE_VALUE then
  begin
  CloseHandle(hFile); 
  ErrorHandler('Could not create temporary file.');
  Exit;
  end;

Repeat
  if ReadFile(hFile, buffer, SizeOf(buffer), 
        BytesRead, nil) then 
   begin
   CharUpperBuff(buffer, BytesRead); 
   WriteFile(hTempFile, buffer, BytesRead, 
            BytesWritten, nil);
   end;
until BytesRead <> SizeOf(buffer); // 4096 
 
CloseHandle(hFile); 
CloseHandle(hTempFile);

// Move the temporary file to the new text file.
 
if not MoveFile(TempName, 'ALLCAPS.TXT') then 
    ErrorHandler('Could not move temp. file.');  
    

The ErrorHandler( ) function is an application function to show an error message, not a windows API function. In C code there is no variable declaration like var in Pascal, the variables are usually defined at the begining,
look at
HANDLE hFile;
and
HANDLE hTempFile;
The type (HANDLE) is before the variable (hFile), and the type is capitalized, while the variable name will have a hungarian notation prefix, and will not be Capitalized. If you look at the CreateFile( ) function there are 2 NULL paramerter values in the C code, and in Pascal there is a nil and a 0 value. In C code a NULL is translated to a 0 value for numeric (HANDLE) values, in Pascal you will have to use a 0 for numeric values, since nil can only be used for Pointer types. Instead of the Pascal "begin" and "end;" to associate the code with a function, C uses a "{" and "}" (there are no Procedures in C, just functions). In C an "if" test does not have a "then" (it is implied that an "if" Always has a "then", so the then is not written out), but usually wraps the code that would happen in { } after the binary test. In Pascal a single "=" is used for a binary test ( if A = B then ). In C a double "= =" is used ( if A = = B ). The Pascal binary operator "or" is the charater "|" in C, the Pascal "and" operator is a "&" in C, the binary operations of "|" and "&", are the same in C and Pascal. In C a "!" would be a "not" in Pascal, "if (!MoveFile(" would be, "if not MoveFile(". Many times you can look at these code examples in the API help and find the functions that are being explained, usually you can get some idea of the order to call these functions, and what the parameters and structure members need to be set to, or read from. But the use of pointers, dereferencing pointers, and typcasting pointers are often very different than what is needed for Delphi Pascal Code. Hopefuly the code examples in these pages will help you to get these functions working.

H O M E