I posted this question elsewhere. Im hoing I will get more feedback
here.
I have a MFC class derived from CStdioFile declared as follows
// Datafile.h
class CDataFile : public CStdioFile
{
public:
CDataFile(void);
~CDataFile(void);
int OpenFile(LPCWSTR FileName);
}
After my OpenFile function is called the FileName variable is being
corrupted.
int CDataFile::OpenFile(LPCWSTR FileName)
{
m_OpenFlags = CFile::modeNoTruncate | CFile::modeReadWrite;
// Before open. FileName = "c:\afile.txt"
if (!Open(FileName, m_OpenFlags, NULL))
{
// open always fails as filename corrupted
return GetLastError();
}
//After open. FileName =
""ﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮﻮވĚᗸ÷ᘸ÷㼠碞"
// other stuff
}
}
But if I change the FileName to
WCHAR FileName[] = _T("c:\\afile.txt");
Before opening the File the variable Filename remains untouched. I
have seen this behaviour before with the MFC/Winapi and always worked
around it be by using character arrays instead of LPCWSTR or CString.
Why does this happen? and what is the best way to track down problems
such as this with the VS Debugger. The corruption appears to happen
here in the MFC file Filecore.cpp
if (!CFile::Open(lpszFileName, (nOpenFlags & ~typeText), pException))
return FALSE;
Thanks....
Kind of unclear what you are doing there.
But you are obviously mixing data types:
> int CDataFile::OpenFile(LPCWSTR FileName)
> // Before open. FileName = "c:\afile.txt"
You cannot put "c:\afile.txt" in a LPCWSTR.
It should be L"c:\afile.txt".
And \a is a control character. I guess you mean "c:\\afile.txt"
> WCHAR FileName[] = _T("c:\\afile.txt");
This is also wrong, you try to store the "generic text" into UTF-16 string.
Should be either
TCHAR FileName[] = _T("c:\\afile.txt");
or
WCHAR FileName[] = L"c:\\afile.txt";
--
Mihai Nita [Microsoft MVP, Visual C++]
http://www.mihai-nita.net
------------------------------------------
Replace _year_ with _ to get the real email
" You cannot put "c:\afile.txt" in a LPCWSTR" I wasnt I was just
showing what FileName Contained before the call to CFile::Open.
The FileName Parameter in the calling function would be for example
LPCWSTR Workfile = _T("c:\\AFile.txt)"
Please explain this statement "This is also wrong, you try to store
the "generic text" into UTF-16 string."
Thanks..
> The FileName Parameter in the calling function would be for example
> LPCWSTR Workfile = _T("c:\\AFile.txt)"
You must have a typo above; the right hand side should be
_T("c:\\AFile.txt").
> Please explain this statement "This is also wrong, you try to store
> the "generic text" into UTF-16 string."
'LPCWSTR' means 'const WCHAR *' or the equivalent 'const wchar_t *'.
'wchar_t' strings are UTF-16 string on Windows. You identify UTF-16 string
literals using L"" prefix, e.g. L"c:\\AFile.txt".
_T("...") is a preprocessor macro that expands to "..." in ANSI/MBCS builds,
and expands to L"..." in Unicode builds (when _UNICODE and UNICODE are
#define'd).
So, in ANSI/MBCS builds, _T("c:\\AFile.txt") expands to "c:\\AFile.txt"
(ANSI string literal); in Unicode builds, _T("c:\\AFile.txt") expands to
L"c:\\AFile.txt" (UTF-16 string literal).
If you use _T("...") decoration, you should use 'TCHAR' strings (e.g. 'const
TCHAR *', or 'LPCTSTR'). In fact, 'TCHAR' expands to 'char' in ANSI/MBCS
builds, and to 'wchar_t' in Unicode builds.
So, to summarize:
1. if you use generic text, you should use _T() (or TEXT()) decoration for
string literals, and you should use LPCTSTR (or 'const TCHAR *')
2. if you use UTF-16 strings, you should use L"" decoration for string
literals, and you should use LPCWSTR (or 'const wchar_t *')
3. if you use ANSI/MBCS strings, you should use "..." for string literals,
and you should use LPCSTR (or 'const char *').
Mihai correctly pointed out that your use of:
WCHAR FileName[] = _T("c:\\afile.txt");
is wrong, because you have a UTF-16 string (WCHAR array) on the left side,
and a generic text string (_T() decoration) on the right side.
BTW: an interesting reading:
http://blogs.msdn.com/oldnewthing/archive/2004/02/12/71851.aspx
HTH,
Giovanni
> Mihai correctly pointed out that your use of:
>
> WCHAR FileName[] = _T("c:\\afile.txt");
>
> is wrong, because you have a UTF-16 string (WCHAR array) on the left side,
> and a generic text string (_T() decoration) on the right side.
Note that the above statement will compile in Unicode builds, because in
this case _T("...") expands to L"...", so the above statement becomes:
// In Unicode builds:
WCHAR FileName[] = L"c:\\afile.txt";
// OK: WCHAR strings on both left and right side of operator=
but it will fail in ANSI/MBCS builds, because in this case you have a WCHAR
array on the left side, and a char-based string ("c:\\afile.txt") on the
right side.
Giovanni
Thanks for your explanations. Having read the replies a few times the
errors pointed out seem to relate to compilation problems if I try to
compile my application in Ansi rather than Unicode. The Application
has been Unicode since the start and that is highly unlikely to
change. I am also using TCHAR where appropriative but posted WCHAR
for clarity. I take your advice regarding LPCTSTR which would allow
both Unicode & Ansi builds and I will use from now on.
Unless I have failed to grasp something I am still having the same
corruption problem with the FileName Variable... :-(
Thanks for your explanations. Having read the replies a few times the
Thanks for your explanations. Having read the replies a few times the
Thanks for your explanations. Having read the replies a few times the
Thanks for your explanations. Having read the replies a few times the
Giovanni
"Canacourse" <canac...@gmail.com> ha scritto nel messaggio
news:f1127288-e071-403d...@r31g2000vbi.googlegroups.com...
> Thanks for your explanations.
You are welcome.
> Having read the replies a few times the
> errors pointed out seem to relate to compilation problems if I try to
> compile my application in Ansi rather than Unicode.
I confirm that I think that you will have compilation problems if you write
this:
WCHAR FileName[] = _T("c:\\afile.txt");
and compile the app in ANSI/MBCS mode, because of mismatch between left
(wchar_t string) and right (char string) sides of operator=.
> The Application
> has been Unicode since the start and that is highly unlikely to
> change.
This is not a good reason to write "fragile" code.
If you want to use WCHAR UTF-16 strings all the time, it is just fine
(recent Windows APIs tend to be Unicode-only as well and use only WCHAR*
instead of TCHAR*), but it is important to write coherent code, e.g.
WCHAR FileName[] = L"c:\\afile.txt";
> Unless I have failed to grasp something I am still having the same
> corruption problem with the FileName Variable... :-(
Please show the exactly calling code and please give more information about
the context of the offending call (and, if possible, the body of the
function that processes the 'FileName' variable).
I read this in a previous post:
int CDataFile::OpenFile(LPCWSTR FileName)
so the input string is marked as *const* (LPCWSTR = const wchar_t *), so it
seems odd that it is modified by the called function (do you use a
const_cast somewhere?). Probably a buffer overrun somewhere?
Giovanni
No casting involved. That problem of course happens if a FileName
parameter is passed but for test/tracking purposes I was setting the
name of the file in the CDataFile::OpenFile function itself.
FileName = _T("c:\\SomeFile.Txt");
FileName is an optional parameter "int OpenFile(LPCTSTR FileName =
0)" and if not passed the OpenFile Function will create a temp file.
After the setting a Data Breakpoint on the address of the FileName
Variable this is the callstack when the BP is hit.
msvcr90d.dll!memset(unsigned char * dst=0x000000dd, unsigned char
value='–', unsigned long count=16183840) Line 127 Asm
msvcr90d.dll!_free_dbg_nolock(void * pUserData=0x00f6f240, int
nBlockUse=1) Line 1425 + 0x1b bytes C++
msvcr90d.dll!_free_dbg(void * pUserData=0x00f6f240, int nBlockUse=1)
Line 1258 + 0xd bytes C++
mfc90ud.dll!CAfxStringMgr::Free(ATL::CStringData * pData=0x00f6f240)
Line 154 + 0xc bytes C++
mfc90ud.dll!ATL::CStringData::Release() Line 113 C++
mfc90ud.dll!ATL::CSimpleStringT<wchar_t,1>::Empty() Line 466 C++
mfc90ud.dll!CFile::Open(const wchar_t * lpszFileName=0x00f6f250,
unsigned int nOpenFlags=8194, CFileException * pException=0x00000000)
mfc90ud.dll!CStdioFile::Open(const wchar_t * lpszFileName=0x00f6f250,
unsigned int nOpenFlags=8194, CFileException * pException=0x00000000)
MyApp.exe!CDataFile::OpenFile(const wchar_t * FileName=0x00f6f250)
Line 129 + 0x1c bytes C++
Regards...
Not deliberately. Browser went a bit mental when page refreshed..
>Hello,
>
>I posted this question elsewhere. Im hoing I will get more feedback
>here.
>
>
>I have a MFC class derived from CStdioFile declared as follows
>
>// Datafile.h
>class CDataFile : public CStdioFile
>{
> public:
> CDataFile(void);
> ~CDataFile(void);
>
> int OpenFile(LPCWSTR FileName);
****
Already there is a problem. Why an LPCWSTR here? Why move outside the MFC environment? I
would have written
int OpenFile(const CString & FileName);
which would have been consistent with MFC, non-fragile, and been the first step to
eliminate all the problems.
****
>}
>
>After my OpenFile function is called the FileName variable is being
>corrupted.
****
It would be useful to know how, since nothing assigns to it
****
>
>int CDataFile::OpenFile(LPCWSTR FileName)
> {
>
>m_OpenFlags = CFile::modeNoTruncate | CFile::modeReadWrite;
>
>// Before open. FileName = "c:\afile.txt"
>
> if (!Open(FileName, m_OpenFlags, NULL))
>
> {
> // open always fails as filename corrupted
> return GetLastError();
> }
>
>//After open. FileName =
>""???????????????????????????????????????????????????�?�??�"
>
>// other stuff
>}
>
>}
>
>But if I change the FileName to
>
>WCHAR FileName[] = _T("c:\\afile.txt");
****
Why would you need an LPCWSTR at the call site? THere is no reason to have used an
LPCWSTR as the parameter of the call; the error of using _T() has already been pointed
out, but you should not just go around adding LP[C][TW]STR variables in MFC if you are
using CStrings. It is silly to have to keep unwrapping representations, or having these
strange raw arrays of characters around.
The usual excuse is "the API requires an LPWSTR" or something like that; in fact, the API
uses an LPCTSTR, which means a CString works just fine as the parameter.
****
>
>Before opening the File the variable Filename remains untouched. I
>have seen this behaviour before with the MFC/Winapi and always worked
>around it be by using character arrays instead of LPCWSTR or CString.
****
Are you sure your debugger is not lying to you? And how do you know the damage is caused
specifically by the OpenFile? Have you examined the actual memory that is there, and not
relied on the debugger display?
****
>Why does this happen? and what is the best way to track down problems
>such as this with the VS Debugger. The corruption appears to happen
>here in the MFC file Filecore.cpp
****
I have never seen this happen, but then, I never use raw character representations and
other weird things (like local arrays of raw characters) when a CString would do. How do
you know the "other stuff" is not doing the damage? You didn't show it, so we can't tell.
What version of VS are you using? I have never seen anything like this since I started
using VS in 1995, so I seriously doubt FileCore is doing it to you. I suspect that the
debugger could be lying; if you think the debugger is a perfect piece of code, you are
certainly mistaken.
Did you consider single-stepping into CFile::Open to see what it is doing?
joe
****
>
>if (!CFile::Open(lpszFileName, (nOpenFlags & ~typeText), pException))
> return FALSE;
>
>Thanks....
Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
> No casting involved. That problem of course happens if a FileName
> parameter is passed but for test/tracking purposes I was setting the
> name of the file in the CDataFile::OpenFile function itself.
>
> FileName = _T("c:\\SomeFile.Txt");
>
> FileName is an optional parameter "int OpenFile(LPCTSTR FileName =
> 0)" and if not passed the OpenFile Function will create a temp file.
I tried something like this:
<code>
class CDataFile : public CStdioFile
{
public:
CDataFile(void)
{
}
~CDataFile(void)
{
}
DWORD OpenFile(LPCTSTR pszFileName)
{
UINT openFlags = CFile::modeNoTruncate | CFile::modeReadWrite;
if (! Open( pszFileName, openFlags, NULL) )
{
return GetLastError();
}
return 0;
}
};
</code>
with a simple test like this:
<code>
CDataFile df;
df.OpenFile( _T("c:\\test.txt") );
</code>
I set a breakpoint on OpenFile call, and I see no corruption of
'pszFileName' string.
You may want to show us the actual code to try to get a better help.
(Joe suggested to pass a 'const CString &', but in general an 'LPCTSTR'
should be just fine as an input read-only string parameter.)
Giovanni
****
The reason I suggested const CString & is to break the OP of the habit of creating a lot
of raw character-array and pointer-to-character-array code. I find it an unfortunate
misfeature that some people keep insisting on using these base types when there is no
reason to do so. You only use LPTSTR/LPSTR under very restricted and exotic conditions,
such as when you do a GetBuffer so you can do a low-level transfer into the buffer (e.g.,
via ReadFile, or CAsyncSocket::Receive), and I see no reason a LPCTSTR or LPCWSTR would
ever need to exist in this code.
The const CString & is the fastest way to pass a CString because it doesn't involve a
potential copy.
joe
****
>
>Giovanni
Note that changing FileName in CDataFile::OpenFile() will not affect the
original variable at the calling location, because C/C++ pass by value. So if
the original filename is corrupted, it must have been corrupted from the
beginning (perhaps by putting an 8-bit string into a 16-bit array).
But I think I may have lost track of precisely what the problem is...
--
David Wilkinson
Visual C++ MVP
The FileName variable in the OpenFile function was being corrupted
after this call "if (!Open(FileName, m_OpenFlags, NULL))" You are
correct the original variable at the calling location was not altered.
Joe, I started using CString as you suggested and the problem has
disappeared. I did not realize CString could be used for functions
that require LPCWSTR and the like so thanks for putting me right on
that. Thanks also for your Essays - great stuff..