Recent

Author Topic: Windows API test programs / Examples  (Read 12177 times)

440bx

  • Hero Member
  • *****
  • Posts: 3946
WinAPI - Windows bitness & Teaser programs
« Reply #15 on: January 14, 2021, 06:14:21 pm »
Hello,

Attached to this post are six (6) "teaser" API programs that give an idea of what these programs/examples are about.  In addition, there is a "Windows Bitness" program that is more an illustration of how to get the Windows bitness than how to use a specific API.

The teaser examples do _not_ include source at this time.  I will include the source when the time comes to give an example of the API they demonstrate.  The "Windows Bitness" includes full source to give an idea of what the source code for a typical example looks like. 

I will first give a quick description of the purpose of the "teaser" programs before discussing details of the "Windows Bitness" program.  The teaser program/examples are:

ExpandEnvironmentStrings

This is an example of the many trivial API functions in Windows.  These are APIs that don't have much to say about them.  IOW, you read its documentation in MSDN, code the call and you're done.

Roughly (iow, an estimate) 50% of the examples fall in that category.  Their main reason to exist was to test their performance and/or behavior in unusual cases.  (those were my personal reasons.)


SetConsoleWindowInfo

The description of SetConsoleWindowInfo in MSDN isn't particularly enlightening and the MSDN example's purpose seems to be to confuse the reader (just in case you understood the questionable description that preceded it.) 

The teaser example is a visual representation of how that API works.  It shows the parameters before the call, the parameters after the call and the effects of the call.

Roughly, 10% of the examples fall in that category (API operation visualization).

I won't go into a detailed explanation at this time.  It will be included along with the program source when it is its turn.


ExtTextOut (two (2) examples)
InvalidateRect
SelectClipRgn

These examples, in addition to demonstrating what the API does and how it works are related by one common goal which is, reducing or eliminating _flicker_ when redrawing.

The InvalidateRect example flickers when the mouse coordinates are updated in the area dedicated to them.  Selecting "Invalidate entire area" from the InvalidateRect menu shows how the size of the invalid area makes the flicker more noticeable.


ExtTextOut (v1)

That example is almost identical to the InvalidateRect example but, it demonstrates how to use ExtTextOut to significantly reduce flicker.  In the case of the example, to a level that is almost imperceptible.


ExtTextOut (v0)

This example also demonstrates how to significantly reduce flicker but in a larger area.  It also demonstrates the clipping abilities of ExtTextOut.   The example also shows how to slow a GUI program down by using a console and, how to use the console to help in debugging.


SelectClipRgn

This example shows one the ways available to totally eliminate flicker (zero flicker without using double buffering.)  Resize the window horizontally and/or vertically.  Control flicker/no flicker with the menu options under "Flicker".



Window Bitness

Consider a program, let's call it program "A" that can be compiled as a 32 bit and 64 bit versions.

The 64 bit version of the program has it easy.  All it has to do is determine that it is itself a 64 bit program, once it knows that, it must be running on a 64 bit version of Windows (until MS releases a 128 bit version of Windows - won't happen tomorrow.)  To determine if it is itself a 64 bit program, all it has to do is check the size of a pointer, i.e, sizeof(pointer) and if the size is 8 then it knows that it is a 64 bit program and since it is running, it must be running under a 64 bit version of Windows.  Easy as pie.

The 32 bit version cannot use that "trick" since its pointer size will be four (4) whether or not it is running under a 32 bit or 64 bit version of Windows.

MS would have the programmer use the IsWowProcess() or IsWowProcess2() API to make the determination but, those two APIs have a few annoyances associated with them.  First, they may not be present (IsWowProcess() requires XP SP2 or higher) and, even when present, the user running the program must have some privileges, that while not high, he/she may not have.

There is a way to determine the bitness without using either or these APIs that do not require the user to have any "special" privileges.  The "trick" resides in two details.  The first one is that the Windows server is what determines the Windows bitness, the second one is that LoadLibraryEx will load almost anything you want as long as you don't intend to run it.

Using the first observation, if Windows is 32 bit then its csrss.exe (client service runtime subsystem) will also be 32 bit and, it will always be 64 bit in a 64 bit version of Windows.

Using the second observation, we can simply ask LoadLibraryEx to load csrss.exe as a datafile and unless the user is totally "privilege destitute", LoadLibraryEx will serve csrss.exe in a sliver platter. 

All that's left is for the program to rummage in csrss.exe to determine its bitness and whatever its bitness is, that's the Windows bitness too :)  Done!

