TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Rabbit on January 14, 2013, 04:06:48 PM

Title: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: Rabbit on January 14, 2013, 04:06:48 PM
I have found several snippets of code relating to file times, particularity dealing with comparing two different file times.  Each one kept failing and I wasn't sure why.  Then after some more research, I find out about the "flaw" with VL-FILE-SYSTIME reporting NIL when a file is marked as being open.  Most times, that would be fine, but what should I do if the file is open and I need to retrieve it's last saved time stamp?  Is there some ARX or VLAX or some other way to access this information?  I don't want to use something that I have to download, like DOS_LIB, to be placed on each machine.

Thanks,
Rabbit
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: owenwengerd on January 14, 2013, 06:09:05 PM
I don't have any code handy, but you can use the Scripting.FileSystemObject. If you google it, you may find some existing code get the DateLastModified property of a File object.
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: Lee Mac on January 14, 2013, 06:33:55 PM
Perhaps try something like this:

Code - Auto/Visual Lisp: [Select]
  1. (defun _lastmodified ( filename / fnm fso obj rtn )
  2.     (if
  3.         (and
  4.             (setq fnm (findfile filename))
  5.             (setq fso (vlax-create-object "scripting.filesystemobject"))
  6.         )
  7.         (progn
  8.             (setq rtn
  9.                 (vl-catch-all-apply
  10.                     (function
  11.                         (lambda ( )
  12.                             (setq obj (vlax-invoke-method fso 'getfile fnm))
  13.                             (+ 2415019 (vlax-get-property obj 'datelastmodified))
  14.                         )
  15.                     )
  16.                 )
  17.             )
  18.             (if (= 'vla-object (type obj))
  19.                 (vlax-release-object obj)
  20.             )
  21.             (vlax-release-object fso)
  22.             (if (vl-catch-all-error-p rtn)
  23.                 (prompt (vl-catch-all-error-message rtn))
  24.                 rtn
  25.             )
  26.         )
  27.     )
  28. )

Returns Julian date.
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: Rabbit on January 23, 2013, 05:03:54 PM
Exactly what I was needing Lee.  Yet again, you've surprised me at how you went about what you done.  I was trying to compare the VL-FILE-SYSTIME returns.  With your method, it' comparing REAL's which will return better information.  With that all said, I would've never figured it out.  Looks like you got the information about the file from .NET, C#, C++ or something else that I don't know, nor understand.  As soon as I.T. gets Visual Studio on my computer, I'm diving into C#.  I'm so looking forward to learning it.

I can't say it enough, but "Thanks Again!"
Rabbit
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: BlackBox on January 23, 2013, 05:13:20 PM
Looks like you got the information about the file from .NET, C#, C++ or something else that I don't know, nor understand. 

It's not .NET actually, Visual LISP can tap into the ActiveX COM API (similar to VBA), which is what's happening when one invokes the *Create-Object Methods. In this case Lee's code accesses the FileSystemObject (http://msdn.microsoft.com/en-us/library/6kxy1a51%28VS.85%29.aspx)Object.

Like many other Windows Objects, such as Shell.Application, or even the ADsSecurityUtility Object, once you've gotten an active, or created a new instance of (aka an External Object), you can also tap into all of the External Object's Properties, and Methods from LISP (generally speaking)

.NET can also access these Objects, but in a different manor.

Note - Just be sure to safely 'release' External Objects.



As soon as I.T. gets Visual Studio on my computer, I'm diving into C#.  I'm so looking forward to learning it.

You'll enjoy it a lot more after the initial learning curve... This thread (http://www.theswamp.org/index.php?topic=43616.0) may help with that.
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: pBe on January 24, 2013, 12:59:52 AM
Perhaps try something like this:

Code - Auto/Visual Lisp: [Select]
  1. (defun _lastmodified ( filename / fnm fso obj rtn )
  2. <......>
  3.    

Returns Julian date.

Copy/Paste/Toolbox you go.  :)

You'll enjoy it a lot more after the initial learning curve... This thread (http://www.theswamp.org/index.php?topic=43616.0) may help with that.

<Like>  :)
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: BlackBox on January 24, 2013, 01:43:51 AM
 :-D

Mark would appreciate your adaptation of the like button. That HarvardX class I mention is pretty awesome too.

/OffTopic
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: Lee Mac on January 24, 2013, 06:26:56 AM
Thank you for providing the explanation Renderman - saved me some time  :-)

You're very welcome Rabbit & pBe, I'm glad it helps.
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: BlackBox on January 24, 2013, 08:49:49 AM
Thank you for providing the explanation Renderman - saved me some time  :-)

Cheers Lee :beer:
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: MP on November 05, 2014, 02:24:32 PM
For the longest time I have been using DOS_LIB's dos_fileex function to deal with vl-file-systime flakiness.

Odd timing: Today I needed to make a DOS_LIB free variant so I penned the code below. For what it's worth ...

Code: [Select]
(defun _Try ( try_statement / try_catch try_result )

    ;;  General purpose error trapper.

    (if
        (vl-catch-all-error-p
            (setq try_catch
                (vl-catch-all-apply
                    (function
                        (lambda ( )
                            (setq try_result (eval try_statement))
                        )
                    )
                )
            )
        )
        (setq *try_errors* ;; lexical global
            (cons
                (list
                    try_statement
                    (vl-catch-all-error-message try_catch)
                )
                *try_errors*
            )
        )
    )

    try_result

)

(defun _JulianToDateStr ( julian_date / @floor @itoa a b c d e f y z year month day hours mins secs )

    ;;  Renamed, reformatted and generally abused version of Jon
    ;;  Fleming's classic JUL_CAL function written around 1991-09-09.
    ;;  This version is coded to return the resulting value as a string,
    ;;  e.g. "20121104_082248". I need this for file creation utilities
    ;;  so often this is the default date format I use. Apologies if this
    ;;  insults your sensibilities. MP.
    ;;  ~ ~ ~
    ;;  Calculate date. It's magic, don't even ask. Some things we
    ;;  weren't meant to know. Jon Fleming.

    (defun @floor ( number )
        (fix
            (if (> number 0)
                number
                (- number 1)
            )
        )
    )

    (defun @itoa ( i / result )
        (setq result (itoa i))
        (while (< (strlen result) 2)
            (setq result (strcat "0" result))
        )
        result
    )

    (setq
        z     (fix julian_date)
        a     (fix (/ (- z 1867216.25) 36524.25))
        a     (+ z 1 a (- (fix (/ a 4))))
        b     (+ a 1524)
        c     (fix (/ (- b 122.1) 365.25))
        d     (@floor (* 365.25 c))
        e     (fix (/ (- b d) 30.6001))
        day   (fix (- b d (@floor (* 30.6001 e))))
        e     (- e (if (< e 14) 2 14))
        month (1+ e)
        year  (if (> e 1) (- c 4716) (- c 4715))
        year  (if (zerop year) (1- year) year)
        ;;    Calculate time. First strip the time portion
        ;;    from the input.
        y     (- julian_date (fix julian_date))
        ;;    Number of hours since midnight.
        hours (fix (* y 24))
        ;;    A temporary variable we'll use a couple of times.
        f     (- y (/ hours 24.0))
        ;;    Number of minutes since midnight (1440 minutes per
        ;;    day).
        mins  (fix (* f 1440))
        ;;    Number of seconds since midnight (86400 seconds per
        ;;    day). MP added (+ 0.5 ...) to match values returned by
        ;;    the vl-file-systime function.
        secs  (fix (+ 0.5 (* (- f (/ mins 1440.0)) 86400)))
    )

    (strcat
        (itoa year) (@itoa month) (@itoa day)
        "_"
        (@itoa hours) (@itoa mins) (@itoa secs)
    )

)

(defun _GetFileDateVL ( filename / path temp result )

    ;;  Return the file's date (last modified) as a string,
    ;;  e.g. "20120911_073435". I need this for file creation
    ;;  utilities so often this is the default date format I
    ;;  use. Apologies if it insults your sensibilities. MP.

    (if (setq path (findfile (findfile filename)))
        (if (_Try '(setq temp (vl-file-systime path)))
            (strcat
                (substr
                    (setq result
                        (apply 'strcat
                            (mapcar
                                (function
                                    (lambda ( n / s )
                                        (if (eq 1 (strlen (setq s (itoa (nth n temp)))))
                                            (strcat "0" s)
                                            s
                                        )
                                    )
                                )
                               '(0 1 3 4 5 6)
                            )
                        )
                    )
                    1 ;; 2014 11 03
                    8
                )
                "_"
                (substr result 9)
            )
        )
    )
)

(defun _FSO ( )

    ;;  cache it (I call it repeatedly)
    (setq *fso* (vlax-create-object "scripting.filesystemobject"))
    (defun _FSO ( ) *fso*)
    *fso*

)

(defun _GetFileDateFSO ( filename / file result )

    ;;  Return the file's date (last modified) as a string,
    ;;  e.g. "20120911_073435". I need this for file creation
    ;;  utilities so often this is the default date format I
    ;;  use. Apologies if it insults your sensibilities. MP.
    ;;
    ;;  Nods to Lee Mac, Black Box, Irneb and Jon Fleming for
    ;;  respective tips, tricks, resources or sample code that
    ;;  contributed to this variant.

    (_Try
       '(setq result
            (_JulianToDateStr
                (+ 2415019
                    (vlax-get
                        (setq file
                            (vlax-invoke
                                (_FSO)
                                'GetFile
                                (findfile filename)
                            )
                        )
                        'DateLastModified
                    )
                )
            )
        )
    )

    (if file (_Try '(vlax-release-object file)))

    result

)

(defun _GetFileDate ( filename / result )

    ;;  Wrapper function for _GetFileDateVL and _GetFileDateFSO
    ;;  functions, visual lisp and file system object methods
    ;;  respectively.
    ;;
    ;;  Return the file's date (last modified) as a string,
    ;;  e.g. "20120911_073435". I need this for file creation
    ;;  utilities so often this is the default date format I
    ;;  use. Apologies if it insults your sensibilities. MP.

    (or
        ;;  try visual lisp first
        (setq result (_GetFileDateVL filename))
        ;;  vl-file-systime failed, call the fso sledge hammer
        (setq result (_GetFileDateFSO filename))
    )

    result

)

tl;dr: _GetFileDate is a wrapper function, will use vl-file-systime based function if it can, otherwise exploiting the file system object based variant. Nods to Lee Mac, Black Box, Irneb and Jon Fleming for respective tips, tricks, resources or sample code that contributed to the variants above.
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: Cathy on November 05, 2014, 04:25:55 PM
What about using (getvar "tdupdate")? 
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: MP on November 05, 2014, 07:25:19 PM
While it's a worthy suggestion the tdupdate variable is only applicable for the active drawing. I need to be able to (swiftly) determine the date stamp for many files, not just the active drawing, notwithstanding for file types beyond AutoCAD drawings. Cheers. :)
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: BlackBox on November 06, 2014, 02:52:40 PM
... I need to be able to (swiftly) determine the date stamp for many files, not just the active drawing, notwithstanding for file types beyond AutoCAD drawings. Cheers. :)

[kludge]

Code - Auto/Visual Lisp: [Select]
  1. (defun _FOO (filePath)
  2.   (startapp (strcat "PowerShell -NoExit Get-ChildItem "
  3.                     filePath
  4.                     "| where { $_.LastWriteTime }"
  5.             )
  6.   )
  7.   (princ)
  8. )
  9.  

[/kludge]



[Edit] - For those not already aware, from PowerShell dialog, <Enter> copies selected content to clipboard.

Cheers
Title: Re: Anybody got a work around for VL-FILE-SYSTIME returning NIL if file is open?
Post by: MP on August 09, 2019, 05:18:31 PM
MANY YEARS LATE BUT ...


Failed to notice this response, thanks BB!