FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?) Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

11 Jul 2019, 09:56

Hi,

I'm new here, so I must be doing something wrong to which you can easily point. ;)
Please help me.

I want to open FileSelectFile with RootDir set to "MyVideo" folder.
And I CAN do it as long as I use AHK U32.

Code: Select all

VarSetCapacity(myvideos, 520, 0)
SetGUID(rfid, "{18989B1D-99B5-455B-841C-AB7C74E4DDFC}")
DllCall("Shell32\SHGetKnownFolderPath", "UInt", &rfid, "UInt", 0, "UInt", 0, "UIntP", myvideos)
vdir := StrGet(myvideos)

FileSelectFile, s, M3, %vdir%\Radeon Relive, open, rec (2019*.mp4)

return

SetGUID(ByRef GUID, String) {
    VarSetCapacity(GUID, 16, 0)
    StringReplace,String,String,-,,All
    NumPut("0x" . SubStr(String, 2,  8), GUID, 0,  "UInt")   ; DWORD Data1
    NumPut("0x" . SubStr(String, 10, 4), GUID, 4,  "UShort") ; WORD  Data2
    NumPut("0x" . SubStr(String, 14, 4), GUID, 6,  "UShort") ; WORD  Data3
    Loop, 8
        NumPut("0x" . SubStr(String, 16+(A_Index*2), 2), GUID, 7+A_Index,  "UChar")  ; BYTE  Data4[A_Index]
}
cf. https://github.com/shajul/Autohotkey/blob/master/Scriplets/KnownFolders.ahk


But the same script doesn't work when it has been converted to EXE.
How to reproduce:
  1. Convert the AHK file to an EXE.
  2. Run the EXE. The first run opens "MyVideo" successfully. :)
  3. Click another folder in the FileSelectFile window.
  4. Select some file(s) and finish the window. The first run ends happily. :bravo:
  5. Run the same EXE again. I expect to see "MyVideo" again.
  6. But you see the folder you clicked in the previous run. :crazy:
  7. Rename the EXE and run it.
  8. You see "MyVideo" again. :wtf:
Whenever you run the AHK file, you will see "MyVideo".
But when you run the EXE file more than once, you will see the last selected folder.
Renaming the EXE resets the RootDir.

Is the above-mentioned behavior expected?
Can I make EXE more forgetful? (as forgetful as AHK)


Moreover, I cannot make the code work with U64.
I don't know whether it is relevant to the real cause, though.

Thanks in advance,
Tamo
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

11 Jul 2019, 21:30

This was my workaround for 64-bit Unicode compiled .exe

Code: Select all

FileSelectFile , SelectedFile ,, % GetReliablePath( Path . "\Folder" ) , Select File , Videos (*.mp4)

