Why would CToolBar::LoadToolBar fail? - c++

I have been trying to add a toolbar to a dialog box and when I call m_ToolBar.LoadToolBar it fails.
I created a new toolbar resource and it's named IDR_TOOLBAR1, then I added this to the code
if(!m_ToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD |
WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS |
CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_ToolBar.LoadToolBar(IDR_TOOLBAR1))
{
EndDialog(IDCANCEL);
}
For some reason m_ToolBar.LoadToolBar(IDR_TOOLBAR1) returns false. I created the toolbar resource in Visual Studio so I think that my IDR_TOOLBAR1 is set up correctly.
What could be causing the load to fail?
edit: I'm not sure if this is related, but I noticed that the ID for the toolbar matches the ID for another control
#define IDC_EDIT_EVENTS 213
#define IDR_TOOLBAR1 213
was in the auto-generated resource file
edit2: When I tried to debug LoadToolBar I found that it calls MAKEINTRESOURCE which seems to be returning bad pointers. MAKEINTRESOURCE is just a bunch of casts though so I'm not sure what the issue is here.

MAKEINTRESOURCE will return what appears to be a bad pointer, but this is normal. Resources can be strings or integers casted as strings.
Is this code by chance being compiled as a DLL? If so, maybe you need to add the following code to the top of the function to allow MFC to figure out which DLL to get it from.
AFX_MANAGE_STATE(AfxGetStaticModuleState());

Related

How to filter debug output window on visual studio?

How do i remove or filter this kind of message?
This is very annoying and keeps displaying the whole time I cant understand why.
Im using visual studio 2019 c++.
After reading this line of code:
MessageBox(g_hWnd, string.data(), L"", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND | MB_APPLMODAL | MB_TOPMOST);
The message always is displayed:
windows\dwm\dwmapi\attribute.cpp(105)\dwmapi.dll!00007FFBE41B1940: (caller: 000000018000E820) LogHr(1) tid(83b8) 80070006 Identificador inválido.
But if I remove MB_ICONSTOP and use only:
MessageBox(g_hWnd, string.data(), L"", MB_OK | MB_SETFOREGROUND | MB_APPLMODAL | MB_TOPMOST);it does not display.
It is also displayed by other things that I didn't know.
Some google:
https://social.msdn.microsoft.com/Forums/en-US/3a5a145a-c13d-4898-bb61-a5baadc9332f/why-am-i-getting-hundreds-of-weird-messages-in-debug-output-window?forum=vcgeneral
https://developercommunity.visualstudio.com/content/problem/258494/windowsdwmdwmapiattributecpp92dwmapidll72ed3cf4-ca.html
This is an example of an XY Problem, also discussed here. Instead of trying to prevent the messages from being shown, it would be better to prevent them from being generated in the first place.
Judging by the links you posted, this problem has existed for a few years and has bothered many people. Fortunately your first link appears to have a workaround: the post by user "codeviewer" lists a function called suppress_dwmapi_output() which when added to your code and called from InitInstance() will apparently prevent these messages from being created.
Disclaimer: I haven't tried this myself.
I have added #include <Dwmapi.h> and now it's not spamming that message in the debug console anymore.
https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmgetwindowattribute
I think the error was because it was not loading the lib dwamip.dll.

MFC (C++): Why control on top does not receive event?

