Archive: SHBrowseForFolder problem


SHBrowseForFolder problem
Vista SP1 32-bit
NSIS 2.41 (ANSI)

I have 2 problems with this script fragment, and I'm stumped.

1) The icon index always returns 0. I don't think my code is wrong.
2) 9 times out of 10 the script crashes on exit. This is AFTER the System plugin is unloaded. The crash is either in ole32.dll or ntdll.dll. Again, I have no idea why.

Any insight is appreciated!

;=== Program Details
Name "Folder Test"
OutFile "foldertest.exe"
Caption "Folder Test"

;=== Runtime Switches
CRCCheck On
WindowIcon off
SilentInstall Silent
AutoCloseWindow True
RequestExecutionLevel user
XPStyle on

; Best Compression
SetCompress Auto
SetCompressor /SOLID lzma
SetCompressorDictSize 32
SetDatablockOptimize On

Section
System::Call /NOUNLOAD '*(&t 260)i .r0' ; $0 = address to namebuff
; BROWSEINFO struct
System::Call /NOUNLOAD '*(i n, i n, i r0, t "Folder Dialog Title", i 0x40, i n, i n, i n)i .R0' ; $R0 = address of struct

System::Call /NOUNLOAD 'shell32::SHBrowseForFolderA(i R0)i .r5'

System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
MessageBox MB_OK "Selected folder: $3"

System::Call /NOUNLOAD 'shell32::SHGetPathFromIDListA(i r5, i $0)i'
System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
MessageBox MB_OK "Selected folder path: $3"

System::Call /NOUNLOAD '*$R0(i,i,i,t,i,i,i, i .r2)' ; read icon index
MessageBox MB_OK "Icon index: $2"

; cleanup
System::Call /NOUNLOAD 'ole32::CoTaskMemFree(i r5)v' ; free returned PIDL
System::Free /NOUNLOAD $0 ; free namebuff
System::Free $R0 ; free BROWSEINFO

MessageBox MB_OK "done"
SectionEnd

I always use SHGetFileInfo to get a icon/iconindex, did not even know that BROWSEINFO had it. But the docs say icon index for folder, not file or drive (it failed on my documents also, so who knows) Do you even need the icon index? or just the HICON?

You also really should add a HWND to BROWSEINFO...

I played around with it a bit and the iconindex is 0 for me also every time. (XP SP2)


Section
System::Call /NOUNLOAD '*(&t 261)i .r0' ; $0 = address to namebuff
; BROWSEINFO struct
System::Call /NOUNLOAD '*(i $hwndparent,i, i r0, t "Folder Dialog Title", i 0x40|0x4000,i,i,i)i.R0'

System::Call /NOUNLOAD 'shell32::SHBrowseForFolderA(i R0)i .r5'

System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
DetailPrint "ret = $5, Selected folder: $3"

System::Call /NOUNLOAD 'shell32::SHGetPathFromIDListA(i r5, i $0)i'
System::Call /NOUNLOAD '*$0(&t260 .r3)' ; read namebuff
DetailPrint "Selected folder path: $3"

System::Call /NOUNLOAD '*$R0(i,i,i,i,i,i,i,i.r2)' ; read icon index
DetailPrint "Icon index: $2"

; cleanup
System::Call /NOUNLOAD 'ole32::CoTaskMemFree(i r5)v' ; free returned PIDL
System::Free /NOUNLOAD $0 ; free namebuff
System::Free $R0 ; free BROWSEINFO

DetailPrint "done-----------------"
/*typedef struct _SHFILEINFO {
HICON hIcon;
int iIcon;
DWORD dwAttributes;
TCHAR szDisplayName[MAX_PATH];
TCHAR szTypeName[80];
} SHFILEINFO;*/
!define STRUCTSIZE_SHFILEINFOA 352
#DEFINE SHGFI_ICON 0x000000100
System::Call '*(i,i,i,&t260,&t80)i.r0'
System::Call 'shell32::SHGetFileInfoA(t "$3",i,i $0,i 352,i 0x100)i.r9'
DetailPrint ret=$9,inpath=$3
System::Call '*$0(i.r1,i.r2)'
DetailPrint hIco=$1,icoIdx=$2
System::Free $0
FindWindow $0 "#32770" "" $HWNDPARENT
GetDlgItem $0 $0 0x407
SendMessage $0 ${STM_SETICON} $1 0

SectionEnd


note that it is also possible to use a PIDL with SHGetFileInfo (you did not specify the filesystemonly flag, so you could get virtual paths)

Also, I'm using 2.42 so I don't have to bother with /NOUNLOAD

I don't need the icon index for the folder, but was just curious why it wasn't working.

The bigger issue is why it's crashing consistently on exit on Vista. I'm assuming that it's not crashing on XP since you've tried it...


I just checked with 2.42 and removing /NOUNLOAD, still crashes most of the time.


and if you don't call CoTaskMemFree or free the buffers?


Still crashes unfortunately. And I've seen the faulting module as both ole32.dll and ntdll.dll.


You have a space between &t and 260. The buffer you allocate is therefore sized 1 bytes and the initial value of that string is "260".


Wow. Thanks kickik, that did it. I can't believe that was the problem. So it was a buffer overrun type of crash then?

Well, since I have a topic already here instead of starting a new one, can you briefly explain how the &l is used for structure size? The manual doesn't have an example of usage, and I don't see the N for N bytes after it like the others. Thanks again!


Yes, it caused a heap overflow.

&l is used to get the structure size. It doesn't really set a struct member but only gets the size.

System::Call "*${stBITMAP} (_, &l0 .R7) .R9"
System::Call "${sysGetObject} (r6, R7, R9)"

Ok. So in the above example, the _ character 'skips' all the params and lets you add one to the end of the struct?


Indeed.


Thanks for all the help!

Maybe add those few tips about &l and _ to the System Plugin Documentation when you have an opportunity.

Keep up the great work!


DOH, not sure how I missed this one, copy&paste without checking is baaad mmmkay