How to use IFileOperation from ctypes

前端 未结 2 1283
野的像风
野的像风 2020-12-02 00:43

I want to use IFileOperation to copy files from python code -

  • It\'s fast(er than python)
  • You get a nice dialog
  • Doesn\'t block Python
相关标签:
2条回答
  • 2020-12-02 01:21

    This question put me on track, as it shows that COM loading Windows functionality is in fact avialable from ctypes, albeit it requires a bit more work.

    The question uses comtypes.GUID as the only (non standard) dependency.

    Looking at comtypes itself, it's pure python and uses ctypes (for CoCreateInstance and all else), and the paths to the windows functions needed to load and handle the COM object can be found, specifically -

    import ctypes
    ctypes.oledll.ole32.CoCreateInstance()
    

    The CLSIDs need to be put explicitly, as in the referred question -

    IID_IFileOperation  = '{947AAB5F-0A5C-4C13-B4D6-4BF7836FC9F8}'
    CLSID_FileOperation = '{3AD05575-8857-4850-9277-11B85BDB8E09}'
    

    All and all, comtypes, which is a small pure python library, seems quite enough for this task, if one doesn't want to tinker with ctypes, paste in GUID or else doesn't mind the dependency.

    However, this is fully implementable in ctypes, as proven by comtypes itself, with the caveat of possibly having to add in GUID manually -

    from ctypes import *
    
    BYTE, WORD, DWORD = c_byte, c_ushort, c_ulong
    
    _StringFromCLSID = oledll.ole32.StringFromCLSID
    _ProgIDFromCLSID = oledll.ole32.ProgIDFromCLSID
    _CLSIDFromString = oledll.ole32.CLSIDFromString
    _CLSIDFromProgID = oledll.ole32.CLSIDFromProgID
    _CoCreateGuid    = oledll.ole32.CoCreateGuid
    
    _CoTaskMemFree   = windll.ole32.CoTaskMemFree
    
    class GUID(Structure):
        _fields_ = [("Data1", DWORD),
                    ("Data2", WORD),
                    ("Data3", WORD),
                    ("Data4", BYTE * 8)]
    
        def __init__(self, name=None):
            if name is not None:
                _CLSIDFromString(unicode(name), byref(self))
    
        def __repr__(self):
            return u'GUID("%s")' % unicode(self)
    
        def __unicode__(self):
            p = c_wchar_p()
            _StringFromCLSID(byref(self), byref(p))
            result = p.value
            _CoTaskMemFree(p)
            return result
        __str__ = __unicode__
    
        def __cmp__(self, other):
            if isinstance(other, GUID):
                return cmp(bytes(self), bytes(other))
            return -1
    
        def __nonzero__(self):
            return self != GUID_null
    
        def __eq__(self, other):
            return isinstance(other, GUID) and \
                   bytes(self) == bytes(other)
    
        def __hash__(self):
            # We make GUID instances hashable, although they are mutable.
            return hash(bytes(self))
    
        def copy(self):
            return GUID(unicode(self))
    
        def from_progid(cls, progid):
            """Get guid from progid, ...
            """
            if hasattr(progid, "_reg_clsid_"):
                progid = progid._reg_clsid_
            if isinstance(progid, cls):
                return progid
            elif isinstance(progid, basestring):
                if progid.startswith("{"):
                    return cls(progid)
                inst = cls()
                _CLSIDFromProgID(unicode(progid), byref(inst))
                return inst
            else:
                raise TypeError("Cannot construct guid from %r" % progid)
        from_progid = classmethod(from_progid)
    
        def as_progid(self):
            "Convert a GUID into a progid"
            progid = c_wchar_p()
            _ProgIDFromCLSID(byref(self), byref(progid))
            result = progid.value
            _CoTaskMemFree(progid)
            return result
    
        def create_new(cls):
            "Create a brand new guid"
            guid = cls()
            _CoCreateGuid(byref(guid))
            return guid
        create_new = classmethod(create_new)
    
    0 讨论(0)
  • 2020-12-02 01:31

    Sure, it's located in pythoncom and shell for constants, for example:

    from win32com.shell import shell
    import pythoncom
    
    # create an instance of IFileOperation
    fo = pythoncom.CoCreateInstance(shell.CLSID_FileOperation, None, pythoncom.CLSCTX_ALL, shell.IID_IFileOperation)
    
    # here you can use SetOperationFlags, progress Sinks, etc.
    
    # create an instance of IShellItem for the source item
    item1 = shell.SHCreateItemFromParsingName("c:\\temp\\source.txt", None, shell.IID_IShellItem)
    
    # create an instance of IShellItem for the target folder
    folder = shell.SHCreateItemFromParsingName("c:\\another", None, shell.IID_IShellItem)
    
    # queue the copy operation
    fo.CopyItem(item1, folder, "new name.txt", None)
    
    # commit
    fo.PerformOperations()
    
    0 讨论(0)
提交回复
热议问题