the function CWnd::CreateControl succeeds, but m_hWnd is NULL - c++

I run the code with VC++ 6.0, everything is OK. But when run the same code under Visual C++ 2010, the handle of wnd(namely m_hWnd) is always NULL. Besides, the return value bRet is TRUE (i.e. success).
Here is my code:
BOOL CDemoDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
CRect rect;
GetClientRect(rect);
CWnd wnd;
BOOL bRet = wnd.CreateControl(_T("WMPlayer.OCX"), NULL, WS_VISIBLE, rect, this, 19089);
return TRUE; // return TRUE unless you set the focus to a control
}

The wnd object is going out of scope - try making it a member and checking what happens then. Also, if you are trying to assign a different handle to your dialog m_hWnd object, then you are making a mistake, since the m_hWnd should be valid for your dialog by the time that OnInitDialog is called (in response to the Create call), so you should not be reassigning the dialogs member window handle, but rather creating a separate member for it. Hope this helps.

Related

Wrong parent HWND in modal dialog

Why do i get desktop as a parent HWND for my modal dialog here?
class CSaveProfileAsDlg:
public CSimpleDialog<IDD_DLG_RESOURCE>
{
....
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
{
...
HWND parent = GetParent(); // or GetAncestor(m_hWnd, GA_PARENT);
assert(parent != GetDesktopWindow()); // not ok
...
}
....
}
//somewhere in code
//m_hWnd is some valid HWND
assert(m_hWnd != GetDesktopWindow()); //ok
CSaveProfileAsDlg dlg;
dlg.DoModal(m_hWnd /*as a parent wnd*/);
I can "solve" it by passing corret HWND in CSaveProfileAsDlg ctor, but i'd like to have correct solution.
Thank you!
The documentation is very confusing but I think I found the problem. DoModal internally calls ::DialogBox(), one parameter of which takes a HWND named hWndParent. From the documentation:
hWndParent [in, optional]
Type: HWND
A handle to the window that owns the dialog box.
The keyword here is the word "owns". The section about owned windows confirms this:
Dialog boxes and message boxes are owned windows by default. An application specifies the owner window when calling a function that creates a dialog box or message box.
So we actually talk about the owner window instead of its parent. This makes sense as the dialog is a free floating window and not part of a window hierarchy as "parenthood" would imply.
You can get the owning window by using:
HWND parent = ::GetWindow(m_hWnd, GW_OWNER);
I had a similiar issue. I was wondering why GetParent() return always a different CWnd*.
The right solution is simple, just pass the desired pWnd to the dlg Constructor.
It will be stored in the CDialog member variable m_pParentWnd.
Then you can always get the passed pWnd with this member variable in your Dialog.
//somewhere in code
//pWnd some valid CWnd pointer
CSaveProfileAsDlg dlg (pWnd); // relevant!
dlg.DoModal();
.
class CSaveProfileAsDlg:
public CSimpleDialog<IDD_DLG_RESOURCE>
{
....
LRESULT OnInitDialog(UINT, WPARAM, LPARAM, BOOL&)
{
...
CWnd* _pWnd = GetParent(); // not ok, returns probably CMainFrame or similiar
CWnd* pWnd = m_pParentWnd; // your parent Wnd
...
}
....
}
I've got two versions of the same application and one of them disables all parent popup windows as it should when DoModal is called. Second version disables only top-level CMainFrame and real parent is stay enabled so I can call modal dialog twice and more.
This happen in CWnd::GetSafeOwner_, line :
hWnd = ::GetLastActivePopup(hWnd);
Firsts version return real parent while second version return CMainFrame.
I've spent one day and could not find the cause of such behaviour. However I've found workaround:
When DoModal is called it Disable CMainFrame so I can disable it's children also:
afx_msg void OnEnable(BOOL bEnable);
ON_WM_ENABLE()
void CMainFrame::OnEnable(BOOL bEnable)
{
std::for_each(m_bars.begin(), m_bars.end(),
[=](const std::pair<EBar, BaseBar*>& bar)
{
bar.second->EnableWindow(bEnable);
});
}

Why constructor doesn't execute all the code using WinAPI?

