[转]Mozilla JS-Ctypes 实例

Components.utils.import("resource://gre/modules/ctypes.jsm");
 
/* Change the dll path if your main windows directory is not on C:\WINDOWS! */
var lib = ctypes.open("C:\\WINDOWS\\system32\\user32.dll");
 
/* Declare the signature of FindWindows function */
var findWindowEx = lib.declare("FindWindowW",
                               ctypes.stdcall_abi,
                               ctypes.int32_t,
                               ctypes.ustring,
                               ctypes.int32_t);
 
/* Search for Foobar windows by it's id */
/* this ID is often changing of value at each release :/ */
var win = findWindowEx("{DA7CD0DE-1602-45e6-89A1-C2CA151E008E}/1", 0);
if (!win)
  win = findWindowEx("{DA7CD0DE-1602-45e6-89A1-C2CA151E008E}", 0);
if (!win)
  win = findWindowEx("{97E27FAA-C0B3-4b8e-A693-ED7881E99FC1}", 0);  
if (!win)
  win = findWindowEx("{E7076D1C-A7BF-4f39-B771-BCBE88F2A2A8}", 0);
 
/* Define another signature of windows API function */
var getWindowText = lib.declare("GetWindowTextW",
                               ctypes.stdcall_abi,
                               ctypes.int32_t,
                               ctypes.int32_t,
                               ctypes.ustring,
                               ctypes.int32_t);
 
/* Fill the string buffer we give to JSCtypes call */
var text="";
var max_len = 100;
for(var i=0; i < max_len; i++)
  text+=" ";
var text_len = getWindowText(win,text,100);
 
