jsctypes unleashed

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 : 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);

Comments

You can use your Fediverse (i.e. Mastodon, among many others) account to reply to this post
(Note that comments from locked accounts won't be visible on the blog, but only to me)