Cannot create window (CreateWindowEx) with existing child class - c++

I have a parent window and a few child windows attached to this. With SpyXX I can see the children all have a certain style class, lets say ChildWindowClass.
When I create the window with the name of this particular class, CreateWindowEx returns a NULL handle. If I use my own class and just set the parent, the window is a child window, but - of course - has a different class as all the other children.
If I get me the style and then set it, the style is found, but not set for my child window. It still shows the style used with CreateWindowEx
HWND firstChild = FindWindowEx(MyClass::_parent, NULL, szFsxChildWindowClass, NULL);
LONG childStyle = GetWindowLong(firstChild, GWL_STYLE);
...
SetWindowLong(MyClass::_child,GWL_STYLE, childStyle);
The ChildWindowClass is not registered by me, so I can not crosscheck how it is registered. So how can I set this style for my child window?
-- Edit call as requested --
child = CreateWindowEx( WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR,
szWindowClass, // this is where I want to place the name of the child class
_T("Test"),
WS_CHILDWINDOW | WS_VISIBLE,
x,y, // 0,0
w, h, // 500,100
MyClass::_parent, // parent
NULL,
MyClass::_hInstance, // must this be 0??
NULL
);

Check GetLastError. If it's nonzero, you're most probably misusing API. If it is 0, it means that window procedure explicitly failed the creation by returning FALSE from WM_NCCREATE or WM_CREATE.
When handling these messages the window procedure has access to all parameters that you pass to the function (styles, title, coordinates, parent window and menu), and that specific window class may require additional data to be passed via lpCreateParams, or even in title or coordinates, failing the creation otherwise.
Set breakpoint or hook WM_CREATE for windows of that class and examine how those existing child windows were created, what were the parameters. (Assuming you don't just have documentation on it!)

Related

How to set control focus inside an MFC custom control

Experts!
I am using a class that inherits CWnd to make the content visible using a horizontal scroll bar
The control I want to create looks like this:
However, I have some problems and leave a question
When the button receives focus, it changes to blue. If another button is pressed, the button that received the existing focus should be unfocused.
The button does not release focus as shown in the second picture.
However, the above problem occurs when implemented in Dialog, not in SDI.
I need help solving this problem.
Custom Control Create Code;
m_ScrollWnd.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 1234);
BOOL CScrollWnd::Create(DWORD dwStyle, CRect &rect, CWnd *pParent, UINT nID)
{
dwStyle |= ((WS_HSCROLL) );
return CWnd::Create(CScrollWnd::IID, nullptr, dwStyle, rect, pParent, nID);
}
m_Button3.Create(_T("Hello3"), WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(0, 0, 0, 0), this, 1238);
The so called "default button handling" is done by a function named IsDialogMessage.
The easiest way to control this is to make your parent control a window derived from CDialog, or if it's a view derive from CFormView. The MFC will handle all this for you in the appropriate PreTranslateMessage handler.
If you want to do this by your own you might insert your own PreTranslateMessage handler and use IsDialogMessage. The CWnd class also has a predefined implementation named CWnd::PreTranslateInput.
So this might be sufficient:
BOOL CYourParentClass::PreTranslateMessage(MSG* pMsg)
{
// allow standard processing
if (__super::PreTranslateMessage(pMsg))
return TRUE;
return PreTranslateInput(pMsg);
}
Using CFormView / CDialog is the better way from my point of view, because also other "problematic things about dialogs" are solved in it. Including loosing and getting focus and activation...
Official document from MSDN: Dialog Box Keyboard Interface
BTW, xMRi explains it very well.

Switch between edit controls using Tab?

