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.


Round widgets

changing the shape of a widget

based on an example by Sturla Johnsen



The animated gif shows an impression of Rounddemo.w.
Rounddemo, written by Sturla Johnsen, creates a normal Progress dialog box with some widgets on it (a frame, two fill-ins and two buttons) and demonstrates how the default rectangular region of any widget can be replaced by a different shaped region. In this case by elliptic regions.
Rounddemo.w calls procedure Roundwidget.p from within the CHOOSE trigger of the button. Both procedures are attched (see table near end of this topic) and can be downloaded from here to see for yourself.


Force Combo-box drop down

by Stuart Morris

Suppose you have a combo-box widget (named combo-box-1) and you want to drop down its built-in selection-list on some event. The following source will do just that.

{windows.i}
&GLOBAL-DEFINE CB_SHOWDROPDOWN 335
 
DEFINE VARIABLE retval AS INTEGER NO-UNDO.
 
  RUN SendMessage{&A} IN hpApi (INPUT  COMBO-BOX-1:HWND,
                                       {&CB_SHOWDROPDOWN},
                                       1,   /* True */
                                       0,
                                OUTPUT retval
                                )
                                NO-ERROR /* Stop C Stack Errors */.

Associated icon

Chris Herring submitted the following code to draw the associated icon for any document on a button. For example: you created a button to open a file like "c:\invoices\abc001.doc", the file extension "doc" is associated with MS-Word so you want the icon for Word-documents displayed on the Progress button.
The remainder of the text is from Chris. As you see, he has some issues left. If you know the solution, please click the "Edit"-link near the bottom of this page to help out.
There were two ways I found to add the icon, using SendMessageA and ImageList_Draw. SendMessageA works ok except it suffers from the same limitations and the toggle button - can't remove focus. ImageList_Draw seems to be able to draw the icon on progress widgets that have the HWND attribute( at least the button and frame anyway ) but the image is release whenever the display for the image is refreshed. On the plus side it would work with flat buttons if you could get the image to stay. Anyway I've put some of my code below. Only thing that I'm aware of that is not entirely correct is the size of the fileinfo memptr regarding the last two string parameters. I wasn't sure of the size so I set them to 1 which only returns the first char of the string if the display name and type tags are added to the flag.


Widgets

.


Tranparent window

In Windows 2000 you can make transparent windows, by using function SetLayeredWindowAttributes. The attached Progress procedure demonstrates this.

Attachments

transparent.w.zip : demo SetLayeredWindowAttributes


Creating a Palette or floating toolwindow


This example uses the source in procedure winstyle.p available in WinStyle.p.

A palette, or floating toolwindow should have these three features:
* a small title bar
* no associated button on the Taskbar because it is considered a popup-window of its 'client'
* stays on top, at least relative to the window it is 'serving'

The first two features are done automatically when pushing the WS_EX_PALETTEWINDOW style. Controlling the behavior of 'stay-on-top' requires some extra work in P4GL.


Minimizing a window to the System Tray

by Rob den Boer

