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.
/*-------------------------------------------------------------------------- File : open-doc.p Purpose : Open a windows document using the associated application. If no assocoated application, run the OpenAs dialog to allow the user to pick an application. Syntax : Description : Author(s) : TWT Created : 22 Dec 1999 Notes : --------------------------------------------------------------------------*/ DEFINE INPUT PARAM cFileName AS CHARACTER NO-UNDO. DEFINE INPUT PARAM cParams AS CHARACTER NO-UNDO. DEFINE INPUT PARAM cDirectory AS CHARACTER NO-UNDO. DEFINE INPUT PARAM lPrint AS LOG NO-UNDO. &SCOPED-DEFINE SE_ERR_NOASSOC 31 &SCOPED-DEFINE SE_ERR_ASSOCINCOMPLETE 27 DEFINE VARIABLE iInstance AS INTEGER NO-UNDO. DEFINE VARIABLE cWorkDirectory AS CHARACTER NO-UNDO. /* in case parameter cDirectory contains a relative path it has to be replaced by a fully-qualified path: */ ASSIGN FILE-INFO:FILE-NAME = cDirectory. IF FILE-INFO:FULL-PATHNAME > "" THEN cWorkDirectory = FILE-INFO:FULL-PATHNAME. /* try to execute the document: */ RUN ShellExecuteA(INPUT 0, INPUT (IF lPrint THEN "print":u ELSE "open":u), INPUT cFileName, INPUT cParams, INPUT cWorkDirectory, INPUT 1, /* normal mode */ OUTPUT iInstance). /* if no associated application, run OpenAs dialog: */ IF (iInstance = {&SE_ERR_NOASSOC} OR iInstance = {&SE_ERR_ASSOCINCOMPLETE}) AND NOT lPrint THEN DO: /* Ignore cParams because cFileName is a document. cParams is only valid with executables */ RUN ShellExecuteA (INPUT 0, INPUT "open":u, INPUT "rundll32.exe":u, INPUT "shell32.dll,OpenAs_RunDLL ":u + cFileName, INPUT cWorkDirectory, INPUT 1, OUTPUT iInstance). END. /* if */ /* test for error: */ RUN TestErrorCode(iInstance). IF RETURN-VALUE > "" THEN MESSAGE RETURN-VALUE VIEW-AS ALERT-BOX ERROR BUTTON OK. /****************************************************************************/ PROCEDURE ShellExecuteA EXTERNAL "shell32":U : 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 PROCEDURE. PROCEDURE TestErrorCode : DEFINE INPUT PARAMETER iCode AS INTEGER. DEFINE VARIABLE cTxt AS CHARACTER NO-UNDO. IF iCode < 0 OR iCode > 32 THEN RETURN "". /* no error */ CASE iCode : WHEN 0 THEN cTxt = "The operating system is out of memory or resources.":T132. WHEN 2 THEN cTxt = "The specified file was not found":T132. WHEN 3 THEN cTxt = "The specified path was not found.":T132. WHEN 5 THEN cTxt = "The operating system denied access to the specified file.":T132. WHEN 8 THEN cTxt = "There was not enough memory to complete the operation.":T132. WHEN 10 THEN cTxt = "Wrong Windows version":T132. WHEN 11 THEN cTxt = "The .EXE file is invalid (non-Win32 .EXE or error in .EXE image).":T132. WHEN 12 THEN cTxt = "Application was designed for a different operating system.":T132. WHEN 13 THEN cTxt = "Application was designed for MS-DOS 4.0.":T132. WHEN 15 THEN cTxt = "Attempt to load a real-mode program.":T132. WHEN 16 THEN cTxt = "Attempt to load a second instance of an application with non-readonly data segments.":T132. WHEN 19 THEN cTxt = "Attempt to load a compressed application file.":T132. WHEN 20 THEN cTxt = "Dynamic-link library (DLL) file failure.":T132. WHEN 26 THEN cTxt = "A sharing violation occurred.":T132. WHEN 27 THEN cTxt = "The filename association is incomplete or invalid.":T132. WHEN 28 THEN cTxt = "The DDE transaction could not be completed because the request timed out.":T132. WHEN 29 THEN cTxt = "The DDE transaction failed.":T132. WHEN 30 THEN cTxt = "The DDE transaction could not be completed because other DDE transactions were being processed.":T132. WHEN 31 THEN cTxt = "There is no application associated with the given filename extension.":T132. WHEN 32 THEN cTxt = "The specified dynamic-link library was not found.":T132. OTHERWISE cTxt = "Undocumented error code returned":T132. END. RETURN cTxt. END PROCEDURE.
This example by Tim Townsend replaces the old example, which was published here until 5 januari 2000. For those who still use a copy of the old source: this new one is better because you can now pass a URL, like "www.progress.com", to the cFilename parameter.