how to know if my control is visible or not - c++

I have a dialog containing controls (edits, combobox, etc...) some are visible and some or not.
What in a function, I want is looping on all controls and get the last shown control.
I want to add that when creating the dialog, I set the visibility to some controls as SW_HIDE and others to SW_SHOW.
What I did is using the ::IsWindowVisible, but returns false even if I set the visibility to SW_SHOW.
NB: the function is called just after the creation of the dialog, the dialog is not yet visible.

The control is not visible at the time you call the function, because the dialog that contains it is not visible. As per the documentation for the IsWindowVisible function:
If the specified window, its parent window, its parent's parent window, and so forth, have the WS_VISIBLE style, the return value is nonzero. Otherwise, the return value is zero.
This not only explains the behavior that you're seeing, but also suggests a possible solution. If you want to know whether a particular window has the WS_VISIBLE style bit set (and don't care about any of its ancestors), then just retrieve that window's styles and test for the presence of the WS_VISIBLE bit directly. For example:
LONG_PTR wndStyles = GetWindowLongPtr(hwndCtrl, GWL_STYLE);
bool isVisible = (wndStyles & WS_VISIBLE) == WS_VISIBLE;
That said, I don't really understand why you would need to do this. If your dialog-initialization code sets the visibility of controls, then you know what their visibility is. You don't need to retrieve it dynamically at run-time. In other words, this sounds like an X-Y problem. I suspect there is a better way to write your code so that this whole issue is a non-issue.

Related

Get window icon: GetClassLong VS SendMessage

There are two methods to get window icon if i know his handle:
SendMessage(HWND,0x7F lParam, wParam)
and
GetClassLong(HWND, -14|-34)
But even if I get icon from window with GetClassLong i can't set new icon with SetClassLong, but successfully set new icon with SendMessage.
I need to know: why in some times work second get method, but doen't work first method. And why always from SendMessage(WN_SETICON) and doen't work SetClassLong(HWND, -14|-34, HICON)?
GetClassLong retrieves longs from the window class.
A window class is a blueprint for creating a window of a specified type, not the window itself.
It can contain quite a lot of defaults, like the default icon, and the default small icon.
But a window is only based on it, it can override everything.
Thus, setting the windowclass' icon does not modify any already created classes, you must send a message to the window instead.
And reading the windowclass-data gets you stale data, which might or might not still be relevant to the window.
As an aside, -14|-34 would be GCL_HICON|GCL_HICONSM, or -2, which does not actually make sense.
Explicitly say that you read with both indices one after the other.
-14 is GCL_HICON which is the (optional resource) icon for the class specified when its registered.
A specific window can subsequently specify its own icon (WM_SETICON), subsequent changes to
GCL_HICON won't affect it.
I also doubt you can attempt to pull GCL_HICON | GCL_HICONSM, if they were different what would the value be?
A few additional things:
1) Don't use magic numbers for Windows API constant values. Use WM_GETICON, not 0x7F. Use the GCL_ names as mentioned by the other answers.
2) You switched wParam and lParam in your SendMessage(). wParam comes first.
3) Don't use GetClassLong(); it is not 64-bit safe (and icon handles are pointers). Use GetClassLongPtr() instead. Also substitute GCLP_ for GCL_ in your named constants.
4) Don't try to replace | in your GetClassLong() with || or with an array of indices and expect that to work either. You don't have a choice but to make two calls.

Parent-Less Button

Can I create a button without a parent in WINAPI?
I tried doing:
CreateWindowEx(0, "Button", "BTN", WS_POPUP | BS_PUSHBUTTON, 0, 0, 15, 15, nullptr, nullptr, nullptr, nullptr);
then setting the parent to a specified window later on and also showing the button using ShowWindow. This indeed created a fine looking button.
However, the button has no ID and cannot be Identified in WM_COMMAND because the ID is 0.. If two buttons were parentless, there'd be no way to tell them apart. Now if I give it an ID through the HMENU parameter:
CreateWindowEx(0, "Button", "BTN", WS_POPUP | BS_PUSHBUTTON, 0, 0, 15, 15, nullptr, 15, nullptr, nullptr);
GetLastError() prints "Invalid Menu Handle" and the button will not be created.
If I give it no parent and WS_CHILD, it will say cannot create a top level child window which is understandable.
So what I did was I set the Parent to GetDesktopWindow() and give the button an ID. That works but the button isn't parentless..
So is there a way to give a button an ID (So as to identify it in WM_COMMAND) and at the same time, have its parent NULL so that I can set the parent later? How does Windows Forms do it? The buttons can be parentless until you do Form.add(ButtonName);
Can the same effect be achieved in WINAPI?
This is appears on its face to be a very silly sort of question.
Button controls are by definition child controls, so the call to the CreateWindowEx function you use to create the button should also be specifying the WS_CHILD style.
Of course, as you mention, you cannot create a child control with no parent; you'll get an error. There is no such thing as a top-level child window.
So then, the answer to the initial question
Can I create a button without a parent in WINAPI?
is clearly no. Buttons are child controls, and all child controls must have a parent.
Just because Windows let you get away with specifying the WS_POPUP flag when you create a button control doesn't mean that it's a valid combination.
I strongly recommend re-reading the documentation for the CreateWindowEx function. In particular, note that the hMenu parameter is overloaded with respect to its meaning. If you are creating an overlapped or pop-up window (WS_OVERLAPPED or WS_POPUP), it specifies a handle to a menu. If you're creating a child window (WS_CHILD), it specifies the identifier of the child window. The fact that the same parameter is used for both things, depending on the style of the window, should tell you something.
How does Windows Forms do it? The buttons can be parentless until you do Form.add(ButtonName);
They most certainly cannot. The button controls are not created until you add them to a form or other parent control. The System.Windows.Forms.Button class constructor does not create a Win32 window. It just holds a collection of necessary styles used to create the underlying Win32 window when appropriate.
You could, of course, do the same thing by writing a C++ Button class. A simple implementation would just have member variables corresponding to the parameters of CreateWindowEx and a Create member function that would actually call CreateWindowEx to create the Win32 window once all of the members had been set. The Create method could throw an exception if one of the necessary members had not yet been set to a valid value.
I solved it. I had to pass HWND_MESSAGE as the Parent Parameter. When you call SetParent, that parameter gets changed to the Parent's handle and all is well.
No, this really is not a "solution" to the problem. As kero points out, you've simply set the button control's parent to the message-only window. Again, this might appear to work, but it's a rather strange thing to do and I hardly recommend it as a solution.
If you really want to hack it, I recommend creating your own hidden top-level window to use as a parent for your "unparented" child controls. Then you could use the same trick of calling SetParent to reparent them.
I solved it. I had to pass HWND_MESSAGE as the Parent Parameter. When
you call SetParent, that parameter gets changed to the Parent's handle
and all is well.
No, you didn't get "Parent-Less Button": the parent window of your message-only button is the "main" message-only window (class "Message").

Custom MFC control contains another control - messages not getting through