The Window is non DialogBox based so WS_TABSTOP doesn't work. Moreover I don't want to Tab through all the controls, I just want to Tab through few Edit controls.
What I did is I superclassed the Edit control and handled the WM_KEYDOWN message, switching between edit controls, by getting next window in the line thorugh ::GetWindow(hwnd,GW_HWNDNEXT); Also I would like to switch focus back to the first Edit control when I have reached the last one.
The Code doesn't work for when I have reached the last Edit control, the ::GetWindow simply returns the next window in the line(?), which happens to be a non superclassed edit control. And there are more hidden child windows(SW_HIDE).
Maybe if I know how to know the class name of the window's HWND ?
Note: Pure Win32 api, c++ oop.
else if ( ( int ) wParam == VK_TAB )
{
HWND nextInLine;
nextInLine = ::GetWindow ( hwnd, GW_HWNDNEXT );
if ( hwnd == NULL ) nextInLine = ::GetWindow ( hwnd, GW_HWNDPREV );
::SendMessage ( nextInLine, EM_SETSEL, ( WPARAM ) 0, ( LPARAM ) -1 );
::SetFocus ( nextInLine );
return 0;
}
You get keyboard navigation for free in any window by using the IsDialogMessage API call. To consume the service a window message loop has to be modified to include a call to IsDialogMessage and only pass the message on to regular message handling if it hasn't been handled by the dialog manager already.
MSG msg = { 0 };
while (GetMessage(&msg, NULL, 0, 0)) {
if (IsDialogMessage(hwnd, &msg)) {
/* Already handled by dialog manager */
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Don't forget to set the WS_EX_CONTROLPARENT extended window style on the parent window, so that the dialog manager recurses into child windows.
It's possible to get away with just calling IsDialogMessage, but the result isn't quite 100% dialog-like. To make an ordinary window behave like a dialog:
Specify DLGWINDOWEXTRA as the cbWndExtra field of your WNDCLASS (don't forget to add on extra space you might already be using and offset your data's indexes)
Call DefDlgProc rather than DefWindowProc
Since this makes your window a dialog, you need to use the DWLP_USER window long instead of GWLP_USERDATA, if you're using that, when calling GetWindowLongPtr or SetWindowLongPtr.
(From memory, the main thing you get from doing the above is support for WM_NEXTDLGCTL, which I've found useful to use for supporting changing focus using the Enter key, using Method I described in http://support.microsoft.com/kb/102589.)
Then in your message pump, call IsDialogMessage for each dialog-like window in your message pump.
Finally, when creating controls for your dialog-like window, set the WS_TABSTOP window style for each window you want to participate in the tabbing, and set the WS_EX_CONTROLPARENT window exstyle (aka Control Parent in the resource editor) for child windows that contain dialog controls.

Is it necessary to destroy a tooltip?

In my application I am handling the WM_HELP message and then creating a tooltip for a control using this method:
Taken from: http://msdn.microsoft.com/en-us/library/bb760252(v=vs.85).aspx
HWND CreateToolTip(int toolID, HWND hDlg, PTSTR pszText)
{
if (!toolID || !hDlg || !pszText)
{
return FALSE;
}
// Get the window of the tool.
HWND hwndTool = GetDlgItem(hDlg, toolID);
// Create the tooltip. g_hInst is the global instance handle.
HWND hwndTip = CreateWindowEx(NULL, TOOLTIPS_CLASS, NULL,
WS_POPUP |TTS_ALWAYSTIP | TTS_BALLOON,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
hDlg, NULL,
g_hInst, NULL);
if (!hwndTool || !hwndTip)
{
return (HWND)NULL;
}
// Associate the tooltip with the tool.
TOOLINFO toolInfo = { 0 };
toolInfo.cbSize = sizeof(toolInfo);
toolInfo.hwnd = hDlg;
toolInfo.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
toolInfo.uId = (UINT_PTR)hwndTool;
toolInfo.lpszText = pszText;
SendMessage(hwndTip, TTM_ADDTOOL, 0, (LPARAM)&toolInfo);
return hwndTip;
}
The tooltip vanishes as soon as I move my mouse pointer.
My questions are:
Is tooltip is destroyed or is it just hidden ?
If it is hidden then how to destroy it and when?
Thanks.
It's been a while since I've done any WinAPI programming but if my memory serves me...
The call to CreateWindowEx passes the hDlg as the hWndParent parameter meaning the dialog window is now the parent of the tooltip.
From the MSDN documentation on the DestroyWindow function it says:
If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.
So you can assume your tooltip window will be destroyed eventually. Be careful if you are calling CreateToolTip in response to every WM_HELP message as you will end up with a number of tooltip windows hanging around in memory until your dialog is closed and DestroyWindow is finally called.
As vz0 pointed out you could create the tooltip once, hang on to the window handle, then show the tooltip in response to the help message rather than creating it again.
In your comment to vz0's answer you said:
there are multiple ways in which a tooltip goes awya. example: mouse move, timeout etc.
All of those only result in the window being hidden so the handle to the tooltip is still valid and can be redisplayed using ShowWindow.
For every CreateWindowEx call you need a matching DestroyWindow call.
As an alternative, instead of creating and destroying the window every time you can use the ShowWindow call with SW_SHOW and SW_HIDE to show and hide the popup.
In my experience, I had to DestroyWindow() on the tooltip so an HFONT (font GDI resource) was properly released. There was a parent-child bond of the two windows at one time - but my system changes this at run-time and could be to blame. Probably no harm in doing it if your system generalizes it.

How to create controls at runtime?

How to create dynamic MFC controls and handle message maps of the controls at runtime?
It really depends on which controls do you want to create, especially if you want to know which flags should you set. In general it goes down to this:
Normally a CWnd-derived control is created using Create or CreateEx. For a CButton, for instance:
CButton button;
button.Create("Button text", WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | DT_CENTER, CRect(5, 5, 55, 19), this, nID);
where the CRect specifies the button position, this is a pointer to the parent window, and nID is the control ID.
If the control doesn't come out as expected, it's probably because some flags are missing. I suggest you draw a sample control in design mode, check out the code for that control in the RC file, and copy the flags to the Create caller.
As for the message maps, they are normally routed to the parent window. The nID value you used in Create is important here, because it will be the number that identifies the control in the message map. If you have a fixed number of controls, you can hard-code the nID numbers for your controls (starting at 10000, for instance); if not, you'll have to provide a way for the parent window to identify them. Then you just add the message map entries.
ON_BN_CLICKED(10000, OnBnClicked)
ON_CONTROL_RANGE(BN_CLICKED, 10010, 10020, OnBtnsClicked)
You can use the ON_CONTROL_RANGE message map to map a range of IDs to the same function.

create a control programmatically using MFC

I just wonder how to do it.
I write :
CEdit m_wndEdit;
and in the button event handler (dialog app),
I write :
m_wndEdit.Create(//with params);
but I still don't see the control appear in the UI.
I actually wrote this in the button handler :
CWnd* pWnd = GetDlgItem(IDC_LIST1);
CRect rect;
pWnd->GetClientRect(&rect);
//pWnd->CalcWindowRect(rect,CWnd::adjustBorder);
wnd_Edit.Create(ES_MULTILINE | ES_NOHIDESEL | ES_READONLY,rect,this,105);
wnd_Edit.ShowWindow(SW_SHOW);
this->Invalidate();
id 105 doesn't exist. (I used it in the Create member function of CEdit). I just put it in there. isn't it supposed to be the id you want to give to the new control ? Should it already exist ?
Check with the following set of flags as the example mentioned in MSDN:
pEdit->Create(ES_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_NOHIDESEL | ES_READONLY,
rect, this, 105);
The Invalidate() is not necessary
Add the WS_VISIBLE flag to your create flags, you don't need the ShowWindow
You are creating the button on the location where IDC_LIST1 is - you probably want to do pWdn->Destroy() after the GetClientRect()
The id you pass to Create() can be anything, of course if you want to handle messages from this button later you'll need to use the correct id. In that case it's easiest to manually add an entry to resource.h.
What do you mean with 'I put this code in the button event handler' - which button? A different one from the one you're trying to create, I may hope? Does your code get called at all, does it stop when you put a breakpoint in? What's the value of wnd_Edit->m_hWnd after the call to Create()?
wnd_Edit is a member of your dialog, right, and not a a function local variable?
What is wnd_Edit exactly? If it's a local variable in that function, that is likely the problem. The CWnd destructor destroys the window associated with the CWnd. So when wnd_Edit goes out of scope, the edit box is destroyed too.
If that's not it, check the return value of Create(). Is it NULL? If it is, check the value of GetLastError().