Search code examples
pythonwinapictypeswin32com

expected LP_SHFILEOPSTRUCTW instance instead of pointer to SHFILEOPSTRUCTW (python ctypes)


I'm using following code to execute some file system operations (copy/move/rename of files and folders) on windows. This code requires pywin32.

from win32com.shell import shell, shellcon
from ctypes.wintypes import HWND, UINT, LPCWSTR, BOOL, WORD
from ctypes import c_void_p, Structure, windll, POINTER, byref

src = unicode(os.path.abspath(_src_) + '\0', 'utf-8')
dest = unicode(os.path.abspath(_dest_) + '\0', 'utf-8')

class SHFILEOPSTRUCTW(Structure):
    _fields_ = [("hwnd", HWND),
                ("wFunc", UINT),
                ("pFrom", LPCWSTR),
                ("pTo", LPCWSTR),
                ("fFlags", WORD),
                ("fAnyOperationsAborted", BOOL),
                ("hNameMappings", c_void_p),
                ("lpszProgressTitle", LPCWSTR)]

SHFileOperationW = windll.shell32.SHFileOperationW
SHFileOperationW.argtypes = [POINTER(SHFILEOPSTRUCTW)]

args = SHFILEOPSTRUCTW(wFunc=UINT(op), pFrom=LPCWSTR(src), pTo=LPCWSTR(dest), fFlags=WORD(flags), fAnyOperationsAborted=BOOL())

result = SHFileOperationW(byref(args))
aborted = bool(args.fAnyOperationsAborted)

if not aborted and result != 0:
    # Note: raising a WindowsError with correct error code is quite
    # difficult due to SHFileOperation historical idiosyncrasies.
    # Therefore we simply pass a message.
    raise WindowsError('SHFileOperationW failed: 0x%08x' % result)

flags are always: shellcon.FOF_SILENT | shellcon.FOF_NOCONFIRMATION | shellcon.FOF_NOERRORUI | shellcon.FOF_NOCONFIRMMKDIR

op is for e.g.: shellcon.FO_COPY

The problem I have is that sometimes this function gives me error:

ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_SHFILEOPSTRUCTW instance instead of pointer to SHFILEOPSTRUCTW 

especially when dealing with very long paths (e.g. len(dest)=230)

What I'm I doing wrong here?

[edit]

There is a shell.SHFileOperation but we need to use custom wrapper SHFileOperationW to support unicodes.

[edit2]

As Barmak Shemirani wrote, in python3 you can just simply use shell.SHFileOperation and it will work with any special unicode chars. If I will find a solution to fix this in python2, I'll share it here.


Solution

  • In version 3 you can use shell.SHFileOperation with SHFILEOPSTRUCT which will also append double null terminator when needed.

    from win32com.shell import shell, shellcon
    
    shell.SHFileOperation((
        None,
        shellcon.FO_COPY,
        "c:\\test\\test1.txt\0c:\\test\\test2.txt",
        "c:\\test\\ελληνική+漢語+English",
        shellcon.FOF_SILENT | shellcon.FOF_NOCONFIRMATION | 
        shellcon.FOF_NOERRORUI | shellcon.FOF_NOCONFIRMMKDIR,
        None,
        None))