This snipplet will extract the PIDL from a given path. You just pass a window handle and the address of a string containing a fully qualified path to the function and the PIDL is returned in eax. Others might find this useful for any place where you need a simple DWORD to identify a file, for me it has saved alot of space as I no longer have to store full paths in my proggy
GetPIDLFromPath proc hWnd:DWORD,pszObject:DWORD

LOCAL pShellFolder :DWORD

invoke CoInitialize,NULL
mov LibLoaded,eax

invoke MultiByteToWideChar,CP_ACP,NULL,pszObject,-1,ADDR wsz,MAX_PATH
invoke SHGetDesktopFolder,ADDR pShellFolder

lea eax,Attribs
push eax
lea eax,Pidl
push eax
lea eax,Eaten
push eax
lea eax,wsz
push eax
push NULL
push hWnd
push pShellFolder
mov edi,pShellFolder
mov edi,[edi]
call DWORD PTR [edi+12] ; IShellFolder::ParseDisplayName

push pShellFolder
mov edi,pShellFolder
mov edi,[edi]
call DWORD PTR [edi+8] ; IShellFolder::Release

cmp LibLoaded,S_OK
jne @F
invoke CoUninitialize

mov eax,Pidl
GetPIDLFromPath endp
Use the following to extract the path from the returned PIDL :

invoke SHGetPathFromIDList,PIDL,ADDR szPath
Posted on 2003-04-21 13:44:15 by donkey
Nice, Donkey :alright:

Just one comment. I was thinking that maybe it'd be cleaner to keep CoInitialize and CoUninitialize out of there and just remind the reader that they need to initialize the com library before calling it. This way if they need to use more com objects then they can initialize the lib at program startup and no redundant calls to CoInitialize.
Posted on 2003-04-21 13:58:53 by iblis
You're right Iblis,

I made the change. The application I used it in only had this one COM call so I had it in the proc it is better to remove it from the proc completely and make the call independantly. The proc will now attempt to load the COM library and if it is already loaded it will not unload it, otherwise it works as usual.
Posted on 2003-04-21 14:12:32 by donkey
I've been reading a bit more about the SHGetDesktopFolder function and I believe that you have to free the MAlloc of the PIDL that is generated by it. Problem is that once it's freed the PIDL is no longer valid. To solve this problem I have written the following function. All it does is uses the IMalloc interface and frees the memory used by the PIDL, call the function with the PIDL as the only parameter once you are done with it


invoke SHGetMalloc,ADDR pMalloc

push PIDL
push pMalloc
mov edi,pMalloc
mov edi,[edi]
call DWORD PTR [edi+20] ;IMalloc.Free

push pMalloc
mov edi,pMalloc
mov edi,[edi]
call DWORD PTR [edi+8] ; IMalloc:Release

FreePIDL endp
BTW I'm not 100% certain that this is necessary but it can't hurt. A COM guru might be able to tell me more about it.
Posted on 2003-04-21 21:03:52 by donkey