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.


Goodbye GLOBAL-SHARED.COM

In a few days it will be 5 February, the 10th aniversary of the “Progress Reference to Windows API”. It will also be the very last day of the global-shared.com domain.

It all started when Progress 7 was brand new; the first Progress version with widgets and persistent procedures. It was also the first Progress version designed for the Windows operating system and this was quite a culture shock for lots of Unix-oriented Progress developers who were used to editing loops and readkey statements.


Re-parenting Progress' main window

My goal is to create a .Net application that "hosts" multiple legacy Progress applications. The idea is to create a tab deck where a panel on each tab deck host a re-parented Progress runtime. I have been able to to this successfully with another .Net application as the re-parented application.


smtpmail.p

Since this is a chapter about email, it should be noted there is an excellent program named smtpmail.p available for free at [broken link removed]

This program is entirely written in regular Progress ABL without any WIN32 API call.


File Summary Properties

This code was posted to PEG by Jared Middleton.

/*******************************************************************
   Procedure:   shellfile.p
   Description: Demo program to access File Summary Properties
                using Shell FolderItems object GetDetailsOf method.
   Written by:  Jared Middleton  (January 17, 2007)
*******************************************************************/

DEFINE VAR chApp            AS COM-HANDLE NO-UNDO.
DEFINE VAR chFolder         AS COM-HANDLE NO-UNDO.
DEFINE VAR chFolderItem     AS COM-HANDLE NO-UNDO.

File Summary Info

Hi there,

Working with an NTFS based operating system, I'd like to link so-called "File Summary Information" with our R-Codes (and get the "Summary" tab when accessing the "properties" of a R-Code in the Windows Explorer... just like .DOC, .XLS,... files).

I've seen that we have to use these functions to achieve this:
stgCreateStorageEx (to create a "File Summary Information" structure);
stgOpenStorageEx (to access the structure);
SetFileSummaryInfo (to fill the structure with info).


setting file permissions

I am looking for code which can set ntfs file-security on a file.

The application will work as follows,
- user requests a file
- an appserver which is running under a admin-account copies the file from a secure-folder to a shared folder.
- the appserver grants the user rights to the file, so he can access/delete it.

So how to grant the permission to the copied file?

Niek


Get a List of Paper bins for a Printer

The attached code returns an array of Bin IDs and Bin Names for the printer/port specified in pcPrinterName and pcPrinterPort.


ShellExecute return codes

If a call to ShellExecute succeeds, the returned hInstance parameter will be the instance handle of the executed program. But if the hInstance is less then 33, it indicates a failure.
Actually if the hInstance>=0 and hInstance<33 because a very large hInstance will be casted into a signed integer variable and may appear to be negative from Progress' perspective.
This page lists the descriptions for some of the possible failures.

It's actually a combination from different resources, both from WinExec and other procedures so some of the result may never occur when using ShellExecute. There are also some gaps in the list, and moreover: some results should have a different description in 16-bit mode. Where descriptions in 16-bit are different then 32-bit I've picked the 32-bit description


ShellExecute and OpenAs

improved by Tim Townsend

Documents can be associated with executables, Windows recognizes a document by its file extention.
Thanks to associations, the ShellExecute procedure knows how to "open" a document and the Explorer knows which icon to draw next to a document.
If a document does not have an association yet and you choose "open" in the Explorer, you will be presented a "Open As" dialog where you can choose an application. The following example shows how to do this in Progress.
The procedure first tries to open (or print) the document. If this fails the first time, it will try a second time using the OpenAs dialog.


wait until MS-Word finished printing

Scenario:

* You have created an RTF file, c:\temp\test.rtf
* You want MS-Word to print this RTF file, but you don't want to use OLE Automation. In other words: you want to call ShellExecute(..., "print", "c:\temp\test.rtf", .....).
* You want to wait until MS-Word has finished printing.

Why:

OLE Automation would be fine but the OLE commands are application specific (and perhaps even version/translation specific) so you rather rely on the Shell "print"-verb.
You can not easily use CreateProcess and WaitForSingleObject, because MS-Word (and many other word-processors) has an MDI-interface. This means MS-Word (the process) will not terminate if it was already opened before you issued the "print"-request.


