Programatically Change Attributes of Windows File with Wild Cards (*.jpg) in VFP

0

Hoping to use a windows shell API call that can accept wild cards to change attributes programmatically. Utmost thanks/blessings for any/all thoughts.

Borrowing code from http://www.resolvinghere.com/sm/how-do-i-change-an-attribute-of-a-file-from-within-a-visual-foxpro-program.shtml

RUN /N ATTRIB +H "c:\test.txt" && Hidden causes dos window to noise itself RUN /N ATTRIB -H "c:\test.txt" && UnHidden

Tom recalled this ... but it does not take wild-cards:

*------------CHAR-------HEX------------------BIN---------NUM
* READONLY R 0x00000001 00000000 00000001 1
* HIDDEN H 0x00000002 00000000 00000010 2
* SYSTEM S 0x00000004 00000000 00000100 4
* DIRECTORY D 0x00000010 00000000 00010000 16
* ARCHIVE A 0x00000020 00000000 00100000 32
* NORMAL N 0x00000080 00000000 10000000 128
* TEMPORARY T 0x00000100 00000001 00000000 256
* COMPRESS C 0x00000800 00001000 00000000 2048
* NOINDEX I 0x00002000 00100000 00000000 8192
* CHIPHER P 0x00004000 01000000 00000000 16384
* ERROR 0xFFFFFFFF REPL("1",32) 4294967295
* ----------------------------------------------------------------------

LPARAMETER vFilename as String, vNewAttribute as String LOCAL liFlag as Integer, llResult, liAttributes, lnNewAttribute, cDummy, nBitPos, cBitMap

DECLARE INTEGER SetFileAttributes IN Win32API STRING, INTEGER DECLARE INTEGER GetFileAttributes IN Win32API STRING

llResult = .F.

IF !EMPTY(vFilename)

IF VARTYPE(vNewAttribute) = [C]
    lnNewAttribute = 0
    *          1234567890123456 
    cBitMap = [RHS DA NT  C IP ]

    FOR i = 1 TO LEN(vNewAttribute)
        cDummy = SUBSTR(vNewAttribute,i,1)
        nBitPos = AT(cDummy,cBitMap)
        IF nBitPos > 0
            lnNewAttribute = BITSET(lnNewAttribute, nBitPos -1 )
        ENDIF
    ENDFOR
ELSE
    lnNewAttribute = vNewAttribute
ENDIF

liAttributes = GetFileAttributes(vFilename)

IF (liAttributes # -1)
    lnNewAttribute = BITXOR(liAttributes, lnNewAttribute)
    llResult = (SetFileAttributes(vFilename, lnNewAttribute) = 1 )
ENDIF

ENDIF

RETURN llResult

attributes
visual-foxpro
windows-shell
asked on Stack Overflow Mar 16, 2016 by Philip • edited Mar 16, 2016 by dbenham

1 Answer

1

Of course RUN ... should not be one of your selections to accomplish a procedure where you don't need to shell to DOS at all.

Your question is two fold:

  1. How do get a list of files using a wildcard + in all subdirectories.

For this one you can use a bunch of alternatives such as FileSystemObject, Adir() or Filer.dll that ships with VFP and maybe more. Here I will sample with the Filer.dll (which is also the DLL used in HOME()+'tools\filer\filer.scx' ). Here is one enhanced wildcard match using filer:

*GetTree.prg
Lparameters tcStartDir,tcSkeleton,tcCursorName,;
    tlSubfolders,;
    tlWholeWords,tlIgnoreCase,tlSearchAnd,tcSearch1,tcSearch2,tcSearch3
Create Cursor (m.tcCursorName) ;
    (filepath m, filename m, ;
    FileSize i, fattr c(8), createtime T, lastacc T, lastwrite T)
Local oFiler, lnFound
oFiler = Createobject('filer.fileutil')
With m.oFiler
    .SearchPath = m.tcStartDir
    .FileExpression = m.tcSkeleton && Search for skeleton
    .Subfolder   = Iif(m.tlSubfolders,1,0)  && Check subfolders
    .IgnoreCase  = Iif(m.tlIgnoreCase,1,0)
    .WholeWords  = Iif(m.tlWholeWords,1,0)
    .SearchAnd   = Iif(m.tlSearchAnd,1,0)
    .SearchText1 = Iif(Empty(m.tcSearch1),"",m.tcSearch1)
    .SearchText2 = Iif(Empty(m.tcSearch2),"",m.tcSearch2)
    .SearchText3 = Iif(Empty(m.tcSearch3),"",m.tcSearch3)
    lnFound = .Find(0)
    For ix=1 To m.lnFound
        With .Files(m.ix)
            If !(Bittest(.Attr,4) And .Name = '.')
                Insert Into (m.tcCursorName) ;
                    (filepath, filename, FileSize, fattr, createtime, lastacc, lastwrite)  ;
                    values ;
                    (.Path, .Name, .Size, Attr2Char(.Attr), ;
                    Num2Time(.Datetime), Num2Time(.LastAccessTime), Num2Time(.LastWriteTime))
            Endif
        Endwith
    Endfor
Endwith
Return m.lnFound

Function Num2Time
    Lparameters tnFloat
    Return Dtot({^1899/12/30}+Int(m.tnFloat))+86400*(m.tnFloat-Int(m.tnFloat))

Function Attr2Char
    Lparameters tnAttr
    Return ;
        IIF(Bittest(m.tnAttr,0),'RO','RW')+;
        IIF(Bittest(m.tnAttr,1),'H','_')+;
        IIF(Bittest(m.tnAttr,2),'S','_')+;
        IIF(Bittest(m.tnAttr,4),'D','_')+;
        IIF(Bittest(m.tnAttr,5),'A','_')+;
        IIF(Bittest(m.tnAttr,6),'E','_')+;
        IIF(Bittest(m.tnAttr,7),'N','_')
  1. How do I set the attributes.

If you are not after those fancy attributes, that are rarely used, here is the function I have written for myself:

*SetFAttributes.prg
lparameters tcFileName, tlReadOnly, tlHidden, tlSystem
#define FILE_ATTRIBUTE_READONLY    0x00000001  
#define FILE_ATTRIBUTE_HIDDEN      0x00000002  
#define FILE_ATTRIBUTE_SYSTEM      0x00000004  

local lnNewAttr
lnNewAttr = iif(m.tlReadonly,FILE_ATTRIBUTE_READONLY,0)+;
      iif(m.tlHidden,FILE_ATTRIBUTE_HIDDEN,0)+;
      iif(m.tlSystem,FILE_ATTRIBUTE_SYSTEM,0)

declare integer SetFileAttributes in Win32API ;
    string @ lpFileName,  integer dwFileAttributes
declare integer GetFileAttributes in Win32API ;
  string @ lpFileName

return ( SetFileAttributes(@tcFilename, ;
    bitor(bitand(GetFileAttributes(@tcFilename),0xFFFFFFF8),m.lnNewAttr)) = 1)

Having the above prg files on hand, lets say you want to set all .txt files under c:\MyFolder and its subfolders to readonly, (not hidden, not system) you would be doing this:

Local lcFileName
GetTree('c:\MyFolder','*.txt', 'myCursor', .T.)
Select myCursor
scan for Atc('D',fAttr) = 0
   lcFileName = Addbs(Trim(FilePath))+Trim(FileName)
   SetFAttributes(m.lcFileName, .T., .F., .F.)      
endscan
answered on Stack Overflow Mar 16, 2016 by Cetin Basoz

User contributions licensed under CC BY-SA 3.0