|
Hi,
I have serialized a tree control which container is a CView derived class. Everything works fine during serialization and unserialization.
Tree items display perfectly after Unserialization but a message box displays this text: "Unexpected file format."
this message is located in
Vc7\atlmfc\include\afxres.rc( line 74): AFX_IDP_FAILED_INVALID_FORMAT "Unexpected file format."
I’ve tried to find the reason of this message and also found a thread talking of the same problem @ : http://www.codeguru.com/forum/showt...ization+pointer
But no solution is provided. Could you please help me resolve this issue?
I use VS 2003 my application is based on an MDI document view and the message occurs in the debug and release version.
Many thanks for your help
|
|
|
|
|
Are you using CObject serialization?
Are you positive your serialize and unserialize code writes and reads the exact same number of
bytes to/from the file?
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
Yes I use CObject Serialization. About data storing and loading I indent the storing and I use "\r\n" to skip to the next line.
I have attached the code for your review.
void BnBSymbolTreeCtrl::Serialize(CArchive& ar)
{
BnBSymbolInfos* pInfo = NULL;
TVITEM tvi = {0};
UINT state = NULL; ;
LPARAM param = NULL ;
UINT mask = TVIF_HANDLE |TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_STATE|TVIF_TEXT;
int nImage = NULL;
int nSelectedImage = NULL;
if (ar.IsStoring())
{
HTREEITEM hti = GetRootItem();
while( hti )
{
tvi.mask = TVIF_HANDLE |TVIF_PARAM;
tvi.hItem =hti ;
GetItem(&tvi);
LPARAM param = tvi.lParam;
int nImage;
int nSelectedImage;
GetItemImage(hti, nImage, nSelectedImage);
UINT state = GetItemState(hti,TVIS_BOLD);
UINT ste = tvi.state;
CString str = GetItemText( hti );
int indent = GetIndentLevel( hti );
while( indent -- )
ar.WriteString( "\t" );
ar.WriteString( GetItemText( hti ) + "\r\n");
ar << state << param << nImage << nSelectedImage;
ar.WriteString("\r\n" );
pInfo = m_SymbolInfo.GetSymbolInfoObject(hti);
if(pInfo)
ar << pInfo->lparam;
ar.WriteString("\r\n" );
hti = GetNextNearItem( hti );
}
}
else
{
CString sLine;
if(!ar.ReadString( sLine ) )
return;
DeleteAllItems( );
HTREEITEM hti = NULL;
int indent, baseindent = 0;
CString strReturn = "\r\n";
while( sLine[baseindent] == '\t' )
baseindent++;
do
{
if( sLine.GetLength() == 0 )
continue;
for( indent = 0; sLine[indent] == '\t'; indent++ )
;
sLine = sLine.Right( sLine.GetLength() - indent );
indent -= baseindent;
HTREEITEM parent;
int previndent = GetIndentLevel( hti );
if( indent == previndent)
parent = GetParentItem( hti );
else if( indent > previndent )
parent = hti;
else
{
int nLevelsUp = previndent - indent;
parent = GetParentItem( hti );
while( nLevelsUp-- )
parent = GetParentItem( parent );
}
ar >> state >> param >> nImage >> nSelectedImage;
ar.ReadString(strReturn);
hti = InsertItem( mask, sLine,nImage, nSelectedImage,state,\
state ,param, parent ? parent : TVI_ROOT, TVI_LAST );
tvi.hItem = hti;
GetItem(&tvi);
pInfo = new BnBSymbolInfos();
ar >> pInfo->lparam;
if(pInfo)
{
if(pInfo->lparam == tvi.lParam)
{
tvi.lParam = reinterpret_cast<LPARAM> (pInfo);
SetItem(&tvi);
}
}
ar.ReadString(strReturn);
}while( ar.ReadString( sLine ));
}
}
|
|
|
|
|
I'm suspicious ( ) about your serialization of "pInfo->lparam"...
When storing you do this:
pInfo = m_SymbolInfo.GetSymbolInfoObject(hti);
if(pInfo)
ar << pInfo->lparam;
When loading you do this:
ar >> pInfo->lparam;
if(pInfo)
{
if(pInfo->lparam == tvi.lParam)
If you have a conditional write when storing then you should store something if the condition
fails - otherwise at load time you don't know if you should load the next value from the stream
or not.
For example, if when storing, if "if(pInfo)" is false, pInfo->lparam is not archived.
When you load from the archive, you read pInfo->lparam unconditionally - but it won't be there.
Now the stream is off by sizeof(pInfo->lparam) bytes. Make sense?
Also, when loading, you create an object...
pInfo = new BnBSymbolInfos();
...use the object...
ar >> pInfo->lparam;
...Then check if the object is NULL
if(pInfo)//link the symbolinfo to its related node
That makes the NULL check useless
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
You're right about this piece of code but actually it is not responsible of the problem.
With this simple code, storing and loading is ok but I still get this nasty message box after loading.
any idea?
void BnBSymbolTreeCtrl::Serialize(CArchive& ar)
{
HTREEITEM hti = NULL;
if (ar.IsStoring())
{
hti = GetRootItem();
ar.WriteString( GetItemText( hti ));
}
else
{
CString sLine;
ar.ReadString( sLine );
hti = InsertItem( sLine, TVI_ROOT, TVI_LAST );
}
}
|
|
|
|
|
Hmm - You aren't using the same archive object for both serializing and unserializing are you?
Or using the same CFile without calling SeekToBegin()?
Can you show the code that creates the CFIles and CArchives used when it fails?
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
I call Serialize from the CDocument derived class's Serialize method.
This function is called when selecting save and open menus.
in the meantime I'm wondering if CArchive can t support mixing types and especially the ReadString and AddString functions.
Below is my finding
void BnBSymbolTreeCtrl::Serialize(CArchive& ar)
{
CString str;
CString str1 = "Root";
char* pchr= "Root";
if (ar.IsStoring())
{
ar << str1;
}
else
{
ar >> str;
InsertItem( str, TVI_ROOT, TVI_LAST );
}
}
|
|
|
|
|
Ok I've been digging through the source code. I'm on MFC 7.1 (VS2003)
I'm not sure how this compiles since there's no insertion/extraction operators that take a
CString:
CString str;
CString str1 = "Root";
...
ar << str1;
...
ar >> str;
The only way I see to write and read a CString is:
CString str;
CString str1 = "Root";
...
ar.WriteString( (LPCTSTR)str1 );
ar << _T('\n');
...
ar.ReadString( str );
FWIW I hated this about CArchive. I use my own CArchive-derived class which writes strings
using a lead WORD for the string length. I thought it was silly when you want your load/store
code to match 1-to-1 but you have to add an extra line when storing a string to write a newline
Mark
"Posting a VB.NET question in the C++ forum will end in tears." Chris Maunder
|
|
|
|
|
I'm writing a dialog-based application in Visual C++ 2003 and i have the following problem: dialog , buttons and the other components dose not has Windows XP style, rather has the old Windows style. I something wrong with Visual Studio installation? This behavior golds true event for Visual Basic. Please help!
|
|
|
|
|
|
UINT ThreadProc(LPVOID lp)
{
while(bKeepRunning)
{
BlockToDeathLibFunction();
}
}
Imagine the above situation, where BlockToDeathLibFunction is a function inside an external library(meaning to say it's out of our control) blocks the control. Here we want to get out of the thread and set the bKeepRunning to false,. Now if only the blocking call gets released, the thread will get closed. But here it's out of our control. How do we handle this? Should use TerminateThread or something like that? Which is the best way?
Press: 1500 to 2,200 messages in just 6 days? How's that possible sir?
Dr.Brad :Well,I just replied to everything Graus did and then argued with Negus for a bit.
|
|
|
|
|
As is it stated, yes, the only viable solution is TerminateThread (at least IMHO).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
CPallini wrote: TerminateThread
But he's a rude guy you know, like the Terminator.
Press: 1500 to 2,200 messages in just 6 days? How's that possible sir?
Dr.Brad :Well,I just replied to everything Graus did and then argued with Negus for a bit.
|
|
|
|
|
Oh yes, expecially with blocking routines...
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
VuNic wrote:
VuNic wrote: CPallini wrote:
TerminateThread
But he's a rude guy you know, like the Terminator.
True, but you have no other option in this case.
The same call would be made if the user brings up Task Manager and kills the program/process.
"It's supposed to be hard, otherwise anybody could do it!" - selfquote "High speed never compensates for wrong direction!" - unknown
|
|
|
|
|
Roger Stoltz wrote: The same call would be made if the user brings up Task Manager and kills the program/process.
hmm.. Noted.
Press: 1500 to 2,200 messages in just 6 days? How's that possible sir?
Dr.Brad :Well,I just replied to everything Graus did and then argued with Negus for a bit.
|
|
|
|
|
Calling TerminateThread for this function is a sin in Win32 (with barely any exceptions). See here[^] and here[^] here for details. Quote from MSDN:
TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
- If the target thread owns a critical section, the critical section will not be released.
- If the target thread is allocating memory from the heap, the heap lock will not be released.
- If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
- If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
This is one of the most frequent and serious mistakes Win32 programmers make. It creates a class of bug that's very hard to track down and is non-determinisitc.
Steve
|
|
|
|
|
if you want to accomplish what OP ask you have to use TerminateThread , I know well that this is the last resource for a programmer, but, again, if you don't have any other solution, you have to use it (This is the reason MS made it). Personally I hate to use it as I hate to use the task manager to kill a process. But, again, it is a matter of last resource.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
But if the code you're terminating is allocating memory on the heap (and probably most non-trivial threads do this), you just introduced the possibility of a deadlock.
Calling TerminateThread on an thread doing unknown things leaves the process in an undefined state. The only thing you can do is to move out the library call into a separate process and kill the process when aborting. All global resources will be freed by the OS, and all process resources don't have to be freed because the process is dead. The only safe way to kill unknown code is to kill its process.
|
|
|
|
|
Indeed your alternative is valid (and nice), even if (at least IMHO) the TerminateThread MSDN documentation is less severe (than you) about using it.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
CPallini wrote: even if (at least IMHO) the TerminateThread MSDN documentation is less severe (than you) about using it.
Actually I think MSDN underplays the issue; calling TerminateThread is an extremely serious issue.
Steve
|
|
|
|
|
Stephen Hewitt wrote: Actually I think MSDN underplays the issue;
A don't know if they do that above stated.
Stephen Hewitt wrote: calling TerminateThread is an extremely serious issue.
Oh yes, but it's context-dependent and, at least it's no more serious that ternminating abrptly a thread.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
It's not an option; in the same way chopping off your head is not a cure for a brain tumor.
Steve
|
|
|
|
|
A bit crude. That said, I don't agree with you.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
|
|
|
|
|
Then consider this:
==================
// Console.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <process.h>
using namespace std;
unsigned __stdcall ThreadFn(void *)
{
for (;;)
{
// Comment these two lines out and the program will not deadlock. With them it will!
int *pInt = new int;
delete pInt;
}
return 0;
}
int main(int arvc, char* argv[])
{
for (;;)
{
unsigned unused;
unsigned long res = _beginthreadex(
NULL, // void *security
0, // unsigned stack_size
&ThreadFn, // unsigned ( __stdcall *start_address )( void * )
NULL, // void *arglist
0, // unsigned initflag
&unused // unsigned *thrdaddr
);
if (res==0)
{
cerr << "Failed to create thread!" << endl;
return 1;
}
for (int i=1; i<=1000; ++i)
{
int *pInt = new int;
delete pInt;
cout << i << " ";
}
HANDLE hThread = reinterpret_cast<HANDLE>(res);
// Comment this line out and the program will not deadlock. With it it will!
TerminateThread(hThread, 0);
CloseHandle(hThread); // We don't need the HANDLE anymore so close it.
}
return 0;
}
Steve
|
|
|
|