RegisterClassEx Fails as Invalid Parameter - C++ - 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.

Related

How to show Cdialog with std::async

I have a derive class named A was inheritance from CDialog, I created the object to A named a and want to utilize the member function domodal to show dialog. Nonetheless, this dialog cannot show and parent window was block.
A a(this);
auto DlgResult = std::async(std::launch::async, &A::DoModal,&a);
DlgResult.wait();
if (DlgResult.get() == IDOK)
{
std::wstring ss = a.get_text_fromdlg();
}
Can someone help me, thanks!
If I were you, I wouldn't wrestle w/ the Async and DoModal since the purpose of DoModal() is to wait for the response from the dialog to let the app know how to move forward..
Below, I've added a simpler option. Just create member variable pointer to a Dialog class, and then use Show Window. Also, in this instance, you may consider making the dialog topmost so you don't lose focus of it.
MFCClass1* m_pDlg = new MFCClass1();
void CMFCApplication1Dlg::OnBnClickedButton1()
{
m_pDlg->Create(IDD_DIALOG1);
m_pDlg->ShowWindow(SW_SHOWNORMAL);
SetWindowPos(&m_pDlg->wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
}

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.

C++ - WINAPI - Object-oriented approach to closing a window

While trying to create a nice wrapper around Win32 specific GUI components, I eventually ran into a problem. The problem is that I'm unable to close the application after the windows I created no longer exist.
My API works like this:
/// ----------------------------
/// #author God
/// #project Helixirr Widgets
/// ----------------------------
#include <helixirrwidgets/HelixirrWidgets.hpp>
int main(void){
HelixirrWidgets::Window __windows[2] = {HelixirrWidgets::Window("Big Window"), HelixirrWidgets::Window()};
__windows[0].position(200, 200);
__windows[0].size(800, 600);
__windows[0].visible(true);
__windows[0].save_changes();
__windows[1].name("Tiny Window");
__windows[1].position(10, 100);
__windows[1].size(400, 200);
__windows[1].visible(true);
__windows[1].save_changes();
while(__windows[0].active() || __windows[1].active()){
if(__windows[0].visible()){
__windows[0].show();
}
if(__windows[1].visible()){
__windows[1].show();
}
}
return 0;
}
In method of HelixirrWidgets::Window called "active", which is declared like this
inline bool active(void) const noexcept;
I can check, whether my window is active or not.
This method basically return a const reference to a boolean member variable of an instance. This member variable is modified in "show"-method of the same class. Here's the definition:
void Window::show(void){
if(GetMessage(&_m_opHelper->message, _m_opHelper->handle_window, 0, 0)){
if(_m_opHelper->message.message == WM_CLOSE){
_m_bActive = false;
return;
}
TranslateMessage(&_m_opHelper->message);
DispatchMessage(&_m_opHelper->message);
ShowWindow(_m_opHelper->handle_window, SW_SHOWDEFAULT);
UpdateWindow(_m_opHelper->handle_window);
_m_bActive = true;
return;
}
_m_bActive = false;
}
Do note I use pimpl-idiom to hide platform-specific structures ("_m_opHelper" is pointer to implementation).
It may look like it works, but it doesn't and I can't understand why. It all comes down to a simple question: how can I close my window implemented using WINAPI specific functions and structures to be closed appropriately by a user of my application?
I guess the cause of the issue is related to the fact WM_CLOSE simply is not last message HWND gets. Messages like WM_DESTROY, WM_NCDESTROY and possibly more (depending on the particlar window and its state) will come after WM_CLOSE, leading to the assignment _m_bActive = TRUE.
I.e. the window becomes inactive for very short time, and (likely) they will never be inactive at the same time, causing an endless loop in main().

the function CWnd::CreateControl succeeds, but m_hWnd is NULL

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.

CWnd::CreateDlgIndirect leaves m_hWnd==NULL

A dialog I'm working on isn't displaying, using:
CWnd::CreateDlgIndirect(LPCDLGTEMPLATE lpDialogTemplate,CWnd* pParentWnd, HINSTANCE hInst)
The call to CreateDlgIndirect is in a lon-used base-class, which effectively takes the IDD of the dialog template in the resource file - it works fine for many other dialogs but I can't see what's different in my dialog. My dialog works fine when created in a more normal way, but I have to use the base class as it has loads of other functionality built in.
What I find when trawling through CWnd::CreateDlgIndirect in dlgcore.cpp, is that the plain Win32 API call is failing:
hWnd = ::CreateDialogIndirect(hInst, lpDialogTemplate,pParentWnd->GetSafeHwnd(), AfxDlgProc);
I can't step into that function for some reason, so all I see is the HWND is NULL.
Can anyone suggest what kind of problems might be causing this? I compared the two dialog resource templates and their properties are the same.
edit: I have one custom control on the dialog. When I remove this, it works. No idea why, what difference might this make?
One of the more obscure ways for CreateDialogXXX to fail is for a child control on the dialog to fail creation. Usually because the application has not initialized the common controls library before attempting to effect the dialog creation. See InitCommonControlsEx
One way to check this is to open the dialog in the resource editor, go to the dialog's properties, and find and turn on the DS_NOFAILCREATE flag. Usually called something obscure like "No Fail Create". Or add the DS_NOFAILCREATE directly to your dialog template in memory. This will allow the dialog to show, and the culprit should be evident by its absence.
In the case that the child control is an actual custom control - well the custom window class is either not registered correctly, or at all. Check the HINSTANCE used in registration - unless the CS_GLOBAL flag is specified, window classes are identified by (hInstance, ClassName) - this prevents window classes using the same name in different dlls conflicting.
A custom CWnd derived control fails, if you use the wrong HINSTANCE. When using a satelite DLL for the language resources, here's what I had to change:
// ----------------------------------------- //
// RegisterWndClass
// ----------------------------------------- //
/*static*/ BOOL MyCtrl::RegisterWndClass() {
WNDCLASS windowclass = {0};
// !! THIS IS THE IMPORTANT PART: !!
HINSTANCE hInst = AfxGetResourceHandle(); // NOT AfxGetInstanceHandle();
if(!(::GetClassInfo(hInst, MYCTRL_CLASSNAME, &windowclass))) {
//If not then we have to register the new class
windowclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
windowclass.lpfnWndProc = ::DefWindowProc;
windowclass.cbClsExtra = windowclass.cbWndExtra = 0;
windowclass.hInstance = hInst;
windowclass.hIcon = NULL;
windowclass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_IBEAM);
windowclass.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW);
windowclass.lpszMenuName = NULL;
windowclass.lpszClassName = MYCTRL_CLASSNAME;
if(!AfxRegisterClass(&windowclass)) {
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}