Skip to content
⌘ NSIS Forum Archive

NSIS FileOpen in read mode is shared?

6 posts

SJSJ#

NSIS FileOpen in read mode is shared?

Hello,

When I open a file in mode "r" - FileOpen "filename" r, does it lock the file for exclusive use? I believe, in "r" mode, the process shouldn't lock the resource.

I have a common file which is written by a java program and read by NSIS. When NSIS opens the file in "r" mode and reads it, the java program throws an exception during its write with the message that the file is in use by another program.

Is there a way in NSIS to open shared resource for reading without locking it?

Thank you!
LoRd_MuldeR#
When a file is open for reading, it usually is shared for reading (i.e. no exclusive lock), but not for writing.

And it seems that is what NSIS does:
HANDLE NSISCALL myOpenFile(const char *fn, DWORD da, DWORD cd)
{
  int attr = GetFileAttributes(fn);
  return CreateFile(
    fn,
    da,
    FILE_SHARE_READ,
    NULL,
    cd,
    attr == INVALID_FILE_ATTRIBUTES ? 0 : attr,
    NULL
  );
} 
Sharing a file for writing, while you still are reading from it, is inherently dangerous...

(And, as FILE_SHARE_READ is hardcoded, you cannot change it without re-compiling the EXE headers)
Lloigor#
Just made that, hope that can help.. 😉

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Easily opens files with more options than FileOpen
;;   P1 :o: Handle returned
;;   P2 :i: File name
;;   P3 :i: Access Mode
;;         'r'  : Readonly
;;         'w'  : Writeonly
;;         'rw' : Read+Write
;;   P4 :i: Share mode
;;         ''    : None
;;         'r'   : Readonly
;;         'rw'  : Read+Write
;;         'rwd' : Read+Write+Delete
;;   P5 :i: Create mode
;;         ''  : Open existing only
;;         'c' : Create if not exist
;;         'o' : Create and Overwrite
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
!define FileOpenEx "!insertmacro _FileOpenEx"
!macro _FileOpenEx _Handle_ _File_ _Access_ _Share_ _Create_
   Push "${_Create_}"
   Push "${_Share_}"
   Push "${_Access_}"
   Push "${_File_}"
   Call FileOpenEx
   Pop ${_Handle_}
!macroend
Function FileOpenEx  ;; $0:File, $1:Access, $2:Sharing, $3:Create
   Exch $0
   Exch
   Exch $1
   Exch 2
   Exch $2
   Exch 3
   Exch $3
   StrCmp "r" $1 0 +3
      StrCpy $1 0x80000000  ;; GENERIC_READ
      Goto +6
   StrCmp "w" $1 0 +3
      StrCpy $1 0x40000000  ;; GENERIC_WRITE
      Goto +3
   StrCmp "rw" $1 0 +3
      StrCpy $1 0xC0000000  ;; GENERIC_READ | GENERIC_WRITE
   StrCmp "" $2 0 +3
      StrCpy $2 0   ;; FILE_SHARE_NONE
      Goto +9
   StrCmp "r" $2 0 +3
      StrCpy $2 1   ;; FILE_SHARE_READ
      Goto +6
   StrCmp "rw" $2 0 +3
      StrCpy $2 3   ;; FILE_SHARE_READ | FILE_SHARE_WRITE
      Goto +3
   StrCmp "rwd" $2 0 +3
      StrCpy $2 7   ;; FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE
   StrCmp "" $3 0 +3
      StrCpy $3 3   ;; OPEN_EXISTING
      Goto +6
   StrCmp "c" $3 0 +3
      StrCpy $3 4   ;; OPEN_ALWAYS
      Goto +3
   StrCmp "o" $3 0 +3
      StrCpy $3 2   ;; CREATE_ALWAYS
   System::Call 'Kernel32::CreateFile(t, i, i, i, i, i, i) i (r0, r1, r2, 0, r3, 0x80, 0) .r2'  ;; Open/Create file
   Pop $3
   Pop $0
   Pop $1
   Exch $2
FunctionEnd 
Example:
${FileOpenEx} $0 "SomeFile.ext" "r" "rwd" "" ;; opens SomeFile.ext in read mode with full share access, if it exists

*
Afrow UK#
It might be worth changing all those run time string comparisons to compile time (by using !if).

Stu
Lloigor#edited
If you really nead maximum speed, ex: if you open a large amount of files in a tight loop, you may want a more direct approach, something like:
!define ApiCreateFile "!insertmacro _ApiCreateFile"
!macro _ApiCreateFile _Handle_ _File_ _Access_ _Share_ _Create_
   System::Call 'Kernel32::CreateFile(t, i, i, i, i, i, i) i ("${_File_}", ${_Access_}, ${_Share_}, 0, ${_Create_}, 0x80, 0) .s'  ;; Open/Create file
   Pop ${_Handle_}
!macroend