FileSelectFile(Save) on Read-Only Files Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

FileSelectFile(Save) on Read-Only Files

04 Nov 2019, 00:55

Hello Community! I am having a problem on FileSelectFile, I am trying to save save a file with a name that already exist on the target directory, what is bad is that its Attribute is set as read-only. Is there a way to force fileselectfile(in save mode) continue setting the file? I want a workaround to select any files dynamically(read-only or nonread-only) because I often save files in different names and it happens that some of them are read-only(future friendly if read-only files are needed to be selected)
)

here is a test code for this

Code: Select all

FileDelete,readonly.txt
FileAppend,this is a read-only file,readonly.txt
FileSetAttrib,+R,readonly.txt

FileSelectFile,selectedfile,S24,%A_ScriptDir%,choose any file
; I tried selecting the "readonly.txt" and it fails showing a message "this file is set to read-only. Try again with a Different Name"

Please I really need a fix about this problem, waiting for anyone to nail this case.
hd0202
Posts: 183
Joined: 04 Oct 2013, 03:07
Location: Germany near Cologne

Re: FileSelectFile(Save) on Read-Only Files

04 Nov 2019, 01:44

from the docu, modified

Code: Select all

FileGetAttrib, Attributes, % selectedfile
if InStr(Attributes, "R")
    MsgBox The file is read-only.
Hubert
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

04 Nov 2019, 01:53

hd0202 wrote:
04 Nov 2019, 01:44
from the docu, modified

Code: Select all

FileGetAttrib, Attributes, % selectedfile
if InStr(Attributes, "R")
    MsgBox The file is read-only.
Hubert
That is one step ahead from defining if it is read-only. But have you tried selecting the readonly file via "fileselectfile"? How are you going to select it if "FileSelectFile" does not allow you to select this readonly file? That is why I cannot store the selected file at "selectfile" variable
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

04 Nov 2019, 03:04

BUMP

I was thinking of creating an artificial explorer based on autohotkey GUI. But before I come up to that, Any existing workarounds?
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
just me
Posts: 9450
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: FileSelectFile(Save) on Read-Only Files

04 Nov 2019, 12:05

FileSelectFile with the Save option calls the GetSaveFileName dialog. I don't think it'S possible to get the name of a read-only file from this dialog. But after you got the error message you can remove the read-only attribute from the file within the dialog (sufficient rights presumed).
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

05 Nov 2019, 04:55

just me wrote:
04 Nov 2019, 12:05
FileSelectFile with the Save option calls the GetSaveFileName dialog. I don't think it'S possible to get the name of a read-only file from this dialog. But after you got the error message you can remove the read-only attribute from the file within the dialog (sufficient rights presumed).
I see, Can you demonstrate how to remove the read-only attribute of the selected file when the error message pops up? I know how to use "FileSetAttrib". But I have no idea how to execute FileSetAttrib when an error message pops up.
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
just me
Posts: 9450
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: FileSelectFile(Save) on Read-Only Files

05 Nov 2019, 05:48

Because the dialog is still open and the script has no information about the file you'd have to do it manually by calling the "Properties" dialog from the right-click menu
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

06 Nov 2019, 01:07

just me wrote:
05 Nov 2019, 05:48
Because the dialog is still open and the script has no information about the file you'd have to do it manually by calling the "Properties" dialog from the right-click menu
I guess I really need to make an artificial explorer because of this limitation.
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
User avatar
rommmcek
Posts: 1473
Joined: 15 Aug 2014, 15:18

Re: FileSelectFile(Save) on Read-Only Files

06 Nov 2019, 03:48

Try this little dirty trick:

Code: Select all

FileDelete,readonly.txt
FileAppend, this is a read-only file, readonly.txt
FileSetAttrib, +R, readonly.txt
SetTimer, PrepareReadOnly, -300
FileSelectFile, selectedfile, S24, %A_ScriptDir%, choose any file
FileAppend, `r`nthis is a second line in read-only file, % SelectedFile
FileSetAttrib, +R, readonly.txt

Esc::ExitApp

PrepareReadOnly:
    FileSetAttrib, -R, readonly.txt
Return
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

06 Nov 2019, 07:19

rommmcek wrote:
06 Nov 2019, 03:48
Try this little dirty trick:

Code: Select all

FileDelete,readonly.txt
FileAppend, this is a read-only file, readonly.txt
FileSetAttrib, +R, readonly.txt
SetTimer, PrepareReadOnly, -300
FileSelectFile, selectedfile, S24, %A_ScriptDir%, choose any file
FileAppend, `r`nthis is a second line in read-only file, % SelectedFile
FileSetAttrib, +R, readonly.txt

Esc::ExitApp

PrepareReadOnly:
    FileSetAttrib, -R, readonly.txt
Return
It is not Dynamic, the script already know from the start the readonly file. If I selected a random file that is readonly, it will not detect this file.

"FileSelectFile, selectedfile, S24, %A_ScriptDir%, choose any file"

This file will not allow me to proceed.
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
User avatar
rommmcek
Posts: 1473
Joined: 15 Aug 2014, 15:18

Re: FileSelectFile(Save) on Read-Only Files

06 Nov 2019, 11:09

Sorry for that blunder!
aldrinjohnom wrote:I guess I really need to make an artificial explorer because of this limitation.
It's already been done by DigiDon

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

FileDelete,readonly.txt
FileAppend, this is a read-only file, readonly.txt
FileSetAttrib, +R, readonly.txt
WinWaitClose % "ahk_id " FileSelectSpecific("", A_ScriptDir,"File","Please Choose ReadOnly file(s)","",,"",,,1, 300, 650)
if !glb_FSReturn
	msgbox No selection
else
	FileSetAttrib, -R, % ReadOnly:= StrReplace(glb_FSReturn, "`n", "\")
FileAppend, `r`nthis is a second line in read-only file, % ReadOnly
FileSetAttrib, +R, % ReadOnly
run, % ReadOnly

Esc::ExitApp

;by DigiDon https://www.autohotkey.com/boards/viewtopic.php?f=6&t=43898&sid=7fd2a43d23929639506a609aa8681199
FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350") {
global
	
	;*****************************
	; MAKE SURE PREVIOUS OWNER IS RE-ENABLED AND EXISTING FS DESTROYED
	;*****************************
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	try Gui,FileSelectSpecific:Destroy
	;*****************************
	; CONTEXT MENU
	;*****************************
	try
	Menu, FSContextMenu, Add, SELECT, FSSelect
	Menu, FSContextMenu, Add, Create Folder, FSCreateFolder
	Menu, FSContextMenu, Add, Open Folder in Explorer, FSDisplayFolder
	Menu, FSContextMenu, Default, 1&

	;*****************************
	; GLOBAL VARS
	;*****************************
	glb_FSTitle=%A_ScriptName% - File Select Dialog
	
	glb_FSInit:=1
	glb_FSFolder:=P_Path
	glb_FSCurrent:=glb_FSFolder
	glb_FSFilterOK:=P_FilterOK
	glb_FSFilterNO:=P_FilterNO
	glb_FSRestrict:=P_Restrict

	glb_FSType:=P_SelectFileOrFolder
	glb_FSReturn:=""
	glb_FSOwnerNum:=P_OwnerNum
	
	
	if (P_SelectFileOrFolder="File" or P_SelectFileOrFolder="All")
		LoopType:="FD"
	else if (P_SelectFileOrFolder="Folder")
		LoopType:="D"
		
	glb_FSLoopType:=LoopType
	
	if P_Multi
		glb_FSNoMulti:=""
	else
		glb_FSNoMulti:="-Multi"
		
	; Check if the last character of the folder name is a backslash, which happens for root
	; directories such as C:\. If it is, remove it to prevent a double-backslash later on.
	StringRight, LastChar, glb_FSFolder, 1
	if LastChar = \
		StringTrimRight, glb_FSFolder, glb_FSFolder, 1  ; Remove the trailing backslash.
	glb_FSCurrent:=glb_FSFolder
		
	;*****************************
	; GUI CREATION
	;*****************************
	Gui, FileSelectSpecific:Default
	Gui, FileSelectSpecific: New
	Gui +HwndFSHwnd
	Gui +Resize +MinSize330x280
	
	;SET AND DISABLE OWNER
	if (glb_FSOwnerNum) {
		Gui +Owner%glb_FSOwnerNum%
		Gui, %glb_FSOwnerNum%:+Disabled
		}
	
	Gui +OwnDialogs  ; Forces user to dismiss the following dialog before using main window.

	; Create some buttons:
	Gui, Add, Button, xm w20 gFSSwitchView, % Chr(0x02630)
	Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSRefresh, % Chr(0x21BB)
	Gui, Add, Button, x+5 w30 gFSPrevious, % Chr(0x2190)
	; Gui, Font
	; Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSSelect, % "SELECT"
	Gui, Font
	Gui, Add, Edit, xm y+8 w%P_LVWidth% vFSNavBarv, % glb_FSCurrent
	Gui, Add, Text, xm y+8 w%P_LVWidth% vFSPromptv, % P_Prompt
	

	; Create the ListView and its columns:
	ListViewPos:= " w" P_LVWidth
	ListViewPos.= " h" P_LVHeight
	
	Gui, Add, ListView, xm y+10 %ListViewPos% vFSListView gFSListViewHandler %glb_FSNoMulti%, Name|In Folder|Size (KB)|Type
	LV_ModifyCol(3, "Integer")  ; For sorting, indicate that the Size column is an integer.
	
	if (P_DefaultView="Icon") {
		GuiControl, +Icon, FSListView    ; Switch to icon view.
		Glb_FSIconView:=1
	} else {
		GuiControl, +Report, FSListView  ; Switch back to details view.
		Glb_FSIconView:=0
	}
	
	Gui, Font, s10
	if P_ComplementText
		Gui, Add, Text, xm y+8 w%P_LVWidth% vFSComplementv, % P_ComplementText
	
	Gui, Font, Italic s9
	if !glb_FSNoMulti
		Gui, Add, Text, xm y+5 w%P_LVWidth% vFSMultiIndicv, % "Hold Ctrl or Shift for Multi-Selection"
	
	Gui, Font
	
	;*****************************
	; ICONS CREATION
	;*****************************
	; Calculate buffer size required for SHFILEINFO structure.
	FSIconArray:={}

	FSImageListID1 := IL_Create(10)
	FSImageListID2 := IL_Create(10, 10, true)  ; A list of large icons to go with the small ones.
	; Attach the ImageLists to the ListView so that it can later display the icons:
	LV_SetImageList(FSImageListID1)
	LV_SetImageList(FSImageListID2)

	; Gather a list of file names from the selected folder and append them to the ListView:
	;*****************************
	; SEARCH FILES AND SHOW GUI
	;*****************************
	GuiControl, -Redraw, FSListView  ; Improve performance by disabling redrawing during load.
	
	FSAddLoopFiles()
	FSRedrawCol()
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
	Gui, Show,,% glb_FSTitle
	glb_FSInit:=0
	
	return FSHwnd
}