That's what the program below does (full source in the attachment)
Code: Pascal  [Select][+][-]
  1. {$define         DEBUG}     { to cause a breakpoint in WM_CREATE handler      }
  2.  
  3. {$APPTYPE        GUI}
  4.  
  5. {$LONGSTRINGS    OFF}
  6. {$WRITEABLECONST ON}
  7. {$DESCRIPTION    'Win32 API function - WindowsBitness example'}
  8.  
  9. {$R WindowsBitness.Res}
  10.  
  11. program _WindowsBitness;
  12.   { Win32 technique - WindowsBitness example                                  }
  13.  
  14. uses Windows,
  15.      Messages,
  16.      Resource
  17.      ;
  18.  
  19. const
  20.   AppNameBase  = 'WindowsBitness';
  21.  
  22.   {$ifdef WIN64}                         { heading for 64 bit                 }
  23.     Bitness64  = ' - 64bit';
  24.     AppName    = AppNameBase + Bitness64;
  25.   {$else}                                { heading for 32 bit                 }
  26.     Bitness32  = ' - 32bit';
  27.     AppName    = AppNameBase + Bitness32;
  28.   {$endif}
  29.  
  30.   AboutBox     = 'AboutBox';
  31.   APPICON      = 'APPICON';
  32.   APPMENU      = 'APPMENU';
  33.  
  34. {-----------------------------------------------------------------------------}
  35.  
  36. {$ifdef VER90} { Delphi 2.0 }
  37. type
  38.   ptrint  = longint;
  39.   ptruint = dword;
  40. {$endif}
  41.  
  42. {$include ImageHeaders.inc}
  43.  
  44. function IsDebuggerPresent                       { missing in Delphi 2        }
  45.          : BOOL; stdcall; external 'kernel32';
  46.  
  47.  
  48. {-----------------------------------------------------------------------------}
  49.  
  50. function About(DlgWnd : hWnd; Msg : UINT; wParam, lParam : ptrint)
  51.          : ptrint; stdcall;
  52. begin
  53.   About := ord(TRUE);
  54.  
  55.   case Msg of
  56.  
  57.     WM_INITDIALOG: exit;
  58.  
  59.     WM_COMMAND:
  60.     begin
  61.       if (LOWORD(wParam) = IDOK) or (LOWORD(wParam) = IDCANCEL) then
  62.       begin
  63.         EndDialog(DlgWnd, ord(TRUE));
  64.  
  65.         exit;
  66.       end;
  67.     end;
  68.   end;
  69.  
  70.   About := ord(FALSE);
  71. end;
  72.  
  73. {-----------------------------------------------------------------------------}
  74.  
  75. function GetModuleBitness(Module : HMODULE) : integer;
  76. var
  77.   DosHeader      : PIMAGE_DOS_HEADER;
  78.   NtHeader       : PIMAGE_NT_HEADERS;
  79.   OptionalHeader : PIMAGE_OPTIONAL_HEADER;
  80.  
  81. begin
  82.   result := 0;
  83.  
  84.   HMODULE(DosHeader) := Module;
  85.  
  86.   { ensure we got a valid PE file                                             }
  87.  
  88.   if IsBadReadPtr(DosHeader, sizeof(DosHeader^))           then exit;
  89.   if DosHeader^.Signature <> IMAGE_DOS_SIGNATURE           then exit;
  90.  
  91.   pointer(NtHeader) := pchar(DosHeader) + DosHeader^.OffsetToNewExecutable;
  92.  
  93.   if IsBadReadPtr(NtHeader, sizeof(NtHeader^))             then exit;
  94.  
  95.   OptionalHeader := @NtHeader^.OptionalHeader;
  96.  
  97.   if IsBadReadPtr(OptionalHeader, sizeof(OptionalHeader^)) then exit;
  98.  
  99.   case OptionalHeader^.Magic of
  100.     IMAGE_NT_OPTIONAL_HDR32_MAGIC : result := 32;
  101.     IMAGE_NT_OPTIONAL_HDR64_MAGIC : result := 64;
  102.  
  103.     { otherwise leave it at zero                                              }
  104.   end;
  105. end;
  106.  
  107. {-----------------------------------------------------------------------------}
  108.  
  109. function WndProc (Wnd : HWND; Msg : UINT; wParam, lParam : ptrint)
  110.          : ptrint; stdcall;
  111.   { main application/window handler function                                  }
  112. const
  113.   WindowBitness_Call     = 'Windows bitness';
  114.  
  115.   Bitness32              = 'This is a 32 bit Windows installation'#0;
  116.   Bitness64              = 'This is a 64 bit Windows installation'#0;
  117.  
  118.   BitnessUnknown         = 'failed to determine this Windows installation '   +
  119.                            'bitness'#0;
  120.  
  121.   { initialize to "unknown" until we determine the Windows bitness            }
  122.  
  123.   Bitness                : pchar = BitnessUnknown;
  124.  
  125.   CSRSS                  = 'csrss.exe';
  126.   BACKSLASH              = '\';
  127.  
  128.   _64BIT_POINTER_SIZE    = 8;
  129.  
  130. var
  131.   ps                     : TPAINTSTRUCT;
  132.   ClientRect             : TRECT;
  133.  
  134.   TextSize               : TSIZE;
  135.  
  136.   CsrssFullpath : packed array[0..511] of char;
  137.  
  138.   i                      : DWORD;
  139.   CsrssLoadAddress       : HMODULE;
  140.   LoadAddress            : HMODULE;
  141.  
  142. begin
  143.   WndProc := 0;
  144.  
  145.   case Msg of
  146.     WM_CREATE:
  147.     begin
  148.       {$ifdef DEBUG}
  149.         if IsDebuggerPresent() then DebugBreak();
  150.       {$endif}
  151.  
  152.  
  153.       { when using FPC and compiling for 32 bit, ignore the unreachable code  }
  154.       { warning.                                                              }
  155.  
  156.       if sizeof(pointer) = _64BIT_POINTER_SIZE then
  157.       begin
  158.         { we are a running 64bit program, therefore the Windows installation  }
  159.         { must be 64bit.  Not much to do in this case.                        }
  160.  
  161.         Bitness := Bitness64;
  162.  
  163.         exit;                               { we are done!                    }
  164.       end;
  165.  
  166.       { if we are a 32bit program, we need to find out if this is a 32bit or  }
  167.       { 64bit windows installation.                                           }
  168.  
  169.       ZeroMemory(@CsrssFullpath, sizeof(CsrssFullpath));
  170.       GetSystemDirectory(CsrssFullpath,
  171.                          sizeof(CsrssFullpath));
  172.  
  173.       { append CSRSS to the system directory and a backslash if needed        }
  174.  
  175.       i := lstrlen(CsrssFullpath);
  176.  
  177.       if CsrssFullpath[i - 1] <> BACKSLASH then
  178.       begin
  179.         { append the backslash                                                }
  180.  
  181.         lstrcat(CsrssFullpath, BACKSLASH);
  182.       end;
  183.  
  184.       lstrcat(CsrssFullpath, CSRSS);             { path to CSRSS              }
  185.  
  186.       { load CSRSS as a data file. At this time, Windows will not apply file  }
  187.       { system redirection when the call to LoadLibraryEx is to load a file   }
  188.       { as a data file.  Therefore csrss.exe should have been found, if it    }
  189.       { wasn't then we are dealing with an unexpected situation in which case }
  190.       { we declare the attempt to determine the O/S as having failed.         }
  191.  
  192.       CsrssLoadAddress := LoadLibraryEx(CsrssFullpath,
  193.                                         0,
  194.                                         LOAD_LIBRARY_AS_DATAFILE);
  195.  
  196.       if CsrssLoadAddress = 0 then
  197.       begin
  198.  
  199.         exit;
  200.       end;
  201.  
  202.       { because we specified LOAD_LIBRARY_AS_DATAFILE the load address        }
  203.       { returned isn't "quite right".  When LOAD_LIBRARY_AS_DATAFILE is used  }
  204.       { the address points one (1) byte past the actual load address.  We     }
  205.       { need the "real" address, therefore we subtract one (1) from the       }
  206.       { address returned in this case.                                        }
  207.  
  208.       LoadAddress := CsrssLoadAddress;
  209.       if LoadAddress and $1 <> 0 then
  210.       begin
  211.         dec(LoadAddress);
  212.       end;
  213.  
  214.       { presuming there are only two versions of Windows, a 32 bit version    }
  215.       { and a 64 bit version, the module bitness should be 32 bit, if it      }
  216.       { isn't then we must be running under an unexpected version that is     }
  217.       { neither 32 nor 64 bit.  In that case, the Bitness is left as "unknown"}
  218.  
  219.       case GetModuleBitness(LoadAddress) of
  220.         32 : Bitness := Bitness32;
  221.         64 : Bitness := Bitness64;
  222.       end;
  223.  
  224.       FreeLibrary(CsrssLoadAddress);  { we no longer need it                  }
  225.  
  226.       exit;
  227.     end;
  228.  
  229.     WM_PAINT:
  230.     begin
  231.       BeginPaint(Wnd, ps);
  232.  
  233.       { set up the dc                                                         }
  234.  
  235.       GetClientRect(Wnd, ClientRect);
  236.  
  237.       SelectObject(ps.hdc, GetStockObject(DEFAULT_GUI_FONT));
  238.       SetBkMode(ps.hdc, TRANSPARENT);
  239.       SetTextAlign(ps.hdc, TA_CENTER or TA_BOTTOM);
  240.  
  241.       GetTextExtentPoint32(ps.hdc,
  242.                            Bitness,
  243.                            lstrlen(Bitness),
  244.                            TextSize);
  245.  
  246.       {-----------------------------------------------------------------------}
  247.       { output the bitness of this Windows installation as determined during  }
  248.       { WM_CREATE.                                                            }
  249.  
  250.       TextOut(ps.hdc,
  251.               ClientRect.Right  div 2,
  252.               ClientRect.Bottom div 2,
  253.               Bitness,
  254.               lstrlen(Bitness));
  255.  
  256.  
  257.       {-----------------------------------------------------------------------}
  258.       { draw the function call                                                }
  259.  
  260.       TextOut(ps.hdc,
  261.               ClientRect.Right  div 2,
  262.               ClientRect.Bottom - TextSize.cy,
  263.               WindowBitness_Call,
  264.               lstrlen(WindowBitness_Call));
  265.  
  266.       {-----------------------------------------------------------------------}
  267.       { we're done painting                                                   }
  268.  
  269.       EndPaint(Wnd, ps);
  270.  
  271.       exit;
  272.     end;
  273.  
  274.     WM_COMMAND:
  275.     begin
  276.       case LOWORD(wParam) of
  277.         IDM_ABOUT:
  278.         begin
  279.           DialogBox(hInstance, ABOUTBOX, Wnd, @About);
  280.  
  281.           exit;
  282.         end; { IDM_ABOUT }
  283.  
  284.         IDM_EXIT:
  285.         begin
  286.           DestroyWindow(Wnd);
  287.  
  288.           exit;
  289.         end; { IDM_EXIT }
  290.       end; { case LOWORD(wParam) }
  291.     end; { WM_COMMAND }
  292.  
  293.     WM_DESTROY:
  294.     begin
  295.       PostQuitMessage(0);
  296.  
  297.       exit;
  298.     end; { WM_DESTROY }
  299.   end; { case msg }
  300.  
  301.   WndProc := DefWindowProc (Wnd, Msg, wParam, lParam);
  302. end;
  303.  
  304. {-----------------------------------------------------------------------------}
  305.  
  306. function InitAppClass: WordBool;
  307.   { registers the application's window classes                                }
  308. var
  309.   cls : TWndClassEx;
  310.  
  311. begin
  312.   cls.cbSize          := sizeof(TWndClassEx);           { must be initialized }
  313.  
  314.   if not GetClassInfoEx (hInstance, AppName, cls) then
  315.   begin
  316.     with cls do
  317.     begin
  318.       { cbSize has already been initialized as required above                 }
  319.  
  320.       style           := CS_BYTEALIGNCLIENT;
  321.       lpfnWndProc     := @WndProc;                    { window class handler  }
  322.       cbClsExtra      := 0;
  323.       cbWndExtra      := 0;
  324.       hInstance       := system.hInstance;
  325.       hIcon           := LoadIcon (hInstance, APPICON);
  326.       hCursor         := LoadCursor(0, IDC_ARROW);
  327.       hbrBackground   := GetSysColorBrush(COLOR_WINDOW);
  328.       lpszMenuName    := APPMENU;                     { Menu name             }
  329.       lpszClassName   := AppName;                     { Window Class name     }
  330.       hIconSm         := LoadImage(hInstance,
  331.                                    APPICON,
  332.                                    IMAGE_ICON,
  333.                                    16,
  334.                                    16,
  335.                                    LR_DEFAULTCOLOR);
  336.     end; { with }
  337.  
  338.     InitAppClass := WordBool(RegisterClassEx(cls));
  339.   end
  340.   else InitAppClass := TRUE;
  341. end;
  342.  
  343. {-----------------------------------------------------------------------------}
  344.  
  345. function WinMain : integer;
  346.   { application entry point                                                   }
  347. var
  348.   Wnd : hWnd;
  349.   Msg : TMsg;
  350.  
  351. begin
  352.   if not InitAppClass then Halt (255);  { register application's class        }
  353.  
  354.   { Create the main application window                                        }
  355.  
  356.   Wnd := CreateWindowEx(WS_EX_CLIENTEDGE,
  357.                         AppName,                { class name                  }
  358.                         AppName,                { window caption text         }
  359.                         ws_Overlapped       or  { window style                }
  360.                         ws_SysMenu          or
  361.                         ws_MinimizeBox      or
  362.                         ws_ClipSiblings     or
  363.                         ws_ClipChildren     or  { don't affect children       }
  364.                         ws_Visible,             { make showwindow unnecessary }
  365.                         20,                     { x pos on screen             }
  366.                         20,                     { y pos on screen             }
  367.                         400,                    { window width                }
  368.                         200,                    { window height               }
  369.                         0,                      { parent window handle        }
  370.                         0,                      { menu handle 0 = use class   }
  371.                         hInstance,              { instance handle             }
  372.                         nil);                   { parameter sent to WM_CREATE }
  373.  
  374.   { a message box indicating failure and the reason for it would be more      }
  375.   { desirable.                                                                }
  376.  
  377.   if Wnd = 0 then Halt;                         { could not create the window }
  378.  
  379.   while GetMessage (Msg, 0, 0, 0) do            { wait for message            }
  380.   begin
  381.     TranslateMessage (Msg);                     { key conversions             }
  382.     DispatchMessage  (Msg);                     { send to window procedure    }
  383.   end;
  384.  
  385.   WinMain := Msg.wParam;                        { terminate with return code  }
  386. end;
  387.  
  388. begin
  389.   WinMain;
  390. end.
  391.  
On line 192, the program uses LoadLibraryEx to load csrss.exe.  On line 211, it checks the address returned by LoadLibraryEx, which fiddles with the LSB to indicate that it was loaded as a data file and adjusts the address to turn it into the real load address. 

On line 219, using the real load address, it determines the module bitness (see GetModuleBitness on line 75.)  If anything does not go according to plan, the program states it could not determine the Windows bitness, otherwise it outputs it.  Easy as 32 bit pie. :)



My intention is to start with the simplest most trivial API and build from there.  This way those who follow the examples can gain the necessary knowledge to understand more subtle and complex use the API.

NOTE:  There is an example dedicated to LoadLibraryEx by itself which shows how it behaves under various circumstances.



About 1% (maybe slightly more) of the examples are like the one above, where one API along with "peripheral" knowledge can be used to extract information out of Windows.

I suggest creating a "WinAPI" directory and under that directory, create directories named "Techniques" (which the above example would go into), ntdll, kernel32, gdi32 and user32.  Of course, you're free the arrange the examples however you like but, I have found that way to make the large number of programs easier to manage and find.




All comments and feedback welcome.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: WinAPI - Windows bitness & Teaser programs
« Reply #16 on: January 15, 2021, 09:35:25 am »
MS would have the programmer use the IsWowProcess() or IsWowProcess2() API to make the determination but, those two APIs have a few annoyances associated with them.  First, they may not be present (IsWowProcess() requires XP SP2 or higher) and, even when present, the user running the program must have some privileges, that while not high, he/she may not have.

There is a way to determine the bitness without using either or these APIs that do not require the user to have any "special" privileges.  The "trick" resides in two details.  The first one is that the Windows server is what determines the Windows bitness, the second one is that LoadLibraryEx will load almost anything you want as long as you don't intend to run it.

Using the first observation, if Windows is 32 bit then its csrss.exe (client service runtime subsystem) will also be 32 bit and, it will always be 64 bit in a 64 bit version of Windows.

Using the second observation, we can simply ask LoadLibraryEx to load csrss.exe as a datafile and unless the user is totally "privilege destitute", LoadLibraryEx will serve csrss.exe in a sliver platter. 

All that's left is for the program to rummage in csrss.exe to determine its bitness and whatever its bitness is, that's the Windows bitness too :)  Done!

Wouldn't it be better to check for WoW64.dll? If you're running on a 32-bit system that library won't exist/load and on a 64-bit system it will be always loaded into a 32-bit process already thus avoiding the need to map csrss.exe into the address space.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: WinAPI - Windows bitness & Teaser programs
« Reply #17 on: January 15, 2021, 10:41:01 am »
Wouldn't it be better to check for WoW64.dll? If you're running on a 32-bit system that library won't exist/load and on a 64-bit system it will be always loaded into a 32-bit process already thus avoiding the need to map csrss.exe into the address space.
That was my first thought too and ended up being more cumbersome than going after csrss.exe.   

Going after Wow64.dll, the first thing I tried was using GetModuleHandle, it failed.  Tried using LoadLibrary and it also failed, most likely because a 32 bit app is not allowed to load a 64bit dll.  It would work with LoadLibraryEx specifying "load as datafile" but that dll is 238K whereas csrss.exe is only 8K.  Better (faster) to load the smaller one.

Another way that works is to use any of the module enumeration API (toolhelp32 or EnumProcessModules) but that requires more code and it's slower.

After trying a number of ways, going after csrss.exe with LoadLibraryEx ended up being the solution that required the least amount of code, least in required user privileges and still reliable.


ETA

The call to GetTextExtentPoint32 on lines 241 through 244 is superfluous and can be removed.  It cannot be removed because the height of the font is used to calculate the Y coordinate used in TextOut. 
« Last Edit: January 16, 2021, 09:42:01 am by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Windows API test programs / Examples
« Reply #18 on: January 15, 2021, 12:21:14 pm »
Best to use the MS advised way, dynload it if you have to, and only use hackish ways for XP. That avoids the chance that some future way breaks the hackish way for non XP systems.

But I think this goes a bit far for the infinitesimally small percentage of users that still run XP 64-bit, a number that was never very big to being with.   

So dynloading iswowprocess(2) and returning 32-bit if that fails is IMHO more than good enough. 


440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Windows API test programs / Examples
« Reply #19 on: January 15, 2021, 01:01:48 pm »
@marcov

Honestly, I would rather depend on checking the bitness of csrss.exe than use either IsWowProcess or IsWowProcess2. 

csrss.exe isn't going to go away anytime soon and loading it as a data file requires no privileges.  Additionally, the IsWow64Process() documentation states the following:
Quote
If the process is a 32-bit application running under 64-bit Windows 10 on ARM, the value is set to FALSE.
which means that calling IsWow64Process on an ARM platform would tell the 32 bit program that it is _not_ running on a 64 bit Windows even though it is. 

IOW, I avoid APIs that are "moody".  I prefer methods that return unadulterated facts.  Checking csrss.exe's bitness is much more reliable.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Windows API test programs / Examples
« Reply #20 on: January 15, 2021, 01:02:28 pm »
But I think this goes a bit far for the infinitesimally small percentage of users that still run XP 64-bit, a number that was never very big to being with.

It's not only XP, but also Windows Server 2003. It provides the API only starting from SP1.

Going after Wow64.dll, the first thing I tried was using GetModuleHandle, it failed.  Tried using LoadLibrary and it also failed, most likely because a 32 bit app is not allowed to load a 64bit dll.  It would work with LoadLibraryEx specifying "load as datafile" but that dll is 238K whereas csrss.exe is only 8K.  Better (faster) to load the smaller one.

Fair enough.

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: WinAPI - Windows bitness & Teaser programs
« Reply #21 on: January 15, 2021, 05:59:06 pm »
MS would have the programmer use the IsWowProcess() or IsWowProcess2() API to make the determination but, those two APIs have a few annoyances associated with them.  First, they may not be present (IsWowProcess() requires XP SP2 or higher) and, even when present, the user running the program must have some privileges, that while not high, he/she may not have.
Some far-fetched reasons. First, IsWow64Process present in the original XP 64, because it was born from Windows 2003 Server (it also has this function). The 32-bit version of XP may not have this function, but the 64-bit version has always had it, from birth.
Second, the process of course has read rights to its own kernel32.

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: WinAPI - Windows bitness & Teaser programs
« Reply #22 on: January 15, 2021, 06:46:36 pm »
Some far-fetched reasons. First, IsWow64Process present in the original XP 64, because it was born from Windows 2003 Server (it also has this function). The 32-bit version of XP may not have this function, but the 64-bit version has always had it, from birth.
Second, the process of course has read rights to its own kernel32.
Not far fetched.  The fact that the 64 bit version had it from the start is useless since a 64 bit program does not need either function to determine that it is running under a 64 bit version of Windows.

It is the fact that the 32 bit version of Windows did _not_ have it from the start that causes problems.  In addition to that, on some platforms, e.g, ARM the API returns FALSE to a 32 bit program even though it is running under a 64 bit version of Windows.  MS does not say how IsWowProcess2() behaves on the ARM platform in that case but, the inevitable conclusion is that using those APIs to determine whether a 32 bit program is running  under a 64 bit version of Windows is not a reliable method to make the determination.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

ASBzone

  • Hero Member
  • *****
  • Posts: 678
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: Windows API test programs / Examples
« Reply #23 on: January 15, 2021, 08:09:51 pm »

So far, the level of interest does not seem to be high enough to even merit concern on how to go about it.


I'm interested for sure.   I've just been busy of late, but this would be of interest to me, especially APIs dealing with physical memory and the Task Scheduler.
-ASB: https://www.BrainWaveCC.com/

Lazarus v2.2.7-ada7a90186 / FPC v3.2.3-706-gaadb53e72c
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Windows API test programs / Examples
« Reply #24 on: January 15, 2021, 08:16:22 pm »
I'm interested for sure.   I've just been busy of late, but this would be of interest to me, especially APIs dealing with physical memory and the Task Scheduler.
Pleased to hear you're interested, adding one (1) to the "interested count". :) 

As far as APIs that deal with Physical Memory, there are very few APIs that deal with Physical Memory, the great majority deal with Virtual Memory and, they are, I believe, all informational.  As far as the Task Scheduler, unfortunately I don't believe I have any examples that apply to it.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

mika

  • Full Member
  • ***
  • Posts: 102
Re: Windows API test programs / Examples
« Reply #25 on: January 15, 2021, 09:18:59 pm »
csrss.exe isn't going to go away anytime soon and loading it as a data file requires no privileges. 
It fails in wine under linux (failed to determine windows installation bitness).

It's charming to see old style windows gui programing.
« Last Edit: January 15, 2021, 09:24:02 pm by mika »

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Windows API test programs / Examples
« Reply #26 on: January 15, 2021, 10:44:56 pm »
But I think this goes a bit far for the infinitesimally small percentage of users that still run XP 64-bit, a number that was never very big to being with.

It's not only XP, but also Windows Server 2003. It provides the API only starting from SP1.

I stand corrected. Windows Server 2003 that even didn't get all their 2005 patches also suffer. That will be a big number :-)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Windows API test programs / Examples
« Reply #27 on: January 15, 2021, 10:46:10 pm »
csrss.exe isn't going to go away anytime soon

No but your access from some types of accounts might. Like fully ordinary user.



440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Windows API test programs / Examples
« Reply #28 on: January 16, 2021, 03:43:56 am »
It fails in wine under linux (failed to determine windows installation bitness).
Given that it's under Linux, it should be expected for the method to fail.

IOW, there is no _real_ Windows in that case.  Emulation layers often have limitations.

I guess/speculate that IsWowProcess and IsWowProcess2 under Wine might always return FALSE.



ETA

No but your access from some types of accounts might. Like fully ordinary user.
So far, the method seems to work with "ordinary"/"limited" users.  That said, it is conceivable and even likely it would fail for users in a custom and very restricted group.  In that case, IsWowProcess and IsWowProcess2 would probably fail too.

IOW, In the "normal"/common case, the method woks as well or better than the IsWowProcess and IsWowProcess2 APIs.
« Last Edit: January 16, 2021, 03:51:25 am by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: WinAPI - Windows bitness & Teaser programs
« Reply #29 on: January 16, 2021, 11:11:33 am »
Some far-fetched reasons. First, IsWow64Process present in the original XP 64, because it was born from Windows 2003 Server (it also has this function). The 32-bit version of XP may not have this function, but the 64-bit version has always had it, from birth.
Second, the process of course has read rights to its own kernel32.
Not far fetched.  The fact that the 64 bit version had it from the start is useless since a 64 bit program does not need either function to determine that it is running under a 64 bit version of Windows.

Putting aside the ARM64 issue: assuming that every 64-bit Windows OS has the IsWow64Process function then your check in a 32-bit application would simply be: does the IsWow64Process exist? If no, the OS must be 32-bit. Otherwise call IsWow64Process.

In addition to that, on some platforms, e.g, ARM the API returns FALSE to a 32 bit program even though it is running under a 64 bit version of Windows.  MS does not say how IsWowProcess2() behaves on the ARM platform in that case but, the inevitable conclusion is that using those APIs to determine whether a 32 bit program is running  under a 64 bit version of Windows is not a reliable method to make the determination.

MS says that IsWow64Process2 returns the image machine type of the process and of the host. I consider that enough information.

I personally would simply use a combination of IsWow64Process and IsWow64Process2 as even the priviledge issue is highly theoretical with the handle of the current process obtained with GetCurrentProcess as the creator of the process would need to actively disable the QUERY_INFORMATION_PROCESS and QUERY_LIMITED_INFORMATION_PROCESS priviledges and even then I don't know right now whether Windows silently enables them for the handle of the current process anyway (or, considering that the handle returned by GetCurrentProcess is a pseudohandle, doesn't even need them).

 

TinyPortal © 2005-2018