WordOpen.sas

/****************************************************************************/
/*  Program Name  : WordOpen                                                */
/*  Purpose       : Macro utility to open Word application or specific      */
/*                  Word file. Terminates if process takes longer than      */
/*                  10 seconds.                                             */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  Author        : Matt Trzcinski                                          */
/*  Last Update   : 2017/05/06                                              */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  Input(s)      : None or Word file (.doc, .docm, .docx, .docx, .dot,     */
/*                  .dotm, .dotx, .htm, .html, .htm, .html, .mht, .mhtml,   */
/*                  .odt, .pdf, .rtf, .txt, .wps, .xml, .xml, .xps)         */
/*  Output(s)     : None                                                    */
/*  Usage         : To open an Word file, pass the full file path into      */
/*                  WordOpen(). Arguments may be either quoted or           */
/*                  unquoted. Arguments are not case sensitive. To open     */
/*                  the Word application, leave argument blank. A single    */
/*                  Word session is forced to avoid conflicts.              */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  Example       : Open a Word file:                                       */
/*                                                                          */
/*                    %WordOpen(C:\filepath\test.docx);                     */
/*                                                                          */
/*                  Open the Word application:                              */
/*                                                                          */
/*                    %WordOpen();                                          */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*  Note          : Program checks if the Word application has opened by    */
/*                  attempting to establish a Winword|System DDE link.      */
/*                  WordOpen() may run longer than 10 seconds in the case   */
/*                  where the Word application itself has not been fully    */
/*                  loaded due to OS delays.  In terms of DATA step         */
/*                  diagnostics, WordOpen() times out according to the      */
/*                  'cpu time' and not the 'real time'. If the process      */
/*                  hangs on a data step, try closing all Mircosoft         */
/*                  applications before running this macro.                 */
/*                                                                          */
/*                  Exercise caution when opening a document from a network */
/*                  drive. Word must open before loading the document.      */
/*                  Since WordOpen() checks for whether the Word            */
/*                  application has loaded, program execution may continue  */
/*                  before the document has been opened due to network      */
/*                  delays. If a document DDE link is attempted prior to    */
/*                  the document having loaded an error will occur.         */
/*                                                                          */
/****************************************************************************/

%macro IsEmpty(macroVariable);
  %sysevalf(%superq(&macroVariable)=, boolean)
%mend;

%macro SetSystemOptions(opt1, opt2, opt3);
  options &opt1. &opt2. &opt3.;
%mend;

%macro WordOpen(inFile) / minoperator mindelimiter = ',';
%put NOTE: [&SYSMACRONAME] Executing: WordOpen(inFile=&inFile);
%if 0 %then %nrstr(%mend);

  %let macroStart    = %sysfunc(datetime());

  %let originalNOTES = %sysfunc(getoption(notes));
  %let originalXWAIT = %sysfunc(getoption(xwait));
  %let originalXSYNC = %sysfunc(getoption(xsync));

  options nonotes noxsync noxwait;

********************************************************************

** Verify Arguments

********************************************************************;
  %if %IsEmpty(inFile) %then %let filePath = WINWORD;
  %else %let filePath = %sysfunc(dequote(&inFile.));

  %let fileExtension = %substr(&filePath., %sysfunc(findc(&filePath., ., B)) + 1);

  %if not (%upcase(&fileExtension.) in (DOC, DOCM, DOCX, DOCX,
                                        DOT, DOTM, DOTX,
                                        HTM, HTML, HTM, HTML,
                                        MHT, MHTML, ODT, PDF,
                                        RTF, TXT, WPS,
                                        XML, XML, XPS, WINWORD))%then %do;
    %put ERROR: [&SYSMACRONAME] Invalid input. Not a valid Word file.;
    %SetSystemOptions(&originalNOTES., &originalXWAIT., &originalXSYNC.);
    %abort cancel;
    %end;

********************************************************************

** Attempt to open Word/Test whether Word has opened

********************************************************************;
  /*filePath must be quoted in case path contains space.

    Double quotes are used on "WINWORD" to match those

    surrounding the resolved &filePath. The switch /q

    suppresses the splash screen*/
  %if "&filePath." = "WINWORD" %then %do;
    %let cmdStatement = start winword /q;
    %let openMessage  = Word application;
    %end;
  %else %do;
    %let cmdStatement = start winword /q "&filePath.";
    %let openMessage  = &filePath.;
    %end;

  filename wordDDE dde 'winword|system';

  %let linkConnection = %sysfunc(fopen(wordDDE, S));

  %if &linkConnection > 0 %then %do;
    %put ERROR: [&SYSMACRONAME] Word already open.;
    %SetSystemOptions(&originalNOTES., &originalXWAIT., &originalXSYNC.);
    %abort cancel;
    %end;
  %else %do;
    %SetSystemOptions(notes);
    %put NOTE: [&SYSMACRONAME] Opening &openMessage....;
    %SetSystemOptions(nonotes);
    %sysexec(&cmdStatement.);

    /*Run until either Word opens (linkConnection > 0)

      or until 10 seconds have passed.*/
    %let stopTime = %sysevalf(%sysfunc(datetime()) + 10);

    %do %until (&linkConnection. > 0);
      %if (%sysfunc(datetime()) >= &stopTime.) %then %do;
        %put ERROR: [&SYSMACRONAME] Operation timed out.;
        %sysexec(taskkill /f /im winword.exe);
        %SetSystemOptions(&originalNOTES., &originalXWAIT., &originalXSYNC.);
        %abort cancel;
        %end;

      %let linkConnection = %sysfunc(fopen(wordDDE, S));
    %end;
  %end;

  %let closeReturnCode = %sysfunc(fclose(&linkConnection.));

********************************************************************

** Housekeeping

********************************************************************;
  filename wordDDE clear;
  %SetSystemOptions(notes, &originalXWAIT., &originalXSYNC.);

  %put NOTE: [&SYSMACRONAME] Succesfully opened &openMessage..;
  %put NOTE: [&SYSMACRONAME] WORDOPEN macro used (Total process time):;

  %let duration = %sysfunc(putn(%sysevalf(%sysfunc(datetime())-&macroStart.), time12.3));
  %if %sysfunc(minute("&duration."t)) > 0 %then %do;
    %put NO%str(TE-)         real time            %substr(&duration., 3, 8);
    %end;
  %else %do;
    %put NO%str(TE-)         real time            %substr(&duration., 6, 5) seconds;
    %end;

  %SetSystemOptions(&originalNotes.);

%mend;

Powered by peut-publier

©2020 Matt Trzcinski