At design stage,
A (List Box) is drawn before B (List Ctrl)
A is invisible initially
A covers part of B
During runtime, a button toggles the visibility of A, and when A is visible places it on top of B (using SetWindowPos(...)).
When A is shown, it does not receive events in the overlapping area (e.g., when I click "item 4" and "item 5" in the figure below). Why and how to fix it?
The sample code can be accessed here https://138.197.210.223/test/test.zip.
I did check the code, and found that the problem was caused by the ::SetWindowPos() command in OnBnClickedCheck1(). You call it to solve a drawing problem, but you do so by changing the Z-Order, and this causes the B control to capture the input instead. So it must be removed, and the code in OnBnClickedCheck1() can be changed as shown below (I have simplified the syntax, and used MFC, rather than WinAPI commands):
void CTestDlgActXDlg::OnBnClickedCheck1()
{
m_list_A.ShowWindow(m_list_A.IsWindowVisible() ? SW_HIDE : SW_SHOW);
}
The drawing problem can be solved by setting the WS_CLIPSIBLINGS style in the resource script, as suggested in the comments:
.
.
LISTBOX IDC_LIST_A,114,36,48,42,LBS_SORT | LBS_NOINTEGRALHEIGHT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
CONTROL "",IDC_LIST_B,"SysListView32",LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP | WS_CLIPSIBLINGS,108,60,60,54
.
.
This way it works for me, the A control takes precedence over B, and sends LBN_SELCHANGE notifications, for any of its items clicked.
And something strange I have noticed, the DDX_Control(pDX, IDC_LIST_B, m_list_B); command in testdlg.cpp is run twice. Delete the 2nd call.
Weird UI design btw. 😀

EM_SETHANDLE, EM_GETHANDLE works without DS_LOCALEDIT

I made a program similar to Notepad using Visual Studio Community 2017 on Windows 10. It uses edit control created with CreateWindow with the following styles:
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL
| WS_BORDER | ES_LEFT | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL
As you see, there's no DS_LOCALEDIT.
However, using EM_SETHANDLE or EM_GETHANDLE to access the buffer within the edit control seems to work flawlessly. The following is a snippet of code that does initial buffer allocation for edit control that is supposed to have been created with DS_LOCALEDIT:
HLOCAL hEditMem = ::LocalAlloc(LPTR, sizeof(wchar_t) * 51);
wchar_t* pszEdit = reinterpret_cast<wchar_t*>(::LocalLock(hEditMem));
const std::wstring strData(L"Hello");
std::char_traits<wchar_t>::copy(pszEdit, strData.c_str(), strData.size());
::SendMessageW(hwndEdit, EM_SETHANDLE, reinterpret_cast<WPARAM>(hEditMem), 0);
::SendMessageW(hwndEdit, EM_SETMODIFY, TRUE, 0);
The documentation here clearly states that:
An application that uses the default allocation behavior (that is, does not use the
DS_LOCALEDIT style must not send EM_SETHANDLE and EM_GETHANDLE messages to the edit
control.
May be someone in Microsoft inconspicuously made the DS_LOCALEDIT no longer necessary as of Windows 10 or VS 2017 ?
Since no answer from anybody, I decided to answer my own ...
Using heuristic approach, I came to the following conclusions, which are unlike what's written on MSDN docs:
DS_LOCALEDIT is not a prerequisite for EM_SETHANDLE or EM_GETHANDLE, which means that the EM_XXXHANDLE can be used even when you're not managing the buffer customarily.
EM_GETHANDLE seems a far better choice than the WM_GETTEXT when all you need to do is just refer to a portion of text in edit control.
DS_LOCAEDIT seems to be obsolete, as I was able to set my own custom buffer without it. (As a side note, all I needed to do to increase the custom buffer, in response to EN_MAXTEXT, was to send EM_SETLIMITTEXT message with new size as parameter)
To me the second one was particularly important when implementing text find/replace using FindText and ReplaceText; you don't want to copy all the text from the edit control, using WM_GETTEXT, just to search for certain keyword, would you?
I still haven't tested if plain old new can substitute LocalAlloc when setting custom buffer with EM_SETHANDLE.

CMFCShellTreeCtrl not displaying icons

I am programming with C++ and MFC.
I have a CMFCShellTreeCtrl as one of the child windows in my application. It is created like this:
const DWORD dwViewStyle = WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS;
m_wndFileView.Create(dwViewStyle, rectDummy, this, 4))
It displays correctly, but doesn't show any icons for the files. Just blank spaces where icons for folders/files should be. I looked at the function SHGetImageList, it could be my solution to get an appropriate image list and supply it to the Tree control, but I'm having trouble doing the conversion. The image list returned are of type IImageList, but I need CImageList.
Is there a way to convert between these two? Or is there a simple function to make the CMFCShellTreeCtrl show icons that I missed?
Any help would be appreciated.

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().