Win32 API samples

This collection of code snippets used to be hosted on www.global-shared.com.
It is an old collection: it all began in 1996 or 1997, when Progress 8 was new and many of us were still using Windows 3.1 !!
Unlike wine or paintings, program code doesn't get better when it ages. You can find fragments that can be improved because Microsoft continuously expands their API, or are outdated because Progress has added features to the ABL so we don't need to use the WIN32 API anymore.


File version information

Most win32 binaries, like executables (exe), dynamic link libraries (dll) and automation controls (ocx) contain a version information structure. The data in this version information structure is used by setup programs to decide if it's ok to overwrite the file.
The version information can also be useful for support engineers for determining why a feature doesn't work as expected. Especially when used in a list of all modules loaded by the current Progress process, see ListModules.
Typically a file contains both a productversion and fileversion. The version info structure may also contain strings describing the file or its publisher, but this textual information is kind of difficult to read because they are grouped together in codepage blocks. Productversion and fileversion are not language specific so these are easier to read.


Available disk space (not win95)

by Michael Rüsweg-Gilbert

To get the amount of available disk space you can call GetDiskFreeSpace or GetDiskFreeSpaceEx.
GetDiskFreeSpaceEx is best because it supports disks larger than 2 gigabyte. Unfortunately this function may not be available on every Windows version (Windows 95 before OSR2 only supports GetDiskFreeSpace).

The following program shows how to call GetDiskFreeSpaceEx. Note how the 64-bit parameters are cast in MEMPTR variables and converted to decimal values.

/* ===============================================================================

Available disk space (win95)

To get the amount of available disk space you can call GetDiskFreeSpace or GetDiskFreeSpaceEx.
There are differences between Windows 95, Windows 95 OSR/2 and Windows NT 4.0.

This text is quoted from MSDN Library:

In Windows 95, the existing Win32 function GetDiskFreeSpace may obtain
incorrect values for volumes that are larger than 2 gigabytes (GB). 
In OSR 2, the function GetDiskFreeSpace has been modified to cap the 
value returned and never reports volume sizes greater than 2 GB. 
On very large empty volumes, existing applications will see only 2 GB free.

Locking a file

Code found in an e-mail to Peg, send by by Jeffrey L. Boyer

Sometimes you want to read a file and be sure that nobody else is writing to the file in the meantime. So you want to lock it for writing.

&GLOBAL-DEFINE GENERIC_WRITE 1073741824   /* &H40000000 */
&GLOBAL-DEFINE OPEN_EXISTING 3
&GLOBAL-DEFINE FILE_SHARE_READ 1                  /* = &H1 */
&GLOBAL-DEFINE FILE_ATTRIBUTE_NORMAL 128       /* = &H80 */

PROCEDURE CreateFileA EXTERNAL "kernel32":
    DEFINE INPUT PARAMETER lpFileName AS CHARACTER.
    DEFINE INPUT PARAMETER dwDesiredAccess AS LONG.
    DEFINE INPUT PARAMETER dwShareMode AS LONG.

Getting file and directory information

This page explains how to find the size (in bytes) of a certain file, the long and short filenames, the date and time a file was last modified. It also shows a way to get a directory listing.
This is based on a rather large procedure library, file-api.p and file-api.i, which are available in everything.zip in page windows.i and hpApi

Using the library

To use any of the functions in library file-api.p simply include {file-api.i} in the definitions section of your program. This will define some constants you might want to use and it runs file-api.p persistent in handle hpFileApi.


Create Shortcuts

by Todd G. Nist

Program source is available for download: w-createshortcut.p
This program demonstrates how to create a shortcut in Windows and how to modify it. More specifically, the demo will create a folder called "SomeApplication", place a link to a "Readme.txt" file into the folder created, add it to the end users desktop, and create a link to this website under "Favorites".

By using the SHAddToRecentDocs() call, a shortcut can be created on the fly and added to the user's Documents item on the Start menu. Then by using the SHFileOperation function, one can move and rename files or folders across drives. By applying the SHGetSpecialFolderLocation API, we can get the current user's "Special" systems paths - their Start Menu, their Recent Files path, and others.


BrowseForFolder with an initial folder

Cyril O'Floinn has wrapped function SHBrowseForFolder into a higher-level DLL function, named BrowseForFolder. This has the advantage of being able to specify an initial directory.
The source for this new function is written in Delphi and is added to PROEXTRA.DLL.

The declaration is added to PROEXTRA.P and looks like this:

PROCEDURE BrowseForFolder EXTERNAL {&ProExtra} :
  DEFINE INPUT  PARAMETER hWndOwner       AS LONG.
  DEFINE INPUT  PARAMETER lpTitle         AS CHARACTER.
  DEFINE INPUT  PARAMETER uiFlags         AS LONG.
  DEFINE INPUT  PARAMETER lpInitialFolder AS CHARACTER.

BrowseForFolder using COM Automation

Instead of using API-function SHBrowseForFolder to select a directory, you can also use the COM-interface of the "Shell".
There is an example in article 18823 of the Progress Knowledgebase.
Julian Lyndon-Smith wrote the following example, different from the one in the Knowledge Base.

 
FUNCTION DotRGetFolder RETURNS CHARACTER
  ( INPUT ip_cTitle AS CHARACTER /* title for browse dialog */ ) :
 
   /* constants for BrowseForFolder options */
   &SCOPED BIF_RETURNONLYFSDIRS  1
   &SCOPED BIF_DONTGOBELOWDOMAIN 2
 
   DEFINE VARIABLE lv_chShell  AS COM-HANDLE NO-UNDO. /* shell application */

BrowseForFolder

Sometimes you want to choose a folder but the usual system dialogs require you to choose a file as well. The API function SHBrowseForFolder does not show any files: it does exactly what the name implies.

/* a test/demo program */
DEFINE VARIABLE folder AS CHARACTER NO-UNDO.
DEFINE VARIABLE canceled AS LOGICAL NO-UNDO.
 
RUN BrowseForFolder.p ("choose the directory where you want to dump your data",
                       OUTPUT folder, 
                       OUTPUT canceled).
 
MESSAGE "folder=" folder SKIP
        "canceled=" canceled
        VIEW-AS ALERT-BOX.
 
/* ==========================================================

Filesystem

.


mouse-over event

based on an example by Chris Braddock

There is no real MOUSE-OVER event but this example shows one possible way to achieve the same effect.
The general idea is: use the PSTimer.OCX. Read the mouse coordinates on every tick of the timer using API-function GetCursorPos. The resulting coordinates are screen-coordinates. Then use API-function ScreenToClient to convert the screen-coordinates to client-coordinates, where "client" is the window you are interested in. Finally, test if those client coordinates are inside the client rectangle.
Attached example (in mousexy.zip) continuously shows the screen-coordinates and the client-coordinates. It also colors the frame green when the mouse moves over the frame, and colors the frame grey when the mouse moves away from the frame.


Apply the right mouse button

Or: programatic dropping a popup-menu

Sometimes you will want to "apply" a mouse click to a widget, for example to give it focus (with the standard left button) or to force a popup-menu to pop up (with the alternate button).
In this example we have an image widget; the user can perform several actions on that image widget (like loading a new bmp-file or whatever). Those actions are listed in a popup-menu and now you want that popup-menu to appear whenever the user clicks the widget, even when he uses the left mouse button. Unfortunately the P4GL statement 'APPLY "MOUSE-MENU-CLICK" doesn't work but you can fool Progress by sending the appropriate mouse messages.


Apply focus to a widget

Sometimes you may need to force focus to a certain widget.
There must be several solutions but I found this one to be fairly reliable: make Windows think the user clicked on the widget using his left mouse button. 'Click' is a combination of 'buttondown' and 'buttonup' so it involves two messages, but I assume you might be allowed to skip one of them.
So if you want to apply focus to FILL-IN-1 you might say:

  run MouseClick(FILL-IN-1:HANDLE).
{windows.i}
  
PROCEDURE MouseClick :
 DEFINE INPUT PARAMETER hWidget AS HANDLE NO-UNDO.
 
 DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO.

Mouse

.


Right to Left in FILL-INs and EDITORs etc

Found in an e-mail to Peg, sent by Torben Jensby Christensen

We have been experimenting with mixing Arabic and standard Western Eropean
fields on the same screen.

For this to work as seamlessly as possible for the users we are changing
keyboard and writing direction on every field entry.

Following code is working with Progress 9.1

DEFINE VARIABLE we-keyboard AS CHARACTER INIT "00000409":U  NO-UNDO.
DEFINE VARIABLE arabic-keyboard AS CHARACTER INIT "00000429":U  NO-UNDO.

/* Used for change input keyboard behaviour (Arabic) */
PROCEDURE LoadKeyboardLayoutA EXTERNAL "user32.dll":
#
Syndicate content