I have problem with getting the path of the executable from the process. I'm using Windoxs XP 64 bit with Python 2.7.5 x86_64 and the code is:
pbi = create_string_buffer(200)
size = c_int()
NTDLL.NtQueryInformationProcess.restype = c_int
ret = NTDLL.NtQueryInformationProcess(h_process, #previously defined
27,
byref(pbi),
sizeof(pbi),
byref(size))
fbuf = pbi.raw[8:]
fbuf = fbuf[:fbuf.find('\0\0')+1]
return fbuf.decode('utf16', errors="ignore")
This work on Windows XP 32 bit. Founding in MSDN, I found a dfferent mechanism using 'psapi.dll' and specifically GetProcessImageFileName. This method works on Windows 7 x64 and the code is:
PSAPI = ctypes.WinDLL('Psapi.dll')
GetProcessImageFileName = PSAPI.GetProcessImageFileNameA
GetProcessImageFileName.restype = ctypes.wintypes.DWORD
path = create_string_buffer(200)
ret = GetProcessImageFileName(self.h_process, path, 200)
Someone has any idea????
Thanks in advance
Related
I want to get path to roaming, which should end up like this in my case:
A:\Users\Mitja\AppData\Roaming
But when program is ran as windows service all I get is:
C:\Windows\System32\config\systemprofile\AppData\Roaming
I tried multiple libraries, but all did the same. Does anyone maybe know how would I get the path?
I already tried all of these:
roaming_folder = os.getenv('APPDATA')
roaming_folder = os.path.expanduser('~\\AppData\\Roaming')
roaming_folder = os.environ['APPDATA']
def get_appdata():
CSIDL_APPDATA = 26
SHGFP_TYPE_CURRENT = 0
buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH)
ctypes.windll.shell32.SHGetFolderPathW(None, CSIDL_APPDATA, None, SHGFP_TYPE_CURRENT, buf)
return buf.value
roaming_folder = get_appdata()
import win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
roaming_folder = shell.SpecialFolders("AppData")
I have been using Python to run a piece of software via a plug-in which is implemented as a DLL. This is provided through the following wrapper class:
from ctypes import *
import os
ANULL = -999999
gwbdll = None
if os.name == 'posix':
gwbdll = cdll.LoadLibrary('libgwbplugin.so')
else:
gwbdll = cdll.LoadLibrary('gwbplugin')
class GWBplugin:
Name = "GWBplugin"
def __init__(self):
self.plugin = c_void_p (None)
def initialize (self,app_name,file_name=None,cmds=None):
return gwbdll.c_initialize(byref(self.plugin), c_char_p(app_name.encode()), file_name if file_name == None else c_char_p(file_name.encode()), cmds if cmds == None else c_char_p(cmds.encode()))
def exec_cmd (self,uline):
return gwbdll.c_exec_cmd(byref(self.plugin), c_char_p(uline.encode()))
def results (self, value, units=None, ix=0, jy=0):
type = c_void_p
type_result = gwbdll.c_results(byref(self.plugin),c_void_p(None),c_char_p(value.encode()),c_char_p("DATATYPE".encode()),c_int(ix),c_int(jy))
if type_result == 1:
type = c_int
elif type_result == 2:
type = c_double
elif type_result == 3:
type = c_char_p
else:
return []
count = gwbdll.c_results(byref(self.plugin),c_void_p(None),c_char_p(value.encode()),units if units == None else c_char_p(units.encode()),c_int(ix),c_int(jy))
arr = (type*count)()
gwbdll.c_results(byref(self.plugin),cast(arr,c_void_p),c_char_p(value.encode()),units if units == None else c_char_p(units.encode()),c_int(ix),c_int(jy))
if type == c_char_p:
arr = [x.decode('cp1252') for x in arr]
return arr
def destroy (self):
gwbdll.c_destroy(byref(self.plugin))
def __del__(self):
gwbdll.c_destroy(byref(self.plugin))
I am running my program on a Jupyter notebook with Python 3.8.8 with code that looks like:
myPlugin = GWBplugin()
myPlugin.initialize("react", f_out, f_in_flagged)
where "react" is the name of the specific application I am using in this software, f_out looks like 'Output Files/pH 9/Reduced/0.0% Reduced/Output_6.txt', and f_in_flagged looks like "-i 'Input Files/pH 9/Reduced/0.0% Reduced/Input_6.rea'".
This is contained in a loop that runs through many different input files, and was running just fine until a few days ago when I generated more input files (contained within some new subdirectories) to run, and now it spits out the following error:
OSError Traceback (most recent call last)
<ipython-input-6-fdf290a73be1> in <module>
24 # #Initialize: Application, Output file, Input file containing setup
---> 25 myPlugin.initialize("react", f_out, f_in_flagged)
26 #Run
27 myPlugin.exec_cmd("go")
C:\Program Files\Gwb\src\GWBplugin.py in initialize(self, app_name, file_name, cmds)
15
16 def initialize (self,app_name,file_name=None,cmds=None):
---> 17 return gwbdll.c_initialize(byref(self.plugin), c_char_p(app_name.encode()), file_name if file_name == None else c_char_p(file_name.encode()), cmds if cmds == None else c_char_p(cmds.encode()))
18
19 def exec_cmd (self,uline):
OSError: exception: access violation reading 0x0000000000000000
I am not really familiar with C or ctypes, but as far as I can tell this has something to do with the name of the input and output files I'm feeding it. I tried going back and running the files in the original directories that were working before (even tried completely uninstalling and reinstalling everything: the software, anaconda, and deleted all of the new files and directories) and am now getting the same error, so beyond that I am really at a loss as to what is going on. Any help is greatly appreciated!
I'm looking to use the NetUserEnum() function in the Win32 API using Python but would like to use ctypes instead of a library that already performs this function. I have already done this with GlobalMemoryStatusEx() and GetSystemPowerStatus() but I am struggling with NetUserEnum(). I think I am getting tripped up trying to supply LPBYTE *bufptr to the function. I'm not sure how to properly structure the information and call the function correctly. Any help is appreciated.
As [SO]: How to create a Minimal, Reproducible Example (reprex (mcve)) recommends, you should post your current work together with the problem that prevents you from going further.
Before anything else, the references:
[Python.Docs]: ctypes - A foreign function library for Python
[MS.docs]: NetUserEnum function (lmaccess.h)
Yes, that LPBYTE *bufptr argument can be tricky for someone unfamiliar with CTypes (and also processing it afterwards).
code00.py:
#!/usr/bin/env python
import sys
import ctypes as ct
from ctypes import wintypes as wt
DLL_NAME = "netapi32.dll"
FILTER_NORMAL_ACCOUNT = 0x0002
MAX_PREFERRED_LENGTH = wt.DWORD(-1)
NERR_Success = 0
NET_API_STATUS = wt.DWORD
class USER_INFO_0(ct.Structure):
_fields_ = [
("usri0_name", wt.LPWSTR),
]
def user_info_type(level):
if level == 0:
return USER_INFO_0
# elif ...
else:
print("Invalid user info level")
def print_user_info(idx, user_info):
print("\nUser {:d}:".format(idx))
if isinstance(user_info, USER_INFO_0):
print(" Name: {:s}".format(user_info.usri0_name))
# elif ...
else:
print("Invalid data")
def main(*argv):
netapi32 = ct.WinDLL(DLL_NAME)
NetUserEnum = netapi32.NetUserEnum
NetUserEnum.argtypes = (wt.LPCWSTR, wt.DWORD, wt.DWORD, ct.POINTER(wt.LPBYTE), wt.DWORD, wt.LPDWORD, wt.LPDWORD, wt.PDWORD)
NetUserEnum.restype = NET_API_STATUS
NetApiBufferFree = netapi32.NetApiBufferFree
NetApiBufferFree.argtypes = (wt.LPVOID,)
NetApiBufferFree.restype = NET_API_STATUS
info_level = 0
filter_flag = FILTER_NORMAL_ACCOUNT
buf = wt.LPBYTE()
buf_len = MAX_PREFERRED_LENGTH
read, total = wt.DWORD(0), wt.DWORD(0)
resume_handle = None
res = NetUserEnum(None, info_level, filter_flag, ct.byref(buf), buf_len, ct.byref(read), ct.byref(total), resume_handle)
print("\n{0:s} returned: {1:d}".format(NetUserEnum.__name__, res))
if res != NERR_Success:
return -1
print("{:d} (out of {:d}) entries read".format(read.value, total.value))
UserInfoArray = user_info_type(info_level) * read.value
users = UserInfoArray.from_address(ct.addressof(buf.contents))
for idx, user in enumerate(users):
print_user_info(idx, user)
res = NetApiBufferFree(buf)
if res != NERR_Success:
print("Error freing buffer: {:d}".format(res))
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
Notes:
This is an minimum minimorum example to get you past your current problem. There are certain aspects that need to be taken into consideration :
If you want more details about each user, use the appropriate USER_INFO_* structure. You should define it (as I did for USER_INFO_0), and also handle it (in the wrapper functions that I wrote: user_info_type, print_user_info), and (obviously) set the appropriate level (info_level)
This minimal example is OK for a regular computer. But, if you attempt to run it in a domain (with tenths of thousands of users) you might experience some memory issues. In that case, you should set a decent buf_size (maybe 16 MiBs) and call NetUserEnum (and also NetApiBufferFree) in a loop, relying on resume_handle, while it keeps returning ERROR_MORE_DATA
Make sure the user that runs this program has enough privileges
Output:
cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow\q066185045]> "e:\Work\Dev\VEnvs\py_pc064_03.08.07_test0\Scripts\python.exe" code00.py
Python 3.8.7 (tags/v3.8.7:6503f05, Dec 21 2020, 17:59:51) [MSC v.1928 64 bit (AMD64)] 64bit on win32
NetUserEnum returned: 0
6 (out of 6) entries read
User 0:
Name: Administrator
User 1:
Name: cfati
User 2:
Name: DefaultAccount
User 3:
Name: Guest
User 4:
Name: test
User 5:
Name: WDAGUtilityAccount
Done.
Not working in mac os, not sure why this isnt working, please help? Works fine in windows..Just brought a mac so, confused why this isn't working.
SUMMARIES_DIRECTORY_PATH = os.path.join(current_dir, "summaries")
NODECOUNTS_DIRECTORY_PATH = os.path.join(current_dir, "node_counts")
summaries_path_list = os.listdir(SUMMARIES_DIRECTORY_PATH)
nodecounts_path_list = os.listdir(NODECOUNTS_DIRECTORY_PATH)
coop_ratios_list = []
for summary_path in summaries_path_list:
coop_ratio_list = []
abs_summaries_path = os.path.join(SUMMARIES_DIRECTORY_PATH, summary_path)
summaries = os.listdir(abs_summaries_path) //THIS LINE IS BREAKING//
for n in range(len(summaries)):
abs_summary_path_generation = os.path.join(abs_summaries_path, "summary" + str(n) + ".csv")
summary = pd.read_csv(abs_summary_path_generation)
coop_ratio = np.mean(summary.Cooperation_rating)
coop_ratio_list.append(coop_ratio)
coop_ratios_list.append(coop_ratio_list)
traceback
summaries = os.listdir(abs_summaries_path)
NotADirectoryError: [Errno 20] Not a directory:
It was because the being .DS_Store folder created by MacOS. It is a "hidden" (see dotfile). It was then added to the array..
This is how i solved it
if '.DS_Store' in summaries_path_list:
summaries_path_list.remove('.DS_Store')
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:
64-bit Windows 7 SP1 (6.1.7601)
Windows SDK 7.1 (ensure the debuggers are installed)
Visual Studio 2010 SP1
Visual C++ 2010 SP1 Compiler Update
Python 3.4 (and debug files)
Mercurial (hg.exe, not TortoiseHg)
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
I edited setup.py to comment out everything related to building
win32com.mapi. My setup didn't even have the required headers,
and when I obtained them there were problems building the
extension for WIN64.
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'