Class Styles in WNDCLASS, what does it reference to ? Win32 - windows

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

Related

Some quick questions about Windows API control IDs

I've got a few questions here about control IDs:
Can they be changed at runtime by setting GWL(P)_ID? Or will the dialog manager not be fooled? Since this is a framework, I need to generate them at runtime; initially they are 0.
What is the uniqueness scope of control IDs, the whole toplevel window or just the immediate parent of a control? Controls in my framework are stored in a custom container window, there are multiple such in each toplevel window.
Thanks.
Question 1
Control IDs can be changed by calling SetWindowLongPtr:
SetWindowLongPtr(hwndChild, DWL_ID, new_id);
Question 2
From the documentation for CreateWindow, with my emphasis:
hMenu [in, optional]
A handle to a menu, or specifies a child-window identifier depending
on the window style. For an overlapped or pop-up window, hMenu
identifies the menu to be used with the window; it can be NULL if the
class menu is to be used. For a child window, hMenu specifies the
child-window identifier, an integer value used by a dialog box control
to notify its parent about events. The application determines the
child-window identifier; it must be unique for all child windows with
the same parent window.
Or from the documentation of GetDlgItem:
You can use the GetDlgItem function with any parent-child window pair,
not just with dialog boxes. As long as the hDlg parameter specifies a
parent window and the child window has a unique identifier (as
specified by the hMenu parameter in the CreateWindow or CreateWindowEx
function that created the child window), GetDlgItem returns a valid
handle to the child window.
So the scope for IDs is the parent window. But this also tells you that you can specify the ID when you create the child window via the re-purposed hMenu parameter.

Change color of background and title in MFC Control

