* a step forward: actually create the icon (Shell_NotifyIcon)

* cleaning

The icon gets created but GetLastError always returns
ERROR_INVALID_WINDOW_HANDLE, at least under win7.

We should be fine with callbacks' ABI as they are defined outside ctypes-utils.
This commit is contained in:
foudfou 2013-11-17 23:11:17 +01:00
parent bcb7764b8f
commit 02e849c602
6 changed files with 167 additions and 163 deletions

View File

@ -36,7 +36,7 @@
*
* ***** END LICENSE BLOCK ***** */
var EXPORTED_SYMBOLS = [ "ctypes_library", "is64bit" ];
var EXPORTED_SYMBOLS = [ "ctypes_library", "is64bit", "WinCbABI" ];
const Cu = Components.utils;

View File

@ -7,30 +7,39 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
Cu.import("resource://firetray/ctypes/winnt/types.jsm");
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
function kernel32_defines(lib) {
this.OSVERSIONINFOEXW = ctypes.StructType("OSVERSIONINFOEXW", [
{ "dwOSVersionInfoSize": win_t.DWORD },
{ "dwMajorVersion": win_t.DWORD },
{ "dwMinorVersion": win_t.DWORD },
{ "dwBuildNumber": win_t.DWORD },
{ "dwPlatformId": win_t.DWORD },
{ "szCSDVersion": ctypes.ArrayType(win_t.TCHAR, 128) },
{ "wServicePackMajor": win_t.WORD },
{ "wServicePackMinor": win_t.WORD },
{ "wSuiteMask": win_t.WORD },
{ "wProductType": win_t.BYTE },
{ "wReserved": win_t.BYTE }
{ "dwOSVersionInfoSize": win32.DWORD },
{ "dwMajorVersion": win32.DWORD },
{ "dwMinorVersion": win32.DWORD },
{ "dwBuildNumber": win32.DWORD },
{ "dwPlatformId": win32.DWORD },
{ "szCSDVersion": ctypes.ArrayType(win32.TCHAR, 128) },
{ "wServicePackMajor": win32.WORD },
{ "wServicePackMinor": win32.WORD },
{ "wSuiteMask": win32.WORD },
{ "wProductType": win32.BYTE },
{ "wReserved": win32.BYTE }
]);
// lib.lazy_bind("GetLastError", win_t.DWORD); // use ctypes.winLastError instead
lib.lazy_bind("GetVersionExW", win_t.BOOL, this.OSVERSIONINFOEXW.ptr);
lib.lazy_bind("GetConsoleWindow", win_t.HWND);
lib.lazy_bind("GetConsoleTitleW", win_t.DWORD, win_t.LPTSTR, win_t.DWORD);
lib.lazy_bind("GetModuleHandleW", win_t.HMODULE, win_t.LPCTSTR);
// lib.lazy_bind("GetLastError", win32.DWORD); // use ctypes.winLastError instead
lib.lazy_bind("GetVersionExW", win32.BOOL, this.OSVERSIONINFOEXW.ptr);
lib.lazy_bind("GetConsoleWindow", win32.HWND);
lib.lazy_bind("GetConsoleTitleW", win32.DWORD, win32.LPTSTR, win32.DWORD);
lib.lazy_bind("GetModuleHandleW", win32.HMODULE, win32.LPCTSTR);
}
new ctypes_library(KERNEL32_LIBNAME, KERNEL32_ABIS, kernel32_defines, this);
let osvi = new kernel32.OSVERSIONINFOEXW();
osvi.dwOSVersionInfoSize = kernel32.OSVERSIONINFOEXW.size;
if (kernel32.GetVersionExW(osvi.address())) {
win32.WINVER = osvi.dwMajorVersion*10 + osvi.dwMinorVersion;
} else {
Cu.ReportError("win version not found");
}

View File