FileSelectSpecificAdjust(P_Path="") {
	global
	if !P_Path
		P_Path:=glb_FSCurrent
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	LV_Delete()
	FSAddLoopFiles()
	GuiControl,,FSNavBarv, % glb_FSCurrent
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
}

FSAddLoopFiles() {
global
	Gui FileSelectSpecific: Default
	
	FSsfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
	VarSetCapacity(FSsfi, FSsfi_size,0)
	
	if !glb_FSCurrent {
		DriveGet, FSDriveList, list
		FSDriveLabels:={}
		
		Loop, parse, FSDriveList 
			{
			DriveGet, FSDriveLabel, Label, %A_Loopfield%:
			FSDriveLabels[A_Index]:=FSDriveLabel
		
			IconNumber:=FSSetIcon(A_Loopfield ":","",FSIconArray,FSImageListID1,FSImageListID2)
			
			LV_Add("Icon" . IconNumber, A_Loopfield ": " FSDriveLabels[A_Index], "", "", "")
			}
		return
	}

	Loop, Files, %glb_FSCurrent%\*, %glb_FSLoopType%
	{
		if A_LoopFileAttrib not contains R  ; Skip any file that is not (ReadOnly) ; Change: line added
		;if A_LoopFileAttrib contains H,S  ; Skip any file that is either H (Hidden), or S (System). Note: No spaces in "H,S". ; Change: line commented out
			continue  ; Skip this file and move on to the next one.
		
		; FileName := A_LoopFileFullPath  ; Must save it to a writable variable for use below.
		
		If glb_FSfilterOK
			If A_LoopFileExt not in ,%glb_FSfilterOK%
				continue
			
		If glb_FSFilterNO
			If A_LoopFileExt in %glb_FSFilterNO%
				continue
		
		IconNumber:=FSSetIcon(A_LoopFileFullPath,A_LoopFileExt,FSIconArray,FSImageListID1,FSImageListID2)

		; Create the new row in the ListView and assign it the icon number determined above:
		LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, A_LoopFileExt)
	}
}

FSSetIcon(P_Filepath,P_FileExt,ByRef P_IconArray,ByRef P_Imagelist1,ByRef P_ImageList2) {
global
	
	if P_FileExt in EXE,ICO,ANI,CUR
	{
		ExtID := P_FileExt  ; Special ID as a placeholder.
		IconNumber = 0  ; Flag it as not found so that these types can each have a unique icon.
	}
	else  ; Some other extension/file-type, so calculate its unique ID.
	{
		;TTRICK: if no ext it can be drive or directory or a file without ext. In this case we create a fake ext so they won't use the same icons and icons can be re-used
		if !P_FileExt
		{
			
			if Regexmatch(P_Filepath, ":$")
				P_FileExt:="DRIVE"
			else if InStr(FileExist(P_Filepath), "D")
				P_FileExt:="DIR"
			else if FileExist(P_Filepath)
				P_FileExt:="NOEXT"
		}
		ExtID = 0  ; Initialize to handle extensions that are shorter than others.
		Loop 7     ; Limit the extension to 7 characters so that it fits in a 64-bit value.
			{
			StringMid, ExtChar, P_FileExt, A_Index, 1
			if not ExtChar  ; No more characters.
				break
			; Derive a Unique ID by assigning a different bit position to each character:
			ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
			}
		; Check if this file extension already has an icon in the ImageLists. If it does,
		; several calls can be avoided and loading performance is greatly improved,
		; especially for a folder containing hundreds of files:
		IconNumber := P_IconArray[ExtID]
	}
	;can debug icons here
	; msgbox IconNumber %IconNumber% P_Filepath %P_Filepath% P_FileExt %P_FileExt%
	if not IconNumber  ; There is not yet any icon for this extension, so load it.
	{
		; Get the high-quality small-icon associated with this file extension:
		if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str", P_Filepath, "uint", 0, "ptr", &FSsfi, "uint", FSsfi_size, "uint", 0x101)  ; 0x101 is SHGFI_ICON+SHGFI_SMALLICON
			IconNumber = 9999999  ; Set it out of bounds to display a blank icon.
		else ; Icon successfully loaded.
		{
			; Extract the hIcon member from the structure:
			hIcon := NumGet(FSsfi, 0)
			; Add the HICON directly to the small-icon and large-icon lists.
			; Below uses +1 to convert the returned index from zero-based to one-based:
			IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", P_Imagelist1, "int", -1, "ptr", hIcon) + 1
			DllCall("ImageList_ReplaceIcon", "ptr", P_ImageList2, "int", -1, "ptr", hIcon)
			; Now that it's been copied into the ImageLists, the original should be destroyed:
			DllCall("DestroyIcon", "ptr", hIcon)
			; Cache the icon to save memory and improve loading performance:
			P_IconArray[ExtID] := IconNumber
		}
	}
	return IconNumber
}


;*****************************
;FS GUI LABELS
;*****************************
FSCreateFolder:
	Gui FileSelectSpecific: Default
	InputBox, FolderName, , % "Enter Folder Name",,,120
	if (ErrorLevel or !FolderName)
		return
	FileCreateDir, % glb_FSCurrent "/" FolderName
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSDisplayFolder:
	Gui FileSelectSpecific: Default
	FSOpenFolderInExplorer(glb_FSCurrent)
return

FSSwitchView:
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	if not Glb_FSIconView
		GuiControl, +Icon, FSListView    ; Switch to icon view.
	else
		GuiControl, +Report, FSListView  ; Switch back to details view.
	Glb_FSIconView := not Glb_FSIconView             ; Invert in preparation for next time.
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
return

FSRedrawCol() {
global
	Gui FileSelectSpecific: Default
	LV_ModifyCol()  ; Auto-size each column to fit its contents.
	LV_ModifyCol(2,0)  ; Hide FileDir Col
	LV_ModifyCol(3, 60) ; Make the Size column at little wider to reveal its header.
	LV_ModifyCol(4, "AutoHdr") ; Make the Size column at little wider to reveal its header.
}

FSListViewHandler:
	if A_GuiEvent = DoubleClick  ; There are many other possible values the script can check.
	{
		LV_GetText(FileName, A_EventInfo, 1) ; Get the text of the first field.
		LV_GetText(FileDir, A_EventInfo, 2)  ; Get the text of the second field.
		; LV_GetText(FileExt, A_EventInfo, 4)  ; Get the text of the fourth field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					break
				}
		}
			
		if InStr(FileExist(FilePath), "D") {
			glb_FSCurrent:=FilePath
			FileSelectSpecificAdjust(glb_FSCurrent)
			return
		}
		
		else if (FileExist(FilePath) and (glb_FSType="File" or glb_FSType="All")) {
			if glb_FSNoMulti
				glb_FSReturn:=FilePath
			else
				glb_FSReturn:=FileDir "`n" FileName
			
			if (glb_FSOwnerNum)
				Gui, %glb_FSOwnerNum%:-Disabled
			Gui,FileSelectSpecific:Destroy
			return
		}
	}
