Returning LPWSTR variable is wrong

All right, this problem has been bugging me for a week now(had no internet connection). I want to return the name of a Treeview Item using Win32.
My function is:
1
2
3
4
5
6
7
8
9
10
11
12
13
LPWSTR TreeviewGetName(HWND handleTreeview, HTREEITEM treeviewItem)
{
	TVITEMEX tvi;
	ZeroMemory(&tvi,sizeof(TVITEM));
	TCHAR Text[16];
	tvi.mask=TVIF_TEXT;
	tvi.pszText=(LPWSTR)Text;
	tvi.hItem=treeviewItem;
	tvi.cchTextMax=15;
	SendMessage(handleTreeview,TVM_GETITEM,TVGN_CARET,(LPARAM)&tvi);
	MessageBox(handleTreeview,(LPWSTR)tvi.pszText,_T(""),NULL);
	return tvi.pszText;
}

The function contains a message box and the message box says the correct name. Then I have a call to the function that contains:

MessageBox(hWnd,TreeviewGetName(window.hTree,TreeView_GetNextItem(window.hTree,NULL,TVGN_ROOT)),_T(""),NULL);

This shows random characters. Changing the end of the function to

return _T("Testing");

gives the correct output of 'Testing'. Anyone know what the problem is? It could also be a general C++ question, but I'm not sure since I'm not totally clear what's causing this problem.
The function is returning the address of the local TCHAR array variable Text, which is the struct TVITEMEX tvi's pszText member is set to point to.

When the function returns the variable Text goes out of scope as the call stack is popped.

Under some circumstances you can get at the data after you pop the stack, but only if the compiler hasn't reused it for another purpose. As several calls are going on immediately after each other here, the memory is being reused here.

Returning _T("Testing"); is ok as that is a string literal, which have static storage.

Andy
Also: TCHARs are TCHARs
wchar_ts are wchar_ts

Don't cast between pointer types (ie: don't cast LPTSTR to LPWSTR)

char
char, LPSTR, LPCSTR, std::string, "string literal"

wchar_t
wchar_t, LPWSTR, LPCWSTR, std::wstring, L"string literal"

TCHAR
TCHAR, LPTSTR, LPCTSTR, std::basic_string<TCHAR>, _T("string literal")
Last edited on
When the function returns the variable Text goes out of scope as the call stack is popped.

This made the most sense. I got it to work.
1
2
3
4
5
6
7
8
9
10
11
void TreeviewGetName(TCHAR* texthandle,const int textsize,HWND handleTreeview, HTREEITEM treeviewItem)
{
	TVITEMEX tvi;
	ZeroMemory(&tvi,sizeof(TVITEM));
	tvi.mask=TVIF_TEXT;
	tvi.pszText=(LPWSTR)texthandle;
	tvi.hItem=treeviewItem;
	tvi.cchTextMax=textsize;
	SendMessage(handleTreeview,TVM_GETITEM,TVGN_CARET,(LPARAM)&tvi);
	MessageBox(handleTreeview,(LPWSTR)tvi.pszText,_T(""),NULL);
}

1
2
3
4
const int TextSize=16;
TCHAR Text[TextSize];
TreeviewGetName(Text,TextSize,window.hTree,TreeView_GetNextItem(window.hTree,NULL,TVGN_ROOT));
MessageBox(hWnd,Text,_T(""),NULL);

Tell me if there's any problem with my code, since I still have trouble understanding certain aspects of C++.

Also: TCHARs are TCHARs
wchar_ts are wchar_ts

I was using a wchar_t earlier. It really made no difference. According to Microsoft Visual C++ 2010, typedef WCHAR TCHAR, so they are both the same thing.
Last edited on
I was using a wchar_t earlier. It really made no difference. According to Microsoft Visual C++ 2010, typedef WCHAR TCHAR, so they are both the same thing.


It depends on your compiler settings.

Whether or not the UNICODE symbol is defined determines how TCHAR is defined. It can be defined either as a char or a wchar_t.

Your particular setting has it as a wchar_t, so converting between them will work. But doing that is a bad idea because if that setting changes, your program will break.


Personally, I find the TCHAR fiasco to be a mess and avoid it completely. When working with WinAPI I prefer to just use wchar_ts for everything (then just use the accompanying 'W' forms of WinAPI functions... like MessageBoxW(), etc)
It looks safe.

Is there a redundant call to MessageBox at the end of TreeviewGetName?

TCHAR is a typdef of either char or wchar_t. LPTSTR is the same for char*/wchar_t*, etc.

When UNICODE or _UNICODE is defined, TCHAR = wchar_t (= UTF-16)
When it's not, TCHAR = char (ANSI)

(a char is always a char, as is a wchar_t. In Windows code you might also encounter CHAR (= char) and WCHAR (= wchar_t), which are also typedefs, but fixed.

A couple of comments:

1 definitely replace all your LPWSTR with LPTSTR, so the code is consistent. (You code is fine when compiled with _UNICODE defined, so TCHAR = wchar_t, but not otherwise)

2 textsize should prob. be a DWORD in Window code, or unsigned int (sizes cannot be negative, so should be stored in an unsigned type)
Last edited on
Thanks guys, I've made my code consistent and will continue to do so as a good programming habit.

Is there a redundant call to MessageBox at the end of TreeviewGetName?

Yeah, just to test if I was getting the correct input inside the function and outside. The first code I provided had it and it was giving the right values in the function but bad outside of it. I use it for debugging.

Problem solved.
Topic archived. No new replies allowed.