Click to See Complete Forum and Search --> : CString


Jedhi
November 20th, 2003, 10:23 AM
In VC6.0 I have used the CString alot, but I experience that CString do not always do as expected in .NET.

CString str = "";

Does for example not give an empty string.

What must I use in .NET to get string work correctly ?

vicodin451
November 20th, 2003, 10:44 AM
What are you talking about?
I have a attached a simple project that should prove that all is well in CString-land. The program intentionally causes an access violation in the event that the string (initialized just as you postsed) has a length other than 0. Additionally, the program will print the string surrounded by 3 '*' characters. Thus, if the string is empty, 6 consecutive '*' characters will print. Try the project, and if you get different results, post back. Else, provide more information to clarify your original post (a compilable example that demonstrates your problem, etc).

Note that the project was build with VS.NET 2003, but I modified the vcproj to work with VS.NET 2002. It will likely want to convert it if you are using VS.NET 2003. No biggie.

Jedhi
November 20th, 2003, 11:25 AM
Well what can I say, at me it fails. I'm using SDK

and I can garantee that str
CString str="";

does not become empty after this. Also It crash after opening a file twice.

int CFileDialog::DoModal()
{
....
ASSERT(nOffset <= m_ofn.nMaxFile);
}


I have compiled the same code under Visual Studio 6.0. And there everything works perfectly. Whether the CString has influence on the other things I can not guarantee. But for me I think this is really strange

vicodin451
November 20th, 2003, 11:38 AM
Sounds like you're overwriting memory somewhere, and seeing the effects in the CString. The ASSERT failing is another hint that something's wrong.

Did the project that I posted indicate that the CString was not empty?

MSDN for nMaxFile (referenced in the ASSERT):

nMaxFile
Specifies the size, in TCHARs, of the buffer pointed to by lpstrFile. For the ANSI version, this is the number of bytes; for the Unicode version, this is the number of characters. The buffer must be large enough to store the path and file name string or strings, including the terminating NULL character. The GetOpenFileName and GetSaveFileName functions return FALSE if the buffer is too small to contain the file information. The buffer should be at least 256 characters long.

You need to make lpstrFile larger.

Jedhi
November 20th, 2003, 12:00 PM
I am not overloading the OnOpenDocument, so the size of lpstrFile should just be something windows control.

vicodin451
November 20th, 2003, 12:11 PM
Originally posted by Jedhi
I am not overloading the OnOpenDocument, so the size of lpstrFile should just be something windows control.

Right, my bad...
Well, CFileDialog::DoModal has not changed markedly between 6.0 and 7.1 (ints to INT_PTRs is all)...


and I can garantee that str
CString str="";

does not become empty after this. Also It crash after opening a file twice.

Please prove it with code in as simple of a project you can make, that is buildable and debuggable.
If you use str.Empty() rather than assigning the object to "", what happens?

Jedhi
November 20th, 2003, 12:33 PM
Right, my bad...
Well, CFileDialog:oModal has not changed markedly between 6.0 and 7.1 (ints to INT_PTRs is all)...

Well that is exactly what I think what is strange too.

using str.IsEmpty() just tells me that the string is not empty. Really Weard !

I think myself it is something .NET particular, since everything works fine under VC6.0. Do I need to add some references ? or something like that !

I have been reading that it is better to use something else than CString in .NET, but....!!!

vicodin451
November 20th, 2003, 12:39 PM
Originally posted by Jedhi
using str.IsEmpty() just tells me that the string is not empty. Really Weard !

I don' believe it's a CString issue per sé.


I think myself it is something .NET particular, since everything works fine under VC6.0. Do I need to add some references ? or something like that !
Different compiler, potentially different optimizations, different DLLs, all lead to things being laid out differently in the address space of a process. It's not uncommon for a bug that's been dormant in code to rear its ugly head when changing compilers or OS. I wouldn't point a finger at .NET, MFC, or anything other than your code (which we have seen nothing of).


I have been reading that it is better to use something else than CString in .NET, but....!!!
If you're using unmanaged C++ in VC++ .NET, and you're using MFC, why not use CString?

Again:
1) Did the project that I posted indicate that the CString was not empty?
2) Please prove it with code in as simple of a project you can make, that is buildable and debuggable.
3) If you use str.Empty() (not IsEmpty) rather than assigning the object to "", what happens?

pradeepks_61
November 25th, 2003, 12:45 AM
I dont understand how a development env,. can change the behaviour of a class... since the CString class hasent gone through a major change with the dotnet conversion. If ure having initialisation problems then try doing it this way,

CString m_strJedhi(""); using the constructor.

Jedhi
November 25th, 2003, 05:33 AM
I have been reading that the CString class has been modified, so that its behavior in .NET is different than in VC6.0,

Yet I haven't found the solution for it, but will announce it here when coming up to a solution.

vicodin451
November 25th, 2003, 07:23 AM
Originally posted by Jedhi
I have been reading that the CString class has been modified, so that its behavior in .NET is different than in VC6.0,

Yet I haven't found the solution for it, but will announce it here when coming up to a solution.

The internals of the CString have been rehashed significantly from MFC42 to MFC7x, but still should not produce the behavior Jedhi is seeing.

Yet again:
1) Did the project that I posted indicate that the CString was not empty?
2) Please prove it with code in as simple of a project you can make, that is buildable and debuggable.
3) If you use str.Empty() (not IsEmpty) rather than assigning the object to "", what happens?

Jedhi
November 25th, 2003, 08:13 AM
1) Yes, your example show that CString was empty.

2) Well, everything works fine in VC6. So either it is because something has changed dramaticlly in .NET or it is because the project has not been converted correctly to .NET

3) str.Empty() does NOT empty the string in my code.

vicodin451
November 25th, 2003, 08:32 AM
Originally posted by Jedhi
1) Yes, your example show that CString was empty.

2) Well, everything works fine in VC6. So either it is because something has changed dramaticlly in .NET or it is because the project has not been converted correctly to .NET

Originally posted by Vicodin451

Different compiler, potentially different optimizations, different DLLs, all lead to things being laid out differently in the address space of a process. It's not uncommon for a bug that's been dormant in code to rear its ugly head when changing compilers or OS. I wouldn't point a finger at .NET, MFC, or anything other than your code (which we have seen nothing of).

Again:

Please prove it with code in as simple of a project you can make, that is buildable and debuggable.
I think that unless you can provide this, no one will be able to help.


3) str.Empty() does NOT empty the string in my code.

Check out the code for Empty in atlsimpstr.h. If that's not emptying your string, then you've likely trashed memory somewhere.

Rather than setting the string equal to "" or using Empty, then, try assigning the string to something else (a string of 2 or 200 'a' characters, perhaps). See if that works. Then, after that, try using Empty or setting the string equal to "". See if that works.
Or, try adding:
BOOL bHeapIsValid = HeapValidate( GetProcessHeap(), 0, NULL );
in the general area where you are seeing a problem with the CString.

MSDN for HeapValidate:

Return Values
If the specified heap or memory block is valid, the return value is nonzero.

If the specified heap or memory block is invalid, the return value is zero. On a system set up for debugging, the HeapValidate function then displays debugging messages that describe the part of the heap or memory block that is invalid, and stops at a hard-coded breakpoint so that you can examine the system to determine the source of the invalidity. The HeapValidate function does not set the thread's last error value. There is no extended error information for this function; do not call GetLastError.

Jedhi
November 25th, 2003, 10:51 AM
The specified heap is valid.

Maybee it's an error in the code that will only appear in .NET. I do not know.

I find the string error very strange similar that I find it strange that the program crash when I open a file a second time. Open a file is something that is entirely done with the code of .NET, and has nothing to do with mine.

It's hard to tell where it goes wrong in .NET. I can not just copy a little peace of the code, so you can run it, I'm sorry.

vicodin451
November 25th, 2003, 11:00 AM
Originally posted by Jedhi
The specified heap is valid.

Every time? Perhaps multiple heaps are present...
The following function checks the control structures for each heap in the process; if the function returns 0, then all heaps are valid. If the function returns anything other than 0, it returns the "index" of the currupt heap.

DWORD AreHeapsValid( void )
{
DWORD dwNumValidHeaps = GetProcessHeaps( 0, NULL );
HANDLE* pahHeaps = new HANDLE[dwNumValidHeaps];
DWORD dwNumValidHeaps2 = GetProcessHeaps( dwNumValidHeaps, pahHeaps );
if( dwNumValidHeaps != dwNumValidHeaps2 )
{
// This shouldn't be different, unless another thread in the process has used
// HeapCreate in the time between the calls to GetProcessHeaps...
}

for( DWORD ii = 0; ii < dwNumValidHeaps; ii++ )
{
if( !HeapValidate( pahHeaps[ii], 0, NULL ) )
{
delete[] pahHeaps;
return ii;
}
}

delete[] pahHeaps;
return 0;
}