return

FSPrevious:
	Gui FileSelectSpecific: Default
	if !glb_FSCurrent
		return
	if (glb_FSCurrent=glb_FSFolder and glb_FSRestrict) {
		tooltip You can not navigate above the folder `n%glb_FSFolder%
		SetTimer, RemoveToolTip, -3000
		return
	}
	if !InStr(FileExist(FSGetParentDir(glb_FSCurrent)), "D")
		glb_FSCurrent:=""
	else
		glb_FSCurrent:=FSGetParentDir(glb_FSCurrent)
		
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSRefresh:
	Gui FileSelectSpecific: Default
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSSelect:
	Gui FileSelectSpecific: Default
	RowNumber = 0
	RowOkayed = 0 
	if !LV_GetNext(RowNumber) {
		msgbox Please select an element first
		return
	}
		
	Loop
	{
		RowNumber := LV_GetNext(RowNumber)  ; Resume the search at the row after that found by the previous iteration.
		; msgbox RowNumber %RowNumber%
		if not RowNumber  ; The above returned zero, so there are no more selected rows.
			break
		LV_GetText(FileName, RowNumber, 1) ; Get the text of the first field.
		LV_GetText(FileDir, RowNumber, 2)  ; Get the text of the second field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					FileName := A_Loopfield ":"
					break
				}
		}

		if !FileExist(FilePath)
			continue
		
		if (InStr(FileExist(FilePath), "D") and glb_FSType="File")
			continue
			
		if (!InStr(FileExist(FilePath), "D") and glb_FSType="Folder")
			continue
			
		RowOkayed++
		
		glb_FSMultiReturn.= "`n" FileName
		
	}
	
	if (RowOkayed=0) {
		msgbox sorry wrong selection
		return
	}
	
	if (RowOkayed=1 and glb_FSNoMulti)
		glb_FSReturn:=FilePath
	else
		glb_FSReturn:=FileDir . glb_FSMultiReturn

	if (glb_FSOwnerNum)
		Gui, %glb_FSOwnerNum%:-Disabled
		
	Gui,FileSelectSpecific:Destroy
return

;Context-sensitive hotkey to detect Enter on FS navigation bar
#If (FSHwnd and WinActive("ahk_id " FSHwnd))
Enter::
GuiControlGet, OutputVar, FileSelectSpecific:FocusV
; msgbox OutputVar %OutputVar%
if (OutputVar="FSNavBarv")
	Gosub, FSNavBar
Return
#If

;Enter on FS navigation bar
FSNavBar:
Gui, FileSelectSpecific:Default
GuiControlGet, FSNavBarv
StringRight, LastChar, FSNavBarv, 1
	if LastChar = \
		StringTrimRight, FSNavBarv, FSNavBarv, 1  ; Remove the trailing backslash.
if !InStr(FileExist(FSNavBarv), "D")
	return

