News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Q: SHBrowseForFolder

Started by Mark Jones, June 27, 2005, 06:16:36 PM

Previous topic - Next topic

Mark Jones

Hi, I created a BROWSEINFO<> struct and invoked SHBrosweForFolder, then converted the returned PIDL to an ASCII string using SHGetPathFromIDList. The Win32.hlp says:

[SHBrowseForFolder] returns a pointer to an item identifier list that specifies the location of the selected folder relative to the root of the name space. The calling application is responsible for freeing the returned item identifier list using the shell's task allocator.

How do we "free the returned item identifier list using the shell's task allocator?" :dazzled:

I found an example in C under "Using PIDLs and Display Names", but don't understand it. Should I use SHGetMalloc before calling SHBrowseForFolder, then HeapFree afterwards? Thanks.
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Mark Jones

"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

donkey

PIDL's can be freed using ILFree in Windows XP, it was part of the settlement API. In earlier versions it was exported as an ordinal, the ordinal is still valid in XP and 2K3...

; Assumes the pointer to the ID list is held in a buffer named PIDL

ShellDll db "Shell32.dll",0

invoke GetModuleHandle, offset ShellDll
mov [hShell32], eax

invoke GetProcAddress, [hShell32], 155
mov [pFreePIDL], eax

invoke SHGetPathFromIDListA,[PIDL],offset ShBrowsePath
invoke [pFreePIDL],[PIDL] ; ILFree


I do not believe MASM is capable of using a memory operand as the call address with INVOKE so you must first mov it into a register...

mov eax, [pFreePIDL]
invoke eax,[PIDL] ; ILFree
"Ahhh, what an awful dream. Ones and zeroes everywhere...[shudder] and I thought I saw a two." -- Bender
"It was just a dream, Bender. There's no such thing as two". -- Fry
-- Futurama

Donkey's Stable

Tedd

I use this..

    ; ppMalloc:DWORD

    ;esi points to the BROWSEINFO struct
    invoke SHBrowseForFoler, esi
    .IF (eax)
        push ebx
        mov ebx,eax                 ;ebx = pidl
        invoke SHGetPathFromIDList, ebx,lpBuff
        invoke SHGetMalloc, ADDR ppMalloc
        mov eax,ppMalloc            ;eax = ppMalloc
        mov ecx,[eax]               ;ecx = &ppMalloc.interface
        push ebx                    ;pidl
        push eax                    ;(this)
        call DWORD PTR[ecx+20]      ;ppMalloc->Free(pidl)
        pop ebx
    .ENDIF
No snowflake in an avalanche feels responsible.

Mark Jones

#4
Thanks Donkey. Tedd, is there a reason you use EBX instead of say, EDX? :)

LATER: MSDN shows a CoTaskMemFree API which works on all versions of windows. Investigating to see if it will free PIDL's. :)
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Mark Jones

Well here's what I've came up with so far. At least it doesn't crash. :) Checking memory pool next.


.data?
    lpbi        BROWSEINFO<>
    sfnPath     256 dup(?)
.code
LOCAL ppMalloc,ppSHBFF:DWORD
    int 3                       ; debug
    invoke CoInitialize,0
    test eax,eax
    js bypass                           ; COM available?
    invoke SHGetMalloc,addr ppMalloc    ; first pointer
    cmp eax, E_FAIL
    jz fail                             ; out of mem?
    invoke SHBrowseForFolder,offset lpbi
    mov ppSHBFF,eax                     ; second pointer
    .if eax!=0                          ; must have selected something
        invoke SHGetPathFromIDList,eax,addr sfnPath
        invoke SetDlgItemText,hWnd,IDC_EDT2,addr sfnPath
    .endif
fail:                                   ; free pointers
    mov eax,ppMalloc
    mov ecx,[eax]           ; dereference
    push ppSHBFF            ; PIDL
    push eax                ; (this)
    call dword ptr[ecx+20]  ; ppMalloc->Free(PIDL)
    invoke CoUninitialize   ; close COM
bypass:
"To deny our impulses... foolish; to revel in them, chaos." MCJ 2003.08

Tedd

Quote from: Mark Jones on June 28, 2005, 01:41:31 PM
Tedd, is there a reason you use EBX instead of say, EDX? :)

It was supposedly so that the value would survive the other function calls.
But now that you mention it, there's no actual need in this instance.

You could even just push it and leave it there for the function call that needs it :bg

    ; ppMalloc:DWORD

    ;esi points to the BROWSEINFO struct
    invoke SHBrowseForFoler, esi
    .IF (eax)
        ;eax = pidl
        push eax        ; *** pidl on stack now - for call to Free(pidl) - wohoo
        invoke SHGetPathFromIDList, eax,lpBuff
        invoke SHGetMalloc, ADDR ppMalloc
        mov eax,ppMalloc            ;eax = ppMalloc
        mov ecx,[eax]               ;ecx = &ppMalloc.interface
        ;;push ebx                    ;pidl -- already done up there ;)
        push eax                    ;(this)
        call DWORD PTR[ecx+20]      ;ppMalloc->Free(pidl)
    .ENDIF
No snowflake in an avalanche feels responsible.