This is my class constructor:
ActionButton::ActionButton(CallbackFunction function, void* param, HWND parent, int x, int y, int heigth, int width) :
m_function(function), m_parameters(param), m_window(NULL)
{
HWND m_window = CreateWindowEx(0, L"Action button", NULL, WS_CHILD | WS_VISIBLE,
x, y, width, heigth, parent, NULL, NULL, NULL);
DWORD dw = GetLastError();
SetWindowLongPtr(m_window, GWLP_USERDATA, (LONG_PTR)this);
ShowWindow(m_window, SW_NORMAL);
}
I used debuger and found that it executes CreateWindowEx() but after pressing F11 program jumped off the constructor (and I'm using only one thread). Is something wrong with my code?
After CreateWindowEx there is executing window procedure with parameters e.g WM_CREATE, so step after CreateWindowEx is not in constructor, after executing a few window procedure callbacks it goes back into constructor.
While executing CreateWindow[Ex] the system calls the window procedure associated with the window class for several messages (WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALCSIZE, WM_CREATE) before it returns. While the window procedure handles these messages the GWLP_USERDATA is not yet set. The system however guarantees, that GWLP_USERDATA is zero-initialized so you can safely query and handle the uninitialized GWLP_USERDATA.
If you want to set GWLP_USERDATA before CreateWindow[Ex] returns you will have to set up a CBT hook hook using SetWindowsHookEx and handle the HCBT_CREATEWND event. This lets you store any data attached to a HWND before the window procedure gets called with a WM_NCCREATE message.
Unrelated to your question, GWLP_USERDATA is fairly unreliable. A lot of applications will store their own data there, overwriting each other's data. Since this seems to be a private window class that you control you should allocate space in the Extra Window Memory instead and store your data there.

Is there any function that removes icon, using visual studio 6.0?

I couldn't find any function which removes a loaded icon. Please help me:))
Or is there any other function which makes an icon hidden such as setVisible(false), or delete?
if(GetDlgItem (IDC_BUTTON1)->IsWindowEnabled())
{
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
dc.DrawIcon(DT_CENTER,DT_CENTER, m_hIcon);
}
if(GetDlgItem (IDC_BUTTON1)->IsWindowEnabled()==0) //disabled
{ dc.SetTextColor(RGB(192,192,192));
m_hIcon = AfxGetApp()->RemoveIcon(IDI_ICON1);//HERE! // I try another icon
//which is null, however it didn't work because it is transparent.
}
Instead of painting another icon when the button is disabled, either draw a rectangle using a null pen and a brush of the background colour or just invalidate the icon-rectangle with bErase as TRUE when you disable the button
This code is a bit strange, especially since you don't give us any context. What is dc, a device context? Is this code inside of a OnPaint message handler function? And either way, why are you drawing the icon manually instead of letting the button control do it automatically?
The simpler approach is to monitor the enabled state of the control by listening for WM_ENABLE messages via the OnEnable member function, and calling the SetIcon member function to update the button's icon. This way, the button control keeps track of the icon, so there's no need to keep it in a member variable (m_hIcon). And removing an icon is as simple as setting it to display a null icon. There's no need or all of these ugly hacks, like using a second transparent icon, or drawing over the icon with a solid color rectangle.
Sample code, where CMyButton extends CButton:
void CMyButton::OnEnable(BOOL bEnable)
{
CButton::OnEnable(bEnable); // call the base class
if (bEnable)
{
// The button was enabled, so load and set the icon.
const HICON hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
this->SetIcon(hIcon);
}
else
{
// The button was disabled.
// First, retrieve the current icon from the button.
const HICON hIcon = this->GetIcon();
// Then, remove the icon from the button by setting a null icon.
this->SetIcon(NULL);
// Finally, delete the original icon to prevent memory leaks.
::DestroyIcon(hIcon);
}
}
It is, of course, possible to do it your way inside of the OnPaint function, if you absolutely must (though this is poor design). The trick is that the icon only gets drawn if the code to draw it gets executed. Otherwise, no icon gets drawn. The base class will not draw an icon.
So all you need is:
void CMyWindow::OnPaint()
{
CPaintDC dc(this);
const CWnd* pBtn = GetDlgItem(IDC_BUTTON1);
if (pBtn->IsWindowEnabled())
{
m_hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);
dc.DrawIcon(DT_CENTER, DT_CENTER, m_hIcon);
// make sure that you delete m_hIcon when the window is destroyed!
}
else
{
// Do not draw the icon here!
// But write whatever other code you want, like...
dc.SetTextColor(RGB(192,192,192));
}
}
Obviously this tactic will only work if your code is inside of the OnPaint function, but that is where you should do all of your drawing. Otherwise it will be lost whenever the window is repainted. For a demonstration, just try minimizing the window or moving it off the screen. Force a repaint by calling CWnd::Invalidate, followed by CWnd::UpdateWindow (or alternatively `CWnd::RedrawWindow).

MFC: Creating modeless dialog box without displaying

I'm trying to create a simple modeless dialog box which I'm creating from my CWinApp derived InitInstance() function.
BOOL CMyApp::InitInstance()
{
...
m_pMyDialog = new CMyDialog();
m_pMyDialog->Create(CMyDialog::IDD);
...
retrun TRUE;
}
I've created the dialog template in the resource editor and the WS_VISIBLE bit is unset. My intention is to avoid showing the dialog until I explicitly call ShowWindow(SW_SHOW) but for some reason the call to Create displays the dialog.
I've tried to change the return value of OnInitDialog() to FALSE but that doesn't work.
I've even tried to call ModifyStyle() in case something else is setting the WS_VISIBLE bit.
int CMyDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
ModifyStyle(WS_VISIBLE, 0);
return 0;
}
That doesn't work either. In all cases, after I call Create the dialog is displayed which isn't how I've read it should work.
The problem was with AnimateWindow() which was causing the dialog to display prematurely.

RegisterClassEx Fails as Invalid Parameter - C++

A call to RegisterClassEx in my application is failing with error code 87, "The parameter is incorrect."
memset( &m_wcx, 0, sizeof(WNDCLASSEX) );
m_wcx.cbSize = sizeof(WNDCLASSEX); // size of structure
m_wcx.style = WS_ICONIC; // initially minimized
m_wcx.lpfnWndProc = &WndProc; // points to window procedure
m_wcx.cbClsExtra = 0; // no extra class memory
m_wcx.cbWndExtra = 0; // no extra window memory
m_wcx.hInstance = m_hInstance; // handle to instance
m_wcx.hIcon = ::LoadIcon( NULL, IDI_APPLICATION ); // default app icon
m_wcx.hCursor = ::LoadCursor( NULL, IDC_ARROW ); // standard arrow cursor
m_wcx.hbrBackground = NULL; // no background to paint
m_wcx.lpszMenuName = NULL; // no menu resource
m_wcx.lpszClassName = _pwcWindowClass; // name of window class
m_wcx.hIconSm = NULL; // search system resources for sm icon
m_atom = ::RegisterClassEx( &m_wcx );
if ( m_atom == 0 )
{
TRACE(_T("CNotifyWindow::CNotifyWindow : Failed to register window class.\r\n\tError: %d\r\n\tFile: %s\r\n\tLine: %d\r\n"), ::GetLastError(), __WFILE__, __LINE__);
THROW(::GetLastError());
}
Does anyone know what I'm doing wrong? Thanks.
The style member of the WNDCLASSEX structure accepts class styles, not window styles. In other words, you can't make all windows of that class initially minimized that way.
You should pass WS_ICONIC in the dwStyle argument to CreateWindow() or CreateWindowEx() instead.
The first thing is the WS_ICONIC. The window class style is something entirely diferent from window style. The class styles are the CS_* ones.
Usually "The parameter is incorrect" is the WINAPI's way of saying, "dude, you're sending me crap."
So one of the WNDCLASSEX member variables is probably crap. Start by taking a closer look at the variables that are most likely to have something inappropriate in them: m_wcx.hInstance, m_wcx.lpfnWndProc, and m_wcx.lpszClassName.
EDIT:
As pointed out by #Johann Gerell, m_wcx.style = WS_ICONIC is an example of this. The documentation says that this is a class style, but you've sent a window style. No good.
What's the difference? Well, you know the difference between a C++ class and an object, right? A class is like a blueprint. An object is an instantiation of that blueprint. Same is true of Window Classes & Windows. A Window Class is a blueprint for creating a window, and a window is an instantiation of that Window Class. Window Classes have styles that specify things like what kind of DC to use, when to vertical refresh -- low level stuff like that which applies to every instance of that window class. Windows also have styles, but these are different. Window styles specify per-window things like if the window should be visible, minimized, etc. So RegisterClassEx asked you for an orange, and you tried to give it an apple.