if (glb_FSRestrict and !Instr(FSNavBarv,glb_FSFolder)) {
	tooltip You can not navigate above the folder `n%glb_FSFolder%
	SetTimer, RemoveToolTip, -3000
	return
	}
GuiControl,,FSNavBarv,% FSNavBarv

glb_FSCurrent:=FSNavBarv
FileSelectSpecificAdjust()
return

RemoveToolTip:
tooltip
return

;*****************************
;FS GUI SPECIAL LABELS
;*****************************
FileSelectSpecificGuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
Gui FileSelectSpecific: Default
	if A_GuiControl <> FSListView  ; This check is optional. It displays the menu only for clicks inside the ListView.
		return
	Menu, FSContextMenu, Show
return

FileSelectSpecificGuiClose:
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	Gui,Destroy
return

FileSelectSpecificGuiSize:  ; Readjust the controls in response to the user's resizing of the window.
	if A_EventInfo = 1  ; The window has been minimized.  No action needed.
		return
	;Do not trigger during init
	if glb_FSInit
		return
		
	GuiControl, -Redraw, FSListView

	GuiControlGet, FSComplementv
	GuiControlGet, FSMultiIndicv
	
	; Otherwise, the window has been resized or maximized. Resize the controls.
	
	GuiControlGet, FSListViewPos, Pos, FSListView
	
	GuiControl, MoveDraw, FSPromptv, % " W" . (A_GuiWidth-20)
	GuiControl, MoveDraw, FSNavBarv, % " W" . (A_GuiWidth-20)
	
	FSListGap=
	
	if (FSComplementv) {
		GuiControl, MoveDraw, FSComplementv, % "y" FSListViewPosY + FSListViewPosH + 10 " W" . (A_GuiWidth-20)
		FSListGap+=10
	}
	
	GuiControlGet, FSComplementPos, Pos, FSComplementv
	
	if (FSMultiIndicv) {
		GuiControl, MoveDraw, FSMultiIndicv, % "y" A_GuiHeight-20 " W" . (A_GuiWidth-20)
		FSListGap+=5
	}
	
	GuiControlGet, FSMultiIndicPos, Pos, FSMultiIndicv
	
	;Trick : Round() so that empty vars = 0
	FSListGap:=Round(FSComplementPosH) + Round(FSMultiIndicPosH) + 15
	
	GuiControl, MoveDraw, FSListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - FSListViewPosY - Round(FSListGap))
	
	;Set timer to recreate listview if icon view
	if (Glb_FSIconView)
		SetTimer, FileSelectSpecificAdjust, -200
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
return
;*****************************


;*****************************
;SMALL FS FUNCTIONS
;*****************************
FSGetParentDir(Path) {
	return SubStr(Path, 1, InStr(SubStr(Path,1,-1), "\", 0, 0)-1)
}

FSOpenFolderInExplorer(P_Folder) {
global
	if !InStr(FileExist(P_Folder), "D")
		return 0
	Run % P_Folder
}

Return

; **********************************************************
; FileSelectSpecific Functions by DigiDon
; **********************************************************
; Use/modify as you wish
; Based on Main example from https://autohotkey.com/docs/commands/ListView.htm
; **********************************************************
; AHK GUI alternative to the FileSelectFile / FileSelectFolder dialogs
; Allows more parameters/customization
; Allows to restrict navigation within a specific folder
; Allows to select File(s) or/and Folder(s)
; Allows to filter file types in or out
; **********************************************************
; FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350")
;*****************************
;	PARAMETERS
;*****************************
;----- P_OwnerNum: Num/Name of the Gui Owner: it will be disabled the time a selection is made
;----- P_Path: Starting Folder 
;EMPTY: Start with all disks
;----- P_SelectFileOrFolder : Type of Selection to make
;"File" : User should select File(s)
;"Folder" : User should select Folder(s)
;"All" : User should select File(s) and/or Folder(s)
;----- P_Prompt : Text to display at the top of GUI
;----- P_ComplementText : Text to display at the bottom the GUI
;----- P_Multi : MultiSelection
;VALUE: Allowed / EMPTY: Forbidden
;----- P_DefaultView : Default View for the Tree List
;"Icon" / "Report"
;----- P_FilterOK : Comma-list of allowed extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_FilterNO : Comma-list of forbidden extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_Restrict : The user should not be able to navigate above the starting folder
;----- P_LVHeight : Height of ListView in Px
;----- P_LVWidth  : Width  of ListView in Px
;*****************************
;	RETURN VALUE
;*****************************
;----- FSHwnd: Hwnd of the GUI windows
;*****************************
; GLOBAL VALUE TO CHECK AFTER CALL
;*****************************
;----- glb_FSReturn: Contains the path of the selected file(s)
;NO SELECTION : EMPTY
;NO Multi Selection: Path of the selected File
;Multi Selection: Path of the folder "`n" Paths of the selected files (`n separated)
;*****************************
;			USAGE
;*****************************
;ANY SINGLE FILE ANYWHERE
FSHwnd:=FileSelectSpecific("","","File","Please Choose a file")
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
; ONE OR MORE NON-RTF FILES WITHIN C:
FSHwnd:=FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
;*****************************
P.s.: Function is slightly modified (search for Change: line)
hd0202
Posts: 183
Joined: 04 Oct 2013, 03:07
Location: Germany near Cologne

Re: FileSelectFile(Save) on Read-Only Files

06 Nov 2019, 11:54

sorry, I misunderstood the problem. Add the following hotkey to your script to change the attribute:

Code: Select all

#j::
ControlGetText, ifield , Edit1, choose any file
; msgbox, % ifield
FileSetAttrib,-R,% a_scriptdir "\" ifield
; FileGetAttrib,attr,% a_scriptdir "\" ifield
; msgbox, % attr
return
When you select the file and get the message "file already exists" you change the attribute via (in my example) "windows + j" and then press "No", then the Select-window reappears and you press "Save" again, this time you press "Yes" and you can continue with the "selectedfile"

Hubert
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

06 Nov 2019, 21:58

rommmcek wrote:
06 Nov 2019, 11:09
Sorry for that blunder!
aldrinjohnom wrote:I guess I really need to make an artificial explorer because of this limitation.
It's already been done by DigiDon

Code: Select all

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

FileDelete,readonly.txt
FileAppend, this is a read-only file, readonly.txt
FileSetAttrib, +R, readonly.txt
WinWaitClose % "ahk_id " FileSelectSpecific("", A_ScriptDir,"File","Please Choose ReadOnly file(s)","",,"",,,1, 300, 650)
if !glb_FSReturn
	msgbox No selection
else
	FileSetAttrib, -R, % ReadOnly:= StrReplace(glb_FSReturn, "`n", "\")
FileAppend, `r`nthis is a second line in read-only file, % ReadOnly
FileSetAttrib, +R, % ReadOnly
run, % ReadOnly

Esc::ExitApp

;by DigiDon https://www.autohotkey.com/boards/viewtopic.php?f=6&t=43898&sid=7fd2a43d23929639506a609aa8681199
FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350") {
global
	
	;*****************************
	; MAKE SURE PREVIOUS OWNER IS RE-ENABLED AND EXISTING FS DESTROYED
	;*****************************
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	try Gui,FileSelectSpecific:Destroy
	;*****************************
	; CONTEXT MENU
	;*****************************
	try
	Menu, FSContextMenu, Add, SELECT, FSSelect
	Menu, FSContextMenu, Add, Create Folder, FSCreateFolder
	Menu, FSContextMenu, Add, Open Folder in Explorer, FSDisplayFolder
	Menu, FSContextMenu, Default, 1&

	;*****************************
	; GLOBAL VARS
	;*****************************
	glb_FSTitle=%A_ScriptName% - File Select Dialog
	
	glb_FSInit:=1
	glb_FSFolder:=P_Path
	glb_FSCurrent:=glb_FSFolder
	glb_FSFilterOK:=P_FilterOK
	glb_FSFilterNO:=P_FilterNO
	glb_FSRestrict:=P_Restrict

	glb_FSType:=P_SelectFileOrFolder
	glb_FSReturn:=""
	glb_FSOwnerNum:=P_OwnerNum
	
	
	if (P_SelectFileOrFolder="File" or P_SelectFileOrFolder="All")
		LoopType:="FD"
	else if (P_SelectFileOrFolder="Folder")
		LoopType:="D"
		
	glb_FSLoopType:=LoopType
	
	if P_Multi
		glb_FSNoMulti:=""
	else
		glb_FSNoMulti:="-Multi"
		
	; Check if the last character of the folder name is a backslash, which happens for root
	; directories such as C:\. If it is, remove it to prevent a double-backslash later on.
	StringRight, LastChar, glb_FSFolder, 1
	if LastChar = \
		StringTrimRight, glb_FSFolder, glb_FSFolder, 1  ; Remove the trailing backslash.
	glb_FSCurrent:=glb_FSFolder
		
	;*****************************
	; GUI CREATION
	;*****************************
	Gui, FileSelectSpecific:Default
	Gui, FileSelectSpecific: New
	Gui +HwndFSHwnd
	Gui +Resize +MinSize330x280
	
	;SET AND DISABLE OWNER
	if (glb_FSOwnerNum) {
		Gui +Owner%glb_FSOwnerNum%
		Gui, %glb_FSOwnerNum%:+Disabled
		}
	
	Gui +OwnDialogs  ; Forces user to dismiss the following dialog before using main window.

	; Create some buttons:
	Gui, Add, Button, xm w20 gFSSwitchView, % Chr(0x02630)
	Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSRefresh, % Chr(0x21BB)
	Gui, Add, Button, x+5 w30 gFSPrevious, % Chr(0x2190)
	; Gui, Font
	; Gui, Font, Bold
	Gui, Add, Button, x+5 yp gFSSelect, % "SELECT"
	Gui, Font
	Gui, Add, Edit, xm y+8 w%P_LVWidth% vFSNavBarv, % glb_FSCurrent
	Gui, Add, Text, xm y+8 w%P_LVWidth% vFSPromptv, % P_Prompt
	

	; Create the ListView and its columns:
	ListViewPos:= " w" P_LVWidth
	ListViewPos.= " h" P_LVHeight
	
	Gui, Add, ListView, xm y+10 %ListViewPos% vFSListView gFSListViewHandler %glb_FSNoMulti%, Name|In Folder|Size (KB)|Type
	LV_ModifyCol(3, "Integer")  ; For sorting, indicate that the Size column is an integer.
	
	if (P_DefaultView="Icon") {
		GuiControl, +Icon, FSListView    ; Switch to icon view.
		Glb_FSIconView:=1
	} else {
		GuiControl, +Report, FSListView  ; Switch back to details view.
		Glb_FSIconView:=0
	}
	
	Gui, Font, s10
	if P_ComplementText
		Gui, Add, Text, xm y+8 w%P_LVWidth% vFSComplementv, % P_ComplementText
	
	Gui, Font, Italic s9
	if !glb_FSNoMulti
		Gui, Add, Text, xm y+5 w%P_LVWidth% vFSMultiIndicv, % "Hold Ctrl or Shift for Multi-Selection"
	
	Gui, Font
	
	;*****************************
	; ICONS CREATION
	;*****************************
	; Calculate buffer size required for SHFILEINFO structure.
	FSIconArray:={}

	FSImageListID1 := IL_Create(10)
	FSImageListID2 := IL_Create(10, 10, true)  ; A list of large icons to go with the small ones.
	; Attach the ImageLists to the ListView so that it can later display the icons:
	LV_SetImageList(FSImageListID1)
	LV_SetImageList(FSImageListID2)

	; Gather a list of file names from the selected folder and append them to the ListView:
	;*****************************
	; SEARCH FILES AND SHOW GUI
	;*****************************
	GuiControl, -Redraw, FSListView  ; Improve performance by disabling redrawing during load.
	
	FSAddLoopFiles()
	FSRedrawCol()
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
	Gui, Show,,% glb_FSTitle
	glb_FSInit:=0
	
	return FSHwnd
}

FileSelectSpecificAdjust(P_Path="") {
	global
	if !P_Path
		P_Path:=glb_FSCurrent
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	LV_Delete()
	FSAddLoopFiles()
	GuiControl,,FSNavBarv, % glb_FSCurrent
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
}

FSAddLoopFiles() {
global
	Gui FileSelectSpecific: Default
	
	FSsfi_size := A_PtrSize + 8 + (A_IsUnicode ? 680 : 340)
	VarSetCapacity(FSsfi, FSsfi_size,0)
	
	if !glb_FSCurrent {
		DriveGet, FSDriveList, list
		FSDriveLabels:={}
		
		Loop, parse, FSDriveList 
			{
			DriveGet, FSDriveLabel, Label, %A_Loopfield%:
			FSDriveLabels[A_Index]:=FSDriveLabel
		
			IconNumber:=FSSetIcon(A_Loopfield ":","",FSIconArray,FSImageListID1,FSImageListID2)
			
			LV_Add("Icon" . IconNumber, A_Loopfield ": " FSDriveLabels[A_Index], "", "", "")
			}
		return
	}

	Loop, Files, %glb_FSCurrent%\*, %glb_FSLoopType%
	{
		if A_LoopFileAttrib not contains R  ; Skip any file that is not (ReadOnly) ; Change: line added
		;if A_LoopFileAttrib contains H,S  ; Skip any file that is either H (Hidden), or S (System). Note: No spaces in "H,S". ; Change: line commented out
			continue  ; Skip this file and move on to the next one.
		
		; FileName := A_LoopFileFullPath  ; Must save it to a writable variable for use below.
		
		If glb_FSfilterOK
			If A_LoopFileExt not in ,%glb_FSfilterOK%
				continue
			
		If glb_FSFilterNO
			If A_LoopFileExt in %glb_FSFilterNO%
				continue
		
		IconNumber:=FSSetIcon(A_LoopFileFullPath,A_LoopFileExt,FSIconArray,FSImageListID1,FSImageListID2)

		; Create the new row in the ListView and assign it the icon number determined above:
		LV_Add("Icon" . IconNumber, A_LoopFileName, A_LoopFileDir, A_LoopFileSizeKB, A_LoopFileExt)
	}
}

FSSetIcon(P_Filepath,P_FileExt,ByRef P_IconArray,ByRef P_Imagelist1,ByRef P_ImageList2) {
global
	
	if P_FileExt in EXE,ICO,ANI,CUR
	{
		ExtID := P_FileExt  ; Special ID as a placeholder.
		IconNumber = 0  ; Flag it as not found so that these types can each have a unique icon.
	}
	else  ; Some other extension/file-type, so calculate its unique ID.
	{
		;TTRICK: if no ext it can be drive or directory or a file without ext. In this case we create a fake ext so they won't use the same icons and icons can be re-used
		if !P_FileExt
		{
			
			if Regexmatch(P_Filepath, ":$")
				P_FileExt:="DRIVE"
			else if InStr(FileExist(P_Filepath), "D")
				P_FileExt:="DIR"
			else if FileExist(P_Filepath)
				P_FileExt:="NOEXT"
		}
		ExtID = 0  ; Initialize to handle extensions that are shorter than others.
		Loop 7     ; Limit the extension to 7 characters so that it fits in a 64-bit value.
			{
			StringMid, ExtChar, P_FileExt, A_Index, 1
			if not ExtChar  ; No more characters.
				break
			; Derive a Unique ID by assigning a different bit position to each character:
			ExtID := ExtID | (Asc(ExtChar) << (8 * (A_Index - 1)))
			}
		; Check if this file extension already has an icon in the ImageLists. If it does,
		; several calls can be avoided and loading performance is greatly improved,
		; especially for a folder containing hundreds of files:
		IconNumber := P_IconArray[ExtID]
	}
	;can debug icons here
	; msgbox IconNumber %IconNumber% P_Filepath %P_Filepath% P_FileExt %P_FileExt%
	if not IconNumber  ; There is not yet any icon for this extension, so load it.
	{
		; Get the high-quality small-icon associated with this file extension:
		if not DllCall("Shell32\SHGetFileInfo" . (A_IsUnicode ? "W":"A"), "str", P_Filepath, "uint", 0, "ptr", &FSsfi, "uint", FSsfi_size, "uint", 0x101)  ; 0x101 is SHGFI_ICON+SHGFI_SMALLICON
			IconNumber = 9999999  ; Set it out of bounds to display a blank icon.
		else ; Icon successfully loaded.
		{
			; Extract the hIcon member from the structure:
			hIcon := NumGet(FSsfi, 0)
			; Add the HICON directly to the small-icon and large-icon lists.
			; Below uses +1 to convert the returned index from zero-based to one-based:
			IconNumber := DllCall("ImageList_ReplaceIcon", "ptr", P_Imagelist1, "int", -1, "ptr", hIcon) + 1
			DllCall("ImageList_ReplaceIcon", "ptr", P_ImageList2, "int", -1, "ptr", hIcon)
			; Now that it's been copied into the ImageLists, the original should be destroyed:
			DllCall("DestroyIcon", "ptr", hIcon)
			; Cache the icon to save memory and improve loading performance:
			P_IconArray[ExtID] := IconNumber
		}
	}
	return IconNumber
}


;*****************************
;FS GUI LABELS
;*****************************
FSCreateFolder:
	Gui FileSelectSpecific: Default
	InputBox, FolderName, , % "Enter Folder Name",,,120
	if (ErrorLevel or !FolderName)
		return
	FileCreateDir, % glb_FSCurrent "/" FolderName
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSDisplayFolder:
	Gui FileSelectSpecific: Default
	FSOpenFolderInExplorer(glb_FSCurrent)
return

FSSwitchView:
	Gui FileSelectSpecific: Default
	GuiControl, -Redraw, FSListView
	if not Glb_FSIconView
		GuiControl, +Icon, FSListView    ; Switch to icon view.
	else
		GuiControl, +Report, FSListView  ; Switch back to details view.
	Glb_FSIconView := not Glb_FSIconView             ; Invert in preparation for next time.
	FSRedrawCol()
	GuiControl, +Redraw, FSListView
return

FSRedrawCol() {
global
	Gui FileSelectSpecific: Default
	LV_ModifyCol()  ; Auto-size each column to fit its contents.
	LV_ModifyCol(2,0)  ; Hide FileDir Col
	LV_ModifyCol(3, 60) ; Make the Size column at little wider to reveal its header.
	LV_ModifyCol(4, "AutoHdr") ; Make the Size column at little wider to reveal its header.
}

FSListViewHandler:
	if A_GuiEvent = DoubleClick  ; There are many other possible values the script can check.
	{
		LV_GetText(FileName, A_EventInfo, 1) ; Get the text of the first field.
		LV_GetText(FileDir, A_EventInfo, 2)  ; Get the text of the second field.
		; LV_GetText(FileExt, A_EventInfo, 4)  ; Get the text of the fourth field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					break
				}
		}
			
		if InStr(FileExist(FilePath), "D") {
			glb_FSCurrent:=FilePath
			FileSelectSpecificAdjust(glb_FSCurrent)
			return
		}
		
		else if (FileExist(FilePath) and (glb_FSType="File" or glb_FSType="All")) {
			if glb_FSNoMulti
				glb_FSReturn:=FilePath
			else
				glb_FSReturn:=FileDir "`n" FileName
			
			if (glb_FSOwnerNum)
				Gui, %glb_FSOwnerNum%:-Disabled
			Gui,FileSelectSpecific:Destroy
			return
		}
	}