I have a custom CWnd-derived MFC control, which works like this:
the control has its own OnPaint, and a black background
clicking anywhere on the control causes an edit control to appear at that location, borderless and with black-background, so it blends in
the user types in this box and hits enter, the box disappears and the control's custom paint functionality renders the same text in the same position on the background.
So our control owns a CCustomEdit, when you click on the background the control is either created or moved, and made visible:
CCustomEdit::Show(Rect &rc,CCustomControl *pParent)
{
if ( !::IsWindow( m_hWnd ) )
{
Create( ES_LEFT | ES_AUTOHSCROLL | WS_CHILD | ES_NOHIDESEL | ES_CENTER | ES_UPPERCASE, rc, pParent, 999 );
}
else
MoveWindow( &rc );
}
The main parts actually work OK (and we're stuck with the approach). But one thing that's not working is that CCustomEdit self-registers for EN_CHANGE events and so on. When CCustomEdit is created as a normal dialog control (CEdit on the dialog template, DDX-bound to a CCustomEdit variable) these work, but within CCustomControl they are not.
CCustomEdit::PreSubclassWindow() calls SetEventmask() and is being called. And CCustomEdit's ON_CHAR handler is also being called for key-presses in the edit box, however the handlers for edit-box messages like EN_CHANGE are not.
Are there any obvious things like changing the style flags? Otherwise, why is my custom control stopping these events reaching the contained edit control?
I'm not sure I understand the situation, but I have a number of control that work roughly in the same way as what I think is happening and they all work, it is possible.
EN_CHANGE for the edit control is send to your CWnd-derived control. Are you reflecting the messages? Have you tried if EN_CHANGE gets to the custom control? From what you are describing, you are expecting EN_CHANGE to end up in CCustomEdit's message dispatcher macro chain automatically, but it doesn't; you need the help of the containing window. Now MFC does most of that for you in a CDialog, but if you roll your own you need to do it manually, or use the message reflection macro's.
I found it... somehow, my SetEventMask() was being overriden. I don't know how or where but when I added an extra call later on to test, most event handlers started getting called.
I can only assume some part of the init code in MFC is responsible.

how to find a window's SW_SHOW/SW_HIDE status

I am trying to determine a window control's visibility that has been hidden or enabled with CWnd::ShowWindow(). (or ::ShowWindow(hWnd,nCmdShow))
I cannot simply use ::IsWindowVisible(hWnd) as the control is on a tab sheet, which may itself be switched out, causing IsWindowVisible to return FALSE.
Is there a way to get the SW_SHOW/HIDE (or others) window status or do I need to use the retun value of ShowWindow() and reset accordingly?
edit:
as the control is enabled (or disabled) to show, but may not be currently visible, as the tab is switched ot, I would think that it's SW_SHOW status would remain the same, even if the window itself is not actually switched in. If I'm unrealistic in my expectations that that's fine.
So really I'm looking for 'can this window/control be shown'
Call GetWindowLong( handle, GWL_STYLE), check the returned value for WS_VISIBLE style presence.
Use GetWindowPlacement. It fills WINDOWPLACEMENT structure, which has field showCmd.
showCmd
Specifies the current show state of the window. This member can be one of the following values.
I would use GetWindowPlacement, however I am not sure if I understood what you want.
It fills in a WINDOWPLACEMENT structure and then use the showCmd member.
GetWindowPlacement() function will work only if the window is maximized or minimized. Otherwise, showCmd member will return SW_SHOWNORMAL also when window is hidden, as pointed out in this StackOverflow answer: WINDOWPLACEMENT's showCmd... always 1?
You can use the more straightforward boolean function IsWindowVisible() to get if the specified Window is in a visible state or not.
If it is a multi-tab dialog and not a control, then override as
void MyClass::OnShowWindow(BOOL bShow, UINT nStatus)
{
m_nCmdShow = bShow;
CDialog::OnShowWindow(bShow, nStatus);
}
In BEGIN_MESSAGE_MAP, add ON_WM_SHOWWINDOW().
m_nCmdShow now has the status if the window is SW_SHOW or SW_HIDE.
I don't know if there is a proper method for this task but I would try WindowFromPoint Function.
Remarks
The WindowFromPoint function does not retrieve a handle to a hidden or
disabled window, even if the point is
within the window. An application
should use the ChildWindowFromPoint
function for a nonrestrictive search.
For example I would convert control's corner coords into screen coords and then try to get it's handle from those points.

How can I check if a window has WS_VISIBLE to set? (or if is visible)

How can I do it? It's an external window, not from my program. Thanks
One nuance to be aware of. IsWindowVisible will return the true visibility state of the window, but that includes the visibility of all parent windows as well.
If you need to check the WS_VISIBLE flag for a specific window you can do GetWindowLong(hWnd, GWL_STYLE) and test for WS_VISIBLE.
... It sounds like you don't need to do this for your case, but adding this for future reference in case others run across this question.
Do you have an HWND to the window? If not, then you will need to obtain the window handle somehow, for example through FindWindow() (or FindWindowEx()).
Once you have the HWND to the window, call IsWindowVisible().