/* Extract song information from foobar window title */
var m = text.match(/(.*) - (?:\[([^#]+)([^\]]+)\] |)(.*) \[foobar2000.*\]/);
 
var musicinfo = {
  artist : m[1],
  album : m[2],
  trackNumber : m[3],
  track : m[4]
};
alert(musicinfo.toSource());
 
 
////////////////////////////////////////////////////
 
/* simply load "ctypes" object */
  Components.utils.import("resource://gre/modules/ctypes.jsm");
   
  /* Load libraries that we are going to use */
  var libuser32 = ctypes.open("user32.dll");
  var libshell32 = ctypes.open("shell32.dll");
 
  /* Here is the tedious work of declaring functions arguments types and struct attributes types */
  /* In fact it's quite easy, you just have to find which precise type are using your native functions/struct */
  /* but it may be hard to known, for example in windows API, which precise type is behing their "HANDLE" type ... */
  /* I recommend you to find and look at python ctype binding source code because they already had done this work */
     
  /*
  HANDLE WINAPI LoadImage(
    __in_opt  HINSTANCE hinst,
    __in      LPCTSTR lpszName,
    __in      UINT uType,
    __in      int cxDesired,
    __in      int cyDesired,
    __in      UINT fuLoad
  );
  */
  var loadimage = libuser32.declare("LoadImageA",
    ctypes.stdcall_abi,
    ctypes.int,
    ctypes.int,
    ctypes.char.ptr,
    ctypes.int,
    ctypes.int,
    ctypes.int,
    ctypes.int);
  const LR_LOADFROMFILE = 16;
  const IMAGE_ICON = 1;
   
  var notificationdata = ctypes.StructType("NOTIFICATIONDATA",
                                [{ cbSize  : ctypes.int          },
                                 { hWnd    : ctypes.int          },
                                 { uID     : ctypes.int          },
                                 { uFlags  : ctypes.int          },
                                 { uCallbackMessage : ctypes.int },
                                 { hIcon        : ctypes.int     },
                                 { szTip        : ctypes.char.array(64) },
                                 { dwState      : ctypes.int     },
                                 { dwStateMask  : ctypes.int     },
                                 { szInfo       : ctypes.char.array(256) },
                                 { uTimeoutOrVersion : ctypes.int },
                                 { szInfoTitle  : ctypes.char.array(64) },
                                 { dwInfoFlags  : ctypes.int },
                                 { guidItem     : ctypes.int },
                                 { hBalloonIcon : ctypes.int }
                                ]);
  const NIF_ICON = 0x00000002;
   
  /*
  BOOL Shell_NotifyIcon(
    __in  DWORD dwMessage,
    __in  PNOTIFYICONDATA lpdata
  );
  */
  var notifyicon = libshell32.declare("Shell_NotifyIcon",
                                    ctypes.stdcall_abi,
                                    ctypes.bool,
                                    ctypes.int,
                                    notificationdata.ptr);
  const NIM_ADD = 0x00000000;
   
 
  /* And now, the "real" code that is calling C functions */
 
  /* load our ico file */
  var hIcon = loadimage(0, "c:\\default.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
   
  /* create a C struct that is defining a notification in tray */
  var icon = notificationdata();
  icon.cbSize = notificationdata.size;
  icon.uFlags = NIF_ICON;
  icon.szTip = "My Tray Icon";
  icon.hIcon = hIcon;
   

  /* Display this notification! */

  notifyicon(NIM_ADD, icon.address());



////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////

jsctypes + win32api + jetpack = jetintray

Par Alexandre Poirot le jeudi 26 août 2010, 23:36 - mozilla

    jsctypes
    winapi
    wndproc

JSCtypes! What a powerfull tool, that allows to call native libraries with our simple Javascript.
Jetpack! What a powerfull tool, that allows to build reliably javascript applications, with unittests, memory profiling, web IDE, ...
And WinAPI ... a giant C library still in production in 2010 that allows to do very various things on Windows platform.

Mix all that and you get:

JetInTray
A jetpack API for adding Tray icons on windows via jsctypes and on linux with a binary xpcom component (I didn't had time to work on a jsctypes version).
You may checkout this jetpack package directly from github.
Or if you want to learn jsctypes I suggest you to look at files in lib directory and to read my two previous posts on jsctypes.

    I explained on the first one how to start playing with jsctypes, how to create C-structures and call functions.
    Then I showed in the second post, how to create a JS callback passed to the native library as a function pointer.



That said, I wanted to highlight some underground hacks around win32api! In WinAPI, there is no addEventListener/setEventCallback/addActionListener/... In fact, there is the well known WndProc messages function, that receives absolutely all event of the application!! (Yes for real!) We define this function as a static function named WndProc. But in Jsctypes case, that's impossible to define a static function, we can only create function pointers. That's where comes the not so known hack which allow to register dynamically such event listener.

    First we have to define our listener function following the WinAPI datatypes

    Components.utils.import("resource://gre/modules/ctypes.jsm");
    var libs = {};
    libs.user32 = ctypes.open("user32.dll");

    // Define the function pointer type
    var WindowProcType =
      ctypes.FunctionType(ctypes.stdcall_abi, ctypes.int,
        [ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t]).ptr;

    // Bind a usefull API function
    var DefWindowProc = libs.user32.declare("DefWindowProcA", ctypes.winapi_abi, ctypes.int,
        ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t);

    // Set our javascript callback
    function windowProcJSCallback(hWnd, uMsg, wParam, lParam) {
      
      // ... do something smart with this event!
      
      // You HAVE TO call this api function when you don't known how to handle an event
      // or your apply is going to crash or do nothing
      return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }

    // Retrieve a C function pointer for our Javascript callback
    var WindowProcPointer = WindowProcType(windowProcJSCallback);

    Then we may fill a WNDCLASS structure with our fresh function pointer. This structure is used to create a new window class that use it own WndProc (not the default static function). See msdn doc for more information.

    var WNDCLASS =
      ctypes.StructType("WNDCLASS",
        [
          { style  : ctypes.uint32_t },
          { lpfnWndProc  : WindowProcType }, // here is our function pointer!
          { cbClsExtra  : ctypes.int32_t },
          { cbWndExtra  : ctypes.int32_t },
          { hInstance  : ctypes.voidptr_t },
          { hIcon  : ctypes.voidptr_t },
          { hCursor  : ctypes.voidptr_t },
          { hbrBackground  : ctypes.voidptr_t },
          { lpszMenuName  : ctypes.char.ptr },
          { lpszClassName  : ctypes.char.ptr }
        ]);
    var wndclass = WNDCLASS();
    wndclass.lpszClassName = ctypes.char.array()("class-custom-wndproc");
    wndclass.lpfnWndProc = WindowProcType(windowProcCallback);   // <---- here it is!
    RegisterClass(wndclass.address());

    After that we may create a hidden window that is created only to catch events.

    var CreateWindowEx =
      libs.user32.declare( "CreateWindowExA", ctypes.winapi_abi, ctypes.voidptr_t,
          ctypes.long,
          ctypes.char.ptr,
          ctypes.char.ptr,
          ctypes.int,
          ctypes.int,
          ctypes.int,
          ctypes.int,
          ctypes.int,
          ctypes.voidptr_t,
          ctypes.voidptr_t,
          ctypes.voidptr_t,
          ctypes.voidptr_t
        );
    var HWND_MESSAGE = -3; // This is the code for message-only window
                          // http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
    var win = CreateWindowEx(
        0, wndclass.lpszClassName,
        ctypes.char.array()("messages-only-window"),
        0, 0, 0, 0, 0,
        ctypes.voidptr_t(HWND_MESSAGE), null, null, null);

    Finally, we only have to bind this window to any component which dispatch messages/events in order to receive them in our windowProcJSCallback callback. That's it!

4 commentaires aucun rétrolien

mardi 24 août 2010
jsctypes unleashed

Par Alexandre Poirot le mardi 24 août 2010, 23:24 - mozilla

    jsctypes
    win32api

As bugs 573066 and 585175 are fixed and available in last Firefox nightlies, we can now use JSCtypes at full power!

Thanks to dwitte for quick fixes!
That means :

    Complex C-struct usage,
    The possibility to define a JS callback seen by C library as a function pointer, and,
    Full Win32 API (also called MFC) supports!

Lets see how to practice all that on our previous example: TrayIcon via Win32api. We were able to just display an icon in the previous blogpost. Now we are able to intercept events from win32api thanks to ctypes.FunctionType. First we define a plain old javascript function like this one:

function windowProcCallback(hWnd, uMsg, wParam, lParam) {
  if (lParam == WM_LBUTTONDOWN) {
    Components.utils.reportError("Left click!");
    /* 0 means that we handle this event */
    return 0;
  }
  else if (lParam == WM_RBUTTONDOWN) {
    Components.utils.reportError("Right click!");
    return 0;
  }
  /* Mandatory use default win32 procedure! */
  return DefWindowProc(hWnd, uMsg, wParam, lParam);
};

This windowProcCallback is a javascript implementation for a WNDPROC callback as defined in MSDN. WNDPROC is a key part of Win32Api. These functions receive all kind of events. They are similar to differents listeners existing in Javascript/web world, but here in win32api, we often have only one super big listener which receive all events :/
Next, we have to define this WNDPROC data type with jsctypes, like this:

var WindowProcType =
  ctypes.FunctionType(ctypes.stdcall_abi, ctypes.int,
    [ctypes.voidptr_t, ctypes.int32_t, ctypes.int32_t, ctypes.int32_t]).ptr;

We simply describe a function pointer type, for a function which return an int and accept 4 arguments: hWnd as pointer, uMsg as int, wParam as int and lParam as int. Then, in our case, we give this function pointer via a structure. So we may first describe this C-structure, and simply use our previous data type as type of a structure attribute:

var WNDCLASS =
  ctypes.StructType("WNDCLASS",
    [
      { style : ctypes.uint32_t },
      { lpfnWndProc : WindowProcType}, // <-- Here is the function pointer attribute
      { cbClsExtra : ctypes.int32_t },
      { cbWndExtra : ctypes.int32_t },
      { hInstance : ctypes.voidptr_t },
      { hIcon : ctypes.voidptr_t },
      { hCursor : ctypes.voidptr_t },
      { hbrBackground : ctypes.voidptr_t },
      { lpszMenuName : ctypes.char.ptr },
      { lpszClassName : ctypes.char.ptr }
    ]);

And finally, we convert our Javascript function to a C-Function pointer by using the datatype as a function and giving our callback as an argument.

var wndclass = WNDCLASS();
wndclass.lpszClassName = ctypes.char.array()("class-trayicon");
wndclass.lpfnWndProc = WindowProcType(windowProcCallback);   // <---- here it is!
RegisterClass(wndclass.address());

All this hard work to be able to detect clicks on our tray icon! I've built a full example file right here (with a lot of comments). And here is one hack that allow you to test it remotly in your Javascript Console. You just have to copy an icon in c:\default.ico. Here is a sample ico file.

  var x=new XMLHttpRequest(); x.open("GET","http://blog.techno-barje.fr/public/demo/jsctypes/example-jsctypes-full-power.txt",false); x.send(null); window.parent.eval(x.responseText);

Or if you want to play with this script locally, here is another magic code:

  var x=new XMLHttpRequest(); x.open("GET","file://C:/Users/YourUsername/Downloads/example-jsctypes-full-power.txt",false); x.send(null); window.parent.eval(x.responseText);

5 commentaires aucun rétrolien

vendredi 6 août 2010
JSctypes round two

Par Alexandre Poirot le vendredi 6 août 2010, 01:39 - mozilla

Jsctypes has been introduced in Firefox 3.6 with simple C function call and only simple types: int, char, string, ... But the next iteration of jsctypes that is coming in Firefox 4 is going to allow full C binding, with support of C structures and the ability to define a javascript function and give it to C library as a function pointer.

No more compilation, no more mozilla sdk download, nor XPCOM stuff, just plain javascript and only a tiny part of function and datatype declaration before doing a native binding!

But let the code talk! Here is an example that display a tray icon on windows. You can copy and paste this code in your Javascript Console in Firefox 4 beta, just do not forget to change the icon path defined in the loadimage function call.

  /* simply load "ctypes" object */
  Components.utils.import("resource://gre/modules/ctypes.jsm");
 
  /* Load libraries that we are going to use */
  var libuser32 = ctypes.open("user32.dll");
  var libshell32 = ctypes.open("shell32.dll");

  /* Here is the tedious work of declaring functions arguments types and struct attributes types */
  /* In fact it's quite easy, you just have to find which precise type are using your native functions/struct */
  /* but it may be hard to known, for example in windows API, which precise type is behing their "HANDLE" type ... */
  /* I recommend you to find and look at python ctype binding source code because they already had done this work */
    
  /*
  HANDLE WINAPI LoadImage(
    __in_opt  HINSTANCE hinst,
    __in      LPCTSTR lpszName,
    __in      UINT uType,
    __in      int cxDesired,
    __in      int cyDesired,
    __in      UINT fuLoad
  );
  */
  var loadimage = libuser32.declare("LoadImageA",
    ctypes.stdcall_abi,
    ctypes.int,
    ctypes.int,
    ctypes.char.ptr,
    ctypes.int,
    ctypes.int,
    ctypes.int,
    ctypes.int);
  const LR_LOADFROMFILE = 16;
  const IMAGE_ICON = 1;
 
  var notificationdata = ctypes.StructType("NOTIFICATIONDATA",
                                [{ cbSize  : ctypes.int          },
                                 { hWnd    : ctypes.int          },
                                 { uID     : ctypes.int          },
                                 { uFlags  : ctypes.int          },
                                 { uCallbackMessage : ctypes.int },
                                 { hIcon        : ctypes.int     },
                                 { szTip        : ctypes.char.array(64) },
                                 { dwState      : ctypes.int     },
                                 { dwStateMask  : ctypes.int     },
                                 { szInfo       : ctypes.char.array(256) },
                                 { uTimeoutOrVersion : ctypes.int },
                                 { szInfoTitle  : ctypes.char.array(64) },
                                 { dwInfoFlags  : ctypes.int },
                                 { guidItem     : ctypes.int },
                                 { hBalloonIcon : ctypes.int }
                                ]);
  const NIF_ICON = 0x00000002;
 
  /*
  BOOL Shell_NotifyIcon(
    __in  DWORD dwMessage,
    __in  PNOTIFYICONDATA lpdata
  );
  */
  var notifyicon = libshell32.declare("Shell_NotifyIcon",
                                    ctypes.stdcall_abi,
                                    ctypes.bool,
                                    ctypes.int,
                                    notificationdata.ptr);
  const NIM_ADD = 0x00000000;
 

  /* And now, the "real" code that is calling C functions */

  /* load our ico file */
  var hIcon = loadimage(0, "c:\\default.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
 
  /* create a C struct that is defining a notification in tray */
  var icon = notificationdata();
  icon.cbSize = notificationdata.size;
  icon.uFlags = NIF_ICON;
  icon.szTip = "My Tray Icon";
  icon.hIcon = hIcon;
 
  /* Display this notification! */
  notifyicon(NIM_ADD, icon.address());


We will be able to go futher and define a function callback to handle click events on the trayicon, but there is currently a bug which cause some crashes when using ctypes.FunctionType on windows. (ctypes.FunctionType allow to transform a custom Javascript function to a C function pointer)
Here is related bugs, which are still in process:

    Bug 573066 - Fix ctypes stdcall closure tests
    Bug 585175 - Don't automangle ctypes stdcall symbols for WINAPI

The first leads to crashes with FunctionType, and the second may lead to lib.declare with unfindable symbols errors when using ctypes.stdcall_abi.

3 commentaires aucun rétrolien



你可能感兴趣的:(JavaScript,function,XMLhttpREquest,callback,mozilla,winapi)