The attached example procedure creates a Progress window. When the window is minimized, it shows an icon in the system tray (that's in the corner of the taskbar, next to the clock). Features of this tray icon are:
* on left mouse click, the window is restored
* on right mouse click a popup-menu appears (as shown on picture)
* the icon has a tooltip
* the icon can be animated

Installing the example

Download systray.zip (12 kilobyte) and unzip it to a directory in your PROPATH.
The example was created using the AppBuilder in Progress 9, it will have to be rewritten to run in Progress 8. The example uses the PSTimer ActiveX control and also the MsgBlaster control.

How it works

Run procedure ip-systray-init when the window gets initialized.


Splash window

Splash is the name for a window that is shown during startup of an application. It masks a long loading time (for example during establishing connections to remote databases) and is often used to show the application title, 'licensed to'-info, author name and often a nice picture.

A Splash has no user interaction; a user must simply wait until the show begins. Therefore a Splash should not have a title bar and especially no 'close' button. It's common to display the Splash in the exact center of the screen and it also usually 'stays-on-top'.

Most people use third-party 3GL languages to create a Splash screen because it seems impossible to create one in Progress. The downside of using an external program is that it's hard to determine the proper time to close. This would be lots easier if the Splash was created in Progress and then it would also be possible to give status information (like "now connecting to system.db").


Painting in Progress frames

Sometimes you may want to do some extra painting on a Progress frame or window, for example some circles, dotted lines, dashed area's or just lines that are not horizontal or vertical. Or how about right-aligned text?
The actual drawing can be done with GDI functions, but the result will be erased whenever Progress repaints the frame (or window). This topic is about preventing that.
Let's start with a simple example: drawing an ellipse on a Progress frame.
create a Progress window (doesn't have to be Smart) and place a button on it. On choose of this button: run Paint.

 
PROCEDURE PAINT :
/*----------------------------------------------------
  Purpose:     do some custom painting, in this case:
               draw a circle as large as the window
------------------------------------------------------ */
  DEFINE VARIABLE hdc AS INTEGER NO-UNDO.
  DEFINE VARIABLE Okay AS INTEGER NO-UNDO.
 
  RUN GetDC IN hpApi (INPUT FRAME {&frame-name}:HWND, 
                      OUTPUT hdc).
 
  RUN Ellipse IN hpApi (hdc, 
                        0,
                        0, 
                        FRAME {&frame-name}:WIDTH-PIXELS, 
                        FRAME {&frame-name}:HEIGHT-PIXELS,
                        OUTPUT Okay ).
 
  RUN ReleaseDC IN hpApi (INPUT FRAME {&frame-name}:HWND, 
                          INPUT hdc, 
                          OUTPUT Okay).
 
END PROCEDURE.

Now when you run the window and press the button you will see a large ellipse. When you drag any other window over the surface of your window, you will see that overlapped regions of the ellipse will be erased. To repaint the ellipse you can just press the button again, but you want a way to do this automatically.

When should you repaint your drawings?

A (region of a) window will be painted again when it has been overlapped by another window, or whenever the (region of the) window has become invalidated. MS-Windows sends a series of messages to the window when it is invalidated and Progress responds to it by painting the region again. Among those messages are WM_ERASEBKGND and WM_PAINT.
I have always believed that WM_PAINT was the proper message to wait for, but there are occasions when you see that progress repaints the window without ever having trapped a WM_PAINT message. Result: your custom drawing is erased.
Matt Gilarde at PSC Development explains what's going on:
Progress doesn't repaint a frame when it gets a WM_PAINT message; we do it when we get a WM_ERASEBKGND. Why? I believe the idea was to avoid flashing during repaints. Instead of wiping out the background in the WM_ERASEBKGND and then repainting widgets in the WM_PAINT, Progress does all the painting during WM_ERASEBKGND. Painting a frame consists of the following steps:
* Fill the frame with the background color
* Draw the grid if it is on
* Paint rectangles and images
* Paint all other widgets
* Highlight selected widgets
Since the painting is handled in WM_ERASEBKGND, the WM_PAINT message is not always generated (Windows removes the WM_PAINT from the message queue if there is no invalid region to be painted). So you may have better luck trapping WM_ERASEBKGND. Or you may run into other problems.
So you will have to set up your MessageBlaster to trap WM_ERASEBKGND instead WM_PAINT.


Removing min/max buttons from the title bar


This example uses the source in procedure winstyle.p, available on page WinStyle.
A normal window can be maximized to full-screen but a Progress window doesn't grow much unless you specifically set virtual sizes. Maximizing (or resizing at all) isn't very useful for a window that has a fixed amount of widgets, so you might prefer to hide the Maximize button. And while we are at it let's also hide the Minimize button.
Here's how you do it:
Create a Progress window and place this code fragment somewhere in the source:

  ASSIGN {&window-name} :MIN-BUTTON = NO
         {&window-name} :MAX-BUTTON = NO.

Explanation

Let's take a look at the source in winstyle.p.


Maximize, minimize a window

Ever tried to maximize a Progress window, with respect to the size and position of the Windows Taskbar? It is easy if you know about this not-well-documented feature (in 8.2A and up):

ASSIGN
   {&WINDOW-NAME}:MAX-HEIGHT   = ?
   {&WINDOW-NAME}:MAX-WIDTH    = ?
   {&WINDOW-NAME}:WINDOW-STATE = WINDOW-MAXIMIZED.

The fun part is assigning the unknown value to max-height/width. This results in dynamic resizing even when the user moves the Taskbar or changes the display resolution!

Minimize and Restore

To restore a Window to its original state, use the following code:


Manipulating scrollbars

Progress frames and windows show both scrollbars or none.
It would be better if the scrollbars were shown independently.
The procedure ShowScrollbarsWhenNeeded is to be called 'on end-size' or during initialize.
The procedure HideScrollbars does simply that: hide both scrollbars whether or not the virtual size is larger than the actual size. The procedure is mainly a demonstration of the {&SB_BOTH} constant.

{windows.i}
 
PROCEDURE ShowScrollbarsWhenNeeded :
/* purpose : to be called from "on end-size" or whenever. */
   DEFINE INPUT PARAMETER hFrame AS HANDLE.
 
   DEFINE VARIABLE retval AS INTEGER NO-UNDO.

LockWindowUpdate

If you use dynamic widgets, or if you dynamically resize or reposition widgets, you simply have to use function LockWindowUpdate especially on NT Terminal Server.
This is probably the most widely used API function, covered in every presentation and every publication. Actually that's why I didn't bother to cover LockWindowsUpdate before, but here it is at last...

PROCEDURE LockWindowUpdate EXTERNAL "user32.dll" :
  DEFINE INPUT  PARAMETER hWndLock AS LONG.
  DEFINE RETURN PARAMETER IsLocked AS LONG.
END PROCEDURE.
  • hWndLock specify a windows handle to request a lock for that window. Specify 0 to clear the lock.
  • IsLocked returns 0 if the function fails, nonzero if the function succeeds.

LockWindowUpdate temporarily disables drawing in the specified window. While a window is locked you can change the appearance of the window or the appearance and/or positions of its child windows (widgets). These changes will not be drawn until the window is unlocked. When the window is unlocked its area will be invalidated and will eventually receive a WM_PAINT message. LockWindowUpdate will improve the overall performance of a drawing operation when you need to modify several widgets.
You should not move, resize, or hide/view the locked window while it has a lock. If you do you will see the desktop or other surrounding windows flash.
Only one window at a time can be locked.
If LockWindowUpdate failed (returned IsLocked=0) it may be because an other window owns the lock. This means you should not call LockWindowUpdate(0,..) if you didn't get the lock in the first place, because you may inadvertently unlock a different window.

a demo program

Procedure LockWindowUpdate.w, which is attached, shows a window with a whole lot of widgets in it. When you press button "Move Widgets" each widget will be moved and resized a random amount of pixels. This operation is very slow and flashy if "use LockWindowUpdate" is not toggled.
The demo also shows the effect of hiding the frame during LockWindowUpdate: the window itself will behave quite nicely but all other visible windows, including the desktop will accidently be redrawn.


Hiding the taskbar button

or actually: window parenting

Warning:

Reparenting windows affects messaging. There is no way of knowing if this confuses the internals of the Progress runtime module. I would personally not dare to use something like this in a production environment.

One of the most Frequently Asked Questions is: "Every window has a taskbar button, how can I make those buttons invisible?"
The answer is that every unowned window or every window that does not have a parent has a taskbar button, except windows that have the 'toolwindow' style. So all you have to do is give your window a parent... easier said than done, because a parented window is normally glued to its parents client area and can't be moved away from that parent...


GetDeviceCaps

Procedure GetDeviceCaps allows you to find many device capabilities, like: how many colors can be displayed, can a font be scaled or rotated, is the device capable of drawing lines or circles.
The "Device" can be the display but the procedure is also important for measuring the capabilities of a printer device, because your print routine may have to use different logic for penplotters or laserprinters or matrixprinters. Of course Windows can not actually measure the device but has to rely on the the device driver written by the manufacturer of the device.
You will use this procedure often together with GetSystemMetrics (to find out the dimensions of scrollbars or other objects) and with DeviceCapabilities (for printers only, to find info about paper sizes, orientation, number of bins and more)


#
Syndicate content