I want to change text color and background color for my EDIT CONTROL, STATIC CONTROL and BUTTON CONTROL in MFC application. The control is in a CDialogEx dialogue .
I try to add the OnCtlColor (with wizard in visual studio, on the WM_CTLCOLR message) but I can't set the color of may static control and button control.
I put also a break point in the OnCtlColor function (in the IF construct), but I don't receive anything.
I also tried to use the SetTextColor function retrieving the handle of the control from GetDlgItem, but I can't change the color as I want.
Pleas help me.
I can assert that I tried to use in OnCtlColor in a CDialog and it worked for the static and for the edit controls.
All you have to do is:
For changing background color, you need to create a brush that still exists outside that function and return its HBRUSH with
return (HBRUSH) m_brush.GetSafeHandle();
So you have to make a variable (m_brush in this code) that is member or a static (I recommend the first), and in the dialog initialization you have to create the brush you want.
I thought maybe some controls will not work with this, and for those I also did
pDC->SetBkColor(RGB(0,0,255));
But seems to do nothing; it is in the code for safety.
For changing the text color,I did
pDC->SetTextColor(RGB(255,0,0));
These experiences worked well for edits and statics, but did not work at all for groupboxes!
Groupboxes are a strange entity in MFC, some kind of a platyplus: they are a CButton with the BS_GROUPBOX, but in this function, its nCtlColor is CTLCOLOR_STATIC instead of CTLCOLOR_BTN! I did this for them
UINT nStyle = (UINT)(pWnd->GetStyle() & 0x0F);
if(nStyle == BS_GROUPBOX)
{
return (HBRUSH) m_brush2.GetSafeHandle();
}
and what got painted was the little rectangle behind the groupbox title!
I could not get the text colour of groupboxes changed!
If you have groupboxes and it is really important to change their titles' text color, you can get the one from http://www.codeproject.com/Articles/29016/XGroupBox-an-MFC-groupbox-control-to-display-text and get its essential code parts: to be derived from CStatic, the OnPaint() and DrawItem() methods. Do not forget also the ON_WM_PAINT() on the message map. I don't know if the OnEraseBkgnd() and its is ON_WM_ERASEBKGND() message mapping are so essential.
It is also needed to change them to be Static text controls in the resources, declare a XGroupBox variable and do a DDX_Control of it.
I tested it and it really works.
For buttons, with CButtons it did not work. But, for each button, I simply declared a CMFCButton variable in the class and did a DDX_Control of each one. After, I had two choices:
Set its m_bTransparent property to TRUE in the form constructor (search this variable on afxbutton.cpp file for reference) for the ones I wanted to have the same color as the form (I also painted the form; in my case I was implementing themes on an application)
Set the Background color with SetFaceColor() and set the Text Color with SetTextColor() in form initialization.
When the CMFCButton does not have these things set, it got its color from theme blending of the currently selected CMFCVisualManager.
Note: I also replaced my CSpinButton entities with CMFCSpinButon ones, because I wanted colors from the selected theme.
In the OnCtlColor, the nCtlColor variable is important because it will allow you to personalize different colors to different types, without testing dynamic_cast success or failure for every control.
Do not forget to add ON_WM_CTLCOLOR() to your message map.
UPDATE 1:
After following the advice of the accepted answer on http://social.msdn.microsoft.com/Forums/vstudio/en-US/53f47162-078a-418f-8067-ee61a81ceeac/checkbox-transparent-color-not-working-in-vs2008?forum=vcgeneral , I did my own Groupbox class, and now it is like:
class CMyGroupBox: public CButton
{
protected:
virtual void PreSubclassWindow()
{
SetWindowTheme(*this, _T(""), _T(""));
#pragma comment(lib, "UxTheme.lib")
}
};
I just declared one of this, and did DDX_Control with its respective control ID, and now I can see the text in the color I supplied to SetTextColor. If you return a HBRUSH for this control, what gets painted is a non-filled rectangle drawn around the groupbox's title.
UPDATE 2: I just generalized the CMyGroupBox to be CMyButton, for using its PreSubClassWindow method not only in groupboxes, but also in checkboxes and buttons. In checkboxes it works well, in buttons, I am not so satisfied with the results.
UPDATE 3: I was trying to remove some weird effect on the rendering of the text and I just commented the pDC->SetBkColor(RGB(0,0,255)); line; the result was an ugly while rectangle behind the text :( . Then I replaced it with pDC->SetBkMode(TRANSPARENT); and I also see tht weird effect :(
UPDATE 4: In order to avoid to have to declare all my checkboxes, groupboxes and buttons as the class that contains the PreSubClassWindow method, I researched and discovered that it is not needed to do it. The code
SetThemeAppProperties(0);
#pragma comment(lib, "UxTheme.lib")
AfxGetMainWnd()->SendMessage(WM_THEMECHANGED, 0U, 0L);
disables theming for all controls at the whole application level.

how to route a message to the control's standard WNDPROC

When a standard window control (e.g. an "EDIT" control) is created, its WNDPROC is defined as part of the window class (i.e. "EDIT" has a specific WNDPROC that is designed to make the window display & behave as an edit-control).
MFC allows you to interact with such controls via their wrapper classes, such as a CEdit wrappers the specialized messages for an "EDIT" window control.
MFC further allows you to bind an instance of an "EDIT" window to a C++ subclass of CEdit, say a CMyEdit, where you can override inherited virtual functions of CEdit and CWnd, and you can define a message table to gain access / override messages sent to the window instance itself.
There is CWnd::Default(), which calls this->DefWndProc with the current message arguments. This appears to lookup the WNDPROC for the HWND it is associated with. So is this the correct answer: call DefWndProc() (or equally, Default()), which will hand it off to the WNDPROC of the windows control?
Obviously, this is different than other message table handlers which can return FALSE to indicate that they didn't handle the message, and MFC will automatically route the message up the class inheritance hierarchy to the next message handler for this message, or, I assume, to Default() to be handled by the native WNDPROC?
If I define an arbitrary message handler, say for WM_SETTEXT, what is the correct way to pass this message on to the "EDIT" WNDPROC?
I'd also love to know if there is a way to pass the message up to a superclass (C++ class hierarchy) for handling? Many OnXXX style handlers do have a way to do so, but is there a mechanism that works for ON_MESSAGE handlers?
class CDynamicMenuControlEdit : public CEdit
{
...
LRESULT OnSetText(WPARAM wParam, LPARAM lParam);
...
}
BEGIN_MESSAGE_MAP(CDynamicMenuControlEdit, CEdit)
...
ON_MESSAGE(WM_SETTEXT, OnSetText)
...
END_MESSAGE_MAP()
LRESULT CDynamicMenuControlEdit::OnSetText(
WPARAM wParam, // not used; must be zero
LPARAM lParam // window-text string (LPCTSTR)
)
{
if (m_bHasFocus)
{
// do normal thing
// !!! THIS IS MY QUESTION: IS THIS CALLING EDIT's WNDPROC, or ::DefWinProc()? !!!
return DefWindowProc(WM_SETTEXT, wParam, lParam);
}
...
}
Clarification
You can have multiple MFC subclasses at the C++ level -
so C inherits B inherits A, where A is an MFC class (e.g. CEdit).
Each of those can have an MFC message table - i.e. BEGIN_MESSAGE_MAP ... END_MESSAGE_MAP which can each have a handler for any arbitrary windows message, such as WM_MESSAGE(WM_SETTEXT, OnSetText) - and that OnSetText member is not necessarily virtual - just a static member (each MFC subclass can route that message in any arbitrary way).
My question is - since a WM_MESSAGE dispatch entry doesn't have a return value, how do I allow MFC to walk up the MFC dispatch tables from C to B to A before handing back to the real windows 'EDIT' class's wndproc?
Or are all such entries intended at the MFC design-level NOT to be walked? i.e. the most subclassed layer's dispatcher is intended to be the only one called? And if it wants to leverage an inherited member it has to manually make that call - MFC simply doesn't have any specific generic structure for this?
Calling Default() will cause the "normal" processing that would have happened in response to a message to occur. I'm not entirely clear on what you are trying to achieve, but it seems to me that calling Default() is what you want to do.
If you look at a lot of the handlers from Windows messages in the CWnd handlers (and handlers from classes derived from CWnd such as CEdit) you will see that they call Default().
Word to the wise, that Default() will actually use whatever parameters the original message had - you cannot change them.
You're doing it right. CWnd::DefWindowProc() uses the WINDOWPROC you subclassed from and will call the EDIT window's window procedure.

Design problem in wrapping Windows's Window API

I'm writing an object-oriented window API wrapper for Windows in D, and I'm having a (non-language-specific) design problem.
Windows requires that all windows be previously registered with RegisterClass; extending an existing class requires replacing the window procedure. Furthermore, there seem to be two kinds of window handles: HWNDs that need to be disposed (via DestroyWindow), and HWNDs that don't (e.g. from other applications).
I have created a Window class, and so long as I'm just wrapping the ShowWindow, UpdateWindow, FindWindow, and other such methods, everything is fine and dandy. But as soon as I try to add a constructor with a className parameter to my class that calls CreateWindow, I run across a problem:
The given className must already have been registered by RegisterClass.
In order to register a new window class, I would need to make my subclasses of Window to somehow call RegisterClass before trying to create a new Window, either directly or indirectly.
In order for my design (and inheritance) to make sense, i would need to make sure that, for any given subclass of Window, all instances are actually instances of the same window class; namely, that all classNames from a particular subclass are identical. (This is because the window procedures for all instances of a particular window class need to be the same.)
The problem is, there's no way to have an abstract static method (in order for Window to be able to ask the subclasses for their class info, and to register them once), and so I am forced to say something like CreateWindow(this.className, ...) in order to create a new window, which easily becomes problematic if my subclasses don't respect this rule, and give me a different class name per instance of the window.
Furthermore, I need a one-to-one mapping between the WNDCLASS.lpfnWndProc field and my Window subclass's (overridden) WndProc method. This doesn't exactly work, though, if I'm forced to get the method pointer on a per-instance basis, since it breaks the entire OOP design and messes everything up.
While it's possible for me to enforce this consistency at run-time, it's a bit ugly, and so it's not a great solution.
So, long story short, does anyone have any idea of an elegant solution to the problem of creating an abstract static method? I'm thinking of some design patterns like Factory and whatnot, but I'm not sure if they fit here... if someone thinks they might , I would really appreciate a little explanation on how it would fit into the design.
Thank you!
The standard solution for this is to give the base class two window procedures, a static one and a virtual one.
The base class registers its class with the static window procedure. The static window procedure then invokes the virtual window procedure. Many people omit the HWND parameter from the virtual version since it can be obtained from the this pointer, but I'll leave it in just to simplify the story.
class Window
{
public:
virtual LRESULT WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ return DefWindowProc(hwnd, uMsg, wParam, lParam); }
private:
static LRESULT CALLBACK StaticWndProc(
HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_NCCCREATE) {
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(
reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams);
}
Window *pThis = reinterpret_cast<Window*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
LRESULT lres = pThis ? pThis->WndProc(hwnd, uMsg, wParam, lParam)
: DefWindowProc(hwnd, uMsg, wParam, lParam);
}
};
Derived classes override Window::WndProc.
The window proc doesn't have to be the same for all instances of a particular class name.
Typically, you'd use the RegisterClass function to set the default window proc for windows of that class. When you create a new window that uses the class but you want it to override the default handling, you create the window and then call SetWindowLongPtr(hwnd, GWL_WNDPROC, newWndProc), where newWndProc is a pointer to the new window's window proc.
The new window's window proc can then handle the messages that it wants to override, and call DefWindowProc for the rest.
To construct a window with a new class name, have the constructor copy the class info for the inherited class and create a new class that's identical to that one, except for the name. Then expose a method that will allow the client to change class-specific things. The API functions you're interested in would be GetClassInfoEx and SetClassLong, SetClassWord or SetClassLongPtr.
Inheritance still makes sense in this world because the default processing is the same for every window of a particular class, and inherited classes inherit the default processing from their parents.
You don't need anything like an abstract static method for this. All you need is the window handle. You can get the class name by calling GetClassName with the window handle, and then call GetClassInfoEx with the returned class name.
Wow, I certainly didn't expect this...
I searched for the phrase x86 thunks on Google. And, as it turns out, I wasn't the first person to come across this problem (surprise!).
The first hit was the exact problem and the solution to this question about Window Procs, even though it had nothing to do with my query (or at least, very little to do directly)... hope someone else finds it useful too.

