TweetFollow Us on Twitter

Design Objects
Volume Number:7
Issue Number:1
Column Tag:C Workshop

Related Info: Memory Manager File Manager Event Manager

Designing With Objects

By Wade Maxfield, Dallas, TX

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

How to Design an Object Oriented Program

[Wade Maxfield is a System Analyst Consultant currently working at Mobil Oil company in Dallas, Texas. His interest in computers dates from the late 1960’s, when he wrote his “very first” bubble sort in Fortran for an IBM 1130. His training for the real world comes from the BSEET program at DeVry Institute.]

In a 1960’s era Reader’s Digest “Life in these United States” anecdote, a man told a story about his huge English Sheepdog. One of his neighbors a few blocks down the lane had a Triumph automobile, which was a few inches shorter in height than the dog. As this tiny car would scoot by their house on the way to work, their dog would tear out, barking loudly. This became a ritual, since the neighbor went to work the same time each afternoon.

Finally, the neighbor had enough. In full view of everyone, he skidded to a stop. The dog dug in, missing the car by inches. Sitting on the back of the driver’s seat in the topless car, he turned to the dog and asked, “Now that you have it, what are you going to do with it?”

We are in the same predicament. We have objects. What are we going to do with them? In this article, I will endeavor to show you how to plan, design, and write an object oriented program by example. I have chosen a very simple task-- removing line feeds from a text file. The main thing to learn is that messages are where you start, and objects where you finish. There are several pieces to the design puzzle. Some background is in order. I have listed the key elements by heading.

1. Messages:

Messages are what we describe fully before we write our program. If you program off the cuff, you will find that you will still want to define a message before you write the program, even if it is 30 seconds before.

Conceptually, messages are data. Messages have a transient existence. They are created by the sending object, destroyed by the receiving object. Messages tell the object what to do. A message has a command portion, and a variable data portion.

The command portion in a message always causes some software to be executed but a message has no software in it. In a truly message based system a message can be seen using tools that can examine data lying around inside a program’s environment. In today’s compiled object oriented systems, messages are function calls. The function name is the command portion and the parameters are the variable data portion.

Depending upon the destination and the purpose of a message it might need to be acknowledged. This acknowledgment in a totally message based system is in the form of a message called an ACK(nowledgment). If a message cannot be acted upon, or if the work the object is supposed to do fails, a message is NAK(ed. (not acknowledged)). In a compiled object oriented system, the return value from the function call is the ACK or NAK. An acknowledgment is a conceptual tool. If this tool is exercised properly, it can guarantee system performance. Your objects can always be told whether or not an operation occurred.

2. Objects:

Objects started with SmallTalk in Xerox PARC. Danny Kay and his cohorts came up with SmallTalk during research into where computers should go. Their research spawned the ill-fated Xerox Star, the Apple Lisa, the Macintosh, and now the NeXT. They pioneered the concept of treating software functions as black boxes. You talked to these boxes with messages. These boxes are known as objects.

[an aside:

The object oriented package in the THINK C environment contains very good explanations of objects and messages (methods) from the programming usage viewpoint. Messages as function calls are fully explained. What is not fully explained is how an object works.

An object is defined by declaring a structure with an implicit typedef statement. This creates a structure which is used as a future template for the actual object. The object is declared as a pointer to a structure of type object. Then the new(object) call is made. This function allocates a Macintosh Memory Manager Handle large enough to hold the structure definition, and fills in the new handle with enough address information to derive the addresses of the functions referenced in the structure. From then on, a call through a “message dispatcher” finishes the calling of the routine indicated by the method described in the object or its ancestor. A message call looks like this: object->method(parm1, parm2). ]

3. Data Definitions:

Software engineers at Bell Laboratories pioneered the concept of designing software by describing all of the data you are going to manipulate. You first wrote down all of the variable names, and placed them into a dictionary. In this dictionary, you then described everything you would do to the variables. Once you have rigorously defined everything that can be done to the data, you have described what the software must do to successfully complete its given task.

4. Design Methodology and its Graphics:

Mr. Yourdon, with his cohort Mr. DeMarco, came up with a methodology of analyzing software design. The Yourdon Structured Analysis and Design Methodology is oriented towards real time design, but it works for Macintosh software design. The reason is that all Macintosh programs are near real time programs. All real time software responds to events as they occur. What user will wait minutes for the computer to respond to a mouse click?

The most important (to me) portion of the Yourdon design techniques is the data flow diagrams. These describe where the data goes (but not when). I have modified his diagram concepts, and thrown away a few of his rules. I will lay a few ground rules for drawing these modified diagrams.

First, a circle is an object. An object receives messages from other objects. An objects name is placed in the circle.

Second, messages are drawn as arcs from one object to the next. A directional arrow is placed at the end of the arc and a brief description of the message sent to the object placed near the middle of the arc. This description is usually more of a mnemonic than a true description.

Third, data is indicated by a description sandwiched between two parallel lines (usually horizontal). Variables are data. The data is manipulated by objects (and may be part of the object). An “arrowed” arc is used to show which object manipulated the data, with a description of what happens to the data (read, write, update, Etc.). In object oriented programming, an object should only manipulate its own data. It can be told to manipulate its data with a message, or asked for the current value of the data with a message. Data may also be a disk file, or any other storage location (such as a video screen).

Fourth, a rectangular box is used to indicate an external event which causes some data to flow through the system in the form of messages. This external event may be a mouse click or keyboard entry from the user, a call back routine from a disk write event, or an interrupt from the system time clock. An external event is almost always asynchronous to program execution. The flow of this data is also indicated by labeled arcs.

Diagram 1

Diagram 2

Diagram 3

Diagram 4

Diagram 5

Finally:

So now we have the elements necessary to think of designing for object oriented programming. First we have objects, which accept messages. Second, we have the concept that you describe everything that you must do to the data (ie: describe all of the messages). Third, we have some structured analysis techniques modified from real time design analysis given by Yourdon. Lets do a design.

The Design:

I need to strip line feeds from text files which are sent to me from IBM (yuk!) based systems. I need for this program to 1). display a standard SFGetFile dialog box, 2). open the selected file, 3). display a standard SFPutFile dialog box, 4). create the described file, 5). read in the source data a line at a time until exhausted, and 6). write the same data minus the line feeds to the destination file. I will use THINK C 4.0.

How the messages flow:

(Note, the names are made up as I go along. Any correlation to any code past or present is purely coincidental. Any correlation to objects already known is purposeful.)

I will send a (GetExistingFile) message to myFileManager object to get me the source file the user wants to convert. myFileManager will send a reply message to me telling me one of two things: 1) he has the data for me (ACK), 2) he doesn’t have anything for me (ie: the user canceled, an error occurred), and nothing can be guaranteed about his data (NAK). See diagram 1.

If the message was a success, I will send an (OpenFile) message to myFileManager. He will create a myDataFile object for me that deals with that file, and give that object to me. It will know how to read, write, and close that file. See diagram 3.

Then I will send a (GetNewFile) message to myFileManager object to get me the destination file the user wants as the output. After dealing with the identical return as in the (GetExistingFile) message, I will send an (OpenFile) message to myFileManager, and get the destination myDataFile object. See diagrams 2 and 3. Then I will create my TextFilter object and initialize it.

Now, until the return message from myDataFile input object indicates an error or end of file, I will send (ReadLine) messages to the source file object. I will feed the lines in a (StripLineFeeds) message to the TextFilter object. I can ignore the (ACK) message from this object. Then I will send a (WriteSome) message to the output object. See diagram 4.

At a NAK from the input myDatFile object, I will send a (CloseFile) message to myFileManager object, handing him the input an output objects. That will take care of any clean up for this particular situation. I will also send a (Dispose) message to my TextFilter object. See diagrams 4 and 5.

Normally, an Exit message or a Quit message would be sent, but for this simple situation, the clean up was done in the run method, and no other messages are needed. The program execution falls through to the normal exit code included in the application shell.

Conclusion:

If THINK C 4.0 were truly a message based system, with an interpreter handling the dispatch of messages, and the running of code based on where the message was sent, then you would see very little program logic should you try to examine the “code” without the above narrative. Messages would flow back and forth between objects without apparent rhyme or reason, and you would have a hard time predicting what the system does unless you had the master plan in your hand.

You could design a program that way under THINK C 4.0, or a similar environment. If you did, you would find that under situations where one message triggered a second message which triggered the first message (and so on), the stack would quickly overflow. There would be no returns from the subroutines. The address pushed on the stack for each message call would not be popped. And we know all messages should be popped off! A work around for this would be an assembly language routine which would take the outgoing message as its parameters and do the stack clean up for you. This would be very dangerous for the casual programmer. Any mistake would crash the system.

Another way to handle messages under this type of environment would be to build your own message dispatcher, and tie it into the user defined events in the Macintosh event manager. A message would be posted into the event queue, and the message would be dispatched through the main message processor, Macintosh style.

The messages themselves could be done two ways. You could include every case in the do application event handler. Talk about huge multilevel switch statements! Or, if the message portion of the event was a pointer to the data structure containing the message, and that structure contained the object and the address of its method (the message to be sent), along with some indication of the parameters to be given to the method, a message dispatcher would work. Each object handle would have to be locked down to prevent movement. It would be difficult to send several messages in a row from one object. The design would stay the same, but there could be as much as one method per message sent or received.

For our program, I am going to use the environment handed to me without changes. This solves a problem for me in that I look at the resulting code and it looks like pure C! This makes it easy for me to understand and troubleshoot. However, the advantages of objects do show up. My program reads more like an outline than a typical C program containing a massive amounts of details.

What is not apparent is the design methodology behind the program. The program is easy to modify. It also looks to be simple, and it is. The objects do the hard work, and their code can look very dirty. The benefit is in dealing on a different conceptual plane. Once an object is written, it can be easily reused or stretched.

Once the “system” using objects is designed, the objects themselves don’t have to reside inside the current application. An object can be moved to a different program or computer. As long as the messaging system handles the delivery of messages and their replies, the “system” will always accomplish what it is supposed to. This “lever” [message oriented design] allows multiple processor systems to be built with very little change in design when moving from a single processor system.

The code:

NOTE: For this example, I have taken the standard Starter.c application provided with THINK C 4.0 and modified it for this project. Many of the explanatory notes are the ones given in the THINK C 4.0 source code. For this project, I was able to ignore them!

(This is the root of all object oriented programs for THINK C 4.0. Note that it looks more like an outline than a program.)

/*****
 * RemoveLF.c
 *
 * A starter main file for writing programs with the
 * THINK Class Library
 *****/
#include “CRemoveLFApp.h”
extern  CApplication *gApplication;

void main()
{
 gApplication = new(CRemoveLFApp);
 ((CRemoveLFApp *)gApplication)->IRemoveLFApp();
 gApplication->Run();
 gApplication->Exit();
}

(All of the work in our particular program is done in the Run method.)
/*****
 * CRemoveLFApp.c
 * Application methods for a typical application.
  *****/
#include “oops.h”
#include “messageDefines.h”
#include “CRemoveLFApp.h”
#include “CRemoveLFDoc.h”
#include “CmyFileManager.h”
#include “CmyDataFile.h”
#include “CTextFilter.h”

extern  OSType gSignature;
static char readBuffer[512];
/*..........................................................*/
void CRemoveLFApp::Run(void)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
Run
we need to do our thing here, not the normal built in
code work
Modification History:
*/
{
CmyFileManager *FileManager;
SFReply sourceReply;
SFReply destinationReply;
short returnMessage;
CmyDataFile *sourceDataFile;
CmyDataFile *destinationDataFile;
long bytesRead;
CTextFilter *TextFilter;

 FileManager = new(CmyFileManager);
 FileManager->ImyFileManager();
 
/* ask for the source file */
 returnMessage = FileManager->GetExistingFile(&sourceReply);

 if ( returnMessage == NAK )
    return; /* this application is finished. */
 
/* ask for the destination file. (this creates it also) */
 returnMessage = FileManager->GetNewFile (&destinationReply,’TEXT’);

 if ( returnMessage == NAK )
   return; /* this application is finished. */

 returnMessage = FileManager->OpenFile (&sourceDataFile,&sourceReply);
 
 if ( returnMessage == NAK )
    return;
 
returnMessage = FileManager->OpenFile (&destinationDataFile,&destinationReply);

if ( returnMessage == NAK )
   return;
 
/* we are ready for the new text filter object */
TextFilter = new(CTextFilter);
TextFilter->ITextFilter(); /* initialize it */
 
do {    
   returnMessage = sourceDataFile->ReadLine (readBuffer,512L,&bytesRead);
 
   if ( returnMessage == NAK )
      break;
 
   /* strip the line feeds */
   TextFilter->StripLineFeeds(readBuffer,&bytesRead);
 
   returnMessage = destinationDataFile->WriteSome (readBuffer,bytesRead);
   } while(TRUE);

FileManager->CloseFile(&sourceDataFile);     
FileManager->CloseFile(&destinationDataFile);      
TextFilter->Dispose(); /* get rid of the text filter object */
 }

/***
 * IRemoveLFApp
 *
 * Initialize the application. Your initialization method should 
 at least call the inherited method. If your application class defines 
its own instance variables or global variables, this is a good place 
to initialize them.
 *
 ***/
void CRemoveLFApp::IRemoveLFApp(void)
{
CApplication::IApplication(4, 20480L, 2048L);
}

/***
 * SetUpFileParameters
 *
 * In this routine, you specify the kinds of files your
 * application opens.
 ***/

void CRemoveLFApp::SetUpFileParameters(void)
{
inherited::SetUpFileParameters();  /* Be sure to call the default method 
*/

/**
 **sfNumTypes is the number of file types
 **your application knows about.
 **sfFileTypes[] is an array of file types.
 **You can define up to 4 file types in
 **sfFileTypes[].
 **/
sfNumTypes = 1;
sfFileTypes[0] = ‘TEXT’;

/**
 **Although it’s not an instance variable,
 **this method is a good place to set the
 **gSignature global variable. Set this global
 **to your application’s signature. You’ll use it
 **to create a file (see CFile::CreateNew()).
 **/
gSignature = ‘????’;
}

/***
 * DoCommand
 *
 * Your application will probably handle its own commands.
 * Remember, the command numbers from 1-1023 are reserved.
 * The file Commands.h contains all the reserved commands.
 *
 * Be sure to call the default method, so you can get
 * the default behvior for standard commands.
 ***/
void CRemoveLFApp::DoCommand(long theCommand)
{
switch (theCommand) {
 /* Your commands go here */
 default: inherited::DoCommand(theCommand);
 break;
 }
}

/***
 * Exit
 * Chances are you won’t need this method.
 * This is the last chance your application gets to clean up
 * things like temporary files.
 ***/
void CRemoveLFApp::Exit()
{
/* your exit handler here */
}

/***
 * CreateDocument
 * The user chose New from the File menu.
 * In this method, you need to create a document and send it
 * a NewFile() message.
 ***/
void CRemoveLFApp::CreateDocument()
{
CRemoveLFDoc*theDocument;
 
  theDocument = new(CRemoveLFDoc);
 
/**
 **Send your document an initialization
 **message. The first argument is the
 **supervisor (the application). The second
 **argument is TRUE if the document is printable.
 **/
  theDocument->IRemoveLFDoc(this, TRUE);

/**
 **Send the document a NewFile() message.
 **The document will open a window, and
 **set up the heart of the application.
 **/
 theDocument->NewFile();
}

/***
 * OpenDocument
 *
 * The user chose Open  from the File menu.
 * In this method you need to create a document
 * and send it an OpenFile() message.
 *
 * The macSFReply is a good SFReply record that contains
 * the name and vRefNum of the file the user chose to
 * open.
 ***/
void CRemoveLFApp::OpenDocument(SFReply *macSFReply)
{
CRemoveLFDoc*theDocument;
 
 theDocument = new(CRemoveLFDoc);

/**
 **Send your document an initialization
 **message. The first argument is the
 **supervisor (the application). The second
 **argument is TRUE if the document is printable.
 **/
 theDocument->IRemoveLFDoc(this, TRUE);

/**
 **Send the document an OpenFile() message.
 **The document will open a window, open
** the file specified in the macSFReply record,
** and display it in its window.
**/
 theDocument->OpenFile(macSFReply);
}

 (This object’s file contains the code which describes the myDataFile 
object.  Some of these methods will be useful in future projects.)
/*
*
CmyDataFile.c
 this file adds a method to the standard definition.  It uses some code 
borrowed from another  (non-object oriented) project to do it.
*/

#include “MessageDefines.h”
#include “CmyDataFile.h”

/* needed for code module picked up from another project */
typedef short WORD ;
typedef  char CHAR;

long ReadaLine(WORD refNum,CHAR *tempString,WORD  maxChars) ;
#define NIL 0L
static union {
 HParamBlockRec dfParameterBlock; /* our parameter block for private 
use */
 CInfoPBRec dirPBBlock;
 }p;

/*:........................................................*/
long ReadaLine(WORD refNum,CHAR *tempString,WORD  maxChars) 
/* WORD refNum;  /* Mac file reference number*/
/*CHAR *tempString;/* where to store the data */
/* WORD maxChars;  /* maximum number of characters to read for this line 
*/
/*
Name: Wade Maxfield
Date: Feb 21, 1989
Notes:
Modification History:
11/25/89 -- here we mix objects and standard c code.
*/
{
WORD error;
WORD stringCount;

/*
PBGetFPos (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;

Trap macro  _GetFPos

Parameter block
    -->  12  ioCompletion    pointer
    <--  16  ioResult        word
    -->  24  ioRefNum        word
    <--  36  ioReqCount      long word
    <--  40  ioActCount      long word
    <--  44  ioPosMode       word
    <--  46  ioPosOffset     long word
*/
 p.dfParameterBlock.fileParam.ioCompletion = NIL;
 p.dfParameterBlock.ioParam.ioRefNum = refNum;
 error = PBGetFPos (&p.dfParameterBlock,FALSE ) ;/* false = synchronously 
*/
 if (error != noErr)
 return(error);
 
/*PBRead (paramBlock: ParmBlkPtr; async: BOOLEAN) : OSErr;
   Trap macro  _Read
    Parameter block
        --> 12  ioCompletion    pointer
        <-- 16  ioResult    word
        --> 24  ioRefNum    word
        --> 32  ioBuffer    pointer
        --> 36  ioReqCount  long word
        <-- 40  ioActCount  long word
        --> 44  ioPosMode   word
        <-> 46  ioPosOffset long word
*/
 p.dfParameterBlock.ioParam.ioBuffer = tempString;
 p.dfParameterBlock.ioParam.ioReqCount =maxChars ;
 /* 0d is cr, $80 is newline mode */
 p.dfParameterBlock.ioParam.ioPosMode = fsAtMark+0x0D80;
 /* from present counter */
 
 error = PBRead (&p.dfParameterBlock,FALSE ) ;/* false = synchronously 
*/

 if (p.dfParameterBlock.ioParam.ioActCount)
    stringCount =p.dfParameterBlock.ioParam.ioActCount-1;
 else
    stringCount = 0;
 
 /* all characters exhausted */
 if ( (error == eofErr && stringCount == 0 ) || 
    (error != noErr && error != eofErr) )
    return(error);
 
 if ( tempString[stringCount] == ‘\r’)
    tempString[++stringCount]=0;  /* delimit string */
 else
    tempString[++stringCount] = 0;
 
 return(stringCount);
}

/* now the methods */
/* ............................................*/
void CmyDataFile::ImyDataFile(void)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
initalize this object
Modification History:
*/
{
/* call the superclass function */
CDataFile::IDataFile();
}

/* ..................................................... */
OSErr CmyDataFile::ReadLine(Ptr buffer, long howMuch, long *bytesRead)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
read a line from the file into the buffer, stopping at carriage return
return an ACK or a NAK
Modification History:
*/
{
long returnValue;

returnValue = ReadaLine(refNum,buffer, howMuch);
  
if (returnValue < 0 )
   {
   *bytesRead = 0;
   return(NAK);
   }
else
   {
   *bytesRead = returnValue;
   return(ACK);
   }
}

(Contains the file manager object)
/*
 CmyFileManager.c
 this is the methods file for my file manager object.
*/
#include “oops.h”
#include “MessageDefines.h”
#include “Global.h”
#include “CmyFileManager.h”
#include “CApplication.h”

/**** Global Variables ****/
extern CApplication*gApplication; /* Application object */
extern  OSType gSignature;

/* ............................................... */
void CmyFileManager::ImyFileManager(void)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
initalize this object
Modification History:
*/
{
/* call the superclass function */
CDataFile::IDataFile();
}

/* .................................................. */
short CmyFileManager::GetExistingFile(SFReply *macSFReply)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
put up the SFGetFile dialog box, return result in macSFReply
return a good message(ACK) or a bad message (NAK)
\Modification History:
*/
{
gApplication->ChooseFile(macSFReply);
 
if ( !macSFReply->good )
   return(NAK);
else
   return(ACK);
}
/* .................................................... */
short  CmyFileManager::GetNewFile(SFReply *macSFReply,OSType fType)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
put up the SFPutFile dialog box, return result in macSFReply
create the chosen file, or recreate it.
return a good message(ACK) or a bad message (NAK)
Modification History:
*/
{
Point   corner;  /* Top left corner of dialog box*/
SignedBytesaveHState;
short returnMessage;
 /* Center dialog box on the screen*/
FindDlogPosition(‘DLOG’, gApplication->sfGetDLOGid, &corner);  
saveHState = HGetState(this);
HLock(this);

SFPutFile(corner,”\pSave file as:”,”\p”,NULL,macSFReply);
 
HSetState(this, saveHState);
/* now create the file for a future open. 
  these methods are inherited. */
if ( macSFReply->good)
   {
   SFSpecify(macSFReply);
   returnMessage = CreateNew(gSignature, fType );
 
   /* if is a duplicate, and user said ok to delete old,
   then go ahead and re do it */
   if ( returnMessage == dupFNErr && macSFReply->good)
      {
      ThrowOut(); /* get rid of old file */
      returnMessage = CreateNew(gSignature, fType );
      }
   }

if ( !macSFReply->good || returnMessage < 0)
   return(NAK);
else
   return(ACK);
}
/* ................................................ */
short  CmyFileManager::OpenFile(CmyDataFile **newDataFileObject, SFReply 
*macSFReply)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
Create a myDataFile object, and open the file, hand it back to
the calling method.
return a good message(ACK) or a bad message (NAK)
Modification History:
*/
{
short returnMessage;

/* create the new file object */
*newDataFileObject = NULL; /* to allow test for object create */ 
*newDataFileObject = new(CmyDataFile);
 
if (!(long)(*newDataFileObject)) /* object wasn’t created */
   return(NAK);
 
(*newDataFileObject)->ImyDataFile();
 
/* tell the inherited routine what file we have */
(*newDataFileObject)->SFSpecify(macSFReply); 
 
returnMessage = (*newDataFileObject)->Open(fsRdWrPerm); 
 /* call the inherited open */
 
if ( returnMessage < 0 )
   return(NAK); /* indicate an error (NAK) */
 
return(ACK); /* return a good message */
}

/* ..................................................... */
short  CmyFileManager::CloseFile(CmyDataFile **dataFileObject)
/*
Name: Wade Maxfield
Date: November 25, 1989
Notes:
Close the file and dispose of the data file object.
\return a good message(ACK) 
Modification History:
*/
{
/* first, close the file, then delete the file object */
(*dataFileObject)->Close();
 
(*dataFileObject)->Dispose(); /* close and dispose of the object */
*dataFileObject = NULL; /* indicate is gone */
return(ACK); /* all quiet on western front */
}

/*
CTextFilter.c
 this object has no ancestors
*/
#include “messageDefines.h”
#include “CTextFilter.h”
/* ................................................... */
void CTextFilter::ITextFilter(void)
{
/* we don’t need to do anything right now */
}

/* .................................................... */
short CTextFilter::StripLineFeeds(char *textBuffer, long *bufferSize)
/* remove line feeds within the current text buffer */
{
short index, index2;

for ( index = 0 ; index < *bufferSize; index++ )
   {
   if ( textBuffer[index ] == 0x0a )
      {
       (*bufferSize) --;
       for ( index2 = index; index2 < (*bufferSize)+1; index2++)
           textBuffer[index2] = textBuffer[index2+1];
         }
      }

return(ACK);
}

(Header files)
/*
CmyDataFile.h
this is the definition of my file manager object
*/
#define _H_CmyDataFile  /* Include this file only once */
#include “CDataFile.h”

struct CmyDataFile : CDataFile 
 {
 /* instance variables */
 /* my messages */
 void ImyDataFile(void);
 OSErr ReadLine(Ptr info,long howMuch, long *bytesRead);
 };
/*
CmyFileManager.h
this is the definition of my file manager object
*/
#define _H_CmyFileManager /* Include this file only once */
#include “CDataFile.h”
#include “CmyDataFile.h”
struct CmyFileManager : CDataFile 
 {
 /* instance variables */
 /* my messages */
 void ImyFileManager(void);
 short GetExistingFile(SFReply *macSFReply);
 short GetNewFile(SFReply *macSFReply,OSType fType);
 short OpenFile(CmyDataFile **newDataFileObject,SFReply *macSFReply);
 short CloseFile(CmyDataFile **newDataFileObject);
 };

/*
MessageDefines.h
Generic values need across all messages
*/
#define ACK  1
#define NAK  0

/*
CTextFilter.h
this is the class definition for the text filter .
*/
#define _H_CTextFilter
#include “CObject.h”

struct CTextFilter : CObject
 {
 /* no instance variables */
 /* methods */
 void ITextFilter(void);
 short StripLineFeeds(char *textBuffer, long *bufferSize);
 };

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Dashlane 6.2027.0 - Password manager and...
Dashlane is an award-winning service that revolutionizes the online experience by replacing the drudgery of everyday transactional processes with convenient, automated simplicity - in other words,... Read more
ffWorks 2.1.5 - Convert multimedia files...
ffWorks, focused on simplicity, brings a fresh approach to the use of FFmpeg, allowing you to create ultra-high-quality movies without the need to write a single line of code on the command-line.... Read more
Dropbox 101.4.434 - Cloud backup and syn...
Dropbox for Mac is a file hosting service that provides cloud storage, file synchronization, personal cloud, and client software. It is a modern workspace that allows you to get to all of your files... Read more
1Password 7.6 - Powerful password manage...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
EyeTV 4.0.0 - Watch and record TV on you...
EyeTV brings a rich TV experience to your Mac. Watch live TV on your Mac. Pause, rewind, and record whenever you want. EyeTV gives you powerful control over what you watch and how you watch it. Put... Read more
Tidy Up 5.3.7 - Find duplicate files and...
Tidy Up is a full-featured duplicate finder and disk-tidiness utility. Features: Supports Lightroom: it is now possible to search and collect duplicates directly in the Lightroom library. Multiple... Read more
Pinegrow 5.97 - Mockup and design web pa...
Pinegrow (was Pinegrow Web Designer) is desktop app that lets you mockup and design webpages faster with multi-page editing, CSS and LESS styling, and smart components for Bootstrap, Foundation,... Read more
BlueStacks 4.210.0 - Run Android applica...
BlueStacks App Player lets you run your Android apps fast and fullscreen on your Mac. Feature comparison chart How to install Bluestacks on your Mac Go to MacUpdate and click the green "Download"... Read more
WhatsApp 2.2027.10 - Desktop client for...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Art Text 4.0.1 - $29.99
Art Text is graphic design software specifically tuned for lettering, typography, text mockups and various artistic text effects. Supplied with a great variety of ready to use styles and materials,... Read more

Latest Forum Discussions

See All

Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Steam Link Spotlight - Disco Elysium
Steam Link Spotlight is a feature where we look at PC games that play exceptionally well using the Steam Link app. Our last entry was Signs of the Sojourner Read about how it plays using Steam Link over here. | Read more »
Distract Yourself With These Great Mobil...
There’s a lot going on right now, and I don’t really feel like trying to write some kind of pithy intro for it. All I’ll say is lots of people have been coming together and helping each other in small ways, and I’m choosing to focus on that as I... | Read more »
Pokemon Go's July Community Day wil...
Pokemon Go developers have announced the details concerning the upcoming Gastly Community Day. This particular event was selected by the players of the game after the Gas Pokemon came in second place after a poll that decided which Pokemon would... | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Detective Di is a point-and-click murder...
Detective Di is a point-and-click murder mystery set in Tang Dynasty-era China. You'll take on the role of China's best-known investigator, Di Renjie, as he solves a series of grisly murders that will ultimately lead him on a collision course with... | Read more »
Dissidia Final Fantasy Opera Omnia is se...
Dissidia Final Fantasy Opera Omnia, one of Square Enix's many popular mobile RPGs, has announced a plethora of in-game events that are set to take place over the summer. This will include several rewards, Free Multi Draws and more. [Read more] | Read more »
Sphaze is a neat-looking puzzler where y...
Sphaze is a neat-looking puzzler where you'll work to guide robots through increasingly elaborate mazes. It's set in a visually distinct world that's equal parts fantasy and sci-fi, and it's finally launched today for iOS and Android devices. [... | Read more »
Apple Arcade is in trouble
Yesterday, Bloomberg reported that Apple is disappointed in the performance of Apple Arcade and will be shifting their approach to the service by focusing on games that can retain subscribers and canceling other upcoming releases that don't fit... | Read more »
Pixel Petz, an inventive platform for de...
Pixel Petz has built up a sizeable player base thanks to its layered, easy-to-understand creative tools and friendly social experience. It revolves around designing, trading, and playing with a unique collection of pixel art pets, and it's out now... | Read more »

Price Scanner via MacPrices.net

B&H Photo offers $200-$300 discounts on A...
B&H Photo has new 16″ MacBook Pros on sale today for $200-$300 off Apple’s MSRP, starting at $2149. Expedited shipping is free to many addresses in the US: – 2019 16″ 2.6GHz 6-Core MacBook Pro... Read more
Clearance 2019 15″ MacBook Pros on sale today...
Amazon-owned Woot is blowing out Apple refurbished, clearance 2019 15″ MacBook Pros starting at only $1579 and up to $950 off Apple’s original MSRP. According to Woot, “These MacBooks are Refurbished... Read more
Apple Refurbished iMac Pros available for $35...
Amazon-owned Woot is selling Apple refurbished 27″ 3.2GHz 8-Core iMac Pros for $3599.99 shipped. That’s $1400 off Apple’s original MSRP for this model. According to Woot, these iMac Pros are “Factory... Read more
Clearance 2019 13″ 2.4GHz/256GB MacBook Pro o...
B&H Photo has dropped their price on the clearance 2019 13″ 2.4GHz/256GB Quad-Core Silver MacBook Pro by $500 off Apple’s original MSRP to a new low of only $1299. Expedited shipping is free to... Read more
$219 Apple AirPods Pro are back at Verizon, s...
Verizon has Apple AirPods Pro on sale again for a limited time for $219.99 on their online store. Their price is $30 off Apple’s MSRP, and it’s the lowest price we’ve seen for AirPods Pro. Available... Read more
Apple’s $779 13″ MacBook Air deal returns to...
Apple has clearance, Certified Refurbished, 2019 13″ MacBook Airs available again starting at $779. Each MacBook features a new outer case, comes with a standard Apple one-year warranty, and is... Read more
$200 13″ MacBook Pro discounts are back at Am...
Amazon has 2020 13″ 2.0GHz MacBook Pros on sale again today for $150-$200 off Apple’s MSRP. Shipping is free. Be sure to purchase the MacBook Pro from Amazon, rather than a third-party seller, and... Read more
Deal Alert! Apple AirPods with Wireless Charg...
Sams Club has Apple AirPods with Wireless Charging Case on sale on their online store for only $149.98 from July 6, 2020 to July 9, 2020. Their price is $50 off Apple’s MSRP, and it’s the lowest... Read more
Xfinity Mobile promo: Apple iPhone XS models...
Take $300 off the purchase of any Apple iPhone XS model at Xfinity Mobile while supplies last. Service plan required: – 64GB iPhone XS: $599.99 save $300 – 256GB iPhone XS: $749.99 save $300 – 512GB... Read more
New July 2020 promo at US Cellular: Switch an...
US Cellular has introduced a new July 2020 deal offering free 64GB Apple iPhone 11 smartphones to customers opening a new line of service. No trade-in required, and discounts are applied via monthly... Read more

Jobs Board

Product Manager, *Apple* Commercial Sales -...
Product Manager, Apple Commercial Sales Austin, TX, US Requisition Number:77652 As an Apple Product Manager for the Commercial Sales team at Insight, you Read more
Physical Therapist Assistant - *Apple* Hill...
Physical Therapist Assistant - Apple Hill Rehab - Full Time Tracking Code 62519 Job Description General Summary: Under the direct supervision of a licensed Physical Read more
Operating Room Assistant, *Apple* Hill Surg...
Operating Room Assistant, Apple Hill Surgical Center - Full Time, Day Shift, Monday - Saturday availability required Tracking Code 62363 Job Description Operating Read more
Perioperative RN - ( *Apple* Hill Surgical C...
Perioperative RN - ( Apple Hill Surgical Center) Tracking Code 60593 Job Description Monday - Friday - Full Time Days Possible Saturdays General Summary: Under the Read more
Product Manager, *Apple* Commercial Sales -...
Product Manager, Apple Commercial Sales Austin, TX, US Requisition Number:77652 As an Apple Product Manager for the Commercial Sales team at Insight, you Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.