Forum > Windows

WinAPI - examples - post 2

(1/3) > >>

440bx:
Hello,

The examples will be presented roughly in order of complexity, that is, from simplest to more complex.  The simplest are by far those APIs which should NOT be used since no example will be provided for those.

Amond the APIs that should be avoided and preferably never used are :

GlobalCompact
GlobalFix   
GlobalFlags 
GlobalHandle
GlobalLock   
GlobalReAlloc
GlobalSize   
GlobalUnfix 
GlobalUnlock
GlobalUnWire
GlobalWire   
LocalAlloc   
LocalCompact
LocalFlags   
LocalFree   
LocalHandle 
LocalLock   
LocalReAlloc
LocalShrink 
LocalSize   
LocalUnlock 

All of the above are Windows 16 bit memory management functions which are _not_ well suited for a 32 bit O/S.  Use the 32 bit memory management functions instead.

As mentioned previously, no example for any of the above APIs will be given.



GlobalAlloc
GlobalFree

These two (2) APIs are still commonly found in C programs but, are not as flexible as HeapAlloc() and HeapFree() which should be preferred.

No example of GlobalAlloc and GlobalFree will be given.  An example of HeapAlloc and HeapFree will be given in the future.


GlobalMemoryStatus

GlobalMemoryStatus returns incorrect information on systems with more than 4GB of memory. Use GlobalMemoryStatusEx instead.

An example for both will be given in the future.


GetTextExtentPoint

Use GetTextExtentPoint32 instead which, according to MS, is more accurate.




This post is for examples of API used in the great majority of the examples. Examples attached to this post are :

WinAPI - GetTextExtentPoint      (gdi)
WinAPI - GetTextExtentPoint32  (gdi)

Both of these APIs return the width and height in pixels of a specified string


WinAPI - SetBkMode                    (gdi)

Sets the background color to opaque or transparent.  When the background is opaque then whatever color was chosen as background will be visible.


WinAPI - SetTextAlign                 (gdi)

Sets the text alignment.  This example visually demonstrates the effects of some of the SetTextAlign options. See MSDN for all available options.


WinAPI - TextOut                        (gdi)

Outputs a string at the specified location, using the currently selected font, background color, and text color.


WinAPI - GetClientRect               (user)

Retrieves the coordinates of the client area.  This example draws a frame around the client area.  It also serves as an example of CreatePen, SetCapture, ReleaseCapture, InvalidateRect, SelectObject, Rectangle, lstrcpy, lstrlen and DeleteObject.

NOTE: this example does not include code to eliminate or minimize flicker,which would not be hard to implement (left for future example.)



WinAPI - Windows Bitness       (technique)

This version includes minor editing of the comments and loads csrss.exe as an image resource instead of a data file.  Since Windows uses the low bits of the load address to indicate the mode the file was loaded in, this version aligns the load address instead of simply subtracting one (1) which is valid only when the module is loaded as a data file.  Using alignment works regardless of the way the module is loaded.

recommendation : replace the previous version with this version.


