I'm worried I may have fallen into a bad habit with my use of SetWindowText(). As you know that function takes two parameters; the first being the hWnd whose text one wishes to change, and the second being the address of the null terminated character string one wishes to have reset in hWnd. I've noticed in Petzold that to null out a text box (edit control) he uses this...
SetWindowText(hWnd, '\0');
In my code I've lapsed into this...
SetWindowText(hWnd, NULL);
...and it seems I'm getting away with it. In any case it clears out the text in an edit control and does not return an error value. But nontheless, when I think about it, I find it troubling because NULL certainly isn't a valid address. Is the compiler 'making it right' for me? Is this bad form???
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Well, I do believe that was the problem. My use of the incorrect parameter to clear a simple textbox cost me three weeks of work. It became the ultimate programmer's nightmare. What I mean by that is a situation where a called function seems to perform perfectly, returns a success code, and severely corrupts your data segment so that the application fails totally in unexpected ways at an indeterminate time in the future. This happened to me in a Windows CE project cantaining several thousands of lines of code involving a custom grid control in a dll I created. There were no globals anywhere so absolutely everything was at the end of a pointer somewhere. Also, I had incorporated my own String class into the program, and that is the first time I had ever done that. So what you have here is the ultimate nightmare, that is realizing that data corruption is occurring somehow but not knowing from where.
First thing I did was tear out all the String class code. About two days there with no success. Then I documented every memory allocation, access and release and found no problems there. About two weeks there. Finally I rebuilt the whole project using just stub functions with almost no code (no memory allocations at all) and to my amazement the problem remained. It is at that point I finally got looking at a SetWindowText() call executed from a button click procedure where I was using in one place this...
SetWindowText(hWnd,NULL);
and in another place this...
SetWindowText(hWnd,L"\0");
Under every version of Windows I have tested this on it works in that it will clear out a textbox and return a success code. This is true also on Windows CE. However, in Windows CE it corrupts memory and sets up a 'time bomb' type situation.
Below is the code from a button press procedure where I tested this and it shows what works and what doesn't (it works, but it'll ruin your life!).
long fnWndProc_OnCommand(lpWEA wea)
{
switch(LOWORD(wea->wParam))
{
case IDC_SETTEXT:
{
SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),L"This Is A Line Of Text In A Text Box.");
break;
}
case IDC_ERASETEXT:
{
FILE* fp;
UINT iRet=0;
fp=_wfopen(L"\C_DRIVE\Silvah\Output.txt",L"a+");
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),TEXT("")); //works
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),TEXT('\0')); //disaster!
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),NULL); //disaster
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),L""); //works
iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),_T("")); //works
fwprintf(fp,L"iRet=%u\n",iRet);
fclose(fp);
break;
}
}
return 0;
}
Clifford was totally right on this. All I can surmise is that possibly in the Windows CE implementation of this function a test like Clifford listed above was ommitted, and the function corrupted memory somehow.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I would suggest that neither is strictly correct. '\0' is a character constant not an LPTSTR, but because it has a value of zero, in C++ it is 'allowed' where a pointer is required (make it say '\01' and it fails to compile). NULL is a pointer, but the documentation for SetWindowText() does not specify the semantics of passing NULL (or zero). No doubt the OS does the 'sensible' thing, but nonetheless I would suggest:
SetWindowText(hWnd, _T("") );
The _T macro ensures that the empty string constant is coerced to the appropriate type dependent upon whether the code is built for ANSI, UNICODE, or MBCS character sets. It is defined in <tchar.h>. This is also the meaning of the 'T' in the LPTSTR type - the string type depends on the character mode employed.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks very much for the input on this Clifford. I am, and have been for a very long time, trying to track down a particularly nasty bug in one of my eMbedded C++ programs, which of course makes full use of <tchar.h>. So your remarks are not far from the mark. Even though the function call seems to be working and returning a success value, I think their is some kind of internal mischief going on. What I'm seeing is a classic case of data corruption in my data segment. I've lost a huge amount of time searching for pointer errors, but have found none. I think there is something nasty going on with my use of SetWindowText() as described above. I'm still working on it.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2007-12-21
>> but the documentation for SetWindowText() does not specify the semantics of passing NULL (or zero)
The documentation show that the declaration of the function is
So, strictly, the second argument is type LPCTSTR who is a pointer to null terminated string, and in C++ the definition of a null pointer is NULL. Perhaps the addequate would be make a cast whit yor version of null.
static_cast<LPCTSTR> (/ your null pointer here /);
>>I find it troubling because NULL certainly isn't a valid address.
Just the definition of null pointer if one who does not correspond to any address.
In any case, the null pointer is one of that endless questions among the theoretical of the language.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
A NUL terminated string is not the same as a NULL pointer! NUL is an ASCII character, NULL is a pointer. Moreover UNICODE strings had a 'double NUL'. You never need to cast a NULL pointer; in C++ any representation of zero can be used where a NULL pointer is valid regardless of type, which is why '\0' works, or just plain 0 (zero) would work.
However you missed my point about the semantics (rather than syntax). For passing a NULL pointer to work, the function would require a test such as the following:
if( lpString != 0 )
{
// set the text
}
else
{
// clear the text
}
The documentation does not state that the function behaves this way so the assumption is dangerous. Experience (and Petzold) shows us that this appears to be the way it works, but it is a dangerous assumption in general and such assumptions should be avoided.
Clifford
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm worried I may have fallen into a bad habit with my use of SetWindowText(). As you know that function takes two parameters; the first being the hWnd whose text one wishes to change, and the second being the address of the null terminated character string one wishes to have reset in hWnd. I've noticed in Petzold that to null out a text box (edit control) he uses this...
SetWindowText(hWnd, '\0');
In my code I've lapsed into this...
SetWindowText(hWnd, NULL);
...and it seems I'm getting away with it. In any case it clears out the text in an edit control and does not return an error value. But nontheless, when I think about it, I find it troubling because NULL certainly isn't a valid address. Is the compiler 'making it right' for me? Is this bad form???
Well, I do believe that was the problem. My use of the incorrect parameter to clear a simple textbox cost me three weeks of work. It became the ultimate programmer's nightmare. What I mean by that is a situation where a called function seems to perform perfectly, returns a success code, and severely corrupts your data segment so that the application fails totally in unexpected ways at an indeterminate time in the future. This happened to me in a Windows CE project cantaining several thousands of lines of code involving a custom grid control in a dll I created. There were no globals anywhere so absolutely everything was at the end of a pointer somewhere. Also, I had incorporated my own String class into the program, and that is the first time I had ever done that. So what you have here is the ultimate nightmare, that is realizing that data corruption is occurring somehow but not knowing from where.
First thing I did was tear out all the String class code. About two days there with no success. Then I documented every memory allocation, access and release and found no problems there. About two weeks there. Finally I rebuilt the whole project using just stub functions with almost no code (no memory allocations at all) and to my amazement the problem remained. It is at that point I finally got looking at a SetWindowText() call executed from a button click procedure where I was using in one place this...
SetWindowText(hWnd,NULL);
and in another place this...
SetWindowText(hWnd,L"\0");
Under every version of Windows I have tested this on it works in that it will clear out a textbox and return a success code. This is true also on Windows CE. However, in Windows CE it corrupts memory and sets up a 'time bomb' type situation.
Below is the code from a button press procedure where I tested this and it shows what works and what doesn't (it works, but it'll ruin your life!).
long fnWndProc_OnCommand(lpWEA wea)
{
switch(LOWORD(wea->wParam))
{
case IDC_SETTEXT:
{
SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),L"This Is A Line Of Text In A Text Box.");
break;
}
case IDC_ERASETEXT:
{
FILE* fp;
UINT iRet=0;
fp=_wfopen(L"\C_DRIVE\Silvah\Output.txt",L"a+");
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),TEXT("")); //works
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),TEXT('\0')); //disaster!
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),NULL); //disaster
//iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),L""); //works
iRet=SetWindowText(GetDlgItem(wea->hwnd,IDC_TEXT),_T("")); //works
fwprintf(fp,L"iRet=%u\n",iRet);
fclose(fp);
break;
}
}
return 0;
}
Clifford was totally right on this. All I can surmise is that possibly in the Windows CE implementation of this function a test like Clifford listed above was ommitted, and the function corrupted memory somehow.
I would suggest that neither is strictly correct. '\0' is a character constant not an LPTSTR, but because it has a value of zero, in C++ it is 'allowed' where a pointer is required (make it say '\01' and it fails to compile). NULL is a pointer, but the documentation for SetWindowText() does not specify the semantics of passing NULL (or zero). No doubt the OS does the 'sensible' thing, but nonetheless I would suggest:
SetWindowText(hWnd, _T("") );
The _T macro ensures that the empty string constant is coerced to the appropriate type dependent upon whether the code is built for ANSI, UNICODE, or MBCS character sets. It is defined in <tchar.h>. This is also the meaning of the 'T' in the LPTSTR type - the string type depends on the character mode employed.
Clifford
Thanks very much for the input on this Clifford. I am, and have been for a very long time, trying to track down a particularly nasty bug in one of my eMbedded C++ programs, which of course makes full use of <tchar.h>. So your remarks are not far from the mark. Even though the function call seems to be working and returning a success value, I think their is some kind of internal mischief going on. What I'm seeing is a classic case of data corruption in my data segment. I've lost a huge amount of time searching for pointer errors, but have found none. I think there is something nasty going on with my use of SetWindowText() as described above. I'm still working on it.
>> but the documentation for SetWindowText() does not specify the semantics of passing NULL (or zero)
The documentation show that the declaration of the function is
BOOL SetWindowText(
HWND hWnd,
LPCTSTR lpString
);
So, strictly, the second argument is type LPCTSTR who is a pointer to null terminated string, and in C++ the definition of a null pointer is NULL. Perhaps the addequate would be make a cast whit yor version of null.
static_cast<LPCTSTR> (/ your null pointer here /);
>>I find it troubling because NULL certainly isn't a valid address.
Just the definition of null pointer if one who does not correspond to any address.
In any case, the null pointer is one of that endless questions among the theoretical of the language.
A NUL terminated string is not the same as a NULL pointer! NUL is an ASCII character, NULL is a pointer. Moreover UNICODE strings had a 'double NUL'. You never need to cast a NULL pointer; in C++ any representation of zero can be used where a NULL pointer is valid regardless of type, which is why '\0' works, or just plain 0 (zero) would work.
However you missed my point about the semantics (rather than syntax). For passing a NULL pointer to work, the function would require a test such as the following:
if( lpString != 0 )
{
// set the text
}
else
{
// clear the text
}
The documentation does not state that the function behaves this way so the assumption is dangerous. Experience (and Petzold) shows us that this appears to be the way it works, but it is a dangerous assumption in general and such assumptions should be avoided.
Clifford