return

FSPrevious:
	Gui FileSelectSpecific: Default
	if !glb_FSCurrent
		return
	if (glb_FSCurrent=glb_FSFolder and glb_FSRestrict) {
		tooltip You can not navigate above the folder `n%glb_FSFolder%
		SetTimer, RemoveToolTip, -3000
		return
	}
	if !InStr(FileExist(FSGetParentDir(glb_FSCurrent)), "D")
		glb_FSCurrent:=""
	else
		glb_FSCurrent:=FSGetParentDir(glb_FSCurrent)
		
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSRefresh:
	Gui FileSelectSpecific: Default
	FileSelectSpecificAdjust(glb_FSCurrent)
return

FSSelect:
	Gui FileSelectSpecific: Default
	RowNumber = 0
	RowOkayed = 0 
	if !LV_GetNext(RowNumber) {
		msgbox Please select an element first
		return
	}
		
	Loop
	{
		RowNumber := LV_GetNext(RowNumber)  ; Resume the search at the row after that found by the previous iteration.
		; msgbox RowNumber %RowNumber%
		if not RowNumber  ; The above returned zero, so there are no more selected rows.
			break
		LV_GetText(FileName, RowNumber, 1) ; Get the text of the first field.
		LV_GetText(FileDir, RowNumber, 2)  ; Get the text of the second field.
		FilePath:=FileDir "\" FileName
		
		if !glb_FSCurrent
		{
			loop, parse, FileName, :
				if (A_Index=1) {
					FilePath := A_Loopfield ":"
					FileName := A_Loopfield ":"
					break
				}
		}

		if !FileExist(FilePath)
			continue
		
		if (InStr(FileExist(FilePath), "D") and glb_FSType="File")
			continue
			
		if (!InStr(FileExist(FilePath), "D") and glb_FSType="Folder")
			continue
			
		RowOkayed++
		
		glb_FSMultiReturn.= "`n" FileName
		
	}
	
	if (RowOkayed=0) {
		msgbox sorry wrong selection
		return
	}
	
	if (RowOkayed=1 and glb_FSNoMulti)
		glb_FSReturn:=FilePath
	else
		glb_FSReturn:=FileDir . glb_FSMultiReturn

	if (glb_FSOwnerNum)
		Gui, %glb_FSOwnerNum%:-Disabled
		
	Gui,FileSelectSpecific:Destroy
return

;Context-sensitive hotkey to detect Enter on FS navigation bar
#If (FSHwnd and WinActive("ahk_id " FSHwnd))
Enter::
GuiControlGet, OutputVar, FileSelectSpecific:FocusV
; msgbox OutputVar %OutputVar%
if (OutputVar="FSNavBarv")
	Gosub, FSNavBar
Return
#If

;Enter on FS navigation bar
FSNavBar:
Gui, FileSelectSpecific:Default
GuiControlGet, FSNavBarv
StringRight, LastChar, FSNavBarv, 1
	if LastChar = \
		StringTrimRight, FSNavBarv, FSNavBarv, 1  ; Remove the trailing backslash.
if !InStr(FileExist(FSNavBarv), "D")
	return

