diff options
| author | Glenn Smith <glenn@vector35.com> | 2022-09-26 23:12:20 -0400 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2022-09-29 21:02:20 -0400 |
| commit | 207925956bb8ca0174d40523fda70bfb5bc7bd38 (patch) | |
| tree | 4d5c8cba9ee2ad2b061f1e420c681a793ad397b8 | |
| parent | 5c8aa2ad6c2c03b37cacad4021f81310be12f375 (diff) | |
Interaction::RunProgressDialog
| -rw-r--r-- | binaryninjaapi.cpp | 9 | ||||
| -rw-r--r-- | binaryninjaapi.h | 12 | ||||
| -rw-r--r-- | binaryninjacore.h | 4 | ||||
| -rw-r--r-- | binaryview.cpp | 49 | ||||
| -rw-r--r-- | filemetadata.cpp | 61 | ||||
| -rw-r--r-- | interaction.cpp | 36 | ||||
| -rw-r--r-- | python/interaction.py | 43 | ||||
| -rw-r--r-- | python/plugin.py | 40 | ||||
| -rw-r--r-- | rust/src/interaction.rs | 49 |
9 files changed, 214 insertions, 89 deletions
diff --git a/binaryninjaapi.cpp b/binaryninjaapi.cpp index 610cb494..3c7f5e83 100644 --- a/binaryninjaapi.cpp +++ b/binaryninjaapi.cpp @@ -422,3 +422,12 @@ std::function<bool(size_t, size_t)> BinaryNinja::SplitProgress( return originalFn(subpartStarts[subpart] * steps + subpartProgress, steps); }; } + + +bool BinaryNinja::ProgressCallback(void* ctxt, size_t current, size_t total) +{ + ProgressContext* pctxt = reinterpret_cast<ProgressContext*>(ctxt); + if (!pctxt->callback) + return true; + return pctxt->callback(current, total); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 964e0636..bf00f6f2 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1063,6 +1063,17 @@ namespace BinaryNinja { */ bool OpenUrl(const std::string& url); + /*! Run a given task in a background thread, and show an updating progress bar which the user can cancel + + \param title Dialog title + \param canCancel 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 + */ + bool RunProgressDialog(const std::string& title, bool canCancel, std::function<void(std::function<bool(size_t, size_t)> progress)> task); + /*! Split a single progress function into equally sized subparts. This function takes the original progress function and returns a new function whose signature @@ -11286,6 +11297,7 @@ namespace BinaryNinja { virtual BNMessageBoxButtonResult ShowMessageBox(const std::string& title, const std::string& text, BNMessageBoxButtonSet buttons = OKButtonSet, BNMessageBoxIcon icon = InformationIcon) = 0; virtual bool OpenUrl(const std::string& url) = 0; + virtual bool RunProgressDialog(const std::string& title, bool canCancel, std::function<void(std::function<bool(size_t, size_t)> progress)> task) = 0; }; typedef BNPluginOrigin PluginOrigin; diff --git a/binaryninjacore.h b/binaryninjacore.h index fcd7deb4..f2211a45 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -2638,6 +2638,8 @@ extern "C" BNMessageBoxButtonResult (*showMessageBox)( void* ctxt, const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); bool (*openUrl)(void* ctxt, const char* url); + bool (*runProgressDialog)(void* ctxt, const char* title, bool canCancel, + void (*task)(void* taskCtxt, bool(*progress)(void* progressCtxt, size_t cur, size_t max), void* progressCtxt), void* taskCtxt); }; struct BNObjectDestructionCallbacks @@ -5870,6 +5872,8 @@ extern "C" BINARYNINJACOREAPI BNMessageBoxButtonResult BNShowMessageBox( const char* title, const char* text, BNMessageBoxButtonSet buttons, BNMessageBoxIcon icon); BINARYNINJACOREAPI bool BNOpenUrl(const char* url); + BINARYNINJACOREAPI bool BNRunProgressDialog(const char* title, bool canCancel, + void (*task)(void* taskCtxt, bool(*progress)(void* progressCtxt, size_t cur, size_t max), void* progressCtxt), void* taskCtxt); BINARYNINJACOREAPI BNReportCollection* BNCreateReportCollection(void); BINARYNINJACOREAPI BNReportCollection* BNNewReportCollectionReference(BNReportCollection* reports); diff --git a/binaryview.cpp b/binaryview.cpp index fa00b4e9..8c6080d0 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -3602,19 +3602,6 @@ bool BinaryView::FindNextConstant( } -struct FindProgressCallbackContext -{ - std::function<bool(size_t, size_t)> func; -}; - - -static bool FindProgressCallback(void* ctxt, size_t progress, size_t total) -{ - FindProgressCallbackContext* cb = (FindProgressCallbackContext*)ctxt; - return cb->func(progress, total); -} - - struct MatchCallbackContextForDataBuffer { std::function<bool(uint64_t, const DataBuffer&)> func; @@ -3665,10 +3652,10 @@ static bool MatchCallbackForConstant(void* ctxt, uint64_t addr, BNLinearDisassem bool BinaryView::FindNextData(uint64_t start, uint64_t end, const DataBuffer& data, uint64_t& addr, BNFindFlag flags, const std::function<bool(size_t current, size_t total)>& progress) { - FindProgressCallbackContext fp; - fp.func = progress; + ProgressContext fp; + fp.callback = progress; return BNFindNextDataWithProgress( - m_object, start, end, data.GetBufferObject(), &addr, flags, &fp, FindProgressCallback); + m_object, start, end, data.GetBufferObject(), &addr, flags, &fp, ProgressCallback); } @@ -3676,10 +3663,10 @@ bool BinaryView::FindNextText(uint64_t start, uint64_t end, const std::string& d Ref<DisassemblySettings> settings, BNFindFlag flags, BNFunctionGraphType graph, const std::function<bool(size_t current, size_t total)>& progress) { - FindProgressCallbackContext fp; - fp.func = progress; + ProgressContext fp; + fp.callback = progress; return BNFindNextTextWithProgress( - m_object, start, end, data.c_str(), &addr, settings->GetObject(), flags, graph, &fp, FindProgressCallback); + m_object, start, end, data.c_str(), &addr, settings->GetObject(), flags, graph, &fp, ProgressCallback); } @@ -3687,10 +3674,10 @@ bool BinaryView::FindNextConstant(uint64_t start, uint64_t end, uint64_t constan Ref<DisassemblySettings> settings, BNFunctionGraphType graph, const std::function<bool(size_t current, size_t total)>& progress) { - FindProgressCallbackContext fp; - fp.func = progress; + ProgressContext fp; + fp.callback = progress; return BNFindNextConstantWithProgress( - m_object, start, end, constant, &addr, settings->GetObject(), graph, &fp, FindProgressCallback); + m_object, start, end, constant, &addr, settings->GetObject(), graph, &fp, ProgressCallback); } @@ -3698,11 +3685,11 @@ bool BinaryView::FindAllData(uint64_t start, uint64_t end, const DataBuffer& dat const std::function<bool(size_t current, size_t total)>& progress, const std::function<bool(uint64_t addr, const DataBuffer& match)>& matchCallback) { - FindProgressCallbackContext fp; - fp.func = progress; + ProgressContext fp; + fp.callback = progress; MatchCallbackContextForDataBuffer mc; mc.func = matchCallback; - return BNFindAllDataWithProgress(m_object, start, end, data.GetBufferObject(), flags, &fp, FindProgressCallback, + return BNFindAllDataWithProgress(m_object, start, end, data.GetBufferObject(), flags, &fp, ProgressCallback, &mc, MatchCallbackForDataBuffer); } @@ -3712,12 +3699,12 @@ bool BinaryView::FindAllText(uint64_t start, uint64_t end, const std::string& da const std::function<bool(uint64_t addr, const std::string& match, const LinearDisassemblyLine& line)>& matchCallback) { - FindProgressCallbackContext fp; - fp.func = progress; + ProgressContext fp; + fp.callback = progress; MatchCallbackContextForText mc; mc.func = matchCallback; return BNFindAllTextWithProgress(m_object, start, end, data.c_str(), settings->GetObject(), flags, graph, &fp, - FindProgressCallback, &mc, MatchCallbackForText); + ProgressCallback, &mc, MatchCallbackForText); } @@ -3725,12 +3712,12 @@ bool BinaryView::FindAllConstant(uint64_t start, uint64_t end, uint64_t constant BNFunctionGraphType graph, const std::function<bool(size_t current, size_t total)>& progress, const std::function<bool(uint64_t addr, const LinearDisassemblyLine& line)>& matchCallback) { - FindProgressCallbackContext fp; - fp.func = progress; + ProgressContext fp; + fp.callback = progress; MatchCallbackContextForConstant mc; mc.func = matchCallback; return BNFindAllConstantWithProgress(m_object, start, end, constant, settings->GetObject(), graph, &fp, - FindProgressCallback, &mc, MatchCallbackForConstant); + ProgressCallback, &mc, MatchCallbackForConstant); } diff --git a/filemetadata.cpp b/filemetadata.cpp index 9b1dfee3..84c25e62 100644 --- a/filemetadata.cpp +++ b/filemetadata.cpp @@ -25,19 +25,6 @@ using namespace Json; using namespace std; -struct DatabaseProgressCallbackContext -{ - std::function<bool(size_t, size_t)> func; -}; - - -static bool DatabaseProgressCallback(void* ctxt, size_t progress, size_t total) -{ - DatabaseProgressCallbackContext* cb = (DatabaseProgressCallbackContext*)ctxt; - return cb->func(progress, total); -} - - char* NavigationHandler::GetCurrentViewCallback(void* ctxt) { NavigationHandler* handler = (NavigationHandler*)ctxt; @@ -172,10 +159,10 @@ bool FileMetadata::CreateDatabase(const string& name, BinaryView* data, Ref<Save bool FileMetadata::CreateDatabase(const string& name, BinaryView* data, const function<bool(size_t progress, size_t total)>& progressCallback, Ref<SaveSettings> settings) { - DatabaseProgressCallbackContext cb; - cb.func = progressCallback; + ProgressContext cb; + cb.callback = progressCallback; return BNCreateDatabaseWithProgress( - data->GetObject(), name.c_str(), &cb, DatabaseProgressCallback, settings ? settings->GetObject() : nullptr); + data->GetObject(), name.c_str(), &cb, ProgressCallback, settings ? settings->GetObject() : nullptr); } @@ -191,9 +178,9 @@ Ref<BinaryView> FileMetadata::OpenExistingDatabase(const string& path) Ref<BinaryView> FileMetadata::OpenExistingDatabase( const string& path, const function<bool(size_t progress, size_t total)>& progressCallback) { - DatabaseProgressCallbackContext cb; - cb.func = progressCallback; - BNBinaryView* data = BNOpenExistingDatabaseWithProgress(m_object, path.c_str(), &cb, DatabaseProgressCallback); + ProgressContext cb; + cb.callback = progressCallback; + BNBinaryView* data = BNOpenExistingDatabaseWithProgress(m_object, path.c_str(), &cb, ProgressCallback); if (!data) return nullptr; return new BinaryView(data); @@ -218,29 +205,29 @@ bool FileMetadata::SaveAutoSnapshot(BinaryView* data, Ref<SaveSettings> settings bool FileMetadata::SaveAutoSnapshot( BinaryView* data, const function<bool(size_t progress, size_t total)>& progressCallback, Ref<SaveSettings> settings) { - DatabaseProgressCallbackContext cb; - cb.func = progressCallback; + ProgressContext cb; + cb.callback = progressCallback; return BNSaveAutoSnapshotWithProgress( - data->GetObject(), &cb, DatabaseProgressCallback, settings ? settings->GetObject() : nullptr); + data->GetObject(), &cb, ProgressCallback, settings ? settings->GetObject() : nullptr); } void FileMetadata::GetSnapshotData( Ref<KeyValueStore> data, Ref<KeyValueStore> cache, const std::function<bool(size_t, size_t)>& progress) { - DatabaseProgressCallbackContext cb; - cb.func = progress; - BNGetSnapshotData(GetObject(), data->GetObject(), cache->GetObject(), &cb, DatabaseProgressCallback); + ProgressContext cb; + cb.callback = progress; + BNGetSnapshotData(GetObject(), data->GetObject(), cache->GetObject(), &cb, ProgressCallback); } void FileMetadata::ApplySnapshotData(BinaryView* file, Ref<KeyValueStore> data, Ref<KeyValueStore> cache, const std::function<bool(size_t, size_t)>& progress, bool openForConfiguration, bool restoreRawView) { - DatabaseProgressCallbackContext cb; - cb.func = progress; + ProgressContext cb; + cb.callback = progress; BNApplySnapshotData(GetObject(), file->GetObject(), data->GetObject(), cache->GetObject(), &cb, - DatabaseProgressCallback, openForConfiguration, restoreRawView); + ProgressCallback, openForConfiguration, restoreRawView); } @@ -262,9 +249,9 @@ bool FileMetadata::Rebase(BinaryView* data, uint64_t address) bool FileMetadata::Rebase( BinaryView* data, uint64_t address, const function<bool(size_t progress, size_t total)>& progressCallback) { - DatabaseProgressCallbackContext cb; - cb.func = progressCallback; - return BNRebaseWithProgress(data->GetObject(), address, &cb, DatabaseProgressCallback); + ProgressContext cb; + cb.callback = progressCallback; + return BNRebaseWithProgress(data->GetObject(), address, &cb, ProgressCallback); } @@ -277,9 +264,9 @@ bool FileMetadata::CreateSnapshotedView(BinaryView *data, const std::string &vie bool FileMetadata::CreateSnapshotedView(BinaryView* data, const std::string& viewName, const function<bool(size_t progress, size_t total)>& progressCallback) { - DatabaseProgressCallbackContext cb; - cb.func = progressCallback; - return BNCreateSnapshotedViewWithProgress(data->GetObject(), viewName.c_str(), &cb, DatabaseProgressCallback); + ProgressContext cb; + cb.callback = progressCallback; + return BNCreateSnapshotedViewWithProgress(data->GetObject(), viewName.c_str(), &cb, ProgressCallback); } @@ -291,11 +278,11 @@ MergeResult FileMetadata::MergeUserAnalysis( for (size_t i = 0; i < numHashes; i++) tempList[i] = BNAllocString(excludedHashes[i].c_str()); - DatabaseProgressCallbackContext cb; - cb.func = progress; + ProgressContext cb; + cb.callback = progress; BNMergeResult bnResult = - BNMergeUserAnalysis(m_object, name.c_str(), &cb, DatabaseProgressCallback, tempList, numHashes); + BNMergeUserAnalysis(m_object, name.c_str(), &cb, ProgressCallback, tempList, numHashes); MergeResult result(bnResult); for (size_t i = 0; i < numHashes; i++) diff --git a/interaction.cpp b/interaction.cpp index 580e2a39..8bfe4495 100644 --- a/interaction.cpp +++ b/interaction.cpp @@ -420,6 +420,18 @@ static bool OpenUrlCallback(void* ctxt, const char* url) } +static bool RunProgressDialogCallback(void* ctxt, const char* title, bool canCancel, + void (*task)(void*, bool (*)(void*, size_t, size_t), void*), void* taskCtxt) +{ + InteractionHandler* handler = (InteractionHandler*)ctxt; + return handler->RunProgressDialog(title, canCancel, [=](std::function<bool(size_t, size_t)> progress) { + ProgressContext context; + context.callback = progress; + task(taskCtxt, ProgressCallback, &context); + }); +} + + void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) { BNInteractionHandlerCallbacks cb; @@ -439,6 +451,7 @@ void BinaryNinja::RegisterInteractionHandler(InteractionHandler* handler) cb.getFormInput = GetFormInputCallback; cb.showMessageBox = ShowMessageBoxCallback; cb.openUrl = OpenUrlCallback; + cb.runProgressDialog = RunProgressDialogCallback; BNRegisterInteractionHandler(&cb); } @@ -671,6 +684,29 @@ bool BinaryNinja::OpenUrl(const std::string& url) } +struct TaskContext +{ + std::function<void(std::function<bool(size_t, size_t)> progress)> callback; +}; + + +static void TaskCallback(void* taskCtxt, bool (*progress)(void*, size_t, size_t), void* progressCtxt) +{ + TaskContext* context = (TaskContext*)taskCtxt; + context->callback([=](size_t cur, size_t max) { + return progress(progressCtxt, cur, max); + }); +} + + +bool BinaryNinja::RunProgressDialog(const std::string& title, bool canCancel, std::function<void(std::function<bool(size_t, size_t)> progress)> task) +{ + TaskContext context; + context.callback = task; + return BNRunProgressDialog(title.c_str(), canCancel, TaskCallback, &context); +} + + ReportCollection::ReportCollection() { m_object = BNCreateReportCollection(); 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 diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs index 96af3daa..41289a14 100644 --- a/rust/src/interaction.rs +++ b/rust/src/interaction.rs @@ -17,6 +17,7 @@ use binaryninjacore_sys::*; use std::ffi::CString; +use std::os::raw::c_void; use std::path::PathBuf; use crate::string::BnString; @@ -121,3 +122,51 @@ pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option<Path let string = unsafe { BnString::from_raw(value) }; Some(PathBuf::from(string.as_str())) } + +struct TaskContext<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>(F); + +pub fn run_progress_dialog<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>( + title: &str, + can_cancel: bool, + task: F, +) -> Result<(), ()> { + let title = CString::new(title).unwrap(); + + let mut ctxt = TaskContext::<F>(task); + + unsafe extern "C" fn cb_task<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>( + ctxt: *mut c_void, + progress: Option<unsafe extern "C" fn(*mut c_void, usize, usize) -> bool>, + progress_ctxt: *mut c_void, + ) { + ffi_wrap!("run_progress_dialog", unsafe { + let context = ctxt as *mut TaskContext<F>; + let progress_fn = Box::new(move |cur: usize, max: usize| -> Result<(), ()> { + match progress { + Some(func) => { + if (func)(progress_ctxt, cur, max) { + Ok(()) + } else { + Err(()) + } + } + None => Ok(()), + } + }); + ((*context).0)(progress_fn); + }) + } + + if unsafe { + BNRunProgressDialog( + title.as_ptr(), + can_cancel, + Some(cb_task::<F>), + &mut ctxt as *mut _ as *mut c_void, + ) + } { + Ok(()) + } else { + Err(()) + } +} |
