Python中的Windows DragDrop Shell扩展

时间:2018-07-07 02:58:47

标签: python pywin32 shell-extensions windows-explorer-integration

在Windows资源管理器中,我希望能够将所有文件拖放到正在创建的文件类型上,并将其附加到我的文件中。

我看过win32com演示,并且没有一个专门用于shell拖放扩展的示例,但是看起来很简单。

所以我开始编写一个测试代码,以捕获.py文件的drop事件。我注册并重新启动,但是在拖曳上似乎没有任何视觉效果,所以我肯定忽略了某个地方。

(我意识到下面的代码尚无法执行添加操作。)

-<paramName>:<value>

即使我重新启动资源管理器并尝试拖动,我在win32traceutil中获得的唯一信息是:

import pythoncom
from win32com.shell import shell, shellcon
import win32con
import winerror
import pywintypes
import win32traceutil


class ShellDropHandler:
    """
    Implements IDropTarget:
        https://docs.microsoft.com/en-us/windows/desktop/api/oleidl/nn-oleidl-idroptarget
    and registers it as file type extension:
        https://msdn.microsoft.com/en-us/library/cc144165(v=vs.85).aspx
    Also this interface is translated to python, here:
        http://timgolden.me.uk/pywin32-docs/PyIDropTarget.html
    """
    _name_ = __name__
    _reg_progid_ = "Python.ShellExtension."+_name_
    _reg_desc_ = "Shell DropHandler Extension ("+_name_+")"
    _reg_clsid_ = "{CED0336C-C9EE-4a7f-8D7F-C660393C399F}"
    _com_interfaces_ = [shell.IID_IShellExtInit, pythoncom.IID_IDropTarget]
    _public_methods_ = ['DragEnter','DragOver','DragLeave','Drop'] + shellcon.IShellExtInit_Methods

    def Initialize(self, folder, dataobj, hkey):
        print "init"
        self.dataobj = dataobj

    # --- now implement members of IDropTarget

    def DragEnter(self,dataObj,keyboardModifierState,point,dropEffectFlag):
        """
        Used to display drag-over effects.

        :param dataObj: the data being dragged over us in the form:
            https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-idataobject
        :param keyboardModifierState: an or'ed combo of any of
            MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON
        :param point: location, see
            https://msdn.microsoft.com/library/windows/hardware/ff569166
        :param dropEffectFlag: one of 
            DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_MOVE, DROPEFFECT_LINK, DROPEFFECT_SCROLL
            https://docs.microsoft.com/en-us/windows/desktop/com/dropeffect-constants

        :return: drop effect constant (see above)

        See also:
            dataObj format structure - https://docs.microsoft.com/en-us/windows/desktop/api/objidl/ns-objidl-tagformatetc
            standard format types - https://docs.microsoft.com/en-us/windows/desktop/dataxchg/standard-clipboard-formats
        """
        print "dragenter"
        return shellcon.DROPEFFECT_COPY

    def DragLeave(self):
        """
        Used to remove display of drag-over effects. 

        :return: hresult, I can't think of a reason for other than S_OK
        """
        print "dragleave"
        return winerror.S_OK

    def DragOver(self,keyboardModifierState,point,dropEffectFlag):
        """
        Used to update drag-over effects.

        :param keyboardModifierState: an or'ed combo of any of
            MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON
        :param point: location, see
            https://msdn.microsoft.com/library/windows/hardware/ff569166
        :param dropEffectFlag: one of 
            DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_MOVE, DROPEFFECT_LINK, DROPEFFECT_SCROLL
            https://docs.microsoft.com/en-us/windows/desktop/com/dropeffect-constants
        :return: drop effect constant (see above)
        """
        print "dragOver"
        return shellcon.DROPEFFECT_COPY

    def Drop(self,dataObj,keyboardModifierState,point,dropEffectFlag):
        """
        This is the important one!

        :param dataObj: the data being dragged over us in the form:
            https://docs.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-idataobject
        :param keyboardModifierState: an or'ed combo of any of
            MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON
        :param point: location, see
            https://msdn.microsoft.com/library/windows/hardware/ff569166
        :param dropEffectFlag: one of 
            DROPEFFECT_NONE, DROPEFFECT_COPY, DROPEFFECT_MOVE, DROPEFFECT_LINK, DROPEFFECT_SCROLL
            https://docs.microsoft.com/en-us/windows/desktop/com/dropeffect-constants
        :return: hresult -- ususally S_OK
        """
        print "drop"
        # get the data out
        data=dataObj.GetData(format,medium)
        formatIn,formatOut=dataObj.GetCanonicalFormatEtc()
        if formatOut.cfFormat==win32con.CF_TEXT: # plain text
            text=data
        elif formatOut.cfFormat==win32con.CF_UNICODETEXT: # self explanatory, there
            text=data
        elif formatOut.cfFormat==win32con.CF_OEMTEXT: # multiline text
            text=data
        elif formatOut.cfFormat==win32con.CF_HDROP: # a list of files
            # data is a STGMEDIUM structture
            #    http://msdn.microsoft.com/en-us/library/windows/desktop/ms683812%28v=vs.85%29.aspx
            # that contains a dropfiles structure
            #    https://docs.microsoft.com/en-us/windows/desktop/api/shlobj_core/ns-shlobj_core-_dropfiles
            text=[]
            numFiles=shell.DragQueryFile(data.data_handle,-1)
            for i in range(numFiles):
                filename=shell.DragQueryFile(sm.data_handle,0)
                f=open(filename,'rb')
                text.append(f.read())
            text='\n'.join(text)
        else:
            return winerror.E_FAIL
        # now write the data to the target file
        print text
        # this also implies to "leave" an existing drag operation, therefore
        self.DragLeave()
        return winerror.S_OK


def DllRegisterServer():
    import _winreg
    key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT, "Python.File\\shellex")
    subkey = _winreg.CreateKey(key, "DropHandler")
    subkey2 = _winreg.CreateKey(subkey, ShellDropHandler._name_)
    _winreg.SetValueEx(subkey2, None, 0, _winreg.REG_SZ, ShellDropHandler._reg_clsid_)
    print ShellDropHandler._reg_desc_, "registration complete."


def DllUnregisterServer():
    import _winreg
    try:
        key = _winreg.DeleteKey(_winreg.HKEY_CLASSES_ROOT,
                                "Python.File\\shellex\\DropHandler\\"+ ShellDropHandler._name_)
    except WindowsError, details:
        import errno
        if details.errno != errno.ENOENT:
            raise
    print ShellDropHandler._reg_desc_, "unregistration complete."


if __name__ == '__main__':
    import os
    import sys
    import win32com.shell.shell as shell
    ASADMIN = 'asadmin'
    # run this elevated
    if sys.argv[-1] != ASADMIN:
        script = os.path.abspath(sys.argv[0])
        params = ' '.join([script] + sys.argv[1:] + [ASADMIN])
        shell.ShellExecuteEx(lpVerb='runas', lpFile=sys.executable, lpParameters=params)
        sys.exit(0)
    from win32com.server import register
    register.UseCommandLine(ShellDropHandler,
                   finalize_register = DllRegisterServer,
                   finalize_unregister = DllUnregisterServer)

任何想法都感激!

0 个答案:

没有答案