I'm trying to retrieve file information (specifically info about the icon) using SHGetFileInfo. In reality, I don't have the full path of the file, I only have the pidl.
The following code returns (0L, (0, 0, 0, '', ''))
and my question is why.
from win32com.shell import shell, shellcon
def get_info():
desktop = shell.SHGetDesktopFolder()
eaten, desktop_pidl, attr = desktop.ParseDisplayName(None, None, r"C:\Users\Ella\Desktop")
return shell.SHGetFileInfo(desktop_pidl, 0, shellcon.SHGFI_PIDL | shellcon.SHGFI_SYSICONINDEX | shellcon.SHGFI_ICON | shellcon.SHGFI_DISPLAYNAME)
On the other hand, the code bellow does work for some reason (it uses full path instead of pidl):
from win32com.shell import shell, shellcon
def get_info2():
return shell.SHGetFileInfo(r"C:\Users\Ella\Desktop", 0, shellcon.SHGFI_SYSICONINDEX | shellcon.SHGFI_ICON | shellcon.SHGFI_DISPLAYNAME)
Thanks!
You've uncovered a bug in
PySHGetFileInfo
. IfSHGFI_PIDL
is set in flags, it callsPyObject_AsPIDL
and stores the result topidl_or_name
, but it mistakenly passesname
toSHGetFileInfo
, which in this case is the initialNULL
value. See below for more details.You asked how to set a breakpoint on
shell32!SHGetFileInfoW
. There's no simple answer to that. Instead allow me to share an overview of what I did to test this. Hopefully this will at least get you started.Test environment:
Set up the shell environment.
Create a Python virtual environment.
venv
doesn't link the .pdb files, so grab those manually in a for loop.Activate the virtual environment.
Clone the PyWin32 repo. Build and install version 219.
Build and install the package.
Run Python under the console debugger, cdb.exe.
The option
-xi ld
in the above command line sets a filter to ignore printing loaded modules. There are lots of tutorials and 'cheat sheets' online for using Microsoft's debuggers such as WinDbg, cdb, and kd. The debuggers all use the same engine, so they support a common set of debugging commands.The attached debugger has a breakpoint set on
shell32!SHGetFileInfoW
. When the breakpoint is triggered, the debugger grabs the console. One of the few redeeming features of the Windows console is its per-application input history and aliases. This makes it convenient to recall commands when bouncing in and out of the debugger and debuggee in the same console window.In the Windows x64 ABI, the first argument of a function is passed in register
rcx
. We know from theSHGetFileInfo
docs that this should be thePIDL
, but actuallyNULL
is being passed. Clearly this is a bug. The stack trace lays the blame onshell!PySHGetFileInfo
. Here's a snippet of the problematic code:The mistake is passing
name
as the first argument instead ofpidl_or_name
.The question is tagged ctypes. IMO, using ctypes is worth it if doing so eliminates a large dependency such as PyWin32. I wouldn't normally use ctypes by itself for a COM-based API. The comtypes package builds on ctypes if you want to try that. In this case directly calling COM methods can be avoided by instead calling
SHParseDisplayName
. Other than usingHRESULT
return codes, it's pretty much like any other Win32 API.Example:
Output: