• Keine Ergebnisse gefunden

JY Obiect Filing

Im Dokument PenPomt GO (Seite 149-154)

CNTR_INST inst;

Debugf("Cntr:Cntrlncr");

inst = IDataDeref(pData, CNTR_INST);

inst.currentValue++;

ObjectWrite(self, ctx, &inst);

return stsOK;

MsgHandlerParametersNoWarning;

/* Cntrlncr */

There are a couple of things to note here. The instance data is stored in memory that only the Class Manager can write. When the Class Manager calls the message handler, it passes a pointer to this protected instance data (pData). If the code had tried to update pData->currentValue directly, PenPoint would have generated a general protection fault immediately. So, the code creates a local structure for the instance data and uses the IDataDeref macro to dereference the instance data pointer into local, writable, memory (inst).

There is nothing mysterious about the IDataDeref macro. All it does is provide a short hand way of casting the instance data indicated by pData. IDataDeref is defined in CLSMGR.H as:

#define IDataDeref(pData, type) (*(type*)pData) We could just as easily have written:

inst = (CNTR_INST) pData;

Mter incrementing the value in local memory, clsCntr calls ObjectWrite, which directs the Class Manager to update the instance data stored in the object.

ObjectWrite(self, ctx, &inst);

JY Obiect Filing

The way objects preserve state is by filing it at the appropriate time. The Application Framework sends the application instance msg5ave when the document should save its state and msgRestore when the document should recreate itself. The order in which applications receive these and other messages from the Application Framework is explained in Part 2: Application Framework of the PenPoint Architectural Reference manual.

9.2.5.2

Note A frequent source of programming errors is trying to modifY read-only instance data.

Note Another freq uent source of programming errors is failing to update instance data with ObjectWrite after changing instance data.

9,3

Objects can also preserve state by refusing to be terminated, although this usually consumes memory.

CHAP-TER 9 I SAVING AND RESTORING DATA (COUNTER APP) 141

The message arguments to msgSave and msgRestore include a handle on a resource file. Objects respond by writing out their state to this file and reading it back in. The objects do not care where the resource file is, nor do they care who created it.

The Application Framework creates and manages a resource file for each

document. The file handle passed by msgSave and msgRestore is for this resource file. If you start up the disk viewer with the B debug flag set to 800 hexadecimal, and expand \ \RAM\PENPOINT\SYS\Notebook\CONTENTS\NotebookApplications, you should be able to see these files; look for a file called DOC.RES in each document directory.

At the level of msgSave and msgRestore, classes can just write bytes to a file (the resource file) to save state.

When it receives msgSave,· clsCntrApp could get the value of the counter object (by sending it msgCntrGetValue) and just write the number to the file.

However, this would introduce dependencies between the two objects, which in object-oriented programming is a bad thing. So, instead clsCntrApp tells the counter object to file itself. We'll cover exactly how this happens later, but for now just accept that the clsCntr instance receives msgSave.

Object Filing

".. Handling msgSave

9.3.1

The message argument to msgSaveis a pointer to an OBLSAVE structure:

MsgHandlerArgType(CntrSave, P_OBJ_SAVE)

If you look in \PENPOINT\SDK\INC\CLSMGR.H, you will notice that one of the fields in the OBLSAVE structure is the handle of the file to save to. So all clsCntr has to do is write that part of its instance data that it needs to save to the file:

basically, all of its instance data.

To write to a file, you send msgStreamWrite to the file handle. The message takes a pointer to a STREAM_READ _WRITE structure, in which you specify what to file arid how many bytes to write.

MsgHandlerArgType(CntrSave, P_OBJ_SAVE)

{

STREAM_READ_WRITE fsWrite;

STATUS s;

Debugf("Cntr:CntrSave");

II

II Write instance to the file.

II

fsWrite.numBytes= SizeOf(CNTR_INST);

fsWrite.pBuf= pData;

ObjCallRet(msgStreamWrite, pArgs->file, &fsWrite, s);

return stsOK;

MsgHandlerParametersNoWarning;

1* CntrSave *1

msgStream Write passes back information about how many bytes it actually wrote.

A real application would check this information to make sure that it successfully filed all its state.

".. Handling msgRestore

msgRestore is similar to msgSave. The Class Manager handles msgRestore by creating a new object, so the ancestor must be called first. The message argument to msgRestore is a pointer to an OBLRESTORE structure:

MsgHandlerArgType(CntrRestore, P_OBJ_RESTORE)

Again, one of the fields in this structure is the UID of the file handle to restore from. clsCntr just has to restore seWs instance data from the filed data. This is similar to initializing instance data in msgInit handling, except that the

information has to be read from a file instead of from msgNew arguments. You declare a local instance data structure:

MsgHandlerArgType(CntrRestore, P_OBJ_RESTORE)

{

CNTR_INST inst;

STREAM_READ_WRITE fsRead;

STATUS s;

To read from a file, you send msgStreamRead to the file handle, which takes a pointer to the same STREAM_READ_WRITE structure as msgStreamWrite. In the structure you specify how many bytes to read and give a pointer to your buffer that will receive the data:

Debugf ("Cntr:CntrRestore") ;

II

Read instance data from the file.

II II

fsRead.numBytes= SizeOf(CNTR_INST);

fsRead.pBuf= &inst;

ObjCallRet(msgStreamRead, pArgs->file, &fsRead, s);

You call ObjectWrite to update the object's instance data.

II II

Update instance data.

II

ObjectWrite (self,. ctx, &inst);

return stsOK;

MsgHandlerParametersNoWarning;

1* CntrRestore *1

".. CounterApp's Instance Data

clsCntrApp's instance data contains:

• The display format to use for the counter value

• The UID of the counter object

• A memory-mapped file handle (explained below).

9,3,2

9.4

CHAPTER 9 I SAVING AND RESTORING DATA (COUNTER APP) 143 CounterApp's Instance Dato

When the user turns away from a CounterApp document's page, the Application Framework destroys the counter object (and the application instance). When the user turns back to the CounterApp document, the counter object is restored with a different UID. Hence clsCntrApp should not file the UID of the counter object, because it will be invalid upon restore. clsCntrApp only needs to file the display format and to tell the counter object to save its data.

",. Memory-Mapped File

CounterApp could just write its data to the resource file created by the

Application Framework, just as the counter object did. However, a disadvantage of filing d~ta is that there are two copies of the information when a document is open: the instance data in the object maintained by the Class Manager and the filed data in the document resource file maintained by the file system.

One way to avoid this duplication of data is to use a memory-mapped file.

Instead of reading and writing to a file, you can simply map the file into your address space; reading and writing to the file take place transparently as you access that memory.

clsCntrApp stores its data (the current representation) in a memory-mapped file.

Tip. Saving the UIDs of an object is usually incorrect. Either the object has a well-known UID (there's no reason to file it), or methods. This is useful when you need to differentiate between instance data and other forms of data.

"'''' Opening and Closing The File

9.4.2

Because you need to open the file both when creating the document for the first time, and when restoring the document after it has been filed, you need to open the file in two different places (msgAppInit and msgRestore), but you only need close it in one place (msgFree).

Why close the file in response to msgFree? Why not msgSave? Remember that when an application is created, it is sent msgApplnit (in response to which it creates and initializes objects) and then is immediately sent msgSave (which allows it to save its newly initialized objects before doing anything else). msgSave is also sent when the user checkpoints a document. In other words, receiving msgSave doesn't necessarily mean that we're about to destroy the application object.

,.,.,.. Opening For the First Time

When CounterApp receives msgApplnit, it creates the counter object:

MsgHandler(CntrAppAppInit)

Debugf ("CntrApp: CntrAppAppIni t ");

inst = IDataDeref(pData, CNTRAPP_INST);

9.4.2.1

II II

Create the counter object.

II

ObjCallRet(msgNewDefaults, clsCntr, &Cn, s);

cn.cntr.initialValue = 42;

ObjCallRet(msgNew, clsCntr, &cn, s);

inst.counter = cn.object.uid;

CntrAppAppInit opens the file (called FORMATFILE), initializes the format value, and writes the initial data to the file:

II II

Create a file, fill it with a default value

II

ObjCallRet(msgNewDefaults, clsFileHandle, &fsn, s);

fsn.fs.locator.pPath = "formatfile";

fsn.fs.locator.uid = theWorkingDir;

ObjCallRet(msgNew, clsFileHandle, &fsn, s);

format = dec;

fsWrite.numBytes = SizeOf(CNTRAPP_DISPLAY_FORMAT);

fsWrite.pBuf = &format;

ObjCallRet(msgStreamWrite, fsn.object.uid, &fsWrite, s);

Mapping the file to memory is quite straightfoward. CounterApp sends msgFSMemoryMap to the file handle, and passes the pointer to the address pointer (pp _MEM). Finally updates its instance data and returns:

II

Map the file to memory

II

ObjCallRet(msgFSMemoryMap, fsn.object.uid, &inst.pFormat, s);

II

Update instance data.

ObjectWrite(self, ctx, &inst);

return stsOK;

MsgHandlerParametersNoWarning;

1* CntrAppAppInit *1

Opening To Restore

CntrAppRestore is essentially similar to CntrAppApplnit, only after creating a handle on FORMATFILE, CntrAppRestore maps the file to memory, which immediately makes the format data available in inst.pFormat.

MsgHandlerWithTypes(CntrAppRestore, P_OBJ_RESTORE, P_CNTRAPP_INST)

(

FS NEW fsn;

CNTRAPP INST inst;

STATUS s;

Debugf("CntrApp:CntrAppRestore");

II

Get handle for format file, save the handle ObjCallRet(msgNewDefaults, clsFileHandle, &fsn, s);

fsn.fs.locator.pPath = "formatfile";

fsn.fs.locator.uid = theWorkingDir;

ObjCallRet(msgNew, clsFileHandle, &fsn, s);

inst.fileHandle = fsn.object.uid;

II

Map the file to memory

ObjCallRet(msgFSMemoryMap, fsn.object~uid, &inst.pFormat, s );

CHAPTER 9 / SAVING AND RESTORING DATA (COUNTER APP) 145 CounterApp's Instance Data

(~osing On msglFree

When the application receives msgFree, it destroys the counter object, sends msgFSMemoryMapFree to unmap the file, and then sends msgDestroy to the file handle to close the file.

MsgHandlerWithTypes(CntrAppFree, P_ARGS, P_CNTRAPP_INST)

(

STATUS s;

Debugf(ICntrApp:CntrAppFree");

ObjCallRet(rnsgDestroy, pData->counter, Nil(P_ARGS), s);

II Unrnap the file

ObjCallRet(rnsgFSMernoryMapFree, pData->fileHandle, Nil(P_ARGS), s);

II Free the file handle

.ObjCallRet(rnsgDestroy, pData->fileHandle, Nil(P_ARGS), s );

return stsOK;

MsgHandlerPararnetersNoWarning;

1* CntrAppFree *1

Im Dokument PenPomt GO (Seite 149-154)