I'm writing a Win32 application using plain C and WinAPI. No MFC or C++ is allowed. To get the controls to draw using the appropriate style, I use a manifest, as described in the corresponding MSDN article. Everything is fine, and when I change the system style, my application changes style as well. But the font used is just ugly. How do I force the application to use the standard system font?
You can use SystemParametersInfo with SPI_GETNONCLIENTMETRICS parameter to retrieve the current font. SystemParametersInfo will take into account the current theme and provides font information for captions, menus, and message dialogs. (See remark to GetStockObject http://msdn.microsoft.com/en-us/library/dd144925(VS.85).aspx). The function will retrieve NONCLIENTMETRICS structure (see http://msdn.microsoft.com/en-us/library/ff729175(v=VS.85).aspx) which contains all information you needs:
typedef struct tagNONCLIENTMETRICS {
UINT cbSize;
int iBorderWidth;
int iScrollWidth;
int iScrollHeight;
int iCaptionWidth;
int iCaptionHeight;
LOGFONT lfCaptionFont;
int iSmCaptionWidth;
int iSmCaptionHeight;
LOGFONT lfSmCaptionFont;
int iMenuWidth;
int iMenuHeight;
LOGFONT lfMenuFont;
LOGFONT lfStatusFont;
LOGFONT lfMessageFont;
#if (WINVER >= 0x0600)
int iPaddedBorderWidth;
#endif
} NONCLIENTMETRICS, *PNONCLIENTMETRICS, *LPNONCLIENTMETRICS;
An example how to create and a set font in a window/control if you knows LOGFONT parameter see at the end of the example from change the default window font in a win32 windows project, but use do LOGFONT not from GetStockObject(DEFAULT_GUI_FONT), but returned by SystemParametersInfo with SPI_GETNONCLIENTMETRICS parameter instead.
Related
I'm sending keystrokes to an inactive Adobe Flash Projector window with PostMessage, that part works perfectly. I leave it running in the background and it interferes very little with my normal computer usage, which is the intent. The problem comes when I programmatically send the W (or less frequently Q) key while I happen to be holding Ctrl intended for a different windows shortcut. This triggers Ctrl-Q or Ctrl-W, both of which immediately close the Adobe Flash Projector. Ctrl-F and Ctrl-O have some undesirable effects as well.
EDIT: I'm not interested in solutions that briefly release the Ctrl key.
Is there anyway I can unhook shortcut keys from a third party window? It uses a standard OS menubar across the top of the window which is where the shortcuts are listed, so surely there's a way to reassign, unassign, or block it, right?
In the past I tried using these dlls to break the menu. It made it disappear but didn't break the shortcuts.
DllCall("SetMenu", uint, this.id, uint, 0)
hMenu := DllCall("GetSystemMenu", "UInt",this.id, "UInt",1)
DllCall("DestroyMenu", "Uint",hMenu)
Sorry for the strange syntax, this is from an early version of my program written in autohotkey.
The language I'm using now is C#, but I assume the solution uses a .dll, so that's not as important. Feel free to suggest or change my tags.
You can try to make inactive (WS_DISABLED - use GetWindowStyle and SetWindowStyle) the main window of destination application (the Window that contains menu).
You can try to find which functions are used by application and rewrite them in local copy of application with VirtualProtect and injecting assembler (dangerous if you have no knowledge about virtualization of memory). Check the application use GetKeyState or GetAsyncKeyState (it will be visible after opening the application in text editor).
You can try:
HMENU hMenu=GetMenu(applicationMainWindow);
SetMenu(applicationMainWindow,0);
// here send your input with SendMessageW instead of PostMessageW
SetMenu(applicationMainWindow,hMenu);
Each program can use various methods to handle user keyboard input. In this case probably is used GetAsyncKeyState or GetKeyState (for Ctrl) if you didn't send it and Ctrl is detected.
If it won't help you, please add code with your PostMessage to your question.
BTW. Instead of destroying GetSystemMenu you can clear appropriate window style and after sending input restore it (if the problem is System Menu - probability near 1%).
Using the program Resource Tuner's free trial, I opened up flashplayer_28_sa.exe, went to Accelerator Table (Apparently accelerator means shortcut in the context of Menus), and deleted the offending shortcuts. Then I saved it, and it failed to save, and I saved it again, and again, and again, and then it worked, although I did nothing differently that time.
I think it would work with other shortcuts for programs with standard windows menus.
Although I didn't end up using this method, (because changing the menus was ineffectual for blocking the shortcuts for those menu items), I found various interesting ways to modify a third party window's menus. I'll leave some of what I found here because while it relate to my question, it doesn't solve my problem. Comments are based on my fallible understanding of what they do.
Various externals:
[DllImport("user32.dll")]
//get hMenu of the window's menu
static extern IntPtr GetMenu(IntPtr hWnd);
[DllImport("user32.dll")]
//Attach hMenu to a window. if hMenu is 0, attach no menu (remove menu)
static extern bool SetMenu(IntPtr hWnd, IntPtr hMenu);
[DllImport("user32.dll")]
//Destroy hMenu
private static extern bool DestroyMenu(IntPtr hMenu);
[DllImport("user32.dll")]
//Destroy Destroy submenu at position within menu
private static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);
[DllImport("user32.dll")]
//Like GetMenu, but gets the restore/move/size/minimize/etc menu that you get when clicking on the little icon in the top left of a window (not the window's menu
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
//Adds a menu to a menu
private static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);
[DllImport("user32.dll")]
//Removes a menu from a menu
private static extern bool RemoveMenu(IntPtr hMenu, uint uPosition, int uFlags);
[DllImport("user32.dll")]
//Like AppendMenu, but specifies position
private static extern bool InsertMenu(IntPtr hMenu, int uPosition, int uFlags, int uIDNewItem, string lpNewItem);
[DllImport("user32.dll")]
//Lets you set various properties of a menu (grayed out, checked, etc)
private static extern bool ModifyMenu(IntPtr hMenu, uint uPosition, uint uFlags, IntPtr uIDNewItem, string lpNewItem);
[DllImport("user32.dll")]
//gets the hMenu for a submenu
private static extern IntPtr GetSubMenu(IntPtr hMenu, int pos);
Notes on their parameters:
hWnd is the handle of a window with a standard menu.
hMenu is the menu handle, which can be the handle of the root level menu (Like File, Edit, Help) or a submenu item (Like open, copy, About ...). You can get these with GetSubMenu or GetSystemMenu or
uPosition is an integer position, 0 being the first one.
uFlags can be found on each function's individual page which you can find at https://msdn.microsoft.com/en-us/library/ff468865%28v=vs.85%29.aspx
lpNewItem refers to the string of text shown on the menu item.
uIDNewItem is a pointer like hMenu that will get inserted at the defined location
My question arises from our program running on a Japanese OS. One of my co-workers had done something like embed a property sheet on a dialog and the property sheet has multiple pages. Everything works fine on other languages except Japanese.
On Japanese systems, some of the controls get cut off because there is not enough space. I determined that this was because on Japanese systems, the font used by the property sheet and hence the property pages was different than the font used by the parent dialog of the property sheet. For the record, the font used by the parent dialog and all the property pages was MS Shell Dlg, 8:
FONT 8, "MS Shell Dlg", 0, 0, 0x1
I wanted a simple fix to try and ameliorate the problem for Japanese and all potential system. I examined the fonts on Japanese Windows 7 property sheets/pages and they always SEEMED to be the Default GUI Font. So, when I was creating my first dialog, on the fly after loading the DIALOGTEMPLATE into memory with the MFC class CDialogTemplate, I would modify the font of the parent dialog to match the default GUI font, and everything would be fine on Japanese Windows--Window 7, that is.
A customer has now found that this is not a valid solution for Windows 8/8.1--it exhibits the original problem. After examining the fonts on a Windows 8.1 VM, I did determine that the property sheet on Windows 8.1 and the child property pages does not use the Default GUI Font.
That's lots of words to ask. is there a way to determine what the default font used by property sheets on a Windows system?
I figure my ugly workaround would be to create a property sheet with one property page, determine the font used by that property sheet and page, and then modify the dialog template of my parent dialog on the fly to use that font. Since property sheets have some quirks about activation (they get activated on creation even if invisible), I'd rather not, but it seems to be my only choice--besides re-engineering of my co-worker's dialogs.
Yes, apparently the font for Property Sheet and Wizard is different. There is a dialog template for each language. In WinAPI PropertySheet uses the font from that template.
To find this font use the following (I only tested this on Windows 10)
#define IDD_PROPSHEET 1006
#define IDD_WIZARD 1020
HMODULE hmod = LoadLibrary(L"comctl32.dll");
if (hmod)
{
HRSRC hres = FindResource(hmod, MAKEINTRESOURCEW(IDD_PROPSHEET), (LPWSTR)RT_DIALOG);
if (hres)
{
HGLOBAL hglob = LoadResource(hmod, hres);
if (hglob)
{
CString fontname;
WORD fontsize;
CDialogTemplate::GetFont((DLGTEMPLATE*)hglob, fontname, fontsize);
TRACE(L"%s %d\n", fontname, fontsize);
}
}
FreeLibrary(hmod);
}
This might be somewhat outdated. The font obtained from SystemParametersInfo(SPI_GETNONCLIENTMETRICS...) must already be compatible because it's the main display font.
For some reason, MFC takes things further and applies that template font to property pages as well. MFC does other things which I can't understand, for example VS2015 has this code in "dlgprop.cpp"
LANGID langid = GetUserDefaultUILanguage();
if ((PRIMARYLANGID(langid) == LANG_JAPANESE) && IsFontInstalled(_T("MS UI Gothic")))
{
WORD wLang = MAKELANGID(LANG_JAPANESE, 0x3f);
if (wLang != 0)
{
hResource = ::FindResourceExW(hInst, (LPWSTR) RT_DIALOG,
MAKEINTRESOURCEW(bWizard ? IDD_WIZARD : IDD_PROPSHEET), wLang);
}
...
}
I don't know why it forces a sub-language if a certain font is present. Also as #PRinCEKtd points out, this font might be outdated (but the font could be still be installed) You can step through CPropertySheet to find all the font manipulations.
see also codeguru link, Custom Font in Property Sheets
try use
NONCLIENTMETRICS ncm = { GetNONCLIENTMETRICSWSize() };
if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)){..}
usual all system controls (status bar, list view, tree view,menu, message box..) use fonts from this struct
where GetNONCLIENTMETRICSWSize() can be like this (on XP/2003 (major < 6) struct size is less on 4 byte compare vista+)
ULONG GetNONCLIENTMETRICSWSize()
{
static ULONG m;
if (!m)
{
RtlGetNtVersionNumbers(&m, 0, 0);
}
return m < 6 ? sizeof(NONCLIENTMETRICS) - 4 : sizeof(NONCLIENTMETRICS);
}
From Windows Vista onwards, the Meiryo font family was used as default in the Windows user interface to support Japanese. I think before vista, it was MS Gothic...
How about manually setting a default windows font directly? There are many fonts that support Japanese as well as a wide variety of languages. Some of them have been present from XP upto 10, though they might have some updates.
I want to turn the system network icon on/off in my application likes what we can do via control panel. I know the "HideSCANetwork" registry item, but to use this solution I need to restart the explorer after changing the setting. Is there any other solution which can do this seamlessly like the system?
There is no official API for doing thois. The reason for this is that Microsoft wanted to give the user the ability to keep their notification area from becoming too full. The problem being too many applications starting notification icons that the user doesn't care for.
Since many users don't know how to get rid of these icons, Microsoft decided to help by hiding them by default. If applications had access to these hide/show settings then applications would simply show the notifications by default and we'd be back where we started. So there is no mechanism provided for modifying these settings programmatically.
You want to do something different that sounds equally malicious, namely to hide an important system icon. If you are determined to do this then you can reverse engineer how the setting is stored (likely in the registry) and change the setting that way. However, you'll be going against the system design should you do so.
Now I find a imperfect solution. The basic idea comes from here:
http://www.codeproject.com/Articles/10807/Shell-Tray-Info-Arrange-your-system-tray-icons
Some tips:
This solution supports Win 7, you can remove XP checking code.
On wow64, you need to change the struct TRAYDATA and use TBUTTON64:
struct TRAYDATA
{
DWORD64 hwnd;
UINT uID;
UINT uCallbackMessage;
DWORD Reserved[2];
DWORD64 hIcon;
};
typedef struct _TBBUTTON64
{
int iBitmap;
int idCommand;
BYTE fsState;
BYTE fsStyle;
BYTE bReserved[6];
DWORD64 dwData;
DWORD64 iString;
} TBBUTTON64, NEAR* PTBBUTTON64, *LPTBBUTTON64;
typedef const TBBUTTON64 *LPCTBBUTTON64;
When you find the icon you want to hide(By using the tip text plus the owner process), send a TB_HIDEBUTTON message to the notification area window.
The imperfect part is that the tray icon will be hidden, but the notification area will not resize. So there is a blank area on the notification area.
what does it class style means actually ? it confused me. this is from MSDN: style
Specifies the class style(s). This member can be any combination of the class styles.
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS, *PWNDCLASS;
The class styles are properties that affect every instance of a window of that specific class. To clarify, let's compare window instance properties vs class properties below. Supposes you create a new windows class called MyCoolControl, and you create several instances of this:
Every instance will have its own location, window text, and enabled and visible state - these are window instance properties, and you can set these on one window independently of the others.
However, all instances of this control will share the same WndProc, as specified in the WNDCLASS that you use to create the class. They'll also have the same class properties, such as whether the windows receive double-click messages rather than two separate click messages (CS_DBLCLKS class style bit), or whether the window is completely redrawn when resized (CS_HREDRAW, CS_VREDRAW), or whether the windows have a drop-shadow (CS_DROPSHADOW). The full list of class styles are listed on MSDN here.
So, for example, if you want a window to have a border or not, that's a window style bit (WS_BORDER), and you specify it as a window style value in CreateWindow (or can change it later per-window with SetWindowLongPtr(GWL_STYLE)), and only that window is affected. But if you want to create a window that has a drop shadow, you specify that in the style member of the WNDCLASS, and it affects all instances of that class.
(There are some exceptions to this - the WndProc specified in the WNDCLASS is really the default wndproc for that class of windows; you can actually override it per-instance if you want to. But the big picture is still mostly the same: WNDCLASS and CS_ styles are across-the-board settings, while the WS_ ones and the parameters to CreateWindow are specific to that one window.)
I'm writing an application for a Pocket PC 2003 device. In it there is a dialog where various text information is shown. The information is separated so that each piece resides inside its own label, defined as LTEXT in the resource file.
Now my problem is that, at the moment, all text lables have the same font and style (normal or simple, i.e. not bold or italic); I want want one to be set in bold. I know that I can set the font to bold in the resource file, but that sets the style of all labels.
How does one achieve this? I've seen it be used in the Windows 'About' screen so I know it's possible. I've written the program in C++ using the Win32 API directly (except for certain dialogs where I've used the resource file) so I would appreciate if the answer was given in the same language and approach.
Thanks.
In the resource editor, edit the static text item, and change its control ID to something unique: IDC_BOLD for example.
In the DialogProc for the dialog boxes that is hosting the control, add a WM_CTLCOLORSTATIC handler:
case WM_CTLCOLORSTATIC:
HDC hdc;
HWND hwndCtl;
hwndCtl = (HWND) lParam;
hdc = (HDC) wParam;
if( GetWindowLong(hwndClt, GWL_ID ) == IDC_BOLD )
{
SetBkMode(hdc,TRANSPARENT);
SetTextColor(hdc,RGB(0xff,0,0)); // turn the text red for fun :)
SelectObject(hdc,hBoldFont); // but you want this...
return (INT_PTR)GetSysColorBrush(COLOR_BTNFACE);
//return 0L; // if visual themes are enabled (common controls 6) then 0 is better.
}
// default processing
return 0;
You are developing for Pocket PC 2003, I don't know what buttons styles are available. This Page refers of course to desktop XP. But, if the buttons in the dialogs are not flat grey 95esq buttons, then it might be more appropriate to return 0 as that will paint the text background correctly if the dialogs background is not plain grey.
Pre-visual styles a return of 0 causes the system to reset the DC so its important to know which return is appropriate.