【问题标题】:Working asynchronously with jsctypes in restartless extension在无重启扩展中与 jsctypes 异步工作
【发布时间】:2014-05-05 05:13:59
【问题描述】:

我有一个小的引导扩展,它在startup() 加载一个 dll 文件并将它保存在一个全局变量中。我不知道如何正确使用它,也许你会纠正我,但我更想知道我从 dll 文件中使用的函数是否可以异步调用。

现在我正在做的是:

Components.utils.import("resource://gre/modules/ctypes.jsm");
log = function(str) { Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(str+'\n'); }

var lib;
var someFunc;

...

function startup(aData, aReason) {
   lib = ctypes.open(dllPath);
   if(!lib)
   {
      log("dll load error");
      lib = null;
      return;
   }
   else
   {
      var initDll = lib.declare("Init", ctypes.default_abi, ctypes.long);
      var status = initDll();
      log("Dll returned " + status);

      if(status == ctypes.long(0))
      {
         someFunc = lib.declare("SomeFunc", ctypes.default_abi, ctypes.long, ctypes.long);
      }
   }
}

一旦我有了someFunc,我就经常在代码中使用它,但调用需要很长时间。有没有办法异步调用它?或者以 Firefox 在调用期间不会冻结的方式调用它?

【问题讨论】:

    标签: javascript firefox firefox-addon firefox-addon-restartless


    【解决方案1】:

    如果外部(通过ctypes 绑定)API 本身不是异步的,根据定义,您将无法在 JavaScript 中异步调用它。

    最简单的解决方法是使用某种 WebWorker 在后台线程中调用 API。鉴于您需要做一些特权工作,ChromeWorker API 符合要求。

    它的机制是:

    1. 启动ChromeWorker(又名“工人”)
    2. 通过postMessage 向“工人”发送消息以启动“工作”
    3. 'worker' 中的消息事件处理程序应加载 ctypes 并对外部代码进行同步调用,然后...
    4. 让“工人”通过postMessage 向调用者(您的主代码)发送一条消息,说(实际上是“我完成了”)。

    如果外部 API 需要特定于调用的参数,您可以组织通过第一个 postMessage 发布这些参数。如果外部 API 返回任何重要信息,您可以通过第二个 postMessage 组织接收这些信息。

    所有这些看起来都有些繁琐,因此您需要将其打包成JavaScript code module;这将允许您将ctypes 内容与其余代码分开,并且您可以在调用线程(模块内部)中使用createEventdispatchEvent 使API 看起来是异步的,但隐藏'worker'部分。

    【讨论】:

    • 这正是我想要的。谢谢。
    【解决方案2】:

    这里展示了如何在 jsctypes 中使用不同的函数。它可能不是特定于您上面的内容,如果这对您没有帮助,请告诉我,我会看看您的具体情况。

    const {Cc, Ci, Cu} = require('chrome');
    Cu.import("resource://gre/modules/ctypes.jsm");
    
    /*start getcursorpos*/
    var lib = ctypes.open("user32.dll");
    
    /*foreground window stuff*/
    var FindWindowA = lib.declare('FindWindowA', ctypes.winapi_abi, ctypes.uint32_t, ctypes.jschar.ptr, ctypes.jschar.ptr)
    var GetForegroundWindow = lib.declare('GetForegroundWindow', ctypes.winapi_abi, ctypes.uint32_t)
    function doFindWindow() {
        var wm = Cc['@mozilla.org/appshell/window-mediator;1'].getService(Ci.nsIWindowMediator);
        var title = wm.getMostRecentWindow('navigator:browser').gBrowser.contentDocument.title;
        Cu.reportError('title=' + title)
        var ret = FindWindowA('', title + ' - Mozilla Firefox');
        //var ret = GetForegroundWindow();
    
        Cu.reportError(ret);
    }
    /*end foreground window stuff*/
    
    /* Declare the signature of the function we are going to call */
    const struct_lpPoint = new ctypes.StructType("lpPoint",
                            [ { "x": ctypes.int },
                              { "y": ctypes.int } ]);
    var GetCursorPos = lib.declare('GetCursorPos', ctypes.winapi_abi, ctypes.bool, struct_lpPoint.ptr);
    
    function doGetCursorPos() {
            var point = new struct_lpPoint;
            var ret = GetCursorPos(point.address());
            Cu.reportError(ret);
            Cu.reportError(point);
    }
    /*end getcursorpos*/
    
    
    
    
    /*start setcursorpos*/
    //var lib = ctypes.open("user32.dll"); //already called on line 4
    var SetCursorPos = lib.declare('SetCursorPos', ctypes.winapi_abi, ctypes.bool, ctypes.int, ctypes.int)
    
    function doSetCursorPos() {
        var ret = SetCursorPos(10, 10);
    }
    /*end setcursorpos*/
    
    /*start mouse_event*/
    //used to click
    //const DWORD = ctypes.uint32_t; //this just shows you that DWORD == ctypes.uint32_t
    var mouse_event = lib.declare('mouse_event', ctypes.winapi_abi, ctypes.void_t, ctypes.uint32_t, ctypes.uint32_t, ctypes.uint32_t, ctypes.uint32_t, ctypes.uintptr_t);
    const MOUSEEVENTF_LEFTDOWN = 2;
    const MOUSEEVENTF_LEFTUP = 4;
    
    function domouse_event() {
        var ret = mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
        var ret = mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    }
    /*end mouse_event*/
    
    
    /*start MessageBoxW*/
    //var lib = ctypes.open("user32.dll"); //already called on line 4
    var MessageBoxW = lib.declare('MessageBoxW', ctypes.winapi_abi, ctypes.int32_t, ctypes.int32_t, ctypes.jschar.ptr, ctypes.jschar.ptr, ctypes.int32_t);
    var MB_OK = 0;
    
    function doMessageBoxW() {
        var ret = MessageBoxW(0, "Hello world", "title", MB_OK);
    }
    
    /*end MessageBoxW*/
    
    exports.main = function (options, callbacks) {
    
    
    
    };
    
    
    exports.onUnload = function (reason) {
        lib.close();
    }
    
    var { Hotkey } = require("hotkeys");
    
    var showHotKey = Hotkey({
        combo: "alt-w",
        onPress: function() {
            /*setcursor stuff*/
            //doSetCursorPos();
            //domouse_event();
            /*setcursor stuff*/
    
            /*foreground stuff*/
            doFindWindow();
            /*foreground stuff*/
        }
    });
    

    我发现在 stackoverflow 上的其他 jsctype 主题很有用: * Javascript String to C++ char pointer -LPSTR buffer in JSCTypes * FF addon: How to declare C function fgets in javascript

    【讨论】:

    • 这是一个很好的例子,它帮助我更好地组织我的代码,但我的问题实际上是关于当函数没有立即返回时如何在不冻结 Firefox 的情况下调用这些函数。我需要一种方法来异步调用它们或从不同的上下文中调用它们,例如线程的工作方式。
    • 哦,这很有趣,我从来没有注意到冻结。你能测试一下我上面的函数,它们是否也会冻结浏览器?
    • 我已经对它们进行了测试,它们不会冻结浏览器,因为它们几乎立即返回。在我的 dll 文件中,我有一个函数必须处理图像以进行分析,每个图像最多需要 2 秒。在这 2 秒内,浏览器几乎被冻结。
    • 感谢那个测试人员,帮了很多忙,好的,我会开始考虑如何去异步。
    猜你喜欢
    • 2023-03-14
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多