I'm making a Firefox addon with js-ctypes and was using user32.dll functions to set the icons of all windows of a profile.
I plan to do this for Mac OS and Linux but trying to knock out Windows first.
So I'm setting the icons like this: GitHub - Gist :: Noitidart / _ff-addon-snippet-ChangeWindowIcon.js - Rev2
That code is simplified. This code I use to apply to all windows:
Cu.import('resource://gre/modules/ctypes.jsm');
var user32 = ctypes.open('user32.dll');
var SendMessage = user32.declare('SendMessageW', ctypes.winapi_abi, ctypes.uintptr_t,
ctypes.int32_t,
ctypes.unsigned_int,
ctypes.int32_t,
ctypes.voidptr_t
);
var LoadImage = user32.declare('LoadImageA', ctypes.winapi_abi, ctypes.voidptr_t,
ctypes.int,
ctypes.char.ptr,
ctypes.unsigned_int,
ctypes.int,
ctypes.int,
ctypes.unsigned_int
);
var IMAGE_BITMAP = 0;
var IMAGE_ICON = 1;
var LR_LOADFROMFILE = 16;
// RUNNING STUFF BELOW - ABVOE WAS JUST DEFINING STUFF
var DOMWindows = Services.wm.getEnumerator(null);
while (DOMWindows.hasMoreElements()) {
var aDOMWindow = DOMWindows.getNext();
var basewindow = aDOMWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.treeOwner
.QueryInterface(Ci.nsIInterfaceRequestor)
.nsIBaseWindow;
var nativeHandle = basewindow.nativeHandle;
var targetWindow_handle = parseInt(nativeHandle);
var hIconBig = LoadImage(targetWindow_handle, 'C:\\Documents and Settings\\SONY VAIO\\My Documents\\Downloads\\puzzle.ico', IMAGE_ICON, 256, 256, LR_LOADFROMFILE); //MUST BE A FILEPATH TO A ICO!!!
var hIconSmall = LoadImage(targetWindow_handle, 'C:\\Documents and Settings\\SONY VAIO\\My Documents\\Downloads\\puzzle.ico', IMAGE_ICON, 16, 16, LR_LOADFROMFILE); //MUST BE A FILEPATH TO A ICO!!!
var successSmall = SendMessage(targetWindow_handle, 0x0080 /** WM_SETICON **/ , 0 /** ICON_SMALL **/ , hIconSmall); //if it was success it will return 0? im not sure. on first time running it, and it was succesful it returns 0 for some reason
var successBig = SendMessage(targetWindow_handle, 0x0080 /** WM_SETICON **/ , 1 /** ICON_BIG **/ , hIconBig); //if it was success it will return 0? im not sure. on first time running it, and it was succesful it returns 0 for some reason
}
user32.close();
The issues are as follows:
Issues On WinXP
When press Alt + Tab the icon is the normal one
If windows are lumped into one group (because of taskbar overflow) and ALL icons are changed, the lumped group icon is still not the changed one. As seen in image here:
Issues On Win7
If the application IS PINNED and even if all windows icons are changed to be the same, it still does not changed the pin icon
If the application is NOT PINNED then if change the icon for all windows it will change the icon on the taskbar HOWEVER if you right click on the icon in the taskbar it reverts to what it was normally and running the snippet above again won't set it back, to get it back to icon you set you have to pin and unpin
You really shouldn't put so much questions into a single question...
When press Alt + Tab the icon is the normal one
You're trying to load and set 256x256 icons. XP does not support such icons. You should really add some error checking ;)
IIRC you should set 32x32 icons for the big one. Or more precisely SM_CXICON and/or SM_CXSMICON
If windows are lumped into one group (because of taskbar overflow) and ALL icons are changed, the lumped group icon is still not the changed one. As seen in image here:
I think you're out of luck for this one. XP will take whatever icon is the main resource icon in the .exe IIRC.
XP is dead anyway...
Issues On Win 7
IIRC you'll have to work with System.AppUserModel.RelaunchIcon...
Edit
Actually I might be wrong regarding the XP grouping stuff. Last messed around with icons on win32 quite a while ago. GCLP_HICON/GCLP_HICONSM might work.
Related
I'm trying to place a window either above or below the icons on the desktop. I mostly just want it to stay attached to the desktop at all times. Similar to Rainmeter or Wallpaper engine. So far, everything I tried either disables interaction, or gets minimized when you use the "Show Desktop" button. Any ideas on how to achieve this? I'm using electron and a native module in node to do this.
It's an old subject, but I'll find out how to do it recently and answer it.
The method is to find the handle of SHELLDLL_DefView, the parent of the desktop window, and then make the SHELLDLL_DefView handle the parent of my window to fix it to the desktop.
The method is to find the handle of SHELLDLL_DefView, the owner of the desktop window, and then make the SHELLDLL_DefView handle the owner of my window to fix it to the desktop.
SHELLDLL_DefView is located under the Progma or WorkerW handle. This is a code to prevent ShowDesktop from being used in the Electget package created by ffi-napi to attach the Electron browserWindow to the desktop.
const GWLP_HWNDPARENT = -8;
// find SHELLDLL_DefView in Progma
const progman = user32.FindWindowExA(ref.NULL, ref.NULL, 'Progman', ref.NULL);
let defView = user32.FindWindowExA(progman, ref.NULL, 'SHELLDLL_DefView', ref.NULL );
// find SHELLDLL_DefView in WorkerW
if (!defView) {
const desktopHWnd = user32.GetDesktopWindow();
let workerW = 0;
do {
workerW = user32.FindWindowExA(desktopHWnd, workerW, 'WorkerW', ref.NULL);
defView = user32.FindWindowExA(workerW, ref.NULL, 'SHELLDLL_DefView', ref.NULL );
} while (!defView && workerW);
}
if (!defView) return false;
// make the SHELLDLL_DefView handle the parent of my window
user32.SetWindowLongPtrA(hWnd, GWLP_HWNDPARENT, defView);
This allows you to create a window where you can click and interact without being hidden by ShowDesktop.
2022-03-29
There was a wrong word, so I corrected it. According to doc, it is not a parent window, but an owner window. In the doc, it is strange that the GWLP_HWNDPARENT constant is related to the parent window. However, when tested with Spy++, the corresponding constant changes the owner window.
I'm not sure what am I doing wrong. I have a functionality in my CDialog-based MFC app to increase the font in some common controls. It is done by sending them WM_SETFONT message with a larger font:
//No error checks for brevity
HFONT hFnt = (HFONT)::SendMessage(hCtrlWnd, WM_GETFONT, 0, 0);
LOGFONT lfFont;
::GetObject(hFnt, sizeof(lfFont), &lfFont);
BOOL bPositive = lfFont.lfHeight >= 0;
long nFontSz = abs(lfFont.lfHeight);
nFontSz += nFontDelta;
lfFont.lfHeight = bPositive ? nFontSz : -nFontSz;
HFONT hNewFont = ::CreateFontIndirect(&lfFont);
::SendMessage(hCtrlWnd, WM_SETFONT, (WPARAM)hNewFont, TRUE);
//Need to DeleteObject hNewFont when control gets a new font or is destroyed
This works for most controls except the DateTime picker (or to be more precise, its month-calendar, SysMonthCal32 window class.)
Here's a screenshot on Windows XP, where it works as expected:
Normal magnification:
Enlarged:
But here's what I get on Windows 10, normal magnification:
And (supposed to be) enlarged, but isn't:
So why is it working on XP and stops, starting from Vista onward?
You are probably using ComCtl32.dll version 6 which uses the Visual Styles API.
This means that most text is drawn by either DrawThemeText or DrawThemeTextEx.
Both of these functions use the font specified by the HTHEME argument.
To change the font you could either change the window's theme using SetWindowTheme or use a version of ComCtl32.dll prior to version 6.
The handling of WM_SETFONT and WM_GETFONT seems to be for keeping compatibility with programs that use these messages to store their font. They are not actually used for drawing.
I have an installation dialog (made with nsis) that has two buttons (install and cancel). I'm trying to write automated tests for the install process using low level win32 api. To click on the button(s) I use the following code:
char windowName[] = "Desktop Application Setup";
char cancelButtonText[] = "Cancel";
HWND hWndMainWindow = NULL;
HWND hButton = NULL;
hWndMainWindow = FindWindow(NULL, windowName);
if (hWndMainWindow)
{
hButton = FindWindowEx(hWndMainWindow, NULL, NULL, cancelButtonText);
if (hButton)
{
SendMessage(hButton, BM_CLICK, 0, 0);
}
}
On Windows 7, this works perfectly. On Windows 10, it simply does nothing. It finds the button, it sends the message, but the click just doesn't happen.
Is this some security thing introduced in Windows 10? Is it a known issue?
it is better to send WM_COMMAND with the ID of the button, but the way you are doing works also if Lang is always in English. but the problem with your case is that buttons on dialog usually have an "&" to indicate the keyboard short cut, and usually hidden by system unless you press alt key. (like menus).
so: text of the button is most likely to be "&cancel"
I have been stuck here for 4 days. I made a function that puts a program in the system tray but the problem here is that it wont show balloon title and message. What Am I doing Wrong? I even made a separate function to determine what windows os we are running on and initialize cbSize based on the Os detected. Any help will be appreciated. Bellow is the function.
EDIT: I am using Windows 7 and the Icon shows up in the system tray but wont show the message or title. I am also doing this Console Application right now as this will be used as a plugin in Unity3D. I want a solution that uses windows api but not windows form as I don't want any new window to open from this.
void createSystemTray()
{
HWND wHandler = GetDesktopWindow();
NOTIFYICONDATA iData;
ZeroMemory(&iData,sizeof(iData));
if(getOsVersion()=="Windows Vista" || getOsVersion()=="Windows 7" || getOsVersion()=="Windows 8" || getOsVersion()=="Windows 8.1")
{
iData.cbSize = sizeof(NOTIFYICONDATA);
}
else if (getOsVersion()=="Windows XP"||getOsVersion()=="Windows XP Professional x64 Edition")
{
iData.cbSize = NOTIFYICONDATA_V3_SIZE;
}
else if (getOsVersion()=="Windows 2000")
{
iData.cbSize = NOTIFYICONDATA_V2_SIZE;
}
else if (getOsVersion()=="UNKNOWN OS")
{
//Assume we have old Windows Os such as Me,95....
iData.cbSize = NOTIFYICONDATA_V1_SIZE;
}
iData.hWnd = wHandler;
iData.uID = 100;
iData.uVersion = NOTIFYICON_VERSION_4;
iData.uCallbackMessage = WM_MESSAGE;
iData.hIcon = LoadIcon(NULL,(LPCTSTR)IDI_WARNING);
lstrcpy(iData.szTip,"My First Tray Icon");
lstrcpy(iData.szInfo,"My App Info");
lstrcpy(iData.szInfoTitle,"My Info Title");
iData.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
Shell_NotifyIcon(NIM_SETVERSION,&iData); //called only when usingNIM_ADD
Shell_NotifyIcon(NIM_ADD,&iData);
}
I added NIF_INFO to the uFlags and the problem is gone. Now it displays everything including text, title and info title.
The code below is what solved it.
iData.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP|NIF_SHOWTIP|NIF_INFO;
Your biggest problem with the code in the question is that you pass the wrong window handle. You have to pass one of your window handles. But instead you pass the window handle of the desktop.
You will need to create a window and use its handle. The window does not need to be visible. I believe that you can use a message only window.
You must also call NIM_SETVERSION after NIM_ADD.
I'm very sceptical of your version switching being based on string equality testing. Your code will break on Windows 9 for instance. Use the version helper functions.
You also perform no error checking. This isn't the easiest function to call but your failure to check for errors makes things even harder than they need to be. Please read the documentation and add error checking code.
I'm trying to place my application that is mainly running in the background in a 'tray-like' area on the Windows Mobile 6.5.
I do it the obvious way by with Shell_NotifyIcon
BOOL ShowTrayIcon(HWND hWnd, HINSTANCE hIns, BOOL bShowIcon)
{
BOOL bRet = FALSE;
g_structNotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
g_structNotifyIconData.hIcon = LoadIcon(hIns, MAKEINTRESOURCE(IDI_GPSCOMPASS));
g_structNotifyIconData.hWnd = hWnd;
g_structNotifyIconData.uCallbackMessage = WM_SYSTRAY_MSG;
g_structNotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON;
g_structNotifyIconData.szTip[0] = 'Bzz';
g_structNotifyIconData.uID = ID_TRAY;
if (bShowIcon)
bRet = Shell_NotifyIcon(NIM_ADD, &g_structNotifyIconData);
else
bRet = Shell_NotifyIcon(NIM_DELETE, &g_structNotifyIconData);
return bRet;
}
This is where i am trying to place the icon :
Tray icon within the 'today' area http://www.fotoszok.pl/upload/666d99dc.jpg
The Shell_NotifyIcon does the thing but the Icon is not shown on the Today screen, i can see it's in the tray from any place except the Today/Home screen.
Now I've read somewhere that this is because the Tray area in Today screen is reserved for system notifications and 'we' can't place any icons in there - well if that's true, can somebody please confirm that?
Indeed, Shell_NotifyIcon doesn't support adding the icon in the Today screen. This is even one of the first things mentioned in the function documentation:
This function sends a message to the system to add, modify, or delete an application-specific icon from the taskbar status area. It does not affect icons appearing on the home screen.
You can try using SHNotificationAdd.