Why does clicking a child window not always bring the application to the foreground?

When an application is behind another applications and
I click on my application's taskbar icon, I expect the entire application to
come to the top of the z-order, even if an app-modal, WS_POPUP dialog box is
open.
However, some of the time, for some of my (and others') dialog boxes, only the dialog box comes to the front; the rest of the application stays behind.
I've looked at Spy++ and for the ones that work correctly, I can see
WM_WINDOWPOSCHANGING being sent to the dialog's parent. For the ones that
leave the rest of the application behind, WM_WINDOWPOSCHANGING is not being
sent to the dialog's parent.
I have an example where one dialog usually brings the whole app with it and the other does not. Both the working dialog box and the non-working dialog box have the same window style, substyle, parent, owner, ontogeny.
In short, both are WS_POPUPWINDOW windows created with DialogBoxParam(),
having passed in identical HWNDs as the third argument.
Has anyone else noticed this behavioral oddity in Windows programs? What messages does the TaskBar send to the application when I click its button? Who's responsibility is it to ensure that all of the application's windows come to the foreground?
In my case the base parentage is an MDI frame...does that factor in somehow?
I know this is very old now, but I just stumbled across it, and I know the answer.
In the applications you've seen (and written) where bringing the dialog box to the foreground did not bring the main window up along with it, the developer has simply neglected to specify the owner of the dialog box.
This applies to both modal windows, like dialog boxes and message boxes, as well as to modeless windows. Setting the owner of a modeless popup also keeps the popup above its owner at all times.
In the Win32 API, the functions to bring up a dialog box or a message box take the owner window as a parameter:
INT_PTR DialogBox(
HINSTANCE hInstance,
LPCTSTR lpTemplate,
HWND hWndParent, /* this is the owner */
DLGPROC lpDialogFunc
);
int MessageBox(
HWND hWnd, /* this is the owner */
LPCTSTR lpText,
LPCTSTR lpCaption,
UINT uType
);
Similary, in .NET WinForms, the owner can be specified:
public DialogResult ShowDialog(
IWin32Window owner
)
public static DialogResult Show(
IWin32Window owner,
string text
) /* ...and other overloads that include this first parameter */
Additionally, in WinForms, it's easy to set the owner of a modeless window:
public void Show(
IWin32Window owner,
)
or, equivalently:
form.Owner = this;
form.Show();
In straight WinAPI code, the owner of a modeless window can be set when the window is created:
HWND CreateWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent, /* this is the owner if dwStyle does not contain WS_CHILD */
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
or afterwards:
SetWindowLong(hWndPopup, GWL_HWNDPARENT, (LONG)hWndOwner);
or (64-bit compatible)
SetWindowLongPtr(hWndPopup, GWLP_HWNDPARENT, (LONG_PTR)hWndOwner);
Note that MSDN has the following to say about SetWindowLong[Ptr]:
Do not call SetWindowLongPtr with the GWLP_HWNDPARENT index to change the parent of a child window. Instead, use the SetParent function.
This is somewhat misleading, as it seems to imply that the last two snippets above are wrong. This isn't so. Calling SetParent will turn the intended popup into a child of the parent window (setting its WS_CHILD bit), rather than making it an owned window. The code above is the correct way to make an existing popup an owned window.
When you click on the taskbar icon Windows will send a WM_ACTIVATE message to your application.
Are you sure your code is passing the WM_ACTIVATE message to the DefWindowProc window procedure for processing?
Is the dialog's parent window set correctly?
After I posted this, I started my own Windows Forms application and reproduced the problem you describe. I have two dialogs, one works correctly the other does not and I can't see any immediate reason is to why they behave differently. I'll update this post if I find out.
Raymond Chen where are you!

Resources