CWnd::CreateDlgIndirect leaves m_hWnd==NULL - c++

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;
}

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);
}

COleBusyDialog customization

I would like to customize COleBusyDialog dialog before I call DoModal on it. I am fine with buttons and layout. However I would like to have different static text inside it. How can I change it?
I see it has public member COleBusyDialog::m_bz which is used to customize it:
typedef struct tagOLEUIBUSY
{
DWORD cbStruct;
DWORD dwFlags;
HWND hWndOwner;
LPCTSTR lpszCaption;
LPFNOLEUIHOOK lpfnHook;
LPARAM lCustData;
HINSTANCE hInstance;
LPCTSTR lpszTemplate;
HRSRC hResource;
HTASK hTask;
HWND *lphWndDialog;
} OLEUIBUSY, *POLEUIBUSY, *LPOLEUIBUSY;
I am new to mfc and I don't know if i have to create new dialog in resources and assign it to this struct or is there simple way to modify the text.
Derive from COleMessageFilter and overide OnBusyDialog. To use your customized message filter, replace AfxGetThread()->m_pMessageFilter. Then delete the previous message filter and call Register() on the new one.

CFolderPickerDialog - No MFC

I'm trying to figure out if it is possible to use OR re-create the CFolderPickerDialog dialog without using MFC, or if there has been an attempt. So far I did not find a lot of hints. This old question does not seem to help me either.
I currently open the normal folder dialog with SHBrowseForFolder. But I need an Explorer-style dialog.
Here is the Explorer-style dialog (MFC) from another application:
#include <afxdlgs.h> requires MFC. I cannot use MFC in this specific project.
Is there a way to do this without using MFC ?
Honestly, I didn't even know that MFC had wrapped this. My class library has its own implementation. And, as Barmak points out, the MFC implementation may even be buggy, and certainly has usage caveats that would not be obvious had you failed to read the documentation carefully.
That said, in general, it is good advice to use functionality that is already wrapped up in a library because this makes your life easier. If you don't want to use the whole library, but still want to see how it implements a particular feature, you can check the library's source code. MFC is provided with reference source so that you can do this easily (also so you can debug it). Although it would probably be a violation of the license to copy and paste code directly out of MFC (it would also be nigh-impossible, since it uses so many MFC-specific idioms), you can look at the code to see what they're doing, then go back to the Windows SDK documentation to figure out how to write the code yourself.
In this case, the relevant SDK documentation is here. Modern versions of Windows (since Vista) use the Common Item Dialog API to display open/save file/folder dialogs. The API consists of a base IFileDialog interface, with two sub-interfaces, IFileOpenDialog and IFileSaveDialog. There is a lot of flexibility here; the details are in the documentation, along with sample code.
Note that the Common Item Dialog is only available on Windows Vista and later. If you need to support older operating systems (I still support Windows XP), you need a fallback. The SHBrowseForFolder dialog is that fallback. It certainly has its design flaws, but it is better than nothing.
If all you want is a simple folder-picker dialog, here is an approximation of the code that I use. It uses a couple of ATL/MFC types, like the CString and CComPtr wrapper classes, but you can translate that to alternate classes of your own choosing (such as std::wstring and _com_ptr_t). It displays a simple browse-for-folder dialog, appropriate for the current operating system, with a caller-specified title and starting path. If it succeeds, it returns a string containing the path to the folder selected by the user; otherwise, it returns an empty string.
namespace
{
HRESULT Downlevel_SHCreateItemFromParsingName(PCWSTR pszPath, IBindCtx* pbc, REFIID riid, void** ppv)
{
_ASSERTE(IsWinVistaOrLater());
HRESULT hResult = HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
const HINSTANCE hinstLib = GetModuleHandle(TEXT("shell32"));
if (hinstLib)
{
typedef HRESULT (WINAPI * pfSHCreateItemFromParsingName)(PCWSTR, IBindCtx*, REFIID, void**);
const pfSHCreateItemFromParsingName pf = reinterpret_cast<pfSHCreateItemFromParsingName>(GetProcAddress(hinstLib, _CRT_STRINGIZE(SHCreateItemFromParsingName)));
if (pf)
{
hResult = pf(pszPath, pbc, riid, ppv);
}
}
return hResult;
}
int CALLBACK BrowseForFolderCallbackProc(HWND hWnd, UINT uMsg, LPARAM /* lParam */, LPARAM lData)
{
if (uMsg == BFFM_INITIALIZED)
{
// Start with BFFM_SETSELECTION, which is always available.
SendMessage(hWnd, BFFM_SETSELECTION, TRUE, lData);
#ifdef UNICODE
// If possible, also try to use BFFM_SETEXPANDED, which was introduced with
// version 6.0 of the shell (Windows XP).
SendMessage(hWnd, BFFM_SETEXPANDED, TRUE, lData);
// You can also set the caption for the dialog's "OK" button here, if you like
// (e.g., by loading a string from a resource).
//SendMessage(hWnd,
// BFFM_SETOKTEXT,
// 0,
// reinterpret_cast<LPARAM>(pszOKBtnCaption));
#endif // UNICODE
}
return 0;
}
}
CString ShowFolderBrowserDialog(HWND hwndOwner, const CString& strDlgTitle, const CString& strStartPath)
{
if (IsWinVistaOrLater())
{
CComPtr<IFileOpenDialog> pFileOpenDlg;
if (SUCCEEDED(pFileOpenDlg.CoCreateInstance(__uuidof(FileOpenDialog))))
{
if (SUCCEEDED(pFileOpenDlg->SetTitle(strDlgTitle)))
{
FILEOPENDIALOGOPTIONS options;
if (SUCCEEDED(pFileOpenDlg->GetOptions(&options)))
{
if (SUCCEEDED(pFileOpenDlg->SetOptions(options | FOS_PATHMUSTEXIST | FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM)))
{
CComPtr<IShellItem> psiStartPath;
if (SUCCEEDED(Downlevel_SHCreateItemFromParsingName(static_cast<const TCHAR*>(strStartPath),
NULL,
IID_PPV_ARGS(&psiStartPath))))
{
if (SUCCEEDED(pFileOpenDlg->SetFolder(psiStartPath)))
{
if (SUCCEEDED(pFileOpenDlg->Show(hwndOwner)))
{
CComPtr<IShellItem> pShellItemResult;
pFileOpenDlg->GetResult(&pShellItemResult);
CComHeapPtr<TCHAR> pszSelectedItem;
if (SUCCEEDED(pShellItemResult->GetDisplayName(SIGDN_FILESYSPATH, &pszSelectedItem)))
{
return pszSelectedItem;
}
}
}
}
}
}
}
}
}
else
{
TCHAR szBuffer[MAX_PATH + 1];
szBuffer[0] = TEXT('\0');
BROWSEINFO bi;
bi.hwndOwner = hwndOwner;
bi.pidlRoot = nullptr;
bi.pszDisplayName = szBuffer;
bi.lpszTitle = strDlgTitle;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_SHAREABLE | BIF_NONEWFOLDERBUTTON;
bi.lpfn = BrowseForFolderCallbackProc;
bi.lParam = reinterpret_cast<LPARAM>(static_cast<const TCHAR*>(strStartPath));
CComHeapPtr<ITEMIDLIST> pidl(SHBrowseForFolder(&bi));
if (pidl && SHGetPathFromIDList(pidl, szBuffer))
{
return pszSelectedItem;
}
}
return TEXT("");
}
The dialog only shows actual folders in the filesystem. Although the Common Item Dialog API supports other types of special folders and namespaces, I don't need that in my app, so my code doesn't deal with the complexity. Use this as a starting point, along with the documentation, if you need more features. The most notable aspect is probably the use of SHCreateItemFromParsingName (which I have wrapped up in a dynamic call so that the code continues to run on older operating systems) to translate the caller-specified starting path (which is a string) to a Shell item object (as required by the Common Item Dialog API).

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.

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.