Home |
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.
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;
Pointer Types 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 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.
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. |