我正在尝试使用SHGetFileInfo检索文件信息(特别是有关图标的信息)。实际上,我没有文件的完整路径,只有pidl。
以下代码返回(0L,( 0,0,0,'',''))
,我的问题是为什么。
从win32com.shell导入shell,shellcon
def get_info():
桌面= shell.SHGetDesktopFolder()
被吃掉,desktop_pidl,attr = desktop.ParseDisplayName(None,None,r C: \Users\Ella\Desktop)
返回shell.SHGetFileInfo(desktop_pidl,0,shellcon.SHGFI_PIDL | shellcon.SHGFI_SYSICONINDEX | shellcon.SHGFI_ICON | shellcon.SHGFI_DISPLAYNAME)
另一方面,以下代码确实可以工作(它使用完整路径而不是pidl):
从win32com.shell导入shell,shellcon
def get_info2():
返回shell.SHGetFileInfo(r C:\Users\ \Ella\Desktop,0,shellcon.SHGFI_SYSICONINDEX | shellcon.SHGFI_ICON | shellcon.SHGFI_DISPLAYNAME)
谢谢!
您已经发现。如果在标志中设置了 SHGFI_PIDL
,它将调用 PyObject_AsPIDL
并将结果存储到 pidl_or_name
,但错误地将 name
传递给 SHGetFileInfo
,在本例中为初始的 NULL
值。请参阅下面的更多细节。
您问如何在 shell32!SHGetFileInfoW
上设置断点。没有简单的答案。取而代之的是让我分享测试的概况。希望这至少可以帮助您入门。
测试环境:
设置外壳程序环境。
C:\Program Files\Microsoft SDKs\ Windows\v7.1\Bin\SetEnv.Cmd
设置MSSdk =%WindowsSDKDir%
设置SYMDIR = C:\符号
设置SYMSRV = http://msdl.microsoft.com/download/symbols
设置_NT_SYMBOL_PATH = symsrv * symsrv。 dll *%SYMDIR%*%SYMSRV%
路径C:\Program Files\ Windows调试工具(x64);%PATH%
路径C:\Program Files\Mercurial;%PATH %
创建一个Python虚拟环境。
py -3.4 -m venv --symlinks测试
venv
不会链接.pdb文件,因此请手动获取
set PYDIR =%ProgramW6432%\Python34
set CMD = mklink test\Scripts\%〜nxf%f
用于/ R(* .pdb)中的%PYDIR%%f,可以@%CMD%
激活虚拟环境。
test\脚本激活
克隆PyWin32存储库。生成并安装版本219。
set HGSRV = http://pywin32.hg.sourceforge。净
hg克隆%HGSRV%/ hgroot / pywin32 / pywin32
cd pywin32
hg up b219
构建并安装该软件包。
python setup3。 py install
在控制台调试器cdb.exe下运行Python。
> cdb -xi ld python
Microsoft(R) Windows调试器版本6.12.0002.633 AMD64
版权所有(c)Microsoft Corporation。版权所有。
命令行:python
符号搜索路径为:symsrv * symsrv.dll * C:\Symbols *
http://msdl.microsoft.com/download/symbols
可执行的搜索路径是:
(d50.1174):中断指令异常-代码80000003(第一次机会)
ntdll!LdrpDoDebuggerBreak + 0x30:
00000000`770bcb70 cc int 3
0:000> bp shell32!SHGetFileInfoW
0:000> g
在Win32
上使用Python 3.4.2(v3.4.2:ab2c023a9432,2014年10月6日,22:16:31)
[MSC v.1600 64位(AMD64)] ,版权,信用或许可以获取更多信息。
上面的选项 -xi ld
命令行设置过滤器以忽略打印加载的模块。在线上有很多教程和备忘单,供您使用Microsoft的调试器,例如WinDbg,cdb和kd。调试器都使用相同的引擎,因此它们支持一组通用的调试命令。
附加的调试器在 shell32!SHGetFileInfoW
上设置了一个断点。触发断点后,调试器将获取控制台。 Windows控制台的少数赎回功能之一是按应用程序输入的历史记录和别名。当在同一控制台窗口中跳入和退出调试器和被调试对象时,这使调用回调变得很方便。
>> import os
>>从win32com.shell导入shell,shellcon
>> print(shell .__ file__)
C:\Temp\test\lib\site-packages\win32comext\shell\shell.pyd
>> path = os.path.expanduser(r’〜\Desktop\desktop.ini’)
>>> pidl = shell.SHParseDisplayName(path,0,None)[0]
>>标志=(shellcon.SHGFI_PIDL |
... shellcon.SHGFI_SYSICONINDEX |
... shellcon.SHGFI_ICON |
... shellcon.SHGFI_DISPLAYNAME)
>>> shell.SHGetFileInfo(pidl,0,标志)
断点0命中
SHELL32!SHGetFileInfoW:
000007fe`fd692290 fff3 push rbx
0:000> k 5
***警告:无法验证
的校验和C:\Temp\test\lib\site-packages\win32comext\shell\shell.pyd
Child-SP RetAddr呼叫站点
00000000`003ff2d8 00000000`5f44c5e8 SHELL32!SHGetFileInfoW
00000000`003ff2e0 00000000`5f5af8bd shell!PySHGetFileInfo + 0xf8
00000000`003ff610 00000000`5f62385bCdPython34
00000000`003ff640 00000000`5f625c89 python34!call_function + 0x2ab
00000000`003ff6a0 00000000`5f62770c python34!PyEval_EvalFrameEx + 0x2279
0:000> r rcx
rcx = 0000000000000000
0:000> g
(0,(0,0,0,``,''))
在Windows x64 ABI中,函数的第一个参数在寄存器 rcx
中传递。我们从文档认为这应该是 PIDL
,但实际上是 NULL
正在通过。显然,这是一个错误。堆栈跟踪将责任归咎于。以下是有问题的代码段:
if(flags& SHGFI_PIDL){
ok = PyObject_AsPIDL(obName,& pidl,FALSE);
pidl_or_name =(TCHAR *)pidl;
}否则{
ok = PyWinObject_AsTCHAR(obName,& name,FALSE);
pidl_or_name =名称;
}
如果(!ok)
返回NULL;
SHFILEINFO信息;
memset(& info,0,sizeof(info));
info.dwAttributes = info_attrs;
PY_INTERFACE_PRECALL;
DWORD_PTR dw = SHGetFileInfo(名称,属性,&信息,sizeof(信息),标志);
错误是将 name
作为第一个参数而不是 pidl_or_name
。
问题被标记为ctypes。如果这样做消除了诸如PyWin32之类的大量依赖,则使用ctypes是值得的。对于基于COM的API,我通常不会单独使用ctypes。如果您想尝试使用comtypes包,则它基于ctypes。在这种情况下,可以通过调用 SHParseDisplayName
来避免直接调用COM方法。除了使用 HRESULT
返回代码外,它几乎与其他任何Win32 API一样。
导入类型为_types
导入ctypes为_ctypes
from ctypes import wintypes作为_wtypes
_mtypes = _types.ModuleType('_ mtypes')
_ole32 = _ctypes.WinDLL('ole32')
_shell32 = _ctypes.WinDLL('shell32')
_user32 = _ctypes.WinDLL('user32')
尝试:从win32com.shell导入
作为_shell
,除了ImportError:
_shell = None
尝试:从win32com.shell导入shellcon
,
除了ImportError:
shellcon = _types.ModuleType('shellcon')
shellcon.SHGFI_LARGEICON = 0x00000
shellcon.SHGFI_SMALLICON = 0x00001
shellcon.SHGFI_SHELLICONSIZE = 0x00004
shellcon.SHGFI_PIDL = 0x00008
shellcon.SHGFI_USEFILEATTRI10TES = 0。 SHGFI_ICON = 0x00100
shellcon.SHGFI_DISPLAYNAME = 0x002 00
shellcon.SHGFI_TYPENAME = 0x00400
shellcon.SHGFI_ATTRIBUTES = 0x00800
shellcon.SHGFI_ICONLOCATION = 0x01000
shellcon.SHGFI_EXETYPE = 0x02000
shellcon.SHGFI_SYSICONINDEX = 0x04000 shellcon.SHGFI_LINKOVERLAY = 0x08000
shellcon.SHGFI_SELECTED = 0x10000
shellcon.SHGFI_ATTR_SPECIFIED = 0x20000
试试:
import win32con
除了ImportError:
win32con = _types.ModuleType('win32con')
win32con.MAX_PATH = 260
win32con.FILE_ATTRIBUTE_READONLY = 0x00001
win32con.FILE_ATTRIBUTE_HIDDEN = 0x00002
win32con.FILE_ATTRIxBUTE_SYSTEM = win32con.FILE_ATTRIBUTE_DIRECTORY = 0x00010
win32con.FILE_ATTRIBUTE_ARCHIVE = 0x00020
win32con.FILE_ATTRIBUTE_DEVICE = 0x00040
win32con.FILE_ATTRIBUTE_NORMAL = 0x00080
win32con.FILE_ATTRIBUTE_TEMPORARY = 0x00100
win32con.FILE_ATTRIBUTE_ATOMIC_WRITE = 0x00200
win32con.FILE_ATTRIBUTE_SPARSE_FILE = 0x00200
win32con.FILE_ATTRIBUTE_REACTION = 0x00_00_b_b win32con.FILE_ATTRIBUTE_COMPRESSED = 0x00800
win32con.FILE_ATTRIBUTE_OFFLINE = 0x01000
win32con.FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x02000
win32con.FILE_ATTRIBUTE_ENCRYPTED = 0x04000
win32con.FILE_ATTRIBUTE_VIRTUAL = 0x10000的
_mtypes .CData = _ctypes.Array .__ bases __ [0]
_mtypes.PPIDLIST_ABSOLUTE = _ctypes.POINTER(_ctypes.c_void_p)
_mtypes.SFGAOF = _wtypes.ULONG
_mtypes.PSFGAOF = _Ftypes _mtypes.SFGAOF)
_ole32.CoInitialize.restype = _ctypes.HRESULT#已检查
_ole32.CoInitialize.argtypes =(_ctypes.c_void_p,)
_ole32.CoUninitialize .restype =无
_ole32.CoUninitialize.argtypes =()
_ole32.CoTaskMemFree.restype =无
_ole32.CoTaskMemFree.argtypes =(_ctypes.c_void_p,)
_user32.DestroyIcon .argtypes =(_wtypes.HICON,)
_shell32.SHParseDisplayName.restype = _ctypes.HRESULT#已选中
_shell32.SHParseDisplayName.argtypes =(
_wtypes.LPCWSTR,#pszName, _In_
_ctypes.c_void_p,#pbc,_In_opt_
_mtypes.PPIDLIST_ABSOLUTE,#ppidl,_Out_
_mtypes.SFGAOF,#sfgaoIn,_In_
_fgao_Out,PSF b
$ b类SHFILEINFO(_ctypes.Structure):
_fields_ =(('hIcon',_wtypes.HICON),
('iIcon',_ctypes.c_int),
('dwAttributes',_wtypes.DWORD),
('szDisplayName',_wtypes.WCHAR * win32con.MAX_PATH),
('szTypeName',_wtypes.WCHAR * 80))
_mtypes.SHFILEINFO = SHFILEINFO
_mtypes.PSHFILEINFO = _ctypes.POINTER(SHFILEINFO)
_shell32.SHGetFileInfoW.restype = _ctypes.c_void_p
_shell32.SHGetFileInfoW.argtypes =(
_wtypes.LPVOID,#pszPath,_In_ $ b $$ b _wtypes.DWORD,#dwFileAttributes,
_mtypes.PSHFILEINFO,#psfi,_Inout_
_wtypes.UINT,#cbFileInfo,
_wtypes.UINT)#uFlags
def SHGetFileInfo(pidl,properties = 0,flags = 0):
如果_shell不为None:
如果不是isinstance(pidl,(str,bytes,_mtypes.CData)):
pidl = _shell.PIDLAsString(pidl)
finfo = SHFILEINFO()
_ole32.CoInitialize(None)
try:
retval = _shell32.SHGetFileInfoW(pidl,
属性,
_ctypes.byref(finfo),
_ctypes.sizeof(finfo),
标志)
最后:
_ole32.CoUninitialize()
如果不检索:
如果标志!= shellcon.SHGFI_EXETYPE:
引发_ctypes.WinError()
返回检索,finfo
示例:
如果__name__ =='__main__':
import os
path = os.path.expanduser(r'〜\Desktop\desktop.ini' )
pidl = _shell.SHParseDisplayName(path,0)[0]
断言isinstance(pidl,list)
标志=(shellcon.SHGFI_PIDL |
shellcon.SHGFI_ICON |
shellcon.SHGFI_DISPLAYNAME |
shellcon.SHGFI_TYPENAME |
shellcon.SHGFI_ATTRIBUTES |
shellcon.SHGFI_SYSICONINDEX)
hImageList,finfo = SHGetFileInfo(pidl,0,标志)
print('hImageList:',hImageList)
为名称,键入finfo._fields_:
print(name,':',ascii(getattr(finfo,name)),sep ='')
if finfo.hIcon:
_user32.DestroyIcon(finfo.hIcon)
输出:
hImageList:4411024
图标:10617107
图标:7
dwAttributes:1078497655
szDisplayName:'desktop.ini'
szTypeName:'配置设置'
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
. If SHGFI_PIDL
is set in flags, it calls PyObject_AsPIDL
and stores the result to pidl_or_name
, but it mistakenly passes name
to SHGetFileInfo
, which in this case is the initial NULL
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.
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.Cmd"
set MSSdk=%WindowsSDKDir%
set SYMDIR=C:\Symbols
set SYMSRV=http://msdl.microsoft.com/download/symbols
set _NT_SYMBOL_PATH=symsrv*symsrv.dll*%SYMDIR%*%SYMSRV%
path C:\Program Files\Debugging Tools for Windows (x64);%PATH%
path C:\Program Files\Mercurial;%PATH%
Create a Python virtual environment.
py -3.4 -m venv --symlinks test
venv
doesn't link the .pdb files, so grab those manually in a for loop.
set PYDIR="%ProgramW6432%\Python34"
set CMD=mklink "test\Scripts\%~nxf" "%f"
for /R %PYDIR% %f in (*.pdb) do @%CMD%
Activate the virtual environment.
test\Scripts\activate
Clone the PyWin32 repo. Build and install version 219.
set HGSRV=http://pywin32.hg.sourceforge.net
hg clone %HGSRV%/hgroot/pywin32/pywin32
cd pywin32
hg up b219
Build and install the package.
python setup3.py install
Run Python under the console debugger, cdb.exe.
>cdb -xi ld python
Microsoft (R) Windows Debugger Version 6.12.0002.633 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: python
Symbol search path is: symsrv*symsrv.dll*C:\Symbols*
http://msdl.microsoft.com/download/symbols
Executable search path is:
(d50.1174): Break instruction exception - code 80000003 (first chance)
ntdll!LdrpDoDebuggerBreak+0x30:
00000000`770bcb70 cc int 3
0:000> bp shell32!SHGetFileInfoW
0:000> g
Python 3.4.2 (v3.4.2:ab2c023a9432, Oct 6 2014, 22:16:31)
[MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
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.
>>> import os
>>> from win32com.shell import shell, shellcon
>>> print(shell.__file__)
C:\Temp\test\lib\site-packages\win32comext\shell\shell.pyd
>>> path = os.path.expanduser(r'~\Desktop\desktop.ini')
>>> pidl = shell.SHParseDisplayName(path, 0, None)[0]
>>> flags = (shellcon.SHGFI_PIDL |
... shellcon.SHGFI_SYSICONINDEX |
... shellcon.SHGFI_ICON |
... shellcon.SHGFI_DISPLAYNAME)
>>> shell.SHGetFileInfo(pidl, 0, flags)
Breakpoint 0 hit
SHELL32!SHGetFileInfoW:
000007fe`fd692290 fff3 push rbx
0:000> k 5
*** WARNING: Unable to verify checksum for
C:\Temp\test\lib\site-packages\win32comext\shell\shell.pyd
Child-SP RetAddr Call Site
00000000`003ff2d8 00000000`5f44c5e8 SHELL32!SHGetFileInfoW
00000000`003ff2e0 00000000`5f5af8bd shell!PySHGetFileInfo+0xf8
00000000`003ff610 00000000`5f62385b python34!PyCFunction_Call+0x12d
00000000`003ff640 00000000`5f625c89 python34!call_function+0x2ab
00000000`003ff6a0 00000000`5f62770c python34!PyEval_EvalFrameEx+0x2279
0:000> r rcx
rcx=0000000000000000
0:000> g
(0, (0, 0, 0, '', ''))
In the Windows x64 ABI, the first argument of a function is passed in register rcx
. We know from the SHGetFileInfo
docs that this should be the PIDL
, but actually NULL
is being passed. Clearly this is a bug. The stack trace lays the blame on shell!PySHGetFileInfo
. Here's a snippet of the problematic code:
if (flags & SHGFI_PIDL) {
ok = PyObject_AsPIDL(obName, &pidl, FALSE);
pidl_or_name = (TCHAR *)pidl;
} else {
ok = PyWinObject_AsTCHAR(obName, &name, FALSE);
pidl_or_name = name;
}
if (!ok)
return NULL;
SHFILEINFO info;
memset(&info, 0, sizeof(info));
info.dwAttributes = info_attrs;
PY_INTERFACE_PRECALL;
DWORD_PTR dw = SHGetFileInfo(name, attr, &info, sizeof(info), flags);
The mistake is passing name
as the first argument instead of pidl_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 using HRESULT
return codes, it's pretty much like any other Win32 API.
import types as _types
import ctypes as _ctypes
from ctypes import wintypes as _wtypes
_mtypes = _types.ModuleType('_mtypes')
_ole32 = _ctypes.WinDLL('ole32')
_shell32 = _ctypes.WinDLL('shell32')
_user32 = _ctypes.WinDLL('user32')
try:
from win32com.shell import shell as _shell
except ImportError:
_shell = None
try:
from win32com.shell import shellcon
except ImportError:
shellcon = _types.ModuleType('shellcon')
shellcon.SHGFI_LARGEICON = 0x00000
shellcon.SHGFI_SMALLICON = 0x00001
shellcon.SHGFI_OPENICON = 0x00002
shellcon.SHGFI_SHELLICONSIZE = 0x00004
shellcon.SHGFI_PIDL = 0x00008
shellcon.SHGFI_USEFILEATTRIBUTES = 0x00010
shellcon.SHGFI_ICON = 0x00100
shellcon.SHGFI_DISPLAYNAME = 0x00200
shellcon.SHGFI_TYPENAME = 0x00400
shellcon.SHGFI_ATTRIBUTES = 0x00800
shellcon.SHGFI_ICONLOCATION = 0x01000
shellcon.SHGFI_EXETYPE = 0x02000
shellcon.SHGFI_SYSICONINDEX = 0x04000
shellcon.SHGFI_LINKOVERLAY = 0x08000
shellcon.SHGFI_SELECTED = 0x10000
shellcon.SHGFI_ATTR_SPECIFIED = 0x20000
try:
import win32con
except ImportError:
win32con = _types.ModuleType('win32con')
win32con.MAX_PATH = 260
win32con.FILE_ATTRIBUTE_READONLY = 0x00001
win32con.FILE_ATTRIBUTE_HIDDEN = 0x00002
win32con.FILE_ATTRIBUTE_SYSTEM = 0x00004
win32con.FILE_ATTRIBUTE_DIRECTORY = 0x00010
win32con.FILE_ATTRIBUTE_ARCHIVE = 0x00020
win32con.FILE_ATTRIBUTE_DEVICE = 0x00040
win32con.FILE_ATTRIBUTE_NORMAL = 0x00080
win32con.FILE_ATTRIBUTE_TEMPORARY = 0x00100
win32con.FILE_ATTRIBUTE_ATOMIC_WRITE = 0x00200
win32con.FILE_ATTRIBUTE_SPARSE_FILE = 0x00200
win32con.FILE_ATTRIBUTE_REPARSE_POINT = 0x00400
win32con.FILE_ATTRIBUTE_XACTION_WRITE = 0x00400
win32con.FILE_ATTRIBUTE_COMPRESSED = 0x00800
win32con.FILE_ATTRIBUTE_OFFLINE = 0x01000
win32con.FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x02000
win32con.FILE_ATTRIBUTE_ENCRYPTED = 0x04000
win32con.FILE_ATTRIBUTE_VIRTUAL = 0x10000
_mtypes.CData = _ctypes.Array.__bases__[0]
_mtypes.PPIDLIST_ABSOLUTE = _ctypes.POINTER(_ctypes.c_void_p)
_mtypes.SFGAOF = _wtypes.ULONG
_mtypes.PSFGAOF = _ctypes.POINTER(_mtypes.SFGAOF)
_ole32.CoInitialize.restype = _ctypes.HRESULT # checked
_ole32.CoInitialize.argtypes = (_ctypes.c_void_p,)
_ole32.CoUninitialize.restype = None
_ole32.CoUninitialize.argtypes = ()
_ole32.CoTaskMemFree.restype = None
_ole32.CoTaskMemFree.argtypes = (_ctypes.c_void_p,)
_user32.DestroyIcon.argtypes = (_wtypes.HICON,)
_shell32.SHParseDisplayName.restype = _ctypes.HRESULT # checked
_shell32.SHParseDisplayName.argtypes = (
_wtypes.LPCWSTR, # pszName, _In_
_ctypes.c_void_p, # pbc, _In_opt_
_mtypes.PPIDLIST_ABSOLUTE, # ppidl, _Out_
_mtypes.SFGAOF, # sfgaoIn, _In_
_mtypes.PSFGAOF) # psfgaoOut, _Out_opt_
class SHFILEINFO(_ctypes.Structure):
_fields_ = (('hIcon', _wtypes.HICON),
('iIcon', _ctypes.c_int),
('dwAttributes', _wtypes.DWORD),
('szDisplayName', _wtypes.WCHAR * win32con.MAX_PATH),
('szTypeName', _wtypes.WCHAR * 80))
_mtypes.SHFILEINFO = SHFILEINFO
_mtypes.PSHFILEINFO = _ctypes.POINTER(SHFILEINFO)
_shell32.SHGetFileInfoW.restype = _ctypes.c_void_p
_shell32.SHGetFileInfoW.argtypes = (
_wtypes.LPVOID, # pszPath, _In_
_wtypes.DWORD, # dwFileAttributes,
_mtypes.PSHFILEINFO, # psfi, _Inout_
_wtypes.UINT, # cbFileInfo,
_wtypes.UINT) # uFlags
def SHGetFileInfo(pidl, attributes=0, flags=0):
if _shell is not None:
if not isinstance(pidl, (str, bytes, _mtypes.CData)):
pidl = _shell.PIDLAsString(pidl)
finfo = SHFILEINFO()
_ole32.CoInitialize(None)
try:
retval = _shell32.SHGetFileInfoW(pidl,
attributes,
_ctypes.byref(finfo),
_ctypes.sizeof(finfo),
flags)
finally:
_ole32.CoUninitialize()
if not retval:
if flags != shellcon.SHGFI_EXETYPE:
raise _ctypes.WinError()
return retval, finfo
Example:
if __name__ == '__main__':
import os
path = os.path.expanduser(r'~\Desktop\desktop.ini')
pidl = _shell.SHParseDisplayName(path, 0)[0]
assert isinstance(pidl, list)
flags = (shellcon.SHGFI_PIDL |
shellcon.SHGFI_ICON |
shellcon.SHGFI_DISPLAYNAME |
shellcon.SHGFI_TYPENAME |
shellcon.SHGFI_ATTRIBUTES |
shellcon.SHGFI_SYSICONINDEX)
hImageList, finfo = SHGetFileInfo(pidl, 0, flags)
print('hImageList:', hImageList)
for name, typ in finfo._fields_:
print(name, ': ', ascii(getattr(finfo, name)), sep='')
if finfo.hIcon:
_user32.DestroyIcon(finfo.hIcon)
Output:
hImageList: 4411024
hIcon: 10617107
iIcon: 7
dwAttributes: 1078497655
szDisplayName: 'desktop.ini'
szTypeName: 'Configuration settings'
这篇关于如何在python中将SHGetFileInfo与SHGFI_PIDL一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!