Правильная структура для TB_GETBUTTON? (WinXP) (также определить, является ли процесс 64-битным или 32-битным)

Я использую js-ctypes здесь, чтобы использовать winapi на winxp, чтобы получить кнопку на панели задач с индексом кнопки 1. Однако эта строка здесь приводит к сбою моего кода: var rez = SendMessage(hToolbar, 0x417 /** TB_GETBUTTON **/, 1, aButton.address());. Как исправить, чтобы не вылетало?

Я следую этому руководству здесь: http://w-shadow.com/blog/2006/10/01/manipulating-taskbar-buttons/

Вот скопируйте и вставьте код в блокнот:

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

person Noitidart    schedule 09.06.2014    source источник


Ответы (1)


У меня нет времени/мотивации для самостоятельной отладки, но есть очевидная ошибка, которая, вероятно, вызывает сбои: ваше определение struct_TBButton неверно.

{'bReserved': ctypes.unsigned_char},

vs.

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

bReserved должно быть 2 байта (символы без знака) в 32-битном процессе и 6 в 64-битном процессе. (Этот материал существует в первую очередь, чтобы элементы данных были правильно выровнены по указателю).

Кроме того, ваши типы указателей неверны, что может повлиять на 64-битные процессы.

Собираем все вместе (избегая ArrayType, потому что я ленивый):

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: То же самое касается остальных типов указателей. https://stackoverflow.com/a/18040503/484441

Например. HWND WINAPI FindWindowEx() == void* WINAPI FindWindowEx(...), а не uint32_t WINAPI FindWindowEx(...)

person nmaier    schedule 09.06.2014
comment
Это так круто! Я не знал, как можно определить, является ли это 64-битным для 32-битного!! Спасибо чувак! - person Noitidart; 09.06.2014
comment
Создание структур настолько сложно для меня, что я не понимаю, как правильно перейти от типа C++ к типу js, я просто подключаю и пыхчу, пока он не заработает, большое спасибо за это исправление! И расширение на HWND == void* - person Noitidart; 09.06.2014
comment
Кстати, я только что проверил вашу часть, и вы правы, я получил 20, я 32bit. PS: мне это нравится throw хахахах :P PS PS: он все еще падает даже с исправлением структуры :( Я буду продолжать изучать это - person Noitidart; 10.06.2014
comment
У меня не падает, но и не работает... В любом случае, похоже, это не имеет значения, потому что этот хак с использованием недокументированных деталей поведения/реализации перестал работать в Windows 7 (в TaskmanWindow больше нет ToolbarWindow32). - person nmaier; 10.06.2014
comment
Ах да, в Win7 не вылетает, но у меня тоже не работает. Это только WinXP :( - person Noitidart; 10.06.2014
comment
Spy++ говорит мне, что теперь есть MSTaskListWClass окно, где ToolbarWindow32 использовалось быть. Но он не реагирует на сообщения TB_ и, кажется, не генерирует какие-либо другие полезные сообщения, которые можно было бы присвоить (опять же Spy++), так что никаких игральных костей. - person nmaier; 10.06.2014
comment
О, это не проблема. У меня есть отдельное решение для Win7, но это мое решение для WinXP. Я должен сделать это отдельно. Я значительно упростил суть в самом нижнем комментарии, я избавился от кастинга и типа функции: addon-snippet-GetTaskmanWindowCTypes.js (по-прежнему не работает :( ) - person Noitidart; 10.06.2014