Reading and setting file attributes

Let's start with a couple of definitions:

&GLOBAL-DEFINE FILE_ATTRIBUTE_READONLY 1
&GLOBAL-DEFINE FILE_ATTRIBUTE_HIDDEN 2
&GLOBAL-DEFINE FILE_ATTRIBUTE_SYSTEM 4
&GLOBAL-DEFINE FILE_ATTRIBUTE_DIRECTORY 16
&GLOBAL-DEFINE FILE_ATTRIBUTE_ARCHIVE 32
&GLOBAL-DEFINE FILE_ATTRIBUTE_NORMAL 128
&GLOBAL-DEFINE FILE_ATTRIBUTE_COMPRESSED 2048
 
PROCEDURE SetFileAttributesA EXTERNAL "kernel32" :
   DEFINE INPUT PARAMETER lpFilename AS CHARACTER.
   DEFINE INPUT PARAMETER dwFileAttributes AS LONG.
END.
 
PROCEDURE GetFileAttributesA EXTERNAL "kernel32" :
   DEFINE INPUT PARAMETER lpFilename AS CHARACTER.
   DEFINE RETURN PARAMETER dwFileAttributes AS LONG.
END.

The first example shows how to make a file read-only. It also clears most of the existing attributes because only one attribute is specified.

RUN SetFileAttributesA ( "c:\autoexec.bat", {&FILE_ATTRIBUTE_READONLY} ).

(Specify FILE_ATTRIBUTE_NORMAL to clear all attributes.)
The next example makes the file read-only and leaves the existing attributes intact.

DEFINE VARIABLE lv_attribs AS INTEGER NO-UNDO.
 
RUN GetFileAttributesA ( "c:\autoexec.bat", OUTPUT lv-attribs ).
/* if lv-attribs does not include {&FILE_ATTRIBUTE_READONLY} then */
RUN SetFileAttributesA ( "c:\autoexec.bat", lv-attribs + {&FILE_ATTRIBUTE_READONLY}).

The commented line should be replaced by an actual IF-statement. You can use procedure CheckOneAttribute by Dmitri, or a variant of his procedure, to test if the file already has the attribute set.

/* by Dmitri Levin, dlevin@ryland.com */
DEFINE VARIABLE lv-filename     AS CHARACTER INIT "c:\autoexec.bat" NO-UNDO.
DEFINE VARIABLE lv-attribs      AS INTEGER NO-UNDO.
DEFINE VARIABLE lv-attribs-list AS CHARACTER NO-UNDO.
 
RUN GetFileAttributesA ( lv-filename, OUTPUT lv-attribs ).
 
RUN CheckOneAttribute( lv-attribs, 
                       {&FILE_ATTRIBUTE_READONLY},  
                       "READONLY",
                       INPUT-OUTPUT lv-attribs-list).
RUN CheckOneAttribute( lv-attribs, 
                       {&FILE_ATTRIBUTE_HIDDEN},    
                       "HIDDEN",
                       INPUT-OUTPUT lv-attribs-list).
RUN CheckOneAttribute( lv-attribs, 
                       {&FILE_ATTRIBUTE_SYSTEM},    
                       "SYSTEM",
                       INPUT-OUTPUT lv-attribs-list).
RUN CheckOneAttribute( lv-attribs, 
                       {&FILE_ATTRIBUTE_DIRECTORY}, 
                       "DIRECTORY",
                       INPUT-OUTPUT lv-attribs-list).
RUN CheckOneAttribute( lv-attribs, 
                       {&FILE_ATTRIBUTE_ARCHIVE},   
                       "ARCHIVE",
                       INPUT-OUTPUT lv-attribs-list).
 
MESSAGE "File Attributes:" lv-attribs-list VIEW-AS ALERT-BOX.
 
PROCEDURE CheckOneAttribute :
  DEFINE INPUT PARAMETER lp-attribs  AS INTEGER NO-UNDO.
  DEFINE INPUT PARAMETER lp-attrib-num  AS INTEGER NO-UNDO.
  DEFINE INPUT PARAMETER lp-attrib-name  AS CHARACTER NO-UNDO.
  DEFINE INPUT-OUTPUT PARAMETER lp-attrib-list  AS CHARACTER NO-UNDO.
 
  IF lp-attribs MOD ( lp-attrib-num * 2 ) GE lp-attrib-num THEN
     lp-attrib-list = lp-attrib-list + MIN(lp-attrib-list,", ") + lp-attrib-name.
END.