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

Re: FileSelectFile(Save) on Read-Only Files

08 Nov 2019, 02:02

hd0202 wrote:
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

In my opinion you need not know if the file is readonly !
Y
That is exactly what the script I marked as solution do. It just detects if it is read-only or not. If it is readonly then Then change the file atrribute and extract the selected file name with its path.


You want to rename it in any case, readonly or not.
See this:

Code: Select all

msgbox % ModifiedFileSelectFile("S24",A_ScriptDir,"choose any file")
After the function passed the returned selected file, We can do anything to the file since the "file-path with its name" was now known-ed.



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" ?
The point why LButton and Enter keys are used because that indicates that the user is trying to "click a button". Pressing enter, commands the system to select the actived button. While Left clicking commonly means that the user is trying to click the button. this events has a chance of creating a readonly file message dialog. That is why I used this two keys.

I do not use any "manual push" hotkeys like #j because I am targeting "unaware users" to be able to save the file right away. Meaning no need to push anything to remove the readonly attribute.

The function does not break the process and select a wrong file since it compares two variables:

Code: Select all

if (filecomparer="") and fileexist(Selectedfile)
		return Selectedfile ; if filecomparer is empty, then return the artificially detected file
	else
		return filecomparer ; return the genuine file, its value is always right by the way...
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
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

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

11 Nov 2019, 09:37

- The old-style Common File Dialog and new-style Common Item Dialog have numerous options. However, I could not see any options where the Save As dialog would allow you to choose a read-only file, and no way to disable the read-only file warning. (Apologies if I've overlooked an option.)
- However, the *Open* dialog does allow you to choose a read-only file, and doesn't show a warning.
- So, perhaps the best approach is to use an Open dialog, and tweak the window title/Open button to say 'Save As' and 'Save'.
- This is what I have done in the 2 examples below:

Code: Select all

q:: ;test save as dialog on read-only files
;modify open dialog to appear as a save as dialog

;vOpt := "S" ;save as dialog
vOpt := "O" ;open dialog (but with title/button label changed to look like a save as dialog)

if InStr(vOpt, "S")
{
	;save as dialog:
	CLSID_FileSaveDialog := "{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}"
	IID_IFileSaveDialog := "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}"
	if !(pFD := ComObjCreate(CLSID_FileSaveDialog, IID_IFileSaveDialog))
		return
}
else if InStr(vOpt, "O")
{
	;open dialog:
	CLSID_FileOpenDialog := "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}"
	IID_IFileOpenDialog := "{d57c7288-d4ad-4768-be02-9d969532d960}"
	if !(pFD := ComObjCreate(CLSID_FileOpenDialog, IID_IFileOpenDialog))
		return

	vTitle := "Save As"
	DllCall(NumGet(NumGet(pFD+0)+17*A_PtrSize), "Ptr",pFD, "WStr",vTitle) ;IFileDialog::SetTitle

	vButtonLabel := "&Save"
	DllCall(NumGet(NumGet(pFD+0)+18*A_PtrSize), "Ptr",pFD, "WStr",vButtonLabel) ;IFileDialog::SetOkButtonLabel

	oFilters := ["Text Documents (*.txt)", "*.txt", "All Files", "*.*"]
	VarSetCapacity(ArrayCOMDLG_FILTERSPEC, oFilters.Length()*A_PtrSize)
	Loop % oFilters.Length()
	{
		VarSetCapacity(vFilter%A_Index%, StrLen(oFilters[A_Index])*2+2)
		StrPut(oFilters[A_Index], &vFilter%A_Index%, "UTF-16")
		NumPut(&vFilter%A_Index%, &ArrayCOMDLG_FILTERSPEC, (A_Index-1)*A_PtrSize, "Ptr")
	}
	DllCall(NumGet(NumGet(pFD+0)+4*A_PtrSize), "Ptr",pFD, "UInt",oFilters.Length()/2, "Ptr",&ArrayCOMDLG_FILTERSPEC) ;IFileDialog::SetFileTypes
}

vFlags := 0
DllCall(NumGet(NumGet(pFD+0)+9*A_PtrSize), "Ptr",pFD, "UInt",vFlags) ;IFileDialog::SetOptions

vRet1 := !DllCall(NumGet(NumGet(pFD+0)+3*A_PtrSize), "Ptr",pFD, "Ptr",hWnd) ;IFileDialog::Show

pSI := 0, vPath := ""
if vRet1
&& !DllCall(NumGet(NumGet(pFD+0)+20*A_PtrSize), "Ptr",pFD, "Ptr*",pSI) ;IFileDialog::GetResult
{
	pText := 0
	;SIGDN_DESKTOPABSOLUTEPARSING := 0x80028000 ;source: ShObjIdl.h
	if !DllCall(NumGet(NumGet(pSI+0)+5*A_PtrSize), "Ptr",pSI, "UInt",0x80028000, "Ptr*",pText) ;IShellItem::GetDisplayName
		vPath := StrGet(pText, "UTF-16"), DllCall("ole32\CoTaskMemFree", "Ptr",pText)
	ObjRelease(pSI)

	vTypeIndex := 0 ;1-based index
	DllCall(NumGet(NumGet(pFD+0)+6*A_PtrSize), "Ptr",pFD, "UInt*",vTypeIndex) ;IShellItem::GetFileTypeIndex
	vType := oFilters[vTypeIndex*2]
}

ObjRelease(pFD)
MsgBox, % vPath "`r`n" vType
return

;==================================================

w:: ;test save as dialog on read-only files
;modify open dialog to appear as a save as dialog

;vOpt := "S" ;save as dialog
vOpt := "O" ;open dialog (but with title/button label changed to look like a save as dialog)

;for O option:
;vAddHook := 0 ;on Windows Vista+, shows new-style Common Item Dialog
vAddHook := 1 ;shows old-style Common File Dialog

vSize := A_PtrSize=8?152:88
MAX_PATH := 260
vFlags := 0
pFunc := 0
pTitle := 0

if InStr(vOpt, "O") && vAddHook
{
	vFlags := 0x20, OFN_ENABLEHOOK := 0x20
	vFlags := 0x80020
	pFunc := RegisterCallback("CFDOpenAppearAsSaveAs")
	vTitle := "Save As"
	VarSetCapacity(vTitleW, StrLen(vTitle)*2)
	StrPut(vTitle, &vTitleW, "UTF-16")
	pTitle := &vTitleW
}

VarSetCapacity(OPENFILENAMEW, vSize, 0)
VarSetCapacity(vPath, MAX_PATH*2, 0)
NumPut(vSize, &OPENFILENAMEW, 0, "UInt") ;lStructSize
NumPut(&vPath, &OPENFILENAMEW, A_PtrSize=8?48:28, "Ptr") ;lpstrFile
NumPut(MAX_PATH, &OPENFILENAMEW, A_PtrSize=8?56:32, "UInt") ;nMaxFile
NumPut(pTitle, &OPENFILENAMEW, A_PtrSize=8?88:48, "Ptr") ;lpstrTitle
NumPut(vFlags, &OPENFILENAMEW, A_PtrSize=8?96:52, "UInt") ;Flags
NumPut(pFunc, &OPENFILENAMEW, A_PtrSize=8?120:68, "Ptr") ;lpfnHook
if InStr(vOpt, "S")
	DllCall("comdlg32\GetSaveFileNameW", "Ptr",&OPENFILENAMEW)
else if InStr(vOpt, "O")
	DllCall("comdlg32\GetOpenFileNameW", "Ptr",&OPENFILENAMEW)
vPath := StrGet(&vPath, 260, "UTF-16")
MsgBox, % vPath
return

CFDOpenAppearAsSaveAs(hDlg, uMsg, wParam, lParam)
{
	local
	if (uMsg = 0x110) ;WM_INITDIALOG := 0x110
	{
		DetectHiddenWindows, On
		hWnd := DllCall("user32\GetParent", "Ptr",hDlg, "Ptr")
		ControlSetText, Button2, &Save, % "ahk_id " hWnd
	}
}

;==================================================

Links (script examples):
FileSelectFile, add controls to the Open/Save As dialog - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=29934
AHKv2: Diálogos para seleccionar Icono, Fuente, Color y Más! [27/04/2018] - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=42&t=10802

Links (structs and interfaces):
list of structs with parameters (sizes and types) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=74&t=30497
list of interfaces with method numbers - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=74&t=67431

Links (constants):
_FILEOPENDIALOGOPTIONS (shobjidl_core.h) - Win32 apps | Microsoft Docs
https://docs.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-_fileopendialogoptions
OPENFILENAMEA (commdlg.h) - Win32 apps | Microsoft Docs
https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea
Last edited by jeeswg on 14 Nov 2019, 02:20, edited 3 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
aldrinjohnom
Posts: 77
Joined: 18 Apr 2018, 08:49

Re: FileSelectFile(Save) on Read-Only Files

12 Nov 2019, 19:53

- However, the *Open* dialog does allow you to choose a read-only file, and doesn't show a warning.
- So, perhaps the best approach is to use an Open dialog, and tweak the window title/Open button to say 'Save As' and 'Save'.
I have never thought about that, What a clever Workaround!
jeeswg wrote:
11 Nov 2019, 09:37
- The old-style Common File Dialog and new-style Common Item Dialog have numerous options. However, I could not see any options where the Save As dialog would allow you to choose a read-only file, and no way to disable the read-only file warning. (Apologies if I've overlooked an option.)
- However, the *Open* dialog does allow you to choose a read-only file, and doesn't show a warning.
- So, perhaps the best approach is to use an Open dialog, and tweak the window title/Open button to say 'Save As' and 'Save'.
- This is what I have done in the 2 examples below:

Code: Select all

q:: ;test save as dialog on read-only files
;modify open dialog to appear as a save as dialog

;vOpt := "S" ;save as dialog
vOpt := "O" ;open dialog (but with title/button label changed to look like a save as dialog)

if InStr(vOpt, "S")
{
	;save as dialog:
	CLSID_FileSaveDialog := "{C0B4E2F3-BA21-4773-8DBA-335EC946EB8B}"
	IID_IFileSaveDialog := "{84BCCD23-5FDE-4CDB-AEA4-AF64B83D78AB}"
	if !(pFD := ComObjCreate(CLSID_FileSaveDialog, IID_IFileSaveDialog))
		return
}
else if InStr(vOpt, "O")
{
	;open dialog:
	CLSID_FileOpenDialog := "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}"
	IID_IFileOpenDialog := "{d57c7288-d4ad-4768-be02-9d969532d960}"
	if !(pFD := ComObjCreate(CLSID_FileOpenDialog, IID_IFileOpenDialog))
		return

	vTitle := "Save As"
	DllCall(NumGet(NumGet(pFD+0)+17*A_PtrSize), "Ptr",pFD, "WStr",vTitle) ;IFileDialog::SetTitle

	vButtonLabel := "&Save"
	DllCall(NumGet(NumGet(pFD+0)+18*A_PtrSize), "Ptr",pFD, "WStr",vButtonLabel) ;IFileDialog::SetOkButtonLabel
}

vFlags := 0
DllCall(NumGet(NumGet(pFD+0)+9*A_PtrSize), "Ptr",pFD, "UInt",vFlags) ;IFileDialog::SetOptions

vRet1 := !DllCall(NumGet(NumGet(pFD+0)+3*A_PtrSize), "Ptr",pFD, "Ptr",hWnd) ;IFileDialog::Show

pSI := 0, vPath := ""
if vRet1
&& !DllCall(NumGet(NumGet(pFD+0)+20*A_PtrSize), "Ptr",pFD, "Ptr*",pSI) ;IFileDialog::GetResult
{
	pText := 0
	;SIGDN_DESKTOPABSOLUTEPARSING := 0x80028000 ;source: ShObjIdl.h
	if !DllCall(NumGet(NumGet(pSI+0)+5*A_PtrSize), "Ptr",pSI, "UInt",0x80028000, "Ptr*",pText) ;IShellItem::GetDisplayName
		vPath := StrGet(pText, "UTF-16"), DllCall("ole32\CoTaskMemFree", "Ptr",pText)
	ObjRelease(pSI)
	vRet2 := 1
}

ObjRelease(pFD)
MsgBox, % vPath
return

;==================================================

w:: ;test save as dialog on read-only files
;modify open dialog to appear as a save as dialog

;vOpt := "S" ;save as dialog
vOpt := "O" ;open dialog (but with title/button label changed to look like a save as dialog)

;for O option:
;vAddHook := 0 ;on Windows Vista+, shows new-style Common Item Dialog
vAddHook := 1 ;shows old-style Common File Dialog

vSize := A_PtrSize=8?152:88
MAX_PATH := 260
vFlags := 0
pFunc := 0
pTitle := 0

if InStr(vOpt, "O") && vAddHook
{
	vFlags := 0x20, OFN_ENABLEHOOK := 0x20
	vFlags := 0x80020
	pFunc := RegisterCallback("CFDOpenAppearAsSaveAs")
	vTitle := "Save As"
	VarSetCapacity(vTitleW, StrLen(vTitle)*2)
	StrPut(vTitle, &vTitleW, "UTF-16")
	pTitle := &vTitleW
}

VarSetCapacity(OPENFILENAMEW, vSize, 0)
VarSetCapacity(vPath, MAX_PATH*2, 0)
NumPut(vSize, &OPENFILENAMEW, 0, "UInt") ;lStructSize
NumPut(&vPath, &OPENFILENAMEW, A_PtrSize=8?48:28, "Ptr") ;lpstrFile
NumPut(MAX_PATH, &OPENFILENAMEW, A_PtrSize=8?56:32, "UInt") ;nMaxFile
NumPut(pTitle, &OPENFILENAMEW, A_PtrSize=8?88:48, "Ptr") ;lpstrTitle
NumPut(vFlags, &OPENFILENAMEW, A_PtrSize=8?96:52, "UInt") ;Flags
NumPut(pFunc, &OPENFILENAMEW, A_PtrSize=8?120:68, "Ptr") ;lpfnHook
if InStr(vOpt, "S")
	DllCall("comdlg32\GetSaveFileNameW", "Ptr",&OPENFILENAMEW)
else if InStr(vOpt, "O")
	DllCall("comdlg32\GetOpenFileNameW", "Ptr",&OPENFILENAMEW)
vPath := StrGet(&vPath, 260, "UTF-16")
MsgBox, % vPath
return

CFDOpenAppearAsSaveAs(hDlg, uMsg, wParam, lParam)
{
	local
	if (uMsg = 0x110) ;WM_INITDIALOG := 0x110
	{
		DetectHiddenWindows, On
		hWnd := DllCall("user32\GetParent", "Ptr",hDlg, "Ptr")
		ControlSetText, Button2, &Save, % "ahk_id " hWnd
	}
}

;==================================================

Links:
FileSelectFile, add controls to the Open/Save As dialog - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=5&t=29934
AHKv2: Diálogos para seleccionar Icono, Fuente, Color y Más! [27/04/2018] - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=42&t=10802
list of structs with parameters (sizes and types) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=74&t=30497
list of interfaces with method numbers - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=74&t=67431
WOW! That was even more better than my workaround. But I am not skillfull enough to be far more familiar about structs, dllcalls. I am trying to figure out why the "file extension type downdownlist" is missing, can you add that feature on that modified windows explorer. In which this file extension and the file name is also retrievable.
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
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: FileSelectFile(Save) on Read-Only Files

13 Nov 2019, 19:17

I've added these lines to the q:: example:

Code: Select all

	oFilters := ["Text Documents (*.txt)", "*.txt", "All Files", "*.*"]
	VarSetCapacity(ArrayCOMDLG_FILTERSPEC, oFilters.Length()*A_PtrSize)
	Loop % oFilters.Length()
	{
		VarSetCapacity(vFilter%A_Index%, StrLen(oFilters[A_Index])*2+2)
		StrPut(oFilters[A_Index], &vFilter%A_Index%, "UTF-16")
		NumPut(&vFilter%A_Index%, &ArrayCOMDLG_FILTERSPEC, (A_Index-1)*A_PtrSize, "Ptr")
	}
	DllCall(NumGet(NumGet(pFD+0)+4*A_PtrSize), "Ptr",pFD, "UInt",oFilters.Length()/2, "Ptr",&ArrayCOMDLG_FILTERSPEC) ;IFileDialog::SetFileTypes
[EDIT:] And these lines:

Code: Select all

	vTypeIndex := 0 ;1-based index
	DllCall(NumGet(NumGet(pFD+0)+6*A_PtrSize), "Ptr",pFD, "UInt*",vTypeIndex) ;IShellItem::GetFileTypeIndex
	vType := oFilters[vTypeIndex*2]
And the MsgBox now shows the path and the type.

Btw if you run Notepad, and look at the Open/Save As dialogs, you can see that the filter drop-down lists are in different places. And thus, in the script above, the Open dialog has the text changed in 2 places to look like a Save As dialog, however, the filter drop-down list remains in the same position.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
rommmcek
Posts: 1473
Joined: 15 Aug 2014, 15:18

Re: FileSelectFile(Save) on Read-Only Files

14 Nov 2019, 21:13

@jeeswg: Wow, wow wow! What a clever spotting how to solve the problem (not to mention the skillful coding)!!!
Chapeau!
P.s.: Off topic. In the dialog I saw, for the first time I guess, among "File name" and "Filter" controls the one for "Encoding" too. Purely theoretically, would it be possible to show it if needed?

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], Lamron750 and 382 guests