Recent

Author Topic: WinAPI - examples - post 2  (Read 600 times)

440bx

  • Hero Member
  • *****
  • Posts: 2167
WinAPI - examples - post 2
« on: January 17, 2021, 08:38:45 am »
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  [Select][+][-]
  1. {$APPTYPE        GUI}
  2.  
  3. {$LONGSTRINGS    OFF}
  4. {$WRITEABLECONST ON}
  5. {$DESCRIPTION    'Win32 API function - GetClientRect example'}
  6.  
  7. {$R GetClientRect.Res}
  8.  
  9. program _GetClientRect;
  10.   { Win32 API function - GetClientRect example                                }
  11.  
  12. uses Windows, Messages, Resource, SysUtils;
  13.  
  14. const
  15.   AppNameBase  = 'GetClientRect Example';
  16.  
  17.   {$ifdef WIN64}
  18.     Bitness64  = ' - 64bit';
  19.     AppName    = AppNameBase + Bitness64;
  20.   {$else}
  21.     Bitness32  = ' - 32bit';
  22.     AppName    = AppNameBase + Bitness32;
  23.   {$endif}
  24.  
  25.   AboutBox     = 'AboutBox';
  26.   APPICON      = 'APPICON';
  27.   APPMENU      = 'APPMENU';
  28.  
  29. {-----------------------------------------------------------------------------}
  30.  
  31. {$ifdef VER90} { Delphi 2.0 }
  32. type
  33.   ptrint  = longint;
  34.   ptruint = dword;
  35. {$endif}
  36.  
  37. {-----------------------------------------------------------------------------}
  38.  
  39. function About(DlgWnd : hWnd; Msg : UINT; wParam, lParam : ptrint)
  40.          : ptrint; stdcall;
  41. begin
  42.   About := ord(TRUE);
  43.  
  44.   case msg of
  45.  
  46.     WM_INITDIALOG: exit;
  47.  
  48.     WM_COMMAND:
  49.     begin
  50.       if (LOWORD(wParam) = IDOK) or (LOWORD(wParam) = IDCANCEL) then
  51.       begin
  52.         EndDialog(DlgWnd, ord(TRUE));
  53.  
  54.         exit;
  55.       end;
  56.     end;
  57.   end;
  58.  
  59.   About := ord(FALSE);
  60. end;
  61.  
  62. {-----------------------------------------------------------------------------}
  63.  
  64. function WndProc (Wnd : hWnd; Msg : UINT; wParam, lParam : ptrint)
  65.          : ptrint; stdcall;
  66.   { main application/window handler function                                  }
  67. const
  68.   GetClientRect_Call = 'GetClientRect (Wnd : HWND; var Rect : TRECT) : BOOL;';
  69.  
  70.   Pen                : HPEN = 0;      { deleted when the window is destroyed  }
  71.  
  72.   Hint = 'Press the Left mouse button anywhere in the client area';
  73.  
  74.   Tracking           : BOOL = FALSE;
  75.  
  76. var
  77.   ps                 : TPAINTSTRUCT;
  78.  
  79.   ClientRect         : TRECT;
  80.  
  81.   Buf                : packed array[0..255] of char;
  82.  
  83.   TextSize           : TSIZE;
  84.   OldPen             : HPEN;
  85.  
  86. begin
  87.   WndProc := 0;
  88.  
  89.   case Msg of
  90.     WM_CREATE:
  91.     begin
  92.       {-----------------------------------------------------------------------}
  93.       { Using "not GetSysColor(COLOR_WINDOW)" guarantees that the pen will    }
  94.       { be created using a color that will always be visible.  Note that      }
  95.       { for this to be true, the value passed to GetSysColor must be the      }
  96.       { same as the one passed when the class was registered.                 }
  97.  
  98.       { We AND with $00FFFFFF to make sure that the high byte is zero.        }
  99.       { Windows uses this byte to select a palette which is not something     }
  100.       { we want it to do in this occasion.                                    }
  101.  
  102.       Pen := CreatePen(PS_INSIDEFRAME,
  103.                        3,
  104.                        not GetSysColor(COLOR_WINDOW) and $00FFFFFF);
  105.       exit;
  106.     end;
  107.  
  108.     WM_LBUTTONDOWN:
  109.     begin
  110.       {-----------------------------------------------------------------------}
  111.       { capture the mouse to make sure we always get the button up which      }
  112.       { is the signal to refresh the client area.                             }
  113.  
  114.       SetCapture(Wnd);
  115.       Tracking := TRUE;
  116.       InvalidateRect(Wnd, nil, TRUE);
  117.  
  118.       exit;
  119.     end;
  120.  
  121.     WM_LBUTTONUP:
  122.     begin
  123.       {-----------------------------------------------------------------------}
  124.       { if the mouse was not captured then we don't have anything to do       }
  125.  
  126.       if Tracking then
  127.       begin
  128.         ReleaseCapture;                   { let the cat play with it          }
  129.  
  130.         Tracking := FALSE;
  131.         InvalidateRect(Wnd, nil, TRUE);   { redraw the client area            }
  132.       end;
  133.  
  134.       exit;
  135.     end;
  136.  
  137.     WM_PAINT:
  138.     begin
  139.       BeginPaint(Wnd, ps);
  140.  
  141.       { set up the dc                                                         }
  142.  
  143.       SetBkMode(ps.hdc, TRANSPARENT);
  144.       SetTextAlign(ps.hdc, TA_CENTER);
  145.  
  146.       GetClientRect(Wnd, ClientRect);       { we'll use this quite often      }
  147.  
  148.       if Tracking then
  149.       begin
  150.         {---------------------------------------------------------------------}
  151.         { we have the mouse captured. we draw a frame around the client       }
  152.         { rectangle and display its size.                                     }
  153.  
  154.         OldPen := SelectObject(ps.hdc, Pen);
  155.         SelectObject(ps.hdc, GetStockObject(NULL_BRUSH));
  156.  
  157.         {---------------------------------------------------------------------}
  158.         { draw a frame around the client area. This could be done using       }
  159.         { the FrameRect API instead of Rectangle.                             }
  160.  
  161.         with ClientRect do
  162.         begin
  163.           Rectangle(ps.hdc, Left, Top, Right, Bottom);
  164.         end;
  165.  
  166.         {---------------------------------------------------------------------}
  167.         { draw the size of the client area                                    }
  168.  
  169.         SelectObject(ps.hdc, OldPen);
  170.  
  171.         with ClientRect do
  172.         begin
  173.           StrFmt(Buf,
  174.                  '(Left, Top) (%d, %d) - (Right, Bottom) (%d, %d)',
  175.                  [Left, Top, Right, Bottom]);
  176.         end;
  177.  
  178.         { the code outside the if statement will output the buffer            }
  179.       end
  180.       else
  181.       begin
  182.         {---------------------------------------------------------------------}
  183.         { we don't have the mouse captured.  we draw a string giving          }
  184.         { the user a hint about what to do next.                              }
  185.  
  186.         lstrcpy(Buf, Hint);
  187.       end;
  188.  
  189.       {-----------------------------------------------------------------------}
  190.       { calculate the size of the output string currently in Buf              }
  191.  
  192.       GetTextExtentPoint32(ps.hdc,
  193.                            Buf,
  194.                            lstrlen(Buf), TextSize);
  195.       TextOut(ps.hdc,
  196.               ClientRect.Right  div 2,
  197.               ClientRect.Bottom div 2 - TextSize.cy,
  198.               Buf,
  199.               lstrlen(Buf));
  200.  
  201.       {-----------------------------------------------------------------------}
  202.       { draw the function call                                                }
  203.  
  204.       SelectObject(ps.hdc, GetStockObject(DEFAULT_GUI_FONT));
  205.       SetTextAlign(ps.hdc, TA_CENTER or TA_BOTTOM);
  206.  
  207.       lstrcpy(Buf, GetClientRect_Call);
  208.  
  209.       { calculate the size of the output string                               }
  210.  
  211.       GetTextExtentPoint32(ps.hdc,
  212.                            Buf,
  213.                            lstrlen(Buf), TextSize);
  214.       TextOut(ps.hdc,
  215.               ClientRect.Right div 2,
  216.               ClientRect.Bottom - TextSize.cy,
  217.               Buf,
  218.               lstrlen(Buf));
  219.  
  220.       {-----------------------------------------------------------------------}
  221.       { we're done painting                                                   }
  222.  
  223.       EndPaint(Wnd, ps);
  224.  
  225.       exit;
  226.     end;
  227.  
  228.     WM_COMMAND:
  229.     begin
  230.       case LOWORD(wParam) of
  231.         IDM_ABOUT:
  232.         begin
  233.           DialogBox(hInstance, ABOUTBOX, Wnd, @About);
  234.  
  235.           exit;
  236.         end; { IDM_ABOUT }
  237.  
  238.         IDM_EXIT:
  239.         begin
  240.           DestroyWindow(Wnd);
  241.  
  242.           exit;
  243.         end; { IDM_EXIT }
  244.       end; { case LOWORD(wParam) }
  245.     end; { WM_COMMAND }
  246.  
  247.     WM_DESTROY:
  248.     begin
  249.       if Pen <> 0 then DeleteObject(Pen);
  250.  
  251.  
  252.       PostQuitMessage(0);
  253.  
  254.       exit;
  255.     end; { WM_DESTROY }
  256.   end; { case msg }
  257.  
  258.   WndProc := DefWindowProc (Wnd, Msg, wParam, lParam);
  259. end;
  260.  
  261. {-----------------------------------------------------------------------------}
  262.  
  263. function InitAppClass : WordBool;
  264.   { registers the application's window classes                                }
  265. var
  266.   cls : TWndClassEx;
  267.  
  268. begin
  269.   cls.cbSize          := sizeof(TWndClassEx);         { must be initialized   }
  270.  
  271.   if not GetClassInfoEx (hInstance, AppName, cls) then
  272.   begin
  273.     with cls do begin
  274.       { cbSize has already been initialized as required above                 }
  275.  
  276.       style           := CS_BYTEALIGNCLIENT;
  277.       lpfnWndProc     := @WndProc;                    { window class handler  }
  278.       cbClsExtra      := 0;
  279.       cbWndExtra      := 0;
  280.       hInstance       := system.hInstance;            { qualify instance!     }
  281.       hIcon           := LoadIcon (hInstance, APPICON);
  282.       hCursor         := LoadCursor(0, idc_arrow);
  283.       hbrBackground   := GetSysColorBrush(COLOR_WINDOW);
  284.       lpszMenuName    := APPMENU;                     { Menu name             }
  285.       lpszClassName   := AppName;                     { Window Class name     }
  286.       hIconSm         := LoadImage(hInstance,
  287.                                    APPICON,
  288.                                    IMAGE_ICON,
  289.                                    16,
  290.                                    16,
  291.                                    LR_DEFAULTCOLOR);
  292.     end; { with }
  293.  
  294.     InitAppClass := WordBool(RegisterClassEx(cls));
  295.   end
  296.   else InitAppClass := true;
  297. end;
  298.  
  299. {-----------------------------------------------------------------------------}
  300.  
  301. function WinMain : integer;
  302.   { application entry point                                                   }
  303. var
  304.   Wnd : hWnd;
  305.   Msg : TMsg;
  306.  
  307. begin
  308.   if not InitAppClass then Halt (255);  { register application's class        }
  309.  
  310.   { Create the main application window                                        }
  311.  
  312.   Wnd := CreateWindowEx(WS_EX_CLIENTEDGE,
  313.                         AppName,                { class name                  }
  314.                         AppName,                { window caption text         }
  315.                         ws_Overlapped       or  { window style                }
  316.                         ws_SysMenu          or
  317.                         ws_MinimizeBox      or
  318.                         ws_ClipSiblings     or
  319.                         ws_ClipChildren     or  { don't affect children       }
  320.                         ws_visible,             { make showwindow unnecessary }
  321.                         50,                     { x pos on screen             }
  322.                         50,                     { y pos on screen             }
  323.                         400,                    { window width                }
  324.                         300,                    { window height               }
  325.                         0,                      { parent window handle        }
  326.                         0,                      { menu handle 0 = use class   }
  327.                         hInstance,              { instance handle             }
  328.                         Nil);                   { parameter sent to WM_CREATE }
  329.  
  330.   if Wnd = 0 then Halt;                         { could not create the window }
  331.  
  332.   while GetMessage (Msg, 0, 0, 0) do            { wait for message            }
  333.   begin
  334.     TranslateMessage (Msg);                     { key conversions             }
  335.     DispatchMessage  (Msg);                     { send to window procedure    }
  336.   end;
  337.  
  338.   WinMain := Msg.wParam;                        { terminate with return code  }
  339. end;
  340.  
  341. begin
  342.   WinMain;
  343. end.
  344.  
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.

« Last Edit: January 17, 2021, 08:47:22 am by 440bx »
FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

FlierMate

  • Jr. Member
  • **
  • Posts: 59
Re: WinAPI - examples - post 2
« Reply #1 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?



FPC 3.2.0 on i386-Win32.

440bx

  • Hero Member
  • *****
  • Posts: 2167
Re: WinAPI - examples - post 2
« Reply #2 on: January 21, 2021, 12:57:45 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?
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.)

FPC v3.0.4 and Lazarus 1.8.2 on Windows 7 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 2747
  • Compiler Developer
Re: WinAPI - examples - post 2
« Reply #3 on: January 21, 2021, 01:57:29 pm »
2. Windows API is at the lowest level. Does that mean literally nobody knows how Windows execute the API call?

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

  • Jr. Member
  • **
  • Posts: 59
Re: WinAPI - examples - post 2
« Reply #4 on: January 21, 2021, 02:32:42 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

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

ReactOS was written in C...

All questions are welcome.

Thank you for the assurance.

Another way to see exactly what an API does and, how it does it, is to disassemble the DLL that contains it.

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

For instance, an API such as DebugBreak() can be written as a Pascal assembler routine in just two lines of assembly code. 

This makes sense to me.

(I've done that in the past a few times to find out how some API functions work).

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!
FPC 3.2.0 on i386-Win32.

lucamar

  • Hero Member
  • *****
  • Posts: 3591
Re: WinAPI - examples - post 2
« Reply #5 on: January 21, 2021, 04:27:21 pm »
As an off-topic question: I often saw someone comes up with real-time operating system on freelancer hiring website, is it a hoax?

Why would it be? Lots of people and business need real time OSs and there is not always one readily available for download/purchase; the obvious solution then is to contract some freelancer and pay them (oftentimes through the nose ;)) to build one, more or so as they usually have a very specific scope and need not be what we might term a "general purpose" OS. In fact, OS and application are frequently so interwoven that it's not very clear where one ends and the other starts.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.10/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

FlierMate

  • Jr. Member
  • **
  • Posts: 59
Re: WinAPI - examples - post 2
« Reply #6 on: January 21, 2021, 05:29:35 pm »
Why would it be? Lots of people and business need real time OSs and there is not always one readily available for download/purchase; the obvious solution then is to contract some freelancer and pay them (oftentimes through the nose ;)) to build one, more or so as they usually have a very specific scope and need not be what we might term a "general purpose" OS. In fact, OS and application are frequently so interwoven that it's not very clear where one ends and the other starts.

I have better understanding now. Thanks lucamar.
FPC 3.2.0 on i386-Win32.

PascalDragon

  • Hero Member
  • *****
  • Posts: 2747
  • Compiler Developer
Re: WinAPI - examples - post 2
« Reply #7 on: January 22, 2021, 09:09:40 am »
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

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

ReactOS was written in C...

Windows itself is written in C as well. As is Linux. There are also OSes written in Pascal. Or essentially any language that can compile binary code. And yes, there are also examples in assembly language. ;)

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

Depends on whether the developers know what they're doing. At work we have a custom realtime, microkernel operating system as well. ;)

 

TinyPortal © 2005-2018