how to get Selected treeview item text - c++

I'm using WINAPI Treeview to show some data.
I have to get the selected TV_ITEM text, when I select a TV ITEM.
I'm using following code
case WM_NOTIFY:
switch( ((LPNMHDR)lParam)->code)
{
case TVN_SELCHANGED:
{
NMTREEVIEW* pnmtv = (LPNMTREEVIEW)lParam;
LPTSTR str = (pnmtv->itemNew.pszText);
MessageBox( hWnd, str,"load",MB_OK );
}
break;
}
I can't get the correct value, I got some kind of garbage value.
MessageBox shows some kind of special characters(Those are not in keyboard)
Shall anyone help me, how to get the selected item text.
Thanks in advance

Have you read the documentation on TVN_SELCHANGED? It never mentions pszText. You need to
TVITEM item;
item.hItem = pnmtv->itemNew.hItem;
item.mask = TVIF_TEXT;
item.pszText = // allocate buffer
item.cchTextMax = // length of buffer
::SendMessage(hWnd, TVM_GETITEM, 0, (LPARAM)&item);
and then you'll get item.pszText
P.S. If you're working with windows API, how often have you seen Windows allocating and managing strings for you? It just doesn't happen.

Related

TabCtrl_GetItem macro not working as expected

I'm creating a basic notepad program, and when the user clicks close, I want it to ask the user if they want to save the current document opened. I'm using a tabbed interface, and trying to retrieve the filename ( text on tab ) so I have a MessageBox that says "Would you like to save: untitled.txt" or similar. I'm having trouble getting the file name. This is what I currently have:
case ID_FILE_CLOSE: // When the close button is clicked
{
HWND hEdit, hTabs;
hTabs = GetDlgItem( hwnd, IDC_MAIN_TAB );
int curTab = TabCtrl_GetCurSel( hTabs );
TCITEM curtitem;
TabCtrl_GetItem( hTabs, curTab, &curtitem );
// Check for file name
MessageBox( hwnd, curtitem.pszText, "Test", MB_OK );
}
break;
This is the error I keep getting in a popup box with Break, Continue, Ignore buttons:
Unhandled exception at 0x7597d298 in notepadpremium.exe: 0xC0000005: Access violation reading location 0xcccccccc.
I'm using MS Visual C++ Express 2010.
I also have a listbox with the filenames that also show the extension ( almost like notepad++ document switcher ) and tried LB_GETITEMDATA through a message, but that always returned blank. I think that was because I use LB_ADDSTRING to add it to the listbox. ( the listbox and tabs are interconnected, when you click on a file in the listbox, it changes to the corresponding tab ). Why isnt my code working the way it should?
Read the documentation:
pitem
Type: LPTCITEM
Pointer to a TCITEM structure that specifies the information to retrieve and receives information about the tab. When the message is sent, the mask member specifies which attributes to return. If the mask member specifies the TCIF_TEXT value, the pszText member must contain the address of the buffer that receives the item text, and the cchTextMax member must specify the size of the buffer.
You are not initializing the TCITEM at all. You need to tell TabCtrl_GetItem() what data to retrieve, and more importantly what buffer you provide to receive that data into. You are not doing any of that, you are passing random data to TabCtrl_GetItem(), which is why it crashes.
Try this instead:
case ID_FILE_CLOSE: // When the close button is clicked
{
HWND hTabs = GetDlgItem( hwnd, IDC_MAIN_TAB );
int curTab = TabCtrl_GetCurSel( hTabs );
TCHAR szFileName[MAX_PATH+1] = {0};
TCITEM curtitem = {0};
curitem.mask = TCIF_TEXT;
curitem.pszText = szFileName;
curitem.cchTextMax = MAX_PATH;
if (TabCtrl_GetItem( hTabs, curTab, &curtitem ))
{
// also from the documentation:
//
// "the control may change the pszText member of the structure
// to point to the new text instead of filling the buffer with
// the requested text. The control may set the pszText member
// to NULL to indicate that no text is associated with the item."
//
// which means you cannot rely on the szFileName[] buffer actually
// containing the filename, you have to use whatever buffer the
// TCITEM is actually pointing at, which may or may not be the
// szFileName buffer...
MessageBox( hwnd, curitem.pszText, TEXT("Test"), MB_OK );
}
}
break;
As for your ListBox issue, you said you are using LB_ADDSTRING to add strings to the ListBox, but are using LB_GETITEMDATA to retrieve them. That is wrong. You need to use LB_GETTEXTLEN and LB_GETTEXT instead. LB_GETITEMDATA is used to retrieve user-defined data that was added to the ListBox using LB_SETITEMDATA.