if (glb_FSRestrict and !Instr(FSNavBarv,glb_FSFolder)) {
	tooltip You can not navigate above the folder `n%glb_FSFolder%
	SetTimer, RemoveToolTip, -3000
	return
	}
GuiControl,,FSNavBarv,% FSNavBarv

glb_FSCurrent:=FSNavBarv
FileSelectSpecificAdjust()
return

RemoveToolTip:
tooltip
return

;*****************************
;FS GUI SPECIAL LABELS
;*****************************
FileSelectSpecificGuiContextMenu:  ; Launched in response to a right-click or press of the Apps key.
Gui FileSelectSpecific: Default
	if A_GuiControl <> FSListView  ; This check is optional. It displays the menu only for clicks inside the ListView.
		return
	Menu, FSContextMenu, Show
return

FileSelectSpecificGuiClose:
	if glb_FSOwnerNum
		try, Gui,%glb_FSOwnerNum%:-Disabled
	Gui,Destroy
return

FileSelectSpecificGuiSize:  ; Readjust the controls in response to the user's resizing of the window.
	if A_EventInfo = 1  ; The window has been minimized.  No action needed.
		return
	;Do not trigger during init
	if glb_FSInit
		return
		
	GuiControl, -Redraw, FSListView

	GuiControlGet, FSComplementv
	GuiControlGet, FSMultiIndicv
	
	; Otherwise, the window has been resized or maximized. Resize the controls.
	
	GuiControlGet, FSListViewPos, Pos, FSListView
	
	GuiControl, MoveDraw, FSPromptv, % " W" . (A_GuiWidth-20)
	GuiControl, MoveDraw, FSNavBarv, % " W" . (A_GuiWidth-20)
	
	FSListGap=
	
	if (FSComplementv) {
		GuiControl, MoveDraw, FSComplementv, % "y" FSListViewPosY + FSListViewPosH + 10 " W" . (A_GuiWidth-20)
		FSListGap+=10
	}
	
	GuiControlGet, FSComplementPos, Pos, FSComplementv
	
	if (FSMultiIndicv) {
		GuiControl, MoveDraw, FSMultiIndicv, % "y" A_GuiHeight-20 " W" . (A_GuiWidth-20)
		FSListGap+=5
	}
	
	GuiControlGet, FSMultiIndicPos, Pos, FSMultiIndicv
	
	;Trick : Round() so that empty vars = 0
	FSListGap:=Round(FSComplementPosH) + Round(FSMultiIndicPosH) + 15
	
	GuiControl, MoveDraw, FSListView, % "W" . (A_GuiWidth - 20) . " H" . (A_GuiHeight - FSListViewPosY - Round(FSListGap))
	
	;Set timer to recreate listview if icon view
	if (Glb_FSIconView)
		SetTimer, FileSelectSpecificAdjust, -200
	
	GuiControl, +Redraw, FSListView  ; Re-enable redrawing (it was disabled above).
	
return
;*****************************


;*****************************
;SMALL FS FUNCTIONS
;*****************************
FSGetParentDir(Path) {
	return SubStr(Path, 1, InStr(SubStr(Path,1,-1), "\", 0, 0)-1)
}

FSOpenFolderInExplorer(P_Folder) {
global
	if !InStr(FileExist(P_Folder), "D")
		return 0
	Run % P_Folder
}

Return

; **********************************************************
; FileSelectSpecific Functions by DigiDon
; **********************************************************
; Use/modify as you wish
; Based on Main example from https://autohotkey.com/docs/commands/ListView.htm
; **********************************************************
; AHK GUI alternative to the FileSelectFile / FileSelectFolder dialogs
; Allows more parameters/customization
; Allows to restrict navigation within a specific folder
; Allows to select File(s) or/and Folder(s)
; Allows to filter file types in or out
; **********************************************************
; FileSelectSpecific(P_OwnerNum,P_Path,P_SelectFileOrFolder="File",P_Prompt="",P_ComplementText="",P_Multi="",P_DefaultView="Icon",P_FilterOK="",P_FilterNO="",P_Restrict=1,P_LVHeight="220",P_LVWidth="350")
;*****************************
;	PARAMETERS
;*****************************
;----- P_OwnerNum: Num/Name of the Gui Owner: it will be disabled the time a selection is made
;----- P_Path: Starting Folder 
;EMPTY: Start with all disks
;----- P_SelectFileOrFolder : Type of Selection to make
;"File" : User should select File(s)
;"Folder" : User should select Folder(s)
;"All" : User should select File(s) and/or Folder(s)
;----- P_Prompt : Text to display at the top of GUI
;----- P_ComplementText : Text to display at the bottom the GUI
;----- P_Multi : MultiSelection
;VALUE: Allowed / EMPTY: Forbidden
;----- P_DefaultView : Default View for the Tree List
;"Icon" / "Report"
;----- P_FilterOK : Comma-list of allowed extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_FilterNO : Comma-list of forbidden extensions to be displayed and chosen
;ex "EXE,INI"
;----- P_Restrict : The user should not be able to navigate above the starting folder
;----- P_LVHeight : Height of ListView in Px
;----- P_LVWidth  : Width  of ListView in Px
;*****************************
;	RETURN VALUE
;*****************************
;----- FSHwnd: Hwnd of the GUI windows
;*****************************
; GLOBAL VALUE TO CHECK AFTER CALL
;*****************************
;----- glb_FSReturn: Contains the path of the selected file(s)
;NO SELECTION : EMPTY
;NO Multi Selection: Path of the selected File
;Multi Selection: Path of the folder "`n" Paths of the selected files (`n separated)
;*****************************
;			USAGE
;*****************************
;ANY SINGLE FILE ANYWHERE
FSHwnd:=FileSelectSpecific("","","File","Please Choose a file")
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
; ONE OR MORE NON-RTF FILES WITHIN C:
FSHwnd:=FileSelectSpecific("","C:","File","Please Choose file(s) in C: (no rtf)","",1,,,"rtf",1)
WinWait % "ahk_id " FSHwnd
WinWaitClose % "ahk_id " FSHwnd
if !glb_FSReturn
	msgbox No selection
else
	msgbox selection was %glb_FSReturn%
;*****************************
P.s.: Function is slightly modified (search for Change: line)
I already read his post last month. His Idea is an artificial Explorer wrapped from an autohotkey GUI. That is my second option incase there is no workaround detecting readonly selected file using FileSelectFile.
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

06 Nov 2019, 22:17

hd0202 wrote:
06 Nov 2019, 11:54
sorry, I misunderstood the problem. Add the following hotkey to your script to change the attribute:

Code: Select all

#j::
ControlGetText, ifield , Edit1, choose any file
; msgbox, % ifield
FileSetAttrib,-R,% a_scriptdir "\" ifield
; FileGetAttrib,attr,% a_scriptdir "\" ifield
; msgbox, % attr
return
When you select the file and get the message "file already exists" you change the attribute via (in my example) "windows + j" and then press "No", then the Select-window reappears and you press "Save" again, this time you press "Yes" and you can continue with the "selectedfile"

Hubert
Controlgettext is a good idea, but am I doing something wrong in this code? when the "this file is a read-only" dialog box appears with a title of "choose any file" then I pressed windows+j, it returns a blank "ifield" variable:

Code: Select all

loop
{
	FileSelectFile, selectedfile, S24, %A_ScriptDir%, choose any file
}
return

#j::
DetectHiddenText,On
DetectHiddenWindows,On
;ControlGetText,ifield,ahk_class #32770,choose any file
ControlGetText,ifield,Edit1,choose any file
msgbox, % ifield
FileSetAttrib,-R,% a_scriptdir "\" ifield
FileGetAttrib,attr,% a_scriptdir "\" ifield
msgbox, % attr
DetectHiddenText,Off
DetectHiddenWindows,Off
return
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
hd0202
Posts: 183
Joined: 04 Oct 2013, 03:07
Location: Germany near Cologne

Re: FileSelectFile(Save) on Read-Only Files

07 Nov 2019, 03:15

but am I doing something wrong in this code?
NO, the problem is your handling !

You are one msgbox too late with your hotkey. With the first msgbox, EDIT1 contains the name of your selected file, if it already exists, and you change the fileattribute to -R, even when it is alredy -R.

You can even try to automate the further processing upto saving the file by clicking to relevant buttons.

Hubert
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

07 Nov 2019, 11:24

hd0202 wrote:
07 Nov 2019, 03:15
but am I doing something wrong in this code?
NO, the problem is your handling !

You are one msgbox too late with your hotkey. With the first msgbox, EDIT1 contains the name of your selected file, if it already exists, and you change the fileattribute to -R, even when it is alredy -R.

You can even try to automate the further processing upto saving the file by clicking to relevant buttons.

Hubert
but am I doing something wrong in this code?
NO, the problem is your handling !

You are one msgbox too late with your hotkey. With the first msgbox, EDIT1 contains the name of your selected file, if it already exists, and you change the fileattribute to -R, even when it is alredy -R.
The #j script is made by you btw... I just used it and returns a blank text, which means it does not detect the message box titled "choose any file" . I furtherly inspected this "windows pop-up" dialog for "read-only" using "Windows-Spy" ahk. Its controls are

DirectUIHWND1
CtrlNotifySink1
ScrollBar1
CtrlNotifySink2
ScrollBar2
CtrlNotifySink3
ScrollBar3
CtrlNotifySink4
ScrollBar4
CtrlNotifySink5
SysLink1
CtrlNotifySink6
SysLink2
CtrlNotifySink7
Button1

The Button1 only has text, it was "OK", while all control have no text(blank)... Maybe there is really no solution to that.
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
hd0202
Posts: 183
Joined: 04 Oct 2013, 03:07
Location: Germany near Cologne

Re: FileSelectFile(Save) on Read-Only Files

07 Nov 2019, 14:10

You are one msgbox too late with your hotkey. With the first msgbox, EDIT1 contains the name of your selected file, if it already exists, and you change the fileattribute to -R, even when it is alredy -R.
Sorry for my incorrect reply, I try to make it clear:

You are one window too late with your hotkey. With the first window, which says "readonly.txt already exists" (or so - I have german windows), EDIT1 contains the name of your selected file if it already exists, you type "#j" and you change the fileattribute to -R, even when it is alredy -R. You do not see the second window, which says "readonly.txt is readonly".

In the meantime I tried to automate the whole process. When the window says "readonly.txt already exists", you type "#j" and the selected file is saved (replaced ).

Code: Select all

#j::
DetectHiddenWindows,On
DetectHiddenText,On
ControlGetText, ifield , Edit1, choose any file
;msgbox, % ifield
FileSetAttrib,-R,% a_scriptdir "\" ifield
FileGetAttrib,attr,% a_scriptdir "\" ifield
;msgbox, % attr
title = Speichern unter 	; <== replace with english text, I Think "Save as ..."
winwaitactive, %title%
settimer, goon, -200
controlclick, Button2, A
return

goon:
winwaitactive, choose any file
settimer, goon2, -200
controlclick, Button1, A
return

goon2:
wingetactivetitle, wa3
controlclick, Button1, A
DetectHiddenText,Off
DetectHiddenWindows,Off
return
Hubert
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

07 Nov 2019, 16:16

After 12 hours of research and coding, I finally created the workaround I am looking for... It detects the selected file even if it is read-only or not!

Uses ACC Library that makes the script long:

Code: Select all



FileDelete,test.txt
FileAppend,,test.txt
FileSetAttrib,+R,test.txt

loop
{
	msgbox % ModifiedFileSelectFile("S24",A_ScriptDir,"choose any file")
}
return


;ONLY ENGLISH LANGUAGE IS SUPPORTED, if you want to implement it on other language, modify the english strings fields
ModifiedFileSelectFile(Options:="",RootPath:="",Prompt:="",Filter:="") ; created by aldrinjohnom
{																	   ; known issue, readonly dialog shows up, but the file is detected
	
	; Foreign Language Constants ; I added constants in case users are using different foreign language beside "English"
	string_ConfirmSaveAs:="Confirm Save As" ; the Title of the the prompt of overwriting a file
	string_URLIndicator:="Address: " ; FileDiretory is detected using this string, at the "13th loop" of the retrieved text contents of the parent window has this indicator
	;
	
	;register at top of the script ; initialization for KillReadOnlyDialog()
	static popupwindowhookid
	if (popupwindowhookid="") ;prevent re-initialization of RegisterShellHookWindow
	{
		Gui +LastFound
		DllCall("RegisterShellHookWindow",UInt,WinExist())
	}
	;
	
	Hotkey,~Enter,MonitorSelectedFile,On	;Register "Enter" as Hotkey that will trigger the monitoring
	Hotkey,~LButton,MonitorSelectedFile,On	;Register "Left Mouse click" as Hotkey that will trigger the monitoring
	
	OnMessage(DllCall("RegisterWindowMessage",Str,"SHELLHOOK"), "KillReadOnlyDialog" ) ; enable this KillReadOnlyDialog
	FileSelectFile,filecomparer,%Options%,%RootPath%,%Prompt%,%Filter% ; same working variable
	OnMessage(DllCall("RegisterWindowMessage",Str,"SHELLHOOK"), "KillReadOnlyDialog",0) ; disable this KillReadOnlyDialog
	
	Hotkey,~Enter,MonitorSelectedFile,Off		;After Fileselectfile, disable the hotkey to disable monitoring
	Hotkey,~LButton,MonitorSelectedFile,Off		;After Fileselectfile, disable the hotkey to disable monitoring
	
	if (filecomparer="") and fileexist(Selectedfile)
		return Selectedfile ; if filecomparer is empty, then return the artificially detected file
	else
		return filecomparer ; return the genuine file if not empty, its value is always right by the way...
	
	
	;;;~~~~~~ Everytime the user clicks or presses enter, do the operation
	MonitorSelectedFile:
	global __dialog_count__,__dialog_count__1,__dialog_count__2 ;because it is inside a function, it is required to be a global variable ; making this local or static will not make the system work
	WinGet,__dialog_count__,List, ahk_class #32770 ; detect how many childrens this ahk_class(windows dialog) has
	WinGetTitle,fileinfo,ahk_id %__dialog_count__1% ; detect the title of the 1st children(front text)
	if (fileinfo=string_ConfirmSaveAs) and ((WinExist("A")=__dialog_count__1) or (WinExist("A")=__dialog_count__2)) ; make sure that two children dialogs are open and is confirming saving a file, the gwnd of the actived windows is either those two childrens
	{
		; play with window controls
		DetectHiddenText,On
		DetectHiddenWindows,On
		WinGetText,fileinfo,ahk_id %__dialog_count__2%
		DetectHiddenText,Off
		DetectHiddenWindows,Off
		;~~~~~~~~~~~~~~~~~~~~~~~~~~~
		
		;~~~~parse the directory and the filename
		FileName=		;	empty variable
		FileDiretory=	;	empty variable
		Loop,Parse,fileinfo,`n
		{
			if ((A_Index=2) and (A_LoopField!="")) or ((FileName="") and (A_Index=3)) ;	filename can be found at 2nd and 3rd parsed loop, their strings are similar so either one of them can be used. Need some trimming operations
				FileName:=Trim(A_LoopField,A_Space "`t`r`n")
			else if (A_Index=13) ; current directory can be found at 13th parsed loop... jsut need remove "Adress: " and need some trimming operations
			{
				FileDiretory:=Trim(StrReplace(A_LoopField,string_URLIndicator),A_Space "`t`r`n")
				if !FileExist(FileDiretory "\") ; folders found at "userprofile" has a PLAIN(short) DIRECTORY NAME(eg. Desktop , Documents , Pictures)... This detects this plain(SHORT) directorynames
					FileDiretory=%USERPROFILE%\%FileDiretory%
			}
		}
		Selectedfile=%FileDiretory%\%FileName% ; this is the selected file full path
		tmpr:=FileExist(Selectedfile)
		
		; I do not intend to remove the attribute, I just want to detect the selected filename even if it is readonly or not
		;if tmpr and InStr(tmpr,"R") ; if file exist and has a readonly attribute
		;{
		;	FileSetAttrib,-R,%Selectedfile% ;remove attribute
		;}
	}
	return
}

KillReadOnlyDialog(wParam,lParam) ; created by aldrinjohnom
{		
	; Foreign Language Constants ; I added constants in case users are using different foreign language beside "English"
	string_Save:="&Save" ; Save button text
	string_Cancel:="Cancel" ; Cancel Button text
	message_PromptOverwrite:="already exists.`r`nDo you want to replace it?" ; Substring message of overwriting a file
	message_readonly:="This file is set to read-only.`r`nTry again with a different file name." ; Substring message of readonly file
	;
	static parentid
	
	if (wParam=1) ; wParam=1 indicates a parent window
	{
		WinGetText,tmpr,ahk_id %lParam% ; detect all contents of this window
		Loop,Parse,tmpr,`n ; parse with a delimiter of a newline
		{
			tmpr:=Trim(A_LoopField,A_Space "`t`r`n") ; trim left and right side, remove space,tab,newline
			
			if (tmpr=string_Save) ; indicator that the window has a "Save" Button
				hassave:=1
			else if(tmpr=string_Cancel)  ; indicator that the window has a "Cancel" Button
				hascancel:=1
			
			if hassave and hascancel ; this confirms that it is a "Save" Fileselect FIle if it has a "Save" and "Cancel" Button
			{
				parentid:=lParam
				break
			}
		}
	}
	else
	{
		DetectHiddenWindows,On
		DetectHiddenText,On
		ControlGet hwnd, Hwnd,, DirectUIHWND1,ahk_class #32770 ; get the hwnd of the submessage of the children window(the message strings "eg this file is read-only")
		text:=Acc_Get("Name", "pane1.text1",, "ahk_id " . hwnd) ; detect accesibility(ACC) message from the tree(pane1 > text1)
		If InStr(text,message_readonly) or InStr(text,message_PromptOverwrite) ; if the extracted message contains the substring messages
		{
			WinGet,hwndmain,ID,ahk_class #32770 ; get the whole children window hwnd
			WinKill,ahk_id %hwndmain% ; kill the children window	
			WinKill,ahk_id %parentid% ; kill the parent window	
		}
		DetectHiddenWindows,Off
		DetectHiddenText,Off
	}
}

; http://www.autohotkey.com/board/topic/77303-acc-library-ahk-l-updated-09272012/
; https://dl.dropbox.com/u/47573473/Web%20Server/AHK_L/Acc.ahk
;------------------------------------------------------------------------------
; Acc.ahk Standard Library
; by Sean
; Updated by jethrow:
; 	Modified ComObjEnwrap params from (9,pacc) --> (9,pacc,1)
; 	Changed ComObjUnwrap to ComObjValue in order to avoid AddRef (thanks fincs)
; 	Added Acc_GetRoleText & Acc_GetStateText
; 	Added additional functions - commented below
; 	Removed original Acc_Children function
; last updated 2/25/2010
;------------------------------------------------------------------------------

Acc_Init()
{
	Static	h
	If Not	h
		h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromEvent(ByRef _idChild_, hWnd, idObject, idChild)
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromEvent", "Ptr", hWnd, "UInt", idObject, "UInt", idChild, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	Return	ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}

Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "")
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
	Return	ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}

Acc_ObjectFromWindow(hWnd, idObject = -4)
{
	Acc_Init()
	If	DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
	Return	ComObjEnwrap(9,pacc,1)
}

Acc_WindowFromObject(pacc)
{
	If	DllCall("oleacc\WindowFromAccessibleObject", "Ptr", IsObject(pacc)?ComObjValue(pacc):pacc, "Ptr*", hWnd)=0
	Return	hWnd
}

Acc_GetRoleText(nRole)
{
	nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
	Return	sRole
}

Acc_GetStateText(nState)
{
	nSize := DllCall("oleacc\GetStateText", "Uint", nState, "Ptr", 0, "Uint", 0)
	VarSetCapacity(sState, (A_IsUnicode?2:1)*nSize)
	DllCall("oleacc\GetStateText", "Uint", nState, "str", sState, "Uint", nSize+1)
	Return	sState
}

Acc_SetWinEventHook(eventMin, eventMax, pCallback)
{
	Return	DllCall("SetWinEventHook", "Uint", eventMin, "Uint", eventMax, "Uint", 0, "Ptr", pCallback, "Uint", 0, "Uint", 0, "Uint", 0)
}

Acc_UnhookWinEvent(hHook)
{
	Return	DllCall("UnhookWinEvent", "Ptr", hHook)
}
/*	Win Events:

	pCallback := RegisterCallback("WinEventProc")
	WinEventProc(hHook, event, hWnd, idObject, idChild, eventThread, eventTime)
	{
		Critical
		Acc := Acc_ObjectFromEvent(_idChild_, hWnd, idObject, idChild)
		; Code Here:

	}
*/

; Written by jethrow
Acc_Role(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
Acc_State(Acc, ChildId=0) {
	try return ComObjType(Acc,"Name")="IAccessible"?Acc_GetStateText(Acc.accState(ChildId)):"invalid object"
}
Acc_Location(Acc, ChildId=0, byref Position="") { ; adapted from Sean's code
	try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
	catch
		return
	Position := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
	return	{x:NumGet(x,0,"int"), y:NumGet(y,0,"int"), w:NumGet(w,0,"int"), h:NumGet(h,0,"int")}
}
Acc_Parent(Acc) { 
	try parent:=Acc.accParent
	return parent?Acc_Query(parent):
}
Acc_Child(Acc, ChildId=0) {
	try child:=Acc.accChild(ChildId)
	return child?Acc_Query(child):
}
Acc_Query(Acc) { ; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
	try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Error(p="") {
	static setting:=0
	return p=""?setting:setting:=p
}
Acc_Children(Acc) {
	if ComObjType(Acc,"Name") != "IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren%
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
			return Children.MaxIndex()?Children:
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_ChildrenByRole(Acc, Role) {
	if ComObjType(Acc,"Name")!="IAccessible"
		ErrorLevel := "Invalid IAccessible Object"
	else {
		Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
		if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
			Loop %cChildren% {
				i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
				if NumGet(varChildren,i-8)=9
					AccChild:=Acc_Query(child), ObjRelease(child), Acc_Role(AccChild)=Role?Children.Insert(AccChild):
				else
					Acc_Role(Acc, child)=Role?Children.Insert(child):
			}
			return Children.MaxIndex()?Children:, ErrorLevel:=0
		} else
			ErrorLevel := "AccessibleChildren DllCall Failed"
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="") {
	static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
	AccObj :=   IsObject(WinTitle)? WinTitle
			:   Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
	if ComObjType(AccObj, "Name") != "IAccessible"
		ErrorLevel := "Could not access an IAccessible Object"
	else {
		StringReplace, ChildPath, ChildPath, _, %A_Space%, All
		AccError:=Acc_Error(), Acc_Error(true)
		Loop Parse, ChildPath, ., %A_Space%
			try {
				if A_LoopField is digit
					Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
				else
					RegExMatch(A_LoopField, "(\D*)(\d*)", m), Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
				if Not Children.HasKey(m2)
					throw
				AccObj := Children[m2]
			} catch {
				ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " A_LoopField, Acc_Error(AccError)
				if Acc_Error()
					throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
				return
			}
		Acc_Error(AccError)
		StringReplace, Cmd, Cmd, %A_Space%, , All
		properties.HasKey(Cmd)? Cmd:=properties[Cmd]:
		try {
			if (Cmd = "Location")
				AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0), ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
			  , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int") " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
			else if (Cmd = "Object")
				ret_val := AccObj
			else if Cmd in Role,State
				ret_val := Acc_%Cmd%(AccObj, ChildID+0)
			else if Cmd in ChildCount,Selection,Focus
				ret_val := AccObj["acc" Cmd]
			else
				ret_val := AccObj["acc" Cmd](ChildID+0)
		} catch {
			ErrorLevel := """" Cmd """ Cmd Not Implemented"
			if Acc_Error()
				throw Exception("Cmd Not Implemented", -1, Cmd)
			return
		}
		return ret_val, ErrorLevel:=0
	}
	if Acc_Error()
		throw Exception(ErrorLevel,-1)
}
first release > Issue: Read-only dialog still pops-up, maybe anyone in the future can fix it up. But it is working as expected though...
second release > Issure at readonly dialog now does not pop up.
Last edited by aldrinjohnom on 08 Nov 2019, 09:01, edited 1 time in total.
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

07 Nov 2019, 16:37

hd0202 wrote:
07 Nov 2019, 14:10
You are one msgbox too late with your hotkey. With the first msgbox, EDIT1 contains the name of your selected file, if it already exists, and you change the fileattribute to -R, even when it is alredy -R.
Sorry for my incorrect reply, I try to make it clear:

You are one window too late with your hotkey. With the first window, which says "readonly.txt already exists" (or so - I have german windows), EDIT1 contains the name of your selected file if it already exists, you type "#j" and you change the fileattribute to -R, even when it is alredy -R. You do not see the second window, which says "readonly.txt is readonly".

In the meantime I tried to automate the whole process. When the window says "readonly.txt already exists", you type "#j" and the selected file is saved (replaced ).

Code: Select all

#j::
DetectHiddenWindows,On
DetectHiddenText,On
ControlGetText, ifield , Edit1, choose any file
;msgbox, % ifield
FileSetAttrib,-R,% a_scriptdir "\" ifield
FileGetAttrib,attr,% a_scriptdir "\" ifield
;msgbox, % attr
title = Speichern unter 	; <== replace with english text, I Think "Save as ..."
winwaitactive, %title%
settimer, goon, -200
controlclick, Button2, A
return

goon:
winwaitactive, choose any file
settimer, goon2, -200
controlclick, Button1, A
return

goon2:
wingetactivetitle, wa3
controlclick, Button1, A
DetectHiddenText,Off
DetectHiddenWindows,Off
return
Hubert
EDIT1 contains the name of your selected file if it already exists
ControlGetText, ifield , Edit1, choose any file
This Control Name does not exist on the fileselectfile window or even at the windows dialog. As how I mentioned earlier that this are the list of controls:
aldrinjohnom wrote:
07 Nov 2019, 11:24
I furtherly inspected this "windows pop-up" dialog for "read-only" using "Windows-Spy" ahk. Its controls are

DirectUIHWND1
CtrlNotifySink1
ScrollBar1
CtrlNotifySink2
ScrollBar2
CtrlNotifySink3
ScrollBar3
CtrlNotifySink4
ScrollBar4
CtrlNotifySink5
SysLink1
CtrlNotifySink6
SysLink2
CtrlNotifySink7
Button1

The Button1 only has text, it was "OK", while all control have no text(blank)...
Which means that EDIT1 Control is a blank handle


Searching through the community, I found a problem from this post:
WinGetText and ControlGetText not working on certain windows

The Reason behind this as I search through the community is because of windows/controls/GUI elements. Microsoft Active Accessibility (MSAA) (Acc) can detect this elements:
https://www.autohotkey.com/boards/viewtopic.php?f=7&t=40590
Acc: get text from all window/control elements

It can only be detected by properly browsing its nested accessibility. Can be easily detected using AccViewer
https://autohotkey.com/boards/viewtopic.php?f=6&t=32039
Developer of AJOM's DOTA2 MOD Master, Easiest way to MOD your DOTA2 without the use of internet :lol: . I created this program using Autohotkey thats why I love Autohotkey and the community!

GitHub:
https://github.com/Aldrin-John-Olaer-Manalansan
hd0202
Posts: 183
Joined: 04 Oct 2013, 03:07
Location: Germany near Cologne

Re: FileSelectFile(Save) on Read-Only Files

08 Nov 2019, 01:16

In my opinion you need not know if the file is readonly !
You want to rename it in any case, readonly or not.
Therefore you do not need to get to the second child window, you can modify your script to reach your goal with one ENTER.
And I suggest to not use the LBUTTON hotkey so that you can easy break the process if you selected the wrong file.

Or you can use my routine and modify it to start with ENTER instead of "#j" ?

Hubert

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: zerox and 313 guests