javascriptwinapifirefox-addonwindows-xpjsctypes

Proper structure for TB_GETBUTTON? (WinXP) (also detect if process is 64bit or 32bit)


I'm using js-ctypes here to use winapi on winxp to get a button on the task bar at buton index 1. However this line here is crashing my code: var rez = SendMessage(hToolbar, 0x417 /** TB_GETBUTTON **/, 1, aButton.address());. How can I fix so it doesn't crash?

I'm following this tutorial here: http://w-shadow.com/blog/2006/10/01/manipulating-taskbar-buttons/

Here is copy paste code to scratchpad:

Components.utils.import("resource://gre/modules/ctypes.jsm");

var user32 = ctypes.open('user32.dll');
var kernel = ctypes.open("kernel32.dll");
var HMODULE = ctypes.uint32_t;
var HWND = ctypes.uint32_t;
var LPCTSTR = ctypes.jschar.ptr;
var LPCSTR = ctypes.char.ptr;
var LoadLibrary = kernel.declare("LoadLibraryW", ctypes.winapi_abi, HMODULE, LPCTSTR);
var GetProcAddress = kernel.declare("GetProcAddress", ctypes.winapi_abi, ctypes.void_t.ptr, HMODULE, LPCSTR);

var hUser = LoadLibrary("user32");

/* http://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx
*/
var funcPtr0 = GetProcAddress(hUser, "FindWindowExW");
var FindWindowExType = ctypes.FunctionType(ctypes.winapi_abi, ctypes.int32_t, [HWND, HWND, LPCTSTR, LPCTSTR]);
funcPtr0 = ctypes.cast(funcPtr0, FindWindowExType.ptr);
//funcPtr0(0, "Test1", "Test2", 0);

var funcPtr1 = GetProcAddress(hUser, "GetTaskmanWindow");
var GetTaskmanWindowType = ctypes.FunctionType(ctypes.winapi_abi, ctypes.int32_t, []);
funcPtr1 = ctypes.cast(funcPtr1, GetTaskmanWindowType.ptr);

var hHwnd = funcPtr1();
var hToolbar = funcPtr0(hHwnd, 0, 'ToolbarWindow32', null);
Services.wm.getMostRecentWindow(null).alert(hToolbar)

var struct_TBButton = ctypes.StructType('TBButton', [
    {'iBitmap': ctypes.int},
    {'idCommand': ctypes.int},
    {'fbState': ctypes.unsigned_char},
    {'fsStyle': ctypes.unsigned_char},
    {'bReserved': ctypes.unsigned_char},
    {'dwData': ctypes.unsigned_long},
    {'iString': ctypes.int}
]);


var SendMessage = user32.declare('SendMessageW', ctypes.winapi_abi, ctypes.uintptr_t,
    ctypes.int32_t,
    ctypes.unsigned_int,
    ctypes.int32_t,
    ctypes.voidptr_t
);

var Count = SendMessage(hToolbar, 0x418 /** TB_BUTTONCOUNT **/, 0, ctypes.voidptr_t(0));
Services.wm.getMostRecentWindow(null).alert(Count);

var aButton = new struct_TBButton();
var rez = SendMessage(hToolbar, 0x417 /** TB_GETBUTTON **/, 1, aButton.address());
Services.wm.getMostRecentWindow(null).alert(rez);

Solution

  • I don't have the time/motiviation to debug this myself, but there is an apparent bug that likely causes the crashes: Your struct_TBButton definition is wrong.

    {'bReserved': ctypes.unsigned_char},
    

    vs.

    #ifdef _WIN64
      BYTE      bReserved[6];
    #else 
    #if defined(_WIN32)
      BYTE      bReserved[2];
    #endif 
    #endif
    

    bReserved should be 2 byte (unsigned chars) in a 32-bit process and 6 in a 64 bit process. (This stuff is there in the first place so that the data members are properly pointer aligned).

    Also, your pointer types are wrong, which would have an effect in 64-bit processes.

    Putting it all together (avoiding ArrayType because I'm lazy):

    var struct_TBButton;
    if (ctypes.voidptr_t.size == 4 /* 32-bit */) {
      struct_TBButton = ctypes.StructType('TBButton', [
        {'iBitmap': ctypes.int},
        {'idCommand': ctypes.int},
        {'fbState': ctypes.unsigned_char},
        {'fsStyle': ctypes.unsigned_char},
        {'bReserved': ctypes.unsigned_char},
        {'bReserved2': ctypes.unsigned_char},
        {'dwData': ctypes.uintptr_t},
        {'iString': ctypes.intptr_t}
      ]);  
    }
    else if (ctypes.voidptr_t.size == 8 /* 64-bit */) {
      struct_TBButton = ctypes.StructType('TBButton', [
        {'iBitmap': ctypes.int},
        {'idCommand': ctypes.int},
        {'fbState': ctypes.unsigned_char},
        {'fsStyle': ctypes.unsigned_char},
        {'bReserved': ctypes.unsigned_char},
        {'bReserved2': ctypes.unsigned_char},
        {'bReserved3': ctypes.unsigned_char},
        {'bReserved4': ctypes.unsigned_char},
        {'bReserved5': ctypes.unsigned_char},
        {'bReserved6': ctypes.unsigned_char},
        {'dwData': ctypes.uintptr_t},
        {'iString': ctypes.intptr_t}
      ]);   
    }
    else {
      throw new Error("wut?!");
    }
    
    console.log(struct_TBButton.size);
    // 20 on 32-bit, 32 on 64-bit if I'm not mistaken
    

    PS: The same goes for the rest of your pointer types. https://stackoverflow.com/a/18040503/484441

    E.g. HWND WINAPI FindWindowEx() == void* WINAPI FindWindowEx(...) and not uint32_t WINAPI FindWindowEx(...)