Search code examples
pythonwinapictypes

Opening explorer and selecting files via SHOpenFolderAndSelectItems with ctypes


In python this can be done with pywin32 like so:

from win32com.shell import shell
def showFilesInExplorer(folder, files):
    folder_pidl = shell.SHILCreateFromPath(folder, 0)[0]
    files_pidl = [shell.SHILCreateFromPath(f, 0)[0] for f in files]
    shell.SHOpenFolderAndSelectItems(folder_pidl, files_pidl, 0)

But theoretically it can be done with only ctypes to avoid a dependency on pywin32.


Solution

  • import ctypes
    ctypes.windll.ole32.CoInitialize.restype = ctypes.HRESULT
    ctypes.windll.ole32.CoInitialize.argtypes = [ctypes.c_void_p]
    ctypes.windll.ole32.CoUninitialize.restype = None
    ctypes.windll.ole32.CoUninitialize.argtypes = None
    ctypes.windll.shell32.ILCreateFromPathW.restype = ctypes.c_void_p
    ctypes.windll.shell32.ILCreateFromPathW.argtypes = [ctypes.c_char_p]
    ctypes.windll.shell32.SHOpenFolderAndSelectItems.restype = ctypes.HRESULT
    ctypes.windll.shell32.SHOpenFolderAndSelectItems.argtypes = [ctypes.c_void_p, ctypes.c_uint, ctypes.c_void_p, ctypes.c_ulong]
    ctypes.windll.shell32.ILFree.restype = None
    ctypes.windll.shell32.ILFree.argtypes = [ctypes.c_void_p]
    
    def showFilesInExplorer(folder, files):
        ctypes.windll.ole32.CoInitialize(None)
    
        folder_pidl = ctypes.windll.shell32.ILCreateFromPathW(folder.encode('utf-16le') + b'\0')
        files_pidl = [ctypes.windll.shell32.ILCreateFromPathW(f.encode('utf-16le') + b'\0') for f in files]
        files_pidl_arr = (ctypes.c_void_p * len(files_pidl))(*files_pidl)
    
        ctypes.windll.shell32.SHOpenFolderAndSelectItems(folder_pidl, len(files_pidl_arr), files_pidl_arr, 0)
    
        for pidl in files_pidl[::-1]:
            ctypes.windll.shell32.ILFree(pidl)
        ctypes.windll.shell32.ILFree(folder_pidl)
    
        ctypes.windll.ole32.CoUninitialize()