Common Dialogboxes Win32

I have a common color dialog box that I want to activate on a menu press.
Unfortunately, every time I press on the item, the window loses focus, as if a dialog box is coming up, but the dialog box never shows up.
The code I'm using right now is below:
case ID_TOOL_CHOOSECOLOR:
//show colour dialog
ChooseColor(&cc);
and I've initialized my CHOOSECOLOR structure like this:
cc.lStructSize = sizeof (CHOOSECOLOR) ;
cc.hwndOwner = NULL ;
cc.hInstance = NULL ;
cc.rgbResult = RGB (0x80, 0x80, 0x80) ;
cc.lpCustColors = crCustColor ;
cc.Flags = CC_RGBINIT | CC_FULLOPEN ;
cc.lCustData = 0 ;
cc.lpfnHook = NULL ;
cc.lpTemplateName = NULL ;
What's weird is, the dialog box only shows up after I press the "ALT" key (and only the alt key). Any tips?
I'm trying to do this in an MDI document by the way.
Thanks
The only problem I can see is that you did not specify an owner for the dialog. This could lead to the dialog showing behind your main window. Specify the handle of your main window to be the dialog's owner.
Read more about window ownership on the Window Features page on MSDN.
Fixed it!
Turns out, the issue I had was in the main window's WndProc.
I had set my WM_PAINT command to return 0; instead of break;.
Changing my return 0 to break solved everything!
I think this is cause my return would exit the wndproc, whereas break would allow me to continue to the return MDIFrameProc(hwnd, message, wparam, lparam) .
I maybe wrong, but that's the best explanation that I can come up with that explains why break works but return 0 doesn't.
After you paint, make sure you call ValidateRect(HWND,CONST RECT*);
// https://learn.microsoft.com/en-us/windows/win32/dlgbox/color-dialog-box
// http://winapi.freetechsecrets.com/win32/WIN32Choosing_a_Color.htm
COLORREF acrCustClr[16]; // array of custom colors
CHOOSECOLOR cc = {sizeof(cc)};
ZeroMemory(&cc, sizeof(CHOOSECOLOR));
cc.lStructSize = sizeof(CHOOSECOLOR);
cc.hwndOwner = hwnd;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
cc.lpCustColors = (LPDWORD) acrCustClr;
BOOL fOk = ChooseColor(&cc);
if (fOk) {
}

Get all position values from CScrollBar