What follows is the code for the GetClientRect example (the source for the remaining examples is present in the zip file attached to this post.)

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$APPTYPE        GUI} {$LONGSTRINGS    OFF}{$WRITEABLECONST ON}{$DESCRIPTION    'Win32 API function - GetClientRect example'} {$R GetClientRect.Res} program _GetClientRect;  { Win32 API function - GetClientRect example                                } uses Windows, Messages, Resource, SysUtils; const  AppNameBase  = 'GetClientRect Example';   {$ifdef WIN64}    Bitness64  = ' - 64bit';    AppName    = AppNameBase + Bitness64;  {$else}    Bitness32  = ' - 32bit';    AppName    = AppNameBase + Bitness32;  {$endif}   AboutBox     = 'AboutBox';  APPICON      = 'APPICON';  APPMENU      = 'APPMENU'; {-----------------------------------------------------------------------------} {$ifdef VER90} { Delphi 2.0 }type  ptrint  = longint;  ptruint = dword;{$endif} {-----------------------------------------------------------------------------} function About(DlgWnd : hWnd; Msg : UINT; wParam, lParam : ptrint)         : ptrint; stdcall;begin  About := ord(TRUE);   case msg of     WM_INITDIALOG: exit;     WM_COMMAND:    begin      if (LOWORD(wParam) = IDOK) or (LOWORD(wParam) = IDCANCEL) then      begin        EndDialog(DlgWnd, ord(TRUE));         exit;      end;    end;  end;   About := ord(FALSE);end; {-----------------------------------------------------------------------------} function WndProc (Wnd : hWnd; Msg : UINT; wParam, lParam : ptrint)         : ptrint; stdcall;  { main application/window handler function                                  }const  GetClientRect_Call = 'GetClientRect (Wnd : HWND; var Rect : TRECT) : BOOL;';   Pen                : HPEN = 0;      { deleted when the window is destroyed  }   Hint = 'Press the Left mouse button anywhere in the client area';   Tracking           : BOOL = FALSE; var  ps                 : TPAINTSTRUCT;   ClientRect         : TRECT;   Buf                : packed array[0..255] of char;   TextSize           : TSIZE;  OldPen             : HPEN; begin  WndProc := 0;   case Msg of    WM_CREATE:    begin      {-----------------------------------------------------------------------}      { Using "not GetSysColor(COLOR_WINDOW)" guarantees that the pen will    }      { be created using a color that will always be visible.  Note that      }      { for this to be true, the value passed to GetSysColor must be the      }      { same as the one passed when the class was registered.                 }       { We AND with $00FFFFFF to make sure that the high byte is zero.        }      { Windows uses this byte to select a palette which is not something     }      { we want it to do in this occasion.                                    }       Pen := CreatePen(PS_INSIDEFRAME,                       3,                       not GetSysColor(COLOR_WINDOW) and $00FFFFFF);      exit;    end;     WM_LBUTTONDOWN:    begin      {-----------------------------------------------------------------------}      { capture the mouse to make sure we always get the button up which      }      { is the signal to refresh the client area.                             }       SetCapture(Wnd);      Tracking := TRUE;      InvalidateRect(Wnd, nil, TRUE);       exit;    end;     WM_LBUTTONUP:    begin      {-----------------------------------------------------------------------}      { if the mouse was not captured then we don't have anything to do       }       if Tracking then      begin        ReleaseCapture;                   { let the cat play with it          }         Tracking := FALSE;        InvalidateRect(Wnd, nil, TRUE);   { redraw the client area            }      end;       exit;    end;     WM_PAINT:    begin      BeginPaint(Wnd, ps);       { set up the dc                                                         }       SetBkMode(ps.hdc, TRANSPARENT);      SetTextAlign(ps.hdc, TA_CENTER);       GetClientRect(Wnd, ClientRect);       { we'll use this quite often      }       if Tracking then      begin        {---------------------------------------------------------------------}        { we have the mouse captured. we draw a frame around the client       }        { rectangle and display its size.                                     }         OldPen := SelectObject(ps.hdc, Pen);        SelectObject(ps.hdc, GetStockObject(NULL_BRUSH));         {---------------------------------------------------------------------}        { draw a frame around the client area. This could be done using       }        { the FrameRect API instead of Rectangle.                             }         with ClientRect do        begin          Rectangle(ps.hdc, Left, Top, Right, Bottom);        end;         {---------------------------------------------------------------------}        { draw the size of the client area                                    }         SelectObject(ps.hdc, OldPen);         with ClientRect do        begin          StrFmt(Buf,                 '(Left, Top) (%d, %d) - (Right, Bottom) (%d, %d)',                 [Left, Top, Right, Bottom]);        end;         { the code outside the if statement will output the buffer            }      end      else      begin        {---------------------------------------------------------------------}        { we don't have the mouse captured.  we draw a string giving          }        { the user a hint about what to do next.                              }         lstrcpy(Buf, Hint);      end;       {-----------------------------------------------------------------------}      { calculate the size of the output string currently in Buf              }       GetTextExtentPoint32(ps.hdc,                           Buf,                           lstrlen(Buf), TextSize);      TextOut(ps.hdc,              ClientRect.Right  div 2,              ClientRect.Bottom div 2 - TextSize.cy,              Buf,              lstrlen(Buf));       {-----------------------------------------------------------------------}      { draw the function call                                                }       SelectObject(ps.hdc, GetStockObject(DEFAULT_GUI_FONT));      SetTextAlign(ps.hdc, TA_CENTER or TA_BOTTOM);       lstrcpy(Buf, GetClientRect_Call);       { calculate the size of the output string                               }       GetTextExtentPoint32(ps.hdc,                           Buf,                           lstrlen(Buf), TextSize);      TextOut(ps.hdc,              ClientRect.Right div 2,              ClientRect.Bottom - TextSize.cy,              Buf,              lstrlen(Buf));       {-----------------------------------------------------------------------}      { we're done painting                                                   }       EndPaint(Wnd, ps);       exit;    end;     WM_COMMAND:    begin      case LOWORD(wParam) of        IDM_ABOUT:        begin          DialogBox(hInstance, ABOUTBOX, Wnd, @About);           exit;        end; { IDM_ABOUT }         IDM_EXIT:        begin          DestroyWindow(Wnd);           exit;        end; { IDM_EXIT }      end; { case LOWORD(wParam) }    end; { WM_COMMAND }     WM_DESTROY:    begin      if Pen <> 0 then DeleteObject(Pen);        PostQuitMessage(0);       exit;    end; { WM_DESTROY }  end; { case msg }   WndProc := DefWindowProc (Wnd, Msg, wParam, lParam);end; {-----------------------------------------------------------------------------} function InitAppClass : WordBool;  { registers the application's window classes                                }var  cls : TWndClassEx; begin  cls.cbSize          := sizeof(TWndClassEx);         { must be initialized   }   if not GetClassInfoEx (hInstance, AppName, cls) then  begin    with cls do begin      { cbSize has already been initialized as required above                 }       style           := CS_BYTEALIGNCLIENT;      lpfnWndProc     := @WndProc;                    { window class handler  }      cbClsExtra      := 0;      cbWndExtra      := 0;      hInstance       := system.hInstance;            { qualify instance!     }      hIcon           := LoadIcon (hInstance, APPICON);      hCursor         := LoadCursor(0, idc_arrow);      hbrBackground   := GetSysColorBrush(COLOR_WINDOW);      lpszMenuName    := APPMENU;                     { Menu name             }      lpszClassName   := AppName;                     { Window Class name     }      hIconSm         := LoadImage(hInstance,                                   APPICON,                                   IMAGE_ICON,                                   16,                                   16,                                   LR_DEFAULTCOLOR);    end; { with }     InitAppClass := WordBool(RegisterClassEx(cls));  end  else InitAppClass := true;end; {-----------------------------------------------------------------------------} function WinMain : integer;  { application entry point                                                   }var  Wnd : hWnd;  Msg : TMsg; begin  if not InitAppClass then Halt (255);  { register application's class        }   { Create the main application window                                        }   Wnd := CreateWindowEx(WS_EX_CLIENTEDGE,                        AppName,                { class name                  }                        AppName,                { window caption text         }                        ws_Overlapped       or  { window style                }                        ws_SysMenu          or                        ws_MinimizeBox      or                        ws_ClipSiblings     or                        ws_ClipChildren     or  { don't affect children       }                        ws_visible,             { make showwindow unnecessary }                        50,                     { x pos on screen             }                        50,                     { y pos on screen             }                        400,                    { window width                }                        300,                    { window height               }                        0,                      { parent window handle        }                        0,                      { menu handle 0 = use class   }                        hInstance,              { instance handle             }                        Nil);                   { parameter sent to WM_CREATE }   if Wnd = 0 then Halt;                         { could not create the window }   while GetMessage (Msg, 0, 0, 0) do            { wait for message            }  begin    TranslateMessage (Msg);                     { key conversions             }    DispatchMessage  (Msg);                     { send to window procedure    }  end;   WinMain := Msg.wParam;                        { terminate with return code  }end; begin  WinMain;end. This example also shows how and when to capture the mouse to cause it to update the client area when necessary.  It also serves as an example for CreatePen, SelectObject, Rectangle and DeleteObject.

FlierMate:
Please allow me to ask two general questions here:

1. Can we say Windows API is a "framework"?

2. Windows API is at the lowest level. Does that mean literally nobody knows how Windows execute the API call?



440bx:

--- Quote from: FlierMate on January 21, 2021, 12:09:54 pm ---Please allow me to ask two general questions here:

1. Can we say Windows API is a "framework"?

2. Windows API is at the lowest level. Does that mean literally nobody knows how Windows execute the API call?

--- End quote ---
All questions are welcome.

To the first question, I don't consider the Windows API a framework because, unlike in a framework, a great number of APIs are completely independent of each other.  A framework usually incorporates a significant number of dependencies among the facilities it provides, e.g, .net.

To the second question, a lot of people know _exactly_ how Windows executes its API functions.  A lot of API functions can be traced through using an application debugger.  APIs that cause a ring transition, that is from ring-3 to ring-0, can be traced through using a system debugger.  Another way to see exactly what an API does and, how it does it, is to disassemble the DLL that contains it.

In summary, except for ring transition code and code that executes in ring 0, there is nothing particularly different between Windows API functions and run of the mill code that can be found in application code.  For instance, an API such as DebugBreak() can be written as a Pascal assembler routine in just two lines of assembly code.  Other APIs would require more code and yet other APIs would require calling functions present in Ntdll to trigger execution of ring-0 code (though, even those could be coded in Pascal but, why re-invent the wheel.)

PascalDragon:

--- Quote from: FlierMate on January 21, 2021, 12:09:54 pm ---2. Windows API is at the lowest level. Does that mean literally nobody knows how Windows execute the API call?

--- End quote ---

In addition to what 440bx said: if you're really curious you can look around in ReactOS' source code and find out how some calls are implemented (I've done that in the past a few times to find out how some API functions work).

FlierMate:


--- Quote from: PascalDragon on January 21, 2021, 01:57:29 pm ---In addition to what 440bx said: if you're really curious you can look around in ReactOS' source code and find out how some calls are implemented

--- End quote ---

Whoa, I completely forgot an operating system is written NOT in Assembly language.

ReactOS was written in C...


--- Quote from: 440bx on January 21, 2021, 12:57:45 pm ---All questions are welcome.

--- End quote ---

Thank you for the assurance.


--- Quote from: 440bx on January 21, 2021, 12:57:45 pm --- Another way to see exactly what an API does and, how it does it, is to disassemble the DLL that contains it.

--- End quote ---

Never thought of that. I am delighted to know this.


--- Quote from: 440bx on January 21, 2021, 12:57:45 pm --- For instance, an API such as DebugBreak() can be written as a Pascal assembler routine in just two lines of assembly code. 

--- End quote ---

This makes sense to me.


--- Quote from: PascalDragon on January 21, 2021, 01:57:29 pm ---(I've done that in the past a few times to find out how some API functions work).

--- End quote ---

This means an operating system is not a secret. (I am new to the design of OS and just at very beginning level of design of compiler.) Besides CPU itself, an operating system is such a massive and intelligent work by men.

As an off-topic question: I often saw someone comes up with real-time operating system on freelancer hiring website, is it a hoax? 

It was thrilling to discover ReactOS open-source page. All contributors deserve respect!

Navigation

[0] Message Index

[#] Next page

Go to full version