Techno Barje

Jsctypes + Win32api + Jetpack = Jetintray

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:


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
    var libs = {};
    libs.user32 ="user32.dll");
    // Define the function pointer type
    var WindowProcType = 
        [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.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 = 
          { 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!
  • 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,
    var HWND_MESSAGE = -3; // This is the code for message-only window
    var win = CreateWindowEx(
        0, wndclass.lpszClassName,
        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!