Trying to use a CScrollBar in my MFC C++ application for Windows7.
I receive all messages just fine and have a handler that looks something like this:
void Dialog::OnHScroll(UINT nSBCode, UINT apos, CScrollBar* pScrollBar)
{
SCROLLINFO si;
si.cbSize = sizeof( si );
si.fMask = SIF_TRACKPOS;
m_slider.GetScrollInfo(&si,SIF_TRACKPOS|SIF_POS|SIF_PAGE);
int nTrackPos = si.nTrackPos; //0 except on TB_THUMBTRACK
int nPos = si.nPos; //0 except on TB_THUMBTRACK
UINT nPage = si.nPage; //seems correct always but I dont need it
The reason I try to extract the position using GetScrollInfo is because they may be bigger than what fits inside a 16bit var, and therefore I cannot use the pos being passed as the argument.
My problem however is that I only get a valid position when dragging the bar and receiving the TB_THUMBTRACK as well as the ending TB_ENDTRACK for drag operations. If I click in the scrollbar or use the arrows at each end all positions (argument pos, and everything in the SCROLLINFO struct except page) will be 0.
Does anyone know how to get the correct positions for all messages? Ie TB_LINEUP, TB_LINEDOWN etc.
Take a look at the sample code for the WM_HSCROLL event handler that's shown in MSDN:
MSDN Documentation

TVITEM LPARAM to store string

I've got a treeview listing files that are dropped upon it.
When I make a new treeview item, I'd like to store the address of the file as a string in that item, and retrieve it for various nefarious purposes at a later point in time.
Looking at the TVITEM structure in Microsoft docs, apparently LPARAM is the place to store a value:
lParam
Type: LPARAM
A value to associate with the item.
So, I have gone ahead and done that:
TVITEM tvi;
tvi.mask = TVIF_TEXT;
tvi.pszText = const_cast<char *> (str0.c_str());
tvi.cchTextMax = sizeof(tvi.pszText);
tvi.lParam = (LPARAM) foo; // SETTING LPARAM HERE, foo IS A const char *
TVINSERTSTRUCT tvis;
tvis.item = tvi;
tvis.hInsertAfter = 0;
tvis.hParent = hti0;
// Send message to update tree, and return tree item.
return TreeView_InsertItem(tvw_filelist_, &tvis);
Then, when I try to retrieve my value...
HTREEITEM htiSel = TreeView_GetSelection(tvw_filelist_);
TVITEM tvItem;
tvItem.hItem = htiSel;
TreeView_GetItem(tvw_filelist_, &tvItem);
const char * info = (const char *) tvItem.lParam;
MessageBox(NULL, info, "Alert", MB_OK);
...I just get garbage, indicating my pointer went out of scope or is taking a nap or something. The size of that pointer is always 4.
Is this the right way to do what I'm trying to do? If so, what's going on?
Of course, take the time to post a question after a long time trying to figure it out, and the answer shows up in seconds.
Turns out the TVITEM mask needs to include TVIF_PARAM, similar to this question.
If I change the above code to:
tvi.mask = TVIF_TEXT | TVIF_PARAM;
it works as expected.
I'm still not sure if this is the recommended use for LPARAM, though.
struct CustomTreeData
{
LPSTR str; // or even std::string to forget about memory managment
// TODO: any other data you need
};
...
TVITEM tvi;
tvi.mask = TVIF_TEXT | TVIF_PARAM;
CustomTreeData* myDataPtr = new CustomTreeData; // the memory should be free later
myDataPtr->str = stringWhatIWant; // And don't forget to alloc memory for str!
tvi.lParam = (LPARAM) myDataPtr;
I don't check this code, but it should work. Happy coding :)

Debugging font linking

I have a problem with a program we're developing. It is written using MFC but does not use unicode. We have made a translation into simplified chinese. So far this is our first and only localization. We have moved all strings to resources to make them translateable. Everything seems to work fine on our computers (both Win7 and XP) but for some customers computers running windows XP we get problems:
On those computers all translated strings work except for those we enter into tree cotrols (CTreeCtrl is used directly). I'm not sure if it is the tree control or the text we enter that causes the problem, but the font seems to not get substituted in those controls. My guess is that maybe it does not get substituted because some of the strings also contain latin characters. Still, that kind of substitution seems to work in other places of the program and not all strings entered into the tree contain those characters either.
So my first question is: Is there a way to get to know what is happening inside the control? We can have remote access to the computers where the problem is happening but running a debugger on them may be a little tricky. What kind of tools can be used to diagnose this problem?
One possible solution that crossed my mind was to subclass the tree controls to get more control over the actual text drawing, maybe using the approach from http://blogs.msdn.com/b/oldnewthing/archive/2004/07/16/185261.aspx to get around the problem. Could this be effective or would it just be an awful lot of work for nothing?
Thanks a lot!
Ok, it seems on their system there was either a bug in the tree control implementation or they had some systemwide addin that hooked into the drawing in some way. What I ended up doing was to do custom drawing through notifications in the tree view and then using font linking to resolve the fonts. I dont think font linking would be necessary, though, because I think most of the time it ended up doing just TextOutW() with the preselected font anyway.
Here is a somewhat simplified code sample of what I ended up with:
void MyDlg::OnCustomDrawTreeItem( NMHDR* pNMHDR, LRESULT* pResult )
{
if (!mpFontLink)
{
*pResult = CDRF_DODEFAULT;
return;
}
LPNMTVCUSTOMDRAW pCustomdraw = (LPNMTVCUSTOMDRAW) pNMHDR;
switch(pCustomdraw->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
{
// Ask to do custom draw
*pResult = CDRF_NOTIFYITEMDRAW;
break;
}
case CDDS_ITEMPREPAINT:
{
// Ask for post paint notification
*pResult = CDRF_NOTIFYPOSTPAINT;
break;
}
case CDDS_ITEMPOSTPAINT:
{
// Get the rect of only the item, not the tree stuff
RECT rcItem;
m_pageTree.GetItemRect((HTREEITEM) pCustomdraw->nmcd.dwItemSpec, &rcItem, TRUE);
// Erase the item background in case the previous string drawn was wider
HDC hDC = pCustomdraw->nmcd.hdc;
FillRect( hDC, &rcItem, (HBRUSH) GetClassLongPtr(m_pageTree.GetSafeHwnd(), GCLP_HBRBACKGROUND));
pageStruct *pS = (pageStruct*) pCustomdraw->nmcd.lItemlParam;
DWORD dwFontCodepages = 0, dwStrCodepages = 0;
HFONT hOriginalFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT);
HRESULT hr = mpFontLink->GetFontCodePages( hDC, hOriginalFont, &dwFontCodepages);
OML_CStringW tData = pS->csCaption.GetBuffer();
// Set up position etc
DWORD dwAlignOrig = GetTextAlign(hDC);
if (!(dwAlignOrig & TA_UPDATECP)) {
SetTextAlign(hDC, dwAlignOrig | TA_UPDATECP);
}
POINT ptOrig;
MoveToEx(hDC, 2 + rcItem.left, 1 + rcItem.top, &ptOrig);
SetTextColor( hDC, pCustomdraw->clrText );
SetBkColor( hDC, pCustomdraw->clrTextBk );
// Loop over the parts of the text
TuInt32 nIndex = 1;
while (nIndex <= tData.GetLength())
{
long nActualChars = 0;
wchar_t *pStr = (wchar_t*)tData.BaseGetItemP( nIndex );
TuInt32 nChars = 1 + tData.GetLength() - nIndex;
hr = mpFontLink->GetStrCodePages(pStr, nChars,
dwFontCodepages, &dwStrCodepages, &nActualChars);
if (dwStrCodepages & dwFontCodepages)
{
// We end up here almost every time, that is why TextOutW would probably be enough.
// This part is supported by the original font (or the GDI can help us switch automatically)
TextOutW(hDC, 0, 0, pStr, nActualChars);
}
else
{
// We need to link
HFONT hLinked;
if (FAILED(hr = mpFontLink->MapFont(hDC, dwStrCodepages, 0, &hLinked)))
{
// Fail: Output the rest without linking
TextOutW( hDC, 0, 0, pStr, nChars );
break;
}
// Output with linked font
SelectObject(hDC, hLinked);
TextOutW( hDC, 0, 0, pStr, nActualChars);
SelectObject(hDC, hOriginalFont);
mpFontLink->ReleaseFont( hOriginalFont );
}
nIndex += nActualChars;
}
OML_LOG_1( "_END:");
// Reset alignment mode
if (!(dwAlignOrig & TA_UPDATECP)) {
SetTextAlign(hDC, dwAlignOrig);
MoveToEx(hDC, ptOrig.x, ptOrig.y, NULL);
}
*pResult = CDRF_SKIPDEFAULT;
}
default:
{
*pResult = CDRF_DODEFAULT;
break;
}
}
} /* OnCustomDrawTreeItem */