Maybee it's an error in the code that will only appear in .NET. I do not know.
As said before, if you change the variables, subtle bugs that never popped up before can pop up more frequently.


I find the string error very strange similar that I find it strange that the program crash when I open a file a second time. Open a file is something that is entirely done with the code of .NET, and has nothing to do with mine.
What do you mean by "crash"? What's the call stack at the crash?


It's hard to tell where it goes wrong in .NET. I can not just copy a little peace of the code, so you can run it, I'm sorry.
Again, I wouldn't point a finger at .NET, MFC, or anything other than your code (which we have seen nothing of).

Jedhi
November 25th, 2003, 11:53 AM
AreHeapsValid does always return 0.

Here is a cut from the call stack when I try to open a file second time. It crash in the CFileDialog.

CFileDialog::DoModal() Line 111 + 0x20 CDocManager::DoPromptFileName(ATL::CStringT<char,StrTraitMFC<char,ATL::ChTraitsCRT<char> > > & fileName={...}, unsigned int nIDSTitle=61440, unsigned long lFlags=4100, int bOpenFileDialog=1, CDocTemplate * pTemplate=0x00000000) Line 640 + 0xb
CDocManager::OnFileOpen() Line 861 + 0x1d
CWinApp::OnFileOpen() Line 33
_AfxDispatchCmdMsg(CCmdTarget * pTarget=0x006a28d0, unsigned int nID=57601, int nCode=0, void (void)* pfn=0x004b5853, void * pExtra=0x00000000, unsigned int nSig=53, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) Line 89
CCmdTarget::OnCmdMsg(unsigned int nID=57601, int nCode=0, void * pExtra=0x00000000, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) Line 396 + 0x27 CFrameWnd::OnCmdMsg(unsigned int nID=57601, int nCode=0, void * pExtra=0x00000000, AFX_CMDHANDLERINFO * pHandlerInfo=0x00000000) Line 902 + 0x21
CWnd::OnCommand(unsigned int wParam=57601, long lParam=0) Line 2550
CFrameWnd::OnCommand(unsigned int wParam=57601, long lParam=0) Line 320
CWnd::OnWndMsg(unsigned int message=273, unsigned int wParam=57601, long lParam=0, long * pResult=0x0012fc54) Line 1759 + 0x1c
CWnd::WindowProc(unsigned int message=273, unsigned int wParam=57601, long lParam=0) Line 1745 + 0x1e
AfxCallWndProc(CWnd * pWnd=0x003f5238, HWND__ * hWnd=0x001a0832, unsigned int nMsg=273, unsigned int wParam=57601, long lParam=0) Line 241 + 0x1aAfxWndProc(HWND__ * hWnd=0x001a0832, unsigned int nMsg=273, unsigned int wParam=57601, long lParam=0) Line 389
user32.dll!77d43a50()
user32.dll!77d43b1f()
user32.dll!77d43a33()
CHandleMap::LookupPermanent(void * h=0x00000000) Line 116 + 0x16
user32.dll!77d43d79()
AfxInternalPreTranslateMessage(tagMSG * pMsg=0x00164cd8) Line 246 + 0x8
user32.dll!77d44374()
AfxInternalPumpMessage() Line 188 CWinThread::PumpMessage() Line 916 CWinThread::Run() Line 637 + 0xb CWinApp::Run() Line 701
AfxWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, char * lpCmdLine=0x00141f15, int nCmdShow=1) Line 49 + 0xb
WinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, char * lpCmdLine=0x00141f15, int nCmdShow=1) Line 25
WinMainCRTStartup() Line 251 + 0x30

vicodin451
November 25th, 2003, 12:01 PM
I'm ignorant. What is the "crash" you mentioned? An ASSERT fires? What do you mean by "open a file twice" - there's nothing on the stack that appears to actually be opening a file. There's a call to CDocManager::OnFileOpen, but that would be the handler for choosing File | Open, no?

Does your program compile and link with 0 errors and 0 warnings, with the /W4 compiler option? If not, what are the warnings?

Is there any way you can get your project (with everything required to build it) to me? (Either by posting here, or I can PM you with my email address.)