execute a program and wait until it becomes visible

Suppose your window has a button that is designed to launch an application, using ShellExecute or CreateProcess, but this application takes a few seconds to launch. Since ShellExecute(Ex) and CreateProcess return immediately after the process is created, an impatient user will have time to press the button several times. To work around this problem you may want to disable the button until the application really becomes visible. WaitForInputIdle does the trick. Well, in reality it waits until the application has its input queue (for mouse and keyboard) empty and waiting, but that's at about the same time anyway.

  
  {windows.i}
  DEFINE VARIABLE hProcess AS INTEGER NO-UNDO. 
  DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO.
  hProcess = CreateProcess("notepad.exe",
                           "",
                           3). 

  IF hProcess = 0 THEN DO:
      getlasterror().
      ShowLastError().
  END.
  ELSE DO:
     RUN WaitForInputIdle IN hpApi (hProcess, 
                                    -1,   /* -1=INFINITE */
                                    OUTPUT ReturnValue).
     RUN CloseHandle IN hpApi (hProcess, OUTPUT ReturnValue).
  END.

Note

CreateProcess does not search for applications as good as ShellExecute does. When CreateProcess does not find an application you may have more luck with ShellExecuteEx (not ShellExecute itself, because that does not return a hProcess).


execute a program and wait until it has finished

16-bit (there is a 32-bit solution near end of page)

This code was found on PEG, posted by Stuart Butler a while ago. It is 16 bit code and needs to be reworked for 32-bit. It compiles in version 8.2 but does not wait as expected.
The example program runs notepad, waits until the user has closed notepad and then displays the results of the user's work with notepad.

 /* If we were being run persistent we would want to 
  *** be interrupted when waiting for notepad to finish
  *** if we are closed so include an on close event trigger */
 DEFINE VARIABLE lgClosing AS LOGICAL INITIAL FALSE.

ShellExecuteEx

ShellExecuteEx combines features of ShellExecute and CreateProcess, the most noticable feature is that it returns a PID.

PROCEDURE ShellExecuteExA EXTERNAL "shell32.dll" :
  DEFINE INPUT  PARAMETER lpExecInfo  AS LONG.
  DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.

lpExecInfo is a memory-pointer to a structure of type SHELLEXECUTEINFO, which is a bit complicated to describe. Perhaps it's best to point at an example: See wait until MS-Word finished printing.


CreateProcess

It is recommended to use the CreateProcess procedure instead WinExec. This is a very low-level procedure, it gives complete control over processes, threads and more.
CreateProcess takes 10 parameters, two of which are pointers to structures containing further parameters. Most parameters are not very interesting for our needs, so I have made a function CreateProcess that only takes the three most important params. The function is described in winfunc.p and can be called like in this example:

  {windows.i}
  DEFINE VARIABLE hProcess AS INTEGER NO-UNDO. 
  hProcess = CreateProcess("notepad.exe c:\config.sys",

ShellExecute

ShellExecute is the procedure that is called by the Desktop or Windows Explorer when you double-click an item: if the item is an executable it will run it, if the item is a Word-document it will open it in MS-Word, etc.
There is a lot you can do with this easy-to-use procedure. Let's have a look at the parameters:

PROCEDURE ShellExecute{&A} EXTERNAL "shell32" :
     DEFINE INPUT PARAMETER HWND AS LONG.
     DEFINE INPUT PARAMETER lpOperation AS CHARACTER.
     DEFINE INPUT PARAMETER lpFile AS CHARACTER.
     DEFINE INPUT PARAMETER lpParameters AS CHARACTER.
     DEFINE INPUT PARAMETER lpDirectory AS CHARACTER.
     DEFINE INPUT PARAMETER nShowCmd AS LONG.
     DEFINE RETURN PARAMETER hInstance AS LONG.
  END.

The parameters are:
* hwnd : parent window that will receive a possible messagebox. This parameter is usually 0
* lpOperation : "open" or "print"


#
Syndicate content