summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorGlenn Smith <glenn@vector35.com>2022-09-26 23:12:20 -0400
committerGlenn Smith <glenn@vector35.com>2022-09-29 21:02:20 -0400
commit207925956bb8ca0174d40523fda70bfb5bc7bd38 (patch)
tree4d5c8cba9ee2ad2b061f1e420c681a793ad397b8 /python
parent5c8aa2ad6c2c03b37cacad4021f81310be12f375 (diff)
Interaction::RunProgressDialog
Diffstat (limited to 'python')
-rw-r--r--python/interaction.py43
-rw-r--r--python/plugin.py40
2 files changed, 62 insertions, 21 deletions
diff --git a/python/interaction.py b/python/interaction.py
index 2331b586..9fb5d9c7 100644
--- a/python/interaction.py
+++ b/python/interaction.py
@@ -21,7 +21,7 @@
import ctypes
import traceback
import webbrowser
-from typing import Optional
+from typing import Optional, Callable
# Binary Ninja components
from . import _binaryninjacore as core
@@ -29,6 +29,7 @@ from .enums import FormInputFieldType, MessageBoxIcon, MessageBoxButtonSet, Mess
from . import binaryview
from .log import log_error
from . import flowgraph
+from . import mainthread
class LabelField:
@@ -493,6 +494,7 @@ class InteractionHandler:
self._cb.getFormInput = self._cb.getFormInput.__class__(self._get_form_input)
self._cb.showMessageBox = self._cb.showMessageBox.__class__(self._show_message_box)
self._cb.openUrl = self._cb.openUrl.__class__(self._open_url)
+ self._cb.runProgressDialog = self._cb.runProgressDialog.__class__(self._run_progress_dialog)
def register(self):
self.__class__._interaction_handler = self
@@ -708,6 +710,17 @@ class InteractionHandler:
log_error(traceback.format_exc())
return False
+ def _run_progress_dialog(self, title, can_cancel, task, task_ctxt):
+ try:
+ def py_task(progress: Callable[[int, int], bool]):
+ progress_c = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_size_t, lambda ctxt, cur, max: progress(cur, max))
+ task(task_ctxt, progress_c, None)
+
+ return self.run_progress_dialog(title, can_cancel, py_task)
+ except:
+ log_error(traceback.format_exc())
+ return False
+
def show_plain_text_report(self, view, title, contents):
pass
@@ -762,6 +775,10 @@ class InteractionHandler:
webbrowser.open(url)
return True
+ def run_progress_dialog(self, task: Callable[[Callable[[int, int], bool]], None]) -> bool:
+ mainthread.execute_on_main_thread_and_wait(lambda: task(lambda cur, max: True))
+ return True
+
class PlainTextReport:
def __init__(self, title, contents, view=None):
@@ -1359,3 +1376,27 @@ def open_url(url):
:rtype: bool
"""
return core.BNOpenUrl(url)
+
+
+def run_progress_dialog(title: str, can_cancel: bool, task: Callable[[Callable[[int, int], bool]], None]) -> bool:
+ """
+ ``run_progress_dialog`` runs a given task in a background thread, showing an updating
+ progress bar which the user can cancel.
+
+ :param title: Dialog title
+ :param can_cancel: If the task can be cancelled
+ :param task: Function to perform the task, taking as a parameter a function which should
+ be called to report progress updates and check for cancellation. If the progress function
+ returns false, the user has requested to cancel, and the task should handle this appropriately.
+ :return: True if not cancelled
+ """
+
+ progress_type = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_size_t)
+ task_type = ctypes.CFUNCTYPE(None, ctypes.c_void_p, progress_type, ctypes.c_void_p)
+
+ def do_task(ctxt: ctypes.c_void_p, progress: progress_type, progress_ctxt: ctypes.c_void_p):
+ def py_progress(cur: int, max: int) -> bool:
+ return progress(progress_ctxt, cur, max)
+ task(py_progress)
+
+ return core.BNRunProgressDialog(title, can_cancel, task_type(do_task), None)
diff --git a/python/plugin.py b/python/plugin.py
index f1720ccd..eec25683 100644
--- a/python/plugin.py
+++ b/python/plugin.py
@@ -358,8 +358,8 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView], None],
- is_valid: Optional[Callable[[binaryview.BinaryView], bool]] = None
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView'], None],
+ is_valid: Optional[Callable[['binaryview.BinaryView'], bool]] = None
):
r"""
``register`` Register a plugin
@@ -384,8 +384,8 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_address(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, int], None],
- is_valid: Optional[Callable[[binaryview.BinaryView, int], bool]] = None
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', int], None],
+ is_valid: Optional[Callable[['binaryview.BinaryView', int], bool]] = None
):
r"""
``register_for_address`` Register a plugin to be called with an address argument
@@ -410,8 +410,8 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_range(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, int, int], None],
- is_valid: Optional[Callable[[binaryview.BinaryView, int, int], bool]] = None
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', int, int], None],
+ is_valid: Optional[Callable[['binaryview.BinaryView', int, int], bool]] = None
):
r"""
``register_for_range`` Register a plugin to be called with a range argument
@@ -436,8 +436,8 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_function(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, function.Function], None],
- is_valid: Optional[Callable[[binaryview.BinaryView, function.Function], bool]] = None
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', 'function.Function'], None],
+ is_valid: Optional[Callable[['binaryview.BinaryView', 'function.Function'], bool]] = None
):
r"""
``register_for_function`` Register a plugin to be called with a function argument
@@ -462,9 +462,9 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_low_level_il_function(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, lowlevelil.LowLevelILFunction],
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', 'lowlevelil.LowLevelILFunction'],
None],
- is_valid: Optional[Callable[[binaryview.BinaryView, lowlevelil.LowLevelILFunction], bool]] = None
+ is_valid: Optional[Callable[['binaryview.BinaryView', 'lowlevelil.LowLevelILFunction'], bool]] = None
):
r"""
``register_for_low_level_il_function`` Register a plugin to be called with a low level IL function argument
@@ -490,9 +490,9 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_low_level_il_instruction(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, lowlevelil.LowLevelILInstruction],
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', 'lowlevelil.LowLevelILInstruction'],
None],
- is_valid: Optional[Callable[[binaryview.BinaryView, lowlevelil.LowLevelILInstruction], bool]] = None
+ is_valid: Optional[Callable[['binaryview.BinaryView', 'lowlevelil.LowLevelILInstruction'], bool]] = None
):
r"""
``register_for_low_level_il_instruction`` Register a plugin to be called with a low level IL instruction argument
@@ -519,9 +519,9 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_medium_level_il_function(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, mediumlevelil.MediumLevelILFunction],
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', 'mediumlevelil.MediumLevelILFunction'],
None],
- is_valid: Optional[Callable[[binaryview.BinaryView, mediumlevelil.MediumLevelILFunction], bool]] = None
+ is_valid: Optional[Callable[['binaryview.BinaryView', 'mediumlevelil.MediumLevelILFunction'], bool]] = None
):
r"""
``register_for_medium_level_il_function`` Register a plugin to be called with a medium level IL function argument
@@ -548,8 +548,8 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_medium_level_il_instruction(
cls, name: str, description: str,
- action: Callable[[binaryview.BinaryView, mediumlevelil.MediumLevelILInstruction], None],
- is_valid: Optional[Callable[[binaryview.BinaryView, mediumlevelil.MediumLevelILInstruction], bool]] = None
+ action: Callable[['binaryview.BinaryView', 'mediumlevelil.MediumLevelILInstruction'], None],
+ is_valid: Optional[Callable[['binaryview.BinaryView', 'mediumlevelil.MediumLevelILInstruction'], bool]] = None
):
r"""
``register_for_medium_level_il_instruction`` Register a plugin to be called with a medium level IL instruction argument
@@ -576,9 +576,9 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_high_level_il_function(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, highlevelil.HighLevelILFunction],
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', 'highlevelil.HighLevelILFunction'],
None],
- is_valid: Optional[Callable[[binaryview.BinaryView, highlevelil.HighLevelILFunction], bool]] = None
+ is_valid: Optional[Callable[['binaryview.BinaryView', 'highlevelil.HighLevelILFunction'], bool]] = None
):
r"""
``register_for_high_level_il_function`` Register a plugin to be called with a high level IL function argument
@@ -604,9 +604,9 @@ class PluginCommand(metaclass=_PluginCommandMetaClass):
@classmethod
def register_for_high_level_il_instruction(
- cls, name: str, description: str, action: Callable[[binaryview.BinaryView, highlevelil.HighLevelILInstruction],
+ cls, name: str, description: str, action: Callable[['binaryview.BinaryView', 'highlevelil.HighLevelILInstruction'],
None],
- is_valid: Optional[Callable[[binaryview.BinaryView, highlevelil.HighLevelILInstruction], bool]] = None
+ is_valid: Optional[Callable[['binaryview.BinaryView', 'highlevelil.HighLevelILInstruction'], bool]] = None
):
r"""
``register_for_high_level_il_instruction`` Register a plugin to be called with a high level IL instruction argument