@ -7,10 +7,35 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
Cu.import("resource://firetray/ctypes/winnt/types.jsm");
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
function shell32_defines(lib) {
this.NOTIFYICONDATAW = ctypes.StructType("NOTIFYICONDATAW", [
{ "cbSize": win32.DWORD },
{ "hWnd": win32.HWND },
{ "uID": win32.UINT },
{ "uFlags": win32.UINT },
{ "uCallbackMessage": win32.UINT },
{ "hIcon": win32.HICON },
{ "szTip": ctypes.ArrayType(win32.TCHAR, 64) }, // 128 on win2k+
{ "dwState": win32.DWORD },
{ "dwStateMask": win32.DWORD },
{ "szInfo": ctypes.ArrayType(win32.TCHAR, 256) },
{ "uTimeoutOrVersion": win32.UINT }, // union
{ "szInfoTitle": ctypes.ArrayType(win32.TCHAR, 64) },
{ "dwInfoFlags": win32.DWORD },
{ "guidItem": win32.GUID },
{ "hBalloonIcon": win32.HICON }
]);
this.NOTIFY_VERSION = 3; // 2K+
this.NOTIFYICON_VERSION_4 = 4; // Vista+
this.NOTIFYICONDATA_V1_SIZE = 88;
this.NOTIFYICONDATA_V2_SIZE = 488; // 2K
this.NOTIFYICONDATA_V3_SIZE = 504; // XP
lib.lazy_bind("Shell_NotifyIconW", win32.BOOL, win32.DWORD, this.NOTIFYICONDATAW.ptr);
// notify icon message
this.NIM_ADD = 0x00000000;
this.NIM_MODIFY = 0x00000001;
@ -28,26 +53,6 @@ function shell32_defines(lib) {
this.NIF_REALTIME = 0x00000040;
this.NIF_SHOWTIP = 0x00000080;
this.NOTIFYICONDATAW = ctypes.StructType("NOTIFYICONDATAW", [
{ "cbSize": win_t.DWORD },
{ "hWnd": win_t.HWND },
{ "uID": win_t.UINT },
{ "uFlags": win_t.UINT },
{ "uCallbackMessage": win_t.UINT },
{ "hIcon": win_t.HICON },
{ "szTip": ctypes.ArrayType(win_t.TCHAR, 64) }, // 128 on win2k+
{ "dwState": win_t.DWORD },
{ "dwStateMask": win_t.DWORD },
{ "szInfo": ctypes.ArrayType(win_t.TCHAR, 256) },
{ "uTimeoutOrVersion": win_t.UINT }, // union
{ "szInfoTitle[64]": win_t.TCHAR },
{ "dwInfoFlags": win_t.DWORD },
{ "guidItem": win_t.GUID },
{ "hBalloonIcon": win_t.HICON }
]);
lib.lazy_bind("Shell_NotifyIconW", win_t.BOOL, win_t.DWORD, this.NOTIFYICONDATAW.ptr);
}
new ctypes_library(SHELL32_LIBNAME, SHELL32_ABIS, shell32_defines, this);

View File

@ -7,29 +7,47 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
Cu.import("resource://firetray/ctypes/winnt/types.jsm");
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
function user32_defines(lib) {
lib.lazy_bind("GetWindowTextW", ctypes.int, win_t.HWND, win_t.LPTSTR, ctypes.int);
lib.lazy_bind("FindWindowW", win_t.HWND, win_t.LPCTSTR, win_t.LPCTSTR);
this.CHANGEFILTERSTRUCT = ctypes.StructType("CHANGEFILTERSTRUCT", [
{ "cbSize": win32.DWORD },
{ "ExtStatus": win32.DWORD }
]);
this.MSGFLTINFO_NONE = 0;
this.MSGFLTINFO_ALLOWED_HIGHER = 3;
this.MSGFLTINFO_ALREADYALLOWED_FORWND = 1;
this.MSGFLTINFO_ALREADYDISALLOWED_FORWND = 2;
lib.lazy_bind("SendMessageW", win_t.LRESULT, win_t.HWND, win_t.UINT, win_t.WPARAM, win_t.WPARAM);
lib.lazy_bind("ChangeWindowMessageFilter", win32.BOOL, win32.UINT, win32.DWORD);
this.MSGFLT_ADD = 1;
this.MSGFLT_REMOVE = 2;
lib.lazy_bind("ChangeWindowMessageFilterEx", win32.BOOL, win32.HWND, win32.UINT, win32.DWORD, this.CHANGEFILTERSTRUCT.ptr);
this.MSGFLT_ALLOW = 1;
this.MSGFLT_DISALLOW = 2;
this.MSGFLT_RESET = 0;
lib.lazy_bind("RegisterWindowMessageW", win32.UINT, win32.LPCTSTR);
lib.lazy_bind("GetWindowTextW", ctypes.int, win32.HWND, win32.LPTSTR, ctypes.int);
lib.lazy_bind("FindWindowW", win32.HWND, win32.LPCTSTR, win32.LPCTSTR);
lib.lazy_bind("SendMessageW", win32.LRESULT, win32.HWND, win32.UINT, win32.WPARAM, win32.WPARAM);
this.WM_GETICON = 0x007F;
this.ICON_SMALL = 0;
this.ICON_BIG = 1;
this.ICON_SMALL2 = 2;
lib.lazy_bind("GetClassLongPtrW", win_t.ULONG_PTR, win_t.HWND, ctypes.int);
lib.lazy_bind("GetClassLongW", win_t.DWORD, win_t.HWND, ctypes.int); // 32-bits
lib.lazy_bind("GetClassLongPtrW", win32.ULONG_PTR, win32.HWND, ctypes.int);
lib.lazy_bind("GetClassLongW", win32.DWORD, win32.HWND, ctypes.int); // 32-bits
this.GetClassLong = is64bit ? this.GetClassLongPtrW : this.GetClassLongW;
this.GCLP_HICONSM = -34;
lib.lazy_bind("LoadIconW", win_t.HICON, win_t.HINSTANCE, win_t.LPCTSTR); // superseeded by LoadImage
lib.lazy_bind("LoadIconW", win32.HICON, win32.HINSTANCE, win32.LPCTSTR); // superseeded by LoadImage
this.IDI_APPLICATION = 32512;
lib.lazy_bind("LoadImageW", win_t.HANDLE, win_t.HINSTANCE, win_t.LPCTSTR,
win_t.UINT, ctypes.int, ctypes.int, win_t.UINT);
lib.lazy_bind("LoadImageW", win32.HANDLE, win32.HINSTANCE, win32.LPCTSTR,
win32.UINT, ctypes.int, ctypes.int, win32.UINT);
this.LR_CREATEDIBSECTION = 0x00002000;
this.LR_DEFAULTCOLOR = 0x00000000;
this.LR_DEFAULTSIZE = 0x00000040;
@ -40,6 +58,23 @@ function user32_defines(lib) {
this.LR_SHARED = 0x00008000;
this.LR_VGACOLOR = 0x00000080;
lib.lazy_bind("SetWindowLongPtrW", win32.LONG_PTR , win32.HWND, ctypes.int, win32.LONG_PTR);
lib.lazy_bind("SetWindowLongW", win32.LONG , win32.HWND, ctypes.int, win32.LONG);
this.SetWindowLong = is64bit ? this.SetWindowLongPtrW : this.SetWindowLongW;
this.GWL_EXSTYLE = -20;
this.GWLP_HINSTANCE = -6;
this.GWLP_ID = -12;
this.GWL_STYLE = -16;
this.GWLP_USERDATA = -21;
this.GWLP_WNDPROC = -4;
this.WNDPROC = ctypes.FunctionType(
WinCbABI, win32.LRESULT,
[win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM]).ptr;
lib.lazy_bind("CallWindowProcW", win32.LRESULT, this.WNDPROC, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
lib.lazy_bind("DefWindowProcW", win32.LRESULT, win32.HWND, win32.UINT, win32.WPARAM, win32.LPARAM);
}
new ctypes_library(USER32_LIBNAME, USER32_ABIS, user32_defines, this);

View File

@ -1,4 +1,4 @@
var EXPORTED_SYMBOLS = [ "win_t" ];
var EXPORTED_SYMBOLS = [ "win32" ];
const Cu = Components.utils;
@ -8,9 +8,18 @@ Cu.import("resource://firetray/ctypes/ctypes-utils.jsm");
const UINT_PTR_T = is64bit ? ctypes.uint64_t : ctypes.unsigned_int;
const LONG_PTR_T = is64bit ? ctypes.int64_t : ctypes.long;
const ULONG_PTR_T = is64bit ? ctypes.uint64_t : ctypes.unsigned_long;
const HANDLE_T = ctypes.voidptr_t; // oder ctypes.intptr_t, ctypes.size_t,
const HANDLE_T = ctypes.voidptr_t; // oder ctypes.intptr_t, ctypes.size_t, ctypes.int32_t ?
var win_t = {
var win32 = {
WIN_VERSIONS: { // maj*10 + min
'8': 62, // 2012
'7': 61, // 2009
'Vista': 60, // 2007
'XP': 51, // 2001
'2K': 50, // 2000
},
WINVER: null, // initialized in kernel32.jsm
BOOL: ctypes.bool,
BYTE: ctypes.unsigned_char,
@ -18,6 +27,8 @@ var win_t = {
WORD: ctypes.unsigned_short,
DWORD: ctypes.unsigned_long,
PVOID: ctypes.voidptr_t,
LONG: ctypes.long,
LONG_PTR: LONG_PTR_T,
ULONG_PTR: ULONG_PTR_T,
SIZE_T: ULONG_PTR_T,
HWND: HANDLE_T,
@ -46,6 +57,9 @@ var win_t = {
* #define MAKEINTRESOURCEA(i) ((LPSTR)((ULONG_PTR)((WORD)(i))))
* #define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))
*/
MAKEINTRESOURCE: function(i) {return this.LPWSTR(i); }
MAKEINTRESOURCE: function(i) {return this.LPWSTR(i); },
ERROR_INVALID_WINDOW_HANDLE: 1400,
ERROR_RESOURCE_TYPE_NOT_FOUND: 1813,
};

View File

@ -17,7 +17,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://firetray/ctypes/ctypesMap.jsm");
Cu.import("resource://firetray/ctypes/winnt/types.jsm");
Cu.import("resource://firetray/ctypes/winnt/win32.jsm");
Cu.import("resource://firetray/ctypes/winnt/kernel32.jsm");
Cu.import("resource://firetray/ctypes/winnt/shell32.jsm");
Cu.import("resource://firetray/ctypes/winnt/user32.jsm");
@ -88,140 +88,81 @@ firetray.Handler.getWindowIdFromChromeWindow = firetray.Window.getXIDFromChromeW
firetray.Handler.registerWindow = function(win) {
log.debug("register window");
// TESTING
let baseWin = firetray.Handler.getWindowInterface(win, "nsIBaseWindow");
let nativeHandle = baseWin.nativeHandle; // Moz' private pointer to the GdkWindow
log.info("nativeHandle="+nativeHandle);
let nativeHandle = baseWin.nativeHandle;
let hwnd = nativeHandle ?
new ctypes.voidptr_t(ctypes.UInt64(nativeHandle)) :
user32.FindWindowW("MozillaWindowClass", win.document.title);
log.debug("=== hwnd="+hwnd);
log.info("size="+ctypes.size_t.size);
log.info("psize="+ctypes.voidptr_t.size);
log.info("osvi size="+kernel32.OSVERSIONINFOEXW.size);
// Get TaskbarCreated
const WM_TASKBARCREATED = user32.RegisterWindowMessageW("TaskbarCreated");
// We register this as well, as we cannot know which WM_USER values are already taken
const kTrayMessage = "_MINTRAYR_TrayMessageW";
const kTrayCallback = "_MINTRAYR_TrayCallbackW";
const WM_TRAYMESSAGE = user32.RegisterWindowMessageW(kTrayMessage);
const WM_TRAYCALLBACK = user32.RegisterWindowMessageW(kTrayCallback);
log.debug("WM_*="+WM_TASKBARCREATED+" "+WM_TRAYMESSAGE+" "+WM_TRAYCALLBACK);
let osvi = new kernel32.OSVERSIONINFOEXW();
osvi.dwOSVersionInfoSize = kernel32.OSVERSIONINFOEXW.size;
if (kernel32.GetVersionExW(osvi.address())) {
log.debug("osvi.dwMajorVersion="+osvi.dwMajorVersion);
log.debug("osvi.dwMinorVersion="+osvi.dwMinorVersion);
/* if Administrator, accept messages from applications running in a lower
privilege level */
let rv;
if (win32.WINVER >= win32.WIN_VERSIONS["7"]) {
rv = user32.ChangeWindowMessageFilterEx(hwnd, WM_TASKBARCREATED, user32.MSGFLT_ALLOW, null);
log.debug("ChangeWindowMessageFilterEx res="+rv+" winLastError="+ctypes.winLastError);
} else if (win32.WINVER >= win32.WINVER["Vista"]) {
rv = user32.ChangeWindowMessageFilter(WM_TASKBARCREATED, user32.MSGFLT_ADD);
log.debug("ChangeWindowMessageFilter res="+rv+" winLastError="+ctypes.winLastError);
} else {
log.error("Unsupported windoz version "+win32.WINVER);
}
/*
* Windows 8 6.2
* Windows 7 6.1
* Windows Vista 6.0
* Windows XP 5.1
*/
let version = osvi.dwMajorVersion*10 + osvi.dwMinorVersion; // if (version >= 51)
let nid = new shell32.NOTIFYICONDATAW();
// FIXME: We should check WINVER for NOTIFYICONDATA_*_SIZE
nid.cbSize = shell32.NOTIFYICONDATAW.size;
let hwnd = user32.FindWindowW("MozillaWindowClass", win.document.title);
log.debug("hwnd FindWindow="+hwnd);
/*
let hwnd = new ctypes.voidptr_t(ctypes.UInt64(nativeHandle));
log.debug("hwnd nativeHandle="+hwnd);
*/
const BUF_SIZE = 255;
let buffer_t = ctypes.jschar.array(BUF_SIZE); // LPTSTR
let title = new buffer_t();
let len = user32.GetWindowTextW(hwnd, title, BUF_SIZE);
/* string is truncate to size of buffer and null-terminated. nid.szTip is
initialized automatically by ctypes */
let nMaxCount = 127;
let len = user32.GetWindowTextW(hwnd, nid.szTip, nMaxCount);
log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError);
if (len) {
log.info("title="+title.readString());
if (len != 0) {
log.info("nid.szTip="+nid.szTip.readString());
}
/*
let consoleWin = kernel32.GetConsoleWindow();
log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError);
log.info("consoleWin="+consoleWin);
len = user32.GetWindowTextW(consoleWin, title, 127);
log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError);
log.debug("len="+len);
log.info("title="+title.readString());
len = kernel32.GetConsoleTitleW(title, win_t.DWORD(127));
log.error("errno="+ctypes.errno+" winLastError="+ctypes.winLastError);
log.debug("len="+len);
log.debug("len type="+typeof(len)); // "object" ???
if (len) {
log.info("consoleTitle="+title.readString());
}
*/
let result = user32.SendMessageW(hwnd, user32.WM_GETICON, user32.ICON_SMALL, 0);
rv = user32.SendMessageW(hwnd, user32.WM_GETICON, user32.ICON_SMALL, 0);
// result is a ctypes.Int64. So we need to create a CData from it before
// casting it.
let icon = ctypes.cast(win_t.LRESULT(result), win_t.HICON);
let NULL = win_t.HICON(null);
// casting it to a HICON.
let icon = ctypes.cast(win32.LRESULT(rv), win32.HICON);
let NULL = win32.HICON(null); // for comparison only
log.debug("SendMessageW winLastError="+ctypes.winLastError);
if (firetray.js.strEquals(icon, NULL)) { // OS default icon
result = user32.GetClassLong(hwnd, user32.GCLP_HICONSM);
icon = ctypes.cast(win_t.ULONG_PTR(result), win_t.HICON);
if (firetray.js.strEquals(icon, NULL)) { // from the window class
rv = user32.GetClassLong(hwnd, user32.GCLP_HICONSM);
icon = ctypes.cast(win32.ULONG_PTR(rv), win32.HICON);
log.debug("GetClassLong winLastError="+ctypes.winLastError);
}
if (firetray.js.strEquals(icon, NULL)) { // from the first resource -> ERROR_RESOURCE_TYPE_NOT_FOUND(1813)
icon = user32.LoadIconW(kernel32.GetModuleHandleW(null),
win_t.MAKEINTRESOURCE(0));
win32.MAKEINTRESOURCE(0));
log.debug("LoadIconW module winLastError="+ctypes.winLastError);
}
if (firetray.js.strEquals(icon, NULL)) { // OS default icon
icon = user32.LoadIconW(null, win_t.MAKEINTRESOURCE(user32.IDI_APPLICATION));
icon = user32.LoadIconW(null, win32.MAKEINTRESOURCE(user32.IDI_APPLICATION));
log.debug("LoadIconW default winLastError="+ctypes.winLastError);
}
log.debug("icon="+icon);
log.debug("=== icon="+icon);
nid.hIcon = icon;
// BOOL mintrayr_CreateIcon(void *handle, mouseevent_callback_t callback)
// {
// HWND hwnd = (HWND)handle;
// if (!hwnd) {
// return FALSE;
// }
nid.hwnd = hwnd;
nid.uCallbackMessage = WM_TRAYMESSAGE;
nid.uFlags = shell32.NIF_ICON | shell32.NIF_MESSAGE | shell32.NIF_TIP;
nid.uVersion = shell32.NOTIFYICON_VERSION_4; // 5 ?! niels
// SetupWnd(hwnd);
// NOTIFYICONDATAW *iconData = new(std::nothrow) NOTIFYICONDATAW;
// if (!iconData) {
// return FALSE;
// }
// // Init the icon data according to MSDN
// iconData->cbSize = sizeof(NOTIFYICONDATAW);
// // Copy the title
// if (GetWindowText(hwnd, iconData->szTip, 127)) {
// iconData->szTip[127] = '\0'; // Better be safe than sorry :p
// }
// else{
// iconData->szTip[0] = '\0';
// }
// // Get the window icon
// HICON icon = reinterpret_cast<HICON>(::SendMessageW(hwnd, WM_GETICON, ICON_SMALL, 0));
// if (icon == 0) {
// // Alternative method. Get from the window class
// icon = reinterpret_cast<HICON>(::GetClassLongPtrW(hwnd, GCLP_HICONSM));
// }
// // Alternative method: get the first icon from the main module (executable image of the process)
// if (icon == 0) {
// icon = ::LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(0));
// }
// // Alternative method. Use OS default icon
// if (icon == 0) {
// icon = ::LoadIcon(0, IDI_APPLICATION);
// }
// iconData->hIcon = icon;
// // Set the rest of the members
// iconData->hWnd = hwnd;
// iconData->uCallbackMessage = WM_TRAYMESSAGE;
// iconData->uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
// iconData->uVersion = 5;
// // Install the icon
// ::Shell_NotifyIconW(NIM_ADD, iconData);
// ::Shell_NotifyIconW(NIM_SETVERSION, iconData);
// Install the icon
rv = shell32.Shell_NotifyIconW(shell32.NIM_ADD, nid.address());
log.debug("Shell_NotifyIcon ADD="+rv+" winLastError="+ctypes.winLastError); // ERROR_INVALID_WINDOW_HANDLE(1400)
shell32.Shell_NotifyIconW(shell32.NIM_SETVERSION, nid.address());
log.debug("Shell_NotifyIcon SETVERSION="+rv+" winLastError="+ctypes.winLastError);
// SetupWnd(hwnd);
// ::SetPropW(hwnd, kIconData, reinterpret_cast<HANDLE>(iconData));