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...
The solution was found by accident, it is actually a bug but is seems to work without negative side effects, as far as I can see. In fact, I see some cool side effects...
If you want window A to be parent of window B, you should normally use SetParent(B,A) but I accidently used SetWindowLong(B, -8, A). This was a silly mistake, nothing seemed to happen except the taskbar button for window B was gone!
I wonder if this is a bug or a feature. If it is a bug, it might not work in future Windows versions (mine is 95 with Service Pack 1).
By the way: I love taskbar buttons. I hate windows without taskbar buttons... but since it is a FAQ:

Example source

Suppose the project has one main window (a typical UIB-like menu tool) and this mainwin launches a couple of other windows. You only accept one taskbar button.
The main window uses this procedure to start a window:

{windows.i}
{winfunc.i}
 
ON CHOOSE OF btnLaunch IN FRAME DEFAULT-FRAME /* Start window without Taskbar button */
DO:
  DEFINE VARIABLE hp         AS HANDLE NO-UNDO.
  DEFINE VARIABLE hWindow    AS HANDLE NO-UNDO.
  DEFINE VARIABLE hOldParent AS INTEGER NO-UNDO.
 
  RUN noTaskBar.w PERSISTENT SET hp.
  RUN GetWindowHandle IN hp (OUTPUT hWindow).
 
  RUN SetWindowLongA IN hpApi (GetParent(hWindow:HWND),
                               -8,
                               GetParent({&WINDOW-NAME}:HWND), /* or DEFAULT-WINDOW:HWND */
                               OUTPUT hOldParent).
 
END.

The launched window must have an internal procedure "GetWindowHandle" that returns the Progress widget handle for the newly created window:

PROCEDURE GetWindowHandle :
 
  DEFINE OUTPUT PARAMETER hWindow AS HANDLE NO-UNDO.
 
  hWindow = {&WINDOW-NAME}:HANDLE.
 
END PROCEDURE.

Cool side effects:

As shown in the above example, you can parent the new window to

  GetParent({&WINDOW-NAME}:HWND) 

or to

  DEFAULT-WINDOW:HWND  

or to any other window. There is a strange but great bonus in the first choice:
The main window can not overlap the child windows. In a normal UIB-like application you get to see a lot of pieces of desktop and other underlying programs between your Progress windows, with the risc of activating one of them when you click one by accident.
Now you can safely maximize your main window - it hides the background but will never hide any other project windows. It has like a 'stay-on-bottom' effect.
If you minimize the mainwin, all other windows will be minimized too. If you restore the minimized mainwin, all open child windows will appear again.
If you use DEFAULT-WINDOW:HWND you have the benefit of an always available handle but the mainwin will not control the others.

Problem ON CLOSE:

When you close the parent window, all child windows seem to be closed as well (which is fine). I am not sure if Progress knows about that: if the child window procedure has an 'ON WINDOW-CLOSE' event handler it will not be called. To play safe, you should catch the 'close' in the parent procedure and notify all children.