GetReliablePath(Path){ 
static LastPath

	If (Path = LastPath){	
		StringRight , LastChar , Path , 1	
		If (LastChar = "\")
			StringTrimRight , Path , Path , 1
		Else
			Path .= "\"	
	}
	LastPath := Path
	return Path	
}
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

12 Jul 2019, 00:51

pneumatic wrote:
11 Jul 2019, 21:30
This was my workaround for 64-bit Unicode compiled .exe

Code: Select all

FileSelectFile , SelectedFile ,, % GetReliablePath( Path . "\Folder" ) , Select File , Videos (*.mp4)

GetReliablePath(Path){ 
static LastPath

	If (Path = LastPath){	
		StringRight , LastChar , Path , 1	
		If (LastChar = "\")
			StringTrimRight , Path , Path , 1
		Else
			Path .= "\"	
	}
	LastPath := Path
	return Path	
}
Wow, it works! Thank you, pneumatic!

With some experiments and in hindsight, I just need the trailing "\".
(You don't need GetReliablePath, pneumatic.)

That's strange because the official document says "C:\My Pictures" is OK (not "C:\My Pictures\"). :eh:
https://www.autohotkey.com/docs/commands/FileSelectFile.htm

Anyway, my script now works. Thank you!
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

12 Jul 2019, 02:19

tamo wrote:
12 Jul 2019, 00:51
With some experiments and in hindsight, I just need the trailing "\".
(You don't need GetReliablePath, pneumatic.)
I found that it can still fail if you don't change the starting directory every time. The purpose is to stop Windows from trying to be clever:
https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea wrote: The algorithm for selecting the initial directory varies on different platforms.
Windows 7:
If lpstrInitialDir has the same value as was passed the first time the application used an Open or Save As dialog box, the path most recently selected by the user is used as the initial directory.
edit: actually it seems my workaround would fail under the following scenario:

Launch script
FileSelectFile C:\Folder1 -> user manually navigates to C:\Folder2 -> OK
FileSelectFile C:\Folder3 -> OK
FileSelectfile C:\Folder1 -> Windows sees it "has the same value as was passed the first time the application used an Open or Save As dialog box" and gives you instead "the path most recently selected" which is actually Folder3

edit2: tested the above with compiled .exe and it works fine, no idea why :wtf:
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

12 Jul 2019, 08:42

pneumatic wrote:
12 Jul 2019, 02:19
tamo wrote:
12 Jul 2019, 00:51
With some experiments and in hindsight, I just need the trailing "\".
(You don't need GetReliablePath, pneumatic.)
I found that it can still fail if you don't change the starting directory every time. The purpose is to stop Windows from trying to be clever:
https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea wrote: The algorithm for selecting the initial directory varies on different platforms.
Windows 7:
If lpstrInitialDir has the same value as was passed the first time the application used an Open or Save As dialog box, the path most recently selected by the user is used as the initial directory.
You are right, again. ;) Just adding "\" sometimes works, sometimes fails.
And oh, your quote from Microsoft document is very inspiring. Thanks!
edit: actually it seems my workaround would fail under the following scenario:

Launch script
FileSelectFile C:\Folder1 -> user manually navigates to C:\Folder2 -> OK
FileSelectFile C:\Folder3 -> OK
FileSelectfile C:\Folder1 -> Windows sees it "has the same value as was passed the first time the application used an Open or Save As dialog box" and gives you instead "the path most recently selected" which is actually Folder3

edit2: tested the above with compiled .exe and it works fine, no idea why :wtf:
Hehehe, I even found that an EXE which seems reliably working can stop working if it is just copied to another folder. :headwall:

I'm on Windows 10 Home 64bit 1903 (18362.239).
Autohotkey 1.1.30.03.
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

12 Jul 2019, 09:21

Other useful information sources: I think it's too much work for me to introduce IFileDialog just in order to use SetFolder.
So I'm trying "Folder\Filename" instead of "Folder" or "Folder\". For example, "\Radeon Relive\xxxx.xx.xx.mp4"

edit:
No! Specifying filename doesn't fix it.
If there is a complete solution, it should have something to do with \HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\*. :facepalm:
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)  Topic is solved

12 Jul 2019, 10:43

In the first post, the code should be something like this,

Code: Select all

SetGUID(rfid, "{18989B1D-99B5-455B-841C-AB7C74E4DDFC}")

; function documentation:
;	- https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath

pStr := 0
if ret := DllCall("Shell32\SHGetKnownFolderPath", "ptr", &rfid, "UInt", 0, "ptr", 0, "ptr*", pStr, "int")
	throw exception("SHGetKnownFolderPath fail: " . ret)
msgbox % strget(pStr, "UTF-16")
CoTaskMemFree(pStr)

;FileSelectFile, s, M3, %vdir%\Radeon Relive, open, rec (2019*.mp4)

return

CoTaskMemFree(pv){
	return dllcall("Ole32.dll\CoTaskMemFree", "ptr", pv)
}

SetGUID(ByRef GUID, String) {
    VarSetCapacity(GUID, 16, 0)
    StringReplace,String,String,-,,All
    NumPut("0x" . SubStr(String, 2,  8), GUID, 0,  "UInt")   ; DWORD Data1
    NumPut("0x" . SubStr(String, 10, 4), GUID, 4,  "UShort") ; WORD  Data2
    NumPut("0x" . SubStr(String, 14, 4), GUID, 6,  "UShort") ; WORD  Data3
    Loop, 8
        NumPut("0x" . SubStr(String, 16+(A_Index*2), 2), GUID, 7+A_Index,  "UChar")  ; BYTE  Data4[A_Index]
}
Cheers.
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

12 Jul 2019, 11:02

Helgef wrote:
12 Jul 2019, 10:43

Code: Select all

; function documentation:
;	- https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath

pStr := 0
if ret := DllCall("Shell32\SHGetKnownFolderPath", "ptr", &rfid, "UInt", 0, "ptr", 0, "ptr*", pStr, "int")
	throw exception("SHGetKnownFolderPath fail: " . ret)
msgbox % strget(pStr, "UTF-16")
CoTaskMemFree(pStr)
Thanks, you are clean. ;)
I don't mind memleaks so much when writing in AHK. But appropriate types for DllCalls are important. Appreciated! :D

Also I've found I can get GUID values using ole32. So I can reduce the number of lines removing SetGUID function.

Code: Select all

VarSetCapacity(rfid, 16, 0)
DllCall("ole32\CLSIDFromString", "WStr", "{18989B1D-99B5-455B-841C-AB7C74E4DDFC}", "Ptr", &rfid)
Well, ANSI version has to prepare the Wstr rather than directly giving to DllCall? I'm not clean enough. ;)
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

12 Jul 2019, 11:45

Dllcall will convert your ANSI string to Unicode when you specify wstr, it should work as is.
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

12 Jul 2019, 18:39

Helgef wrote:
12 Jul 2019, 11:45
Dllcall will convert your ANSI string to Unicode when you specify wstr, it should work as is.
Thanks, Helgef. You are cool, kind, and smart. I've come to like AutoHotkey better than before.
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

15 Oct 2019, 07:39

tamo wrote:
12 Jul 2019, 08:42
Just adding "\" sometimes works, sometimes fails.

I finally got to the bottom of this.

So the first time an application opens a FileSelectFile, Windows saves the starting directory parameter to HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\FirstFolder

Then, if your app opens a FileSelectFile with the above starting directory, Windows will instead give you the most recent path that the user previously selected, which is stored in HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedPidlMRU

I am able to reproduce this behaviour in ahk, so it appears to function exactly as Windows describes in the documentation.

Appending "\" or other things like "\\\" or ".\" to the starting directory alone won't work because it can't always circumvent this logic, regardless of how clever you try to be, because there will always be a possible scenario where the application could select the registry's "FirstFolder" value, since the value gets stored between app launches. i.e even your app's very first FileSelectFile starting directory will be compared to the registry value from the previous run, so it doesn't "start fresh" each time, and so you can't know for sure what the FirstFolder value is without keeping a copy between each time the application runs.

Therefore the only ways to overcome it require read/write/deleting external files on disk, which is quite disappointing, but appears to be necessary to get around this problem.

Possible solutions:

Solution 1.
The first time your app opens a FileSelectFile, store your own private copy of the starting directory on disk. Every time you call FileSelectFile, check if it the starting directory matches the one you saved to disk, and if it does, append "\" to it.

Solution 2.
Same as above, but instead of reading it from your own private copy, read it straight from the registry. Iterate through each value inside the FirstFolder regkey and find the one which contains the full path to your script's executable, and that should be the one for your app.

Solution 3.
Same as above, but just delete your app's registry value instead of checking to see if it matches.

Solution 4.
If you are feeling lazy, just delete the entire "FirstFolder" key every time you use FileSelectFile. This will delete "FirstFolder" for all apps on the system. But who cares? The behaviour is retarded and shouldn't exist in the first place :lol: However it won't fix it properly for other apps because they could open and close their own dialogues and then the problem returns for those apps until your app happens to delete the key again.


I was leaning towards solution 3 because it's quite easy, but solution 1 should be more reliable since you have your own copy of FirstFolder and aren't relying on assumptions about Windows registry. eg. different versions of Windows or languages might change the formatting of the key value, or antivirus software might block you from deleting reg keys altogether, or a future version of Windows might change the regkey path.

So I will probably go with solution 1.

If anyone can figure out a clever way to fudge the FileSelectFile starting directory without relying on any disk read/write/delete operations, I'd love to hear it!

Note: I am aware that you can pass FileSelectFile a file path instead of a directory, but that's not quite good enough for me as I want the dialogue's text input to start off blank (especially when the user just wants to open a file; for saving a file, pre-inputting something like "untitled.ext" might be acceptable). i.e I want a complete solution, not half-measure, and it has to be 100% reliable!

edit: and I've just realised Solution 1 won't be 100% reliable because the user could move the app to another location on disk, which would then get its own reg value, which might not match your private value that you previously stored. So you would need to store a copy of the previous A_ScriptDir and if it changes then do what exactly? What if the user had moved it to that location before, then it might still be wrong since we can't assume that it started fresh. Maybe interacting with the registry might be necessary after all...

edit2: I will probably go with solution 1 but append to file a series of records "A_ScriptDir has FirstFolder" so we know which location has which firstfolder. Essentially making our own copy of what Windows itself stores in the registry so we can avoid having to interact with the registry and whatever problems that might entail.
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

18 Oct 2019, 14:28

I've encountered some inconsistent behaviour in the way Windows writes the FirstFolder value to registry.

i.e

Delete registry's FirstFolder key -> run app -> FileSelectFile , , , C:\Path1 -> C:\Path1 gets written to registry FirstFolder value.

FileSelectFile , , , (no path) -> select C:\Path2\File.ext -> OK -> C:\Path2 gets written to registry LastVisitedPidlMRU value.

At this point if you do another FileSelectFile , , , C:\Path1 , per Windows documentation, it will give you C:\Path2, which is consistent with Windows documentation.

But then if I do this:

FileSelectFile , , , C:\Path3 -> the script's exe path gets written to the reg key, and from that point on the issue appears to disappear completely, even if you specify script's exe path as starting directory.

I tried this with compiled and non-compiled, and behaviour was the same.

edit2: after some time thinking about the logic of this, it seems that unfortunately we STILL need to use an external file on disk to remember the value between app launches :x otherwise we can't circumvent the Windows behaviour under all possible scenarios.
pneumatic
Posts: 338
Joined: 05 Dec 2016, 01:51

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

19 Oct 2019, 20:04

Here is my workaround if anyone's interested. Please see the "important" note in the comment, otherwise it may not work.

Code: Select all

FileSelectFile ,,, % GetFileSelectFileDir( "C:\StartingDirectory" )

GetFileSelectFileDir( ThisPath:="" ){ 

/*
Workaround issue where Windows ignores your specified starting directory of FileSelectFile:

"If lpstrInitialDir has the same value as was passed the first time the application used an Open or Save As
dialog box, the path most recently selected by the user is used as the initial directory."

https://docs.microsoft.com/en-us/windows/win32/api/commdlg/ns-commdlg-openfilenamea

Windows stores "first folder" in:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\FirstFolder

"Most recently selected" is stored in:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedPidlMRU

IMPORTANT: if your script has already opened a FileSelectFile dialogue with a non-null starting folder prior
to using this function, you will need to delete the "FirstFolder" regkey above, otherwise this function will
not be in sync with the regkey value.

This function should be effective even after moving your script to another location, or to another Windows
installation, since it stores a "FirstFolder" for each A_ScriptDir, and is stored inside %A_AppDataCommon%
which is unique to each Windows installation.

Note: Windows also appears to have a bug where if the regkey "FirstFolder" is non-null, not equal to the
script's executable path, and the first file select dialogue opened by the app has a starting directory
different to that stored in the regkey, Windows sets the regkey to the script's executable path, and from
that point onwards Windows will always obey the starting directory you specify.  This does not affect the
reliability of this function, nor does this function assume this behaviour.
*/

static IsFirstDialogue := 1
	
	;Remove any trailing backslashes which would interfere with this function, since it works
	;by appending a backslash to make the path different to the "FirstFolder" regkey value, while still
	;pointing to the same location.	
	loop % StrLen(ThisPath)
	{
		StringRight , LastChar , ThisPath, 1
		If (LastChar = "\")
			StringTrimRight , ThisPath , ThisPath, 1
		Else
			break	
	}
	
	If (ThisPath = "")
		return  ;In this case, Windows will give you the "most recently selected" value in the regkey,
				;and will not modify the "FirstFolder" regkey
			
	IniRead , FirstFolder , %A_AppDataCommon%\AutoHotkey\FileSelectDialogue.ini , %A_ScriptDir% , FirstFolder
	(FirstFolder = "ERROR") ? (FirstFolder := "")

	
	If (ThisPath = FirstFolder){
		StringRight , LastChar , ThisPath, 1		
		If (LastChar = "\")
			StringTrimRight , ThisPath , ThisPath, 1
		Else
			ThisPath .= "\"
	}
		
	If (IsFirstDialogue){	
		IniWrite , %ThisPath%, %A_AppDataCommon%\AutoHotkey\FileSelectDialogue.ini , %A_ScriptDir% , FirstFolder
		IsFirstDialogue := 0	
	}

	return ThisPath

}
JBensimon
Posts: 118
Joined: 19 Nov 2017, 11:19

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

07 Jun 2022, 18:27

pneumatic wrote:
15 Oct 2019, 07:39
If anyone can figure out a clever way to fudge the FileSelectFile starting directory without relying on any disk read/write/delete operations, I'd love to hear it!
Hi. I know this is a relatively old thread, but Windows overriding the FileSelectFile RootDir continues to be a pain in the you-know-what, so I thought I'd throw in what I think is the ideal workaround -- I have tested it "manually", but haven't yet implemented it in code (it'll be short and straightforward). The idea is based only on the documented behavior of the FirstFolder key entries you described and on their structure, which in each case is a binary entry consisting of the Unicode full path to the EXE file, followed by a Unicode null (00 00), followed by the Unicode RootPath that was specified the first time an Open or Save dialog was acted upon (i.e. not cancelled), and finally one last Unicode null:

If such a FirstFolder entry is created for a given EXE full path with an empty RootDir, i.e. consisting only of the Unicode path to the EXE followed by two Unicode nulls, then any future FileSelectFile dialog presented by that EXE will obey its specified RootDir (if any) since nothing will ever match the FirstFolder entry's empty RootDir, and Windows' keeping track of the user's last selected folder will be reserved only for FileSelectFile calls that do not specify a RootFolder, which is a sensible behavior.

In terms of implementation, the steps are as follows:

1/ Find the highest numbered value name at the FirstFolder key (reg loop).
2/ Add 1 to it and use the result as the name of the special binary entry described above (regwrite, after a little work to prepare the value).
3/ Read the key's MRUListEx binary entry (it contains a sequence of double words corresponding to all the numeric entries at the key), prepend to it a double word corresponding to the numeric value you just added), and write it back.
4/ To only do this once for each new executable (at each new path), create an entry at some fixed Registry key of your choice with a name consisting of the full path to the EXE and the content anything you like, or nothing.

This can all be wrapped into a short function used by any scripts that need it, and all they'd need to do is check at each launch whether the entry named with their full path exists at that fixed key, and if not call the function to create the "magic" FirstFolder entry.

I'll post some code once I get around to it.

JB
JBensimon
Posts: 118
Joined: 19 Nov 2017, 11:19

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

08 Jun 2022, 07:39

Here's some working code: calling this function at the top of a script will ensure every FileSelectFile RootDir is respected.
(I chose to create a ComDlg32 subkey named FirstFolderTrack as the location of the EXE tracking entries)

Code: Select all

StableRootDir()
{
  EXE := (A_IsCompiled) ? A_ScriptFullPath : A_AhkPath		; current executable
  Key := "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\FirstFolder"
  RegRead, Val, %Key%Track, %EXE%		; does tracking entry for this executable path already exist?
  If !ErrorLevel						; if yes, nothing more to do
    Return

  VarSetCapacity(hEXE, StrLen(EXE) << 2)			; prepare Unicode hex representation of executable path
  Loop, Parse, EXE
    hEXE .= Format("{:04X}", Asc(A_LoopField))
  hEXE := RegExReplace(hEXE, "(..)(..)", "$2$1")	; flip byte pairs to make little-endian
  
  Val := -1
  Loop, Reg, %Key%, V						; find current largest FirstFolder numeric entry name
    If A_LoopRegName is integer
      Val := Max(A_LoopRegName, Val)
  Val += 1							; increment to arrive at new entry name
  RegWrite, REG_BINARY, %Key%, %Val%, %hEXE%00000000		; write the new entry

  hVal := RegExReplace(Format("{:08X}", Val), "(..)(..)(..)(..)", "$4$3$2$1")	; prepare entry name's little-endian double-word representation
  RegRead, MRU, %Key%, MRUListEx				; get current MRUListEx entry
  MRU := ErrorLevel ? "FFFFFFFF" : MRU				; if missing, use empty list representation (hex FFFFFFFF)
  RegWrite, REG_BINARY, %Key%, MRUListEx, %hVal%%MRU%		; update (or create) MRUListEx entry, prepending the new entry number
  
  RegWrite, REG_SZ, %Key%Track, %EXE%, %Val%			; store tracking entry for this executable path
  Return
}
Note that if used in an uncompiled script, the resulting behavior will apply to every other uncompiled script running under the same AutoHotkey interpreter.

*** See updated version (with undo capability) in reply.
Last edited by JBensimon on 09 Jun 2022, 10:57, edited 1 time in total.
tamo
Posts: 11
Joined: 11 Jul 2019, 04:23

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

09 Jun 2022, 00:12

JBensimon wrote:
08 Jun 2022, 07:39
Here's some working code: calling this function at the top of a script will ensure every FileSelectFile RootDir is respected.
Awasome! :bravo: I'll use your code next time. Thanks!
JBensimon
Posts: 118
Joined: 19 Nov 2017, 11:19

Re: FileSelectFile sometimes ignores my Rootdir (ahk2exe or 32/64bit issue?)

09 Jun 2022, 10:56

JBensimon wrote:
08 Jun 2022, 07:39
Here's some working code:
And here's an updated version that now allows for undoing a previous use of the function: calling it with no parameters or with TRUE still leads to FileSelectFile reliably always starting at RootDir, and calling it with FALSE will undo the created Registry entries to restore the default behavior.

Code: Select all

StableRootDir(Bool := TRUE)
{
  EXE := (A_IsCompiled) ? A_ScriptFullPath : A_AhkPath		; current executable
  Key := "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\FirstFolder"
  RegRead, Val, %Key%Track, %EXE%				; does tracking entry for this executable path exist?
  If !ErrorLevel = Bool						; if yes AND "want stable", or no AND "don't want", nothing to do!
    Return

  If !Bool							; if don't want stable, undo what was previously done at the FirstFolder key
  {
    RegDelete, %Key%Track, %EXE%				; delete tracking entry for this EXE
    RegDelete, %Key%, %Val%					; delete the previously added FirstFolder entry for this EXE
    RegRead, MRU, %Key%, MRUListEx				; get current MRUListEx entry (to remove reference to deleted entry)
    If !ErrorLevel
    {
      hVal := RegExReplace(Format("{:08X}", Val), "(..)(..)(..)(..)", "$4$3$2$1")	; prepare entry name's little-endian double-word representation
      MRU := RegExReplace(MRU, "U)^((.{8})*)" hVal, "$1")	; remove reference to deleted entry from MRUListEx hex string
      RegWrite, REG_BINARY, %Key%, MRUListEx, %MRU%		; write back updated MRUListEx entry
    }
    Return
  }

  VarSetCapacity(hEXE, StrLen(EXE) << 2)			; prepare Unicode hex representation of executable path
  Loop, Parse, EXE
    hEXE .= Format("{:04X}", Asc(A_LoopField))
  hEXE := RegExReplace(hEXE, "(..)(..)", "$2$1")		; flip byte pairs to make little-endian
  
  Val := -1
  Loop, Reg, %Key%, V						; find current largest FirstFolder numeric entry name
    If A_LoopRegName is integer
      Val := Max(A_LoopRegName, Val)
  Val += 1							; increment to arrive at new entry name
  RegWrite, REG_BINARY, %Key%, %Val%, %hEXE%00000000		; write the new entry

  hVal := RegExReplace(Format("{:08X}", Val), "(..)(..)(..)(..)", "$4$3$2$1")	; prepare entry name's little-endian double-word representation
  RegRead, MRU, %Key%, MRUListEx				; get current MRUListEx entry
  MRU := ErrorLevel ? "FFFFFFFF" : MRU				; if missing, use empty list representation (hex FFFFFFFF)
  RegWrite, REG_BINARY, %Key%, MRUListEx, %hVal%%MRU%		; update (or create) MRUListEx entry, prepending the new entry number
  
  RegWrite, REG_SZ, %Key%Track, %EXE%, %Val%			; store tracking entry for this executable path
  Return
}

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: jaka1, OrangeCat and 153 guests