From a324923ffabdf63fbb3d6fedc1e4720c4230ab61 Mon Sep 17 00:00:00 2001 From: Andrew Senetar Date: Tue, 2 Mar 2021 19:23:43 -0600 Subject: [PATCH] Add IFileOperationProgressSink - Add sink to allow detection of times when the file would be deleted - Currently can detect, but not stop operations, more work needed --- send2trash/IFileOperationProgressSink.py | 105 +++++++++++++++++++++++ send2trash/plat_win_modern.py | 4 +- 2 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 send2trash/IFileOperationProgressSink.py diff --git a/send2trash/IFileOperationProgressSink.py b/send2trash/IFileOperationProgressSink.py new file mode 100644 index 0000000..24359ea --- /dev/null +++ b/send2trash/IFileOperationProgressSink.py @@ -0,0 +1,105 @@ +# Sample implementation of IFileOperationProgressSink that just prints +# some basic info + +import pythoncom +from win32com.shell import shell, shellcon +from win32com.server.policy import DesignatedWrapPolicy + + +class FileOperationProgressSink(DesignatedWrapPolicy): + _com_interfaces_ = [shell.IID_IFileOperationProgressSink] + _public_methods_ = [ + "StartOperations", + "FinishOperations", + "PreRenameItem", + "PostRenameItem", + "PreMoveItem", + "PostMoveItem", + "PreCopyItem", + "PostCopyItem", + "PreDeleteItem", + "PostDeleteItem", + "PreNewItem", + "PostNewItem", + "UpdateProgress", + "ResetTimer", + "PauseTimer", + "ResumeTimer", + ] + + def __init__(self): + self._wrap_(self) + self.newItem = None + + def PreDeleteItem(self, flags, item): + # Can detect cases where to stop via flags and condition below, however the operation + # does not actual stop, we can resort to raising an exception as that does stop things + # but that may need some additional considerations before implementing. + return ( + 0 if flags & shellcon.TSF_DELETE_RECYCLE_IF_POSSIBLE else 0x80004005 + ) # S_OK, or E_FAIL + + def PostDeleteItem(self, flags, item, hrDelete, newlyCreated): + if newlyCreated: + self.newItem = newlyCreated.GetDisplayName(shellcon.SHGDN_FORPARSING) + + def StartOperations(self): + pass + + def FinishOperations(self, Result): + pass + + def PreRenameItem(self, Flags, Item, NewName): + pass + + def PostRenameItem(self, Flags, Item, NewName, hrRename, NewlyCreated): + pass + + def PreMoveItem(self, Flags, Item, DestinationFolder, NewName): + pass + + def PostMoveItem( + self, Flags, Item, DestinationFolder, NewName, hrMove, NewlyCreated + ): + pass + + def PreCopyItem(self, Flags, Item, DestinationFolder, NewName): + pass + + def PostCopyItem( + self, Flags, Item, DestinationFolder, NewName, hrCopy, NewlyCreated + ): + pass + + def PreNewItem(self, Flags, DestinationFolder, NewName): + pass + + def PostNewItem( + self, + Flags, + DestinationFolder, + NewName, + TemplateName, + FileAttributes, + hrNew, + NewItem, + ): + pass + + def UpdateProgress(self, WorkTotal, WorkSoFar): + pass + + def ResetTimer(self): + pass + + def PauseTimer(self): + pass + + def ResumeTimer(self): + pass + + +def CreateSink(): + return pythoncom.WrapObject( + FileOperationProgressSink(), shell.IID_IFileOperationProgressSink + ) diff --git a/send2trash/plat_win_modern.py b/send2trash/plat_win_modern.py index 54914f8..1bcf039 100644 --- a/send2trash/plat_win_modern.py +++ b/send2trash/plat_win_modern.py @@ -11,6 +11,7 @@ from platform import version import pythoncom import pywintypes from win32com.shell import shell, shellcon +from .IFileOperationProgressSink import CreateSink def send2trash(paths): @@ -50,10 +51,11 @@ def send2trash(paths): # actually try to perform the operation, this section may throw a # pywintypes.com_error which does not seem to create as nice of an # error as OSError so wrapping with try to convert + sink = CreateSink() try: for path in paths: item = shell.SHCreateItemFromParsingName(path, None, shell.IID_IShellItem) - fileop.DeleteItem(item) + fileop.DeleteItem(item, sink) result = fileop.PerformOperations() aborted = fileop.GetAnyOperationsAborted() # if non-zero result or aborted throw an exception