Search code examples
pythoniosiphonewin32com

Copying files usingwin32com.shell pidl reference in Windows - to copy picture files off an iPhone


I've been trying to find a way to copy files off an iPhone but despite being able to list files within it using win32com.shell GetDisplayNameOf and BindToObject, I can't seem to find any way of copying files using only the pidl reference.

Unfortunately when the iPhone is connected to Windows it doesn't mount as a drive letter, requiring you to use the PIDL reference rather than a full path. However after much Googling, I can't seem to find a way of copying using only the PIDL reference.

"path = shell.SHGetPathFromIDList(pidl)" seems to be a potential option to find a filesystem path from a PIDL, however as the iPhone doesn't mount to a filesystem path, this always returns an error when given a PIDL value.

Example code I've used so far (taken from How can I iterate across the photos on my connected iPhone from Windows 7 in Python?):

from win32com.shell import shell, shellcon

desktop = shell.SHGetDesktopFolder()

for pidl in desktop:
    if desktop.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == "This PC":
        # path = shell.SHGetPathFromIDList(pidl)
        print path
        break

folder = desktop.BindToObject(pidl, None, shell.IID_IShellFolder)
for pidl in folder:
     if folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == "My iPhone":
         break

folder = folder.BindToObject(pidl, None, shell.IID_IShellFolder)
for pidl in folder:
    if folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == "Internal Storage":
        break
        
folder = folder.BindToObject(pidl, None, shell.IID_IShellFolder)
for pidl in folder:
    if folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) == "DCIM":
        break

# Each of the image folders
folder = folder.BindToObject(pidl, None, shell.IID_IShellFolder)
for pidl in folder:
    # print folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL)

    files = folder.BindToObject(pidl, None, shell.IID_IShellFolder)

    for curfile in files:
        current_file = folder.GetDisplayNameOf(pidl, shellcon.SHGDN_NORMAL) + "\\" + files.GetDisplayNameOf(curfile, shellcon.SHGDN_NORMAL)
        folder.BindToObject(pidl, )

Does anyone have any ideas?

Key references I've used so far: Example code that correctly reads the filesystem using PIDLs: How can I iterate across the photos on my connected iPhone from Windows 7 in Python?

Example of how to list files off an iPhon, but no details of how to copy them: https://github.com/dblume/list-photos-on-phone/blob/master/list-photos-on-phone.py


Solution

  • Not quite sure of the links to stuff. But I have been able to copy files once I have a PIDL. You have to create a ShellItem of the file and the destination. Then use the IFileOperation. I think it was mostly a lot of googling and looking up the microsoft MSDN docs.

    Anyway here's the code. Hopefully it helps!

    from win32com.shell import shell, shellcon
    import pythoncom
    #fo is the folder IShellFolder object
    #dsk is the destination IShellFolder object
    #fi is the PIDL of the item you wish to copy (eg. the photo on your iPhone)
    
    fidl = shell.SHGetIDListFromObject(fo) #Grab the PIDL from the folder object
    didl = shell.SHGetIDListFromObject(dsk) #Grab the PIDL from the folder object
    
    si = shell.SHCreateShellItem(fidl, None, fi) #Create a ShellItem of the source file
    dst = shell.SHCreateItemFromIDList(didl)
    
    #Python IFileOperation
    pfo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation,None,pythoncom.CLSCTX_ALL,shell.IID_IFileOperation)
    pfo.SetOperationFlags(shellcon.FOF_NOCONFIRMATION)
    pfo.CopyItem(si, dst, "Destination Name.jpg") # Schedule an operation to be performed
    success = pfo.PerformOperations() #perform operation
    

    Good luck with your project!