CArchive, CSocket and ReadObject
Chris Patterson -- cmp@ix.netcom.com
Saturday, February 24, 1996
I am developing an application in 4.0 that connects two PC's over the
Internet using a CSocket/CSocketFile/CArchive combination in a manner
similar to the chat server example included with MFC. While the example
demonstrates how to create a session for a single object type, I'm wanting
to send various CObject-derived types over the session.
The problem I'm encountering is that the receiver doesn't know the object
type before the object arrives. So I'm attempting to use a
CArchive::ReadObject() with a NULL CRuntimeClass pointer so that the object
type will be determined, an object created, the data read into the object
and the object returned for inspection via the IsKindOf() function.
I can't seem to get it to work. I'm always getting a NULL pointer returned
from the ReadObject(NULL) function, and because there is still data ready
in the archive buffer, it tends to loop for an eternity.
I'm trying to avoid giving each class type a unique ID and sending it over
the connection as a WORD to tell the receiver what type of object to expect
and read from the network connection. That just seems to break the benefit
of run-time class information. However, if it's is found that this type of
communication isn't possible, I'll accept it.
Any easy answers to the problem or anything saying that "it just doesn't
work that way" would be appreciated. A solution would be superb.
Chris Patterson
Software Engineer, CIS Technologies, Inc.
cmp@ix.netcom.com
Mukesh Prasad Development Contractor -- mukesh@everest.XAIT.Xerox.COM
Monday, February 26, 1996
[Mini-digest: 3 responses]
I would suggest, in increasing order of difficulty:
1) Check to make sure that the class of interest
is common to both sides of connection.
2) Make sure the IMPLEMENT_SERIAL macro has
been executed on both sides of connection
for the class of interest.
3) Confirm again that the order of writing is
matched exactly by the order of reading.
4) Run the receiver in debug mode, and watch the trace.
(It is a bit surprising that you are not getting an
assertion failure, actually.)
5) In the receiver, set a breakpoint in
the file \msdev\mfc\src\arcobj.cpp at
CArchive::ReadObject. If you step through, you
will find it reads the class name as text, and
then looks it up in its map (hash-table) of all
class names. Obviously, the class must be
available in its map of classes, which means the
class must be available and the appropriate
RUNTIME macros etc should have been used/invoked.
-----From: Gerry Sweeney
Chris,
I have done something similar using 16bit MFC so I didn't use CSocket ect.
The principle should be the same. I derived a class from CMemFile and added
a member function called 'GetBuffer' which returns me a pointer to the
memory that the memory file uses to store its data. I serialize my object(s)
into a CArchive which is associated with the CMemFile derived class. To send
this across the network I use the Winsock API and just send a small header
which has a message ID(tells me what it is in the client), and the length of
the data to follow. then I send the contents of the CMemFile's buffer. In
the client when I get notified that data is available I wait until there is
enough bytes to be a 'header'. When I have this I create a CMemFile and set
its length to the expected data length, get the pointer to the buffer and
receive the outstanding data form the network. I then create a CArchive and
serialize my object to recover the data.
This does work but it still requires you to know what object you are
receiving. As far as I know there is no way to automate that. After all as a
minimum you need a pointer to your object so you should know what to expect.
This is where the initial message in the header becomes useful.
I hope this helps
Gerry Sweeney
gerry@hornbill.com
-----From: Peter Olesen
I think you _must_ have the runtime class to be able to serialize the object
back. But you don't need to give each class a magic number, they allready
have - the runtime class name.
You could send the runtime class name first as a zero terminated string
(allways ANSI even in a UNICODE app.) and then call a function to find the
runtime class:
CRuntimeClass * GetRuntimeClass(LPCSTR pszClassName)
{
CRuntimeClass * pRTC = NULL;
// just walk through the simple list of registered classes
AFX_CORE_STATE * pCoreState = AfxGetCoreState();
for (CRuntimeClass * pRuntimeClass = pCoreState->m_pFirstClass;
pRuntimeClass != NULL;
pRuntimeClass = pRuntimeClass->m_pNextClass)
{
// class name must match
if ( strcmp(pRuntimeClass->m_lpszClassName, pszClassName) == 0 )
{
pRTC = pRuntimeClass;
break;
}
}
return pRTC;
}
This only work if you have the same version of the object on both sides.
I do this in my own app. where I OLE drag and drop several different
CObject-dervived classes. I also have the object size and version to check
so I don't use different versions of application to drag between (excluded
here).
Hope this help
//------------------------------------------------------------//
// Peter Olesen //
// (peter.olesen@mailbox.swipnet.se) //
// //
// "Support the Blue Ribbon Campaign for free speech online." //
//------------------------------------------------------------//
| Вернуться в корень Архива
|