Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
IPCLister.main.c
/* |
File: IPCLister.main.c |
Contains: This shell can be very handy for debugging and testing things |
Add menu items, add dialogs, add controls, or whatever else you need |
This sample contains basic application startup and event loop handling, |
add more features as your needs increase. |
This sample is High Level Event aware, so you can send and receive AppleEvent |
from this application |
Written by: C.K. Haun |
Copyright: Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
7/21/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include "IPCListCode.h" |
#include <TextUtils.h> |
#include <Types.h> |
#include <memory.h> |
#include <Packages.h> |
#include <Errors.h> |
#include <quickdraw.h> |
#include <fonts.h> |
#include <dialogs.h> |
#include <windows.h> |
#include <menus.h> |
#include <events.h> |
#include <OSEvents.h> |
#include <Desk.h> |
#include <diskinit.h> |
#include <OSUtils.h> |
#include <resources.h> |
#include <toolutils.h> |
#include <AppleEvents.h> |
#include <EPPC.h> |
#include <GestaltEqu.h> |
#include <PPCToolbox.h> |
#include <Processes.h> |
#include <Balloons.h> |
#include <ALiases.h> |
#include <Processes.h> |
#include <StandardFile.h> |
#include <Folders.h> |
#include <AppleTalk.h> |
#include <Lists.h> |
/* prototypes */ |
void InitalizeApp(void); |
void DoDiskEvents(long dinfo); /* hi word is error code, lo word is drive number */ |
void DrawMain(WindowPtr drawIt); |
Boolean DoSelected(long val); |
void InitAEStuff(void); |
void DoHighLevel(EventRecord *AERecord); |
void DoDaCall(MenuHandle themenu, long theit); |
pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn); |
pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn); |
pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn); |
pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn); |
void SampleHelpDialog(void); |
void RefreshMacList(ListHandle theList); |
void DoIPCListAndFillList(Cell *theCell, ListHandle theList); |
void SetContextSwitch(Boolean how); |
OSErr myGetMyZone(char *nameBack); |
/* external */ |
extern void _DataInit(); /* this is the C initialization code */ |
extern OSErr myIPCListPorts(short theStartIndex, short theRequestCount, short *theActualCount, Str32 theObjStr, Str32 theZoneStr, |
PortInfoArrayPtr thePortInfoBufferPtr); |
extern OSErr GetAllPPCAbleMachines(MPPParamBlock *paramblk); |
extern OSErr GetPortsOnMachine(); |
extern MPPParamBlock paramblk; |
enum { |
kMBarID = 128 |
}; |
enum { |
kAppleMenu = 128, kFileMenu, kEditMenu, kToolsMenu |
}; |
enum { |
kResumeMask = 1, /* bit of message field for resume vs. suspend */ |
kSampHelp = 129, kAboutBox = 128, kHelpString = 128, kNewItem = 1, kOpenItem, kCloseItem, |
kSaveItem, kSaveAsItem, kFileBlank1, |
kPageSetupItem, kPrintItem, kFileBlank2, kQuitItem, |
kBadSystem = 130, kGenStrings = 128, kMenuToggleStrings = 129, |
kMyModalKind = 1000, kMyDocumentKind |
}; |
enum { |
kItem1 = 1, kWaitDialog = 131 |
}; |
enum { |
kCloseIt = 1, kOpenIt |
}; |
/* string IDs for window */ |
enum { |
kSayMacs = 2, kSayPorts = 3 |
}; |
/* some globals */ |
MenuHandle gAppleMenuHandle, gFileMenuHandle, gEditMenuHandle, gToolMenuHandle; |
Boolean gQuit, gInBackground; |
EventRecord gERecord; |
AEDesc gTheAddress; |
ProcessSerialNumber gOurSN; |
short gHelpItem; |
/* this is our global to tell us if a movable modal is up*/ |
unsigned long gMySleep = 30; |
ListHandle gMacList, gPortsList; |
#ifdef powerc |
QDGlobals qd; |
#endif |
#pragma segment Main |
void main() |
{ |
WindowPtr twindow; |
//UnloadSeg((Ptr)_DataInit); /* throw out setup code */ |
InitalizeApp(); |
//UnloadSeg((Ptr)InitalizeApp); /* get rid of my initialization code */ |
do { |
WaitNextEvent(everyEvent, &gERecord, gMySleep, nil); |
switch (gERecord.what) { |
ProcPtr drawProc; |
short tempKind; |
case nullEvent: |
/* no nul processing in this sample */ |
break; |
case updateEvt: |
tempKind = ((WindowPeek)gERecord.message)->windowKind; |
/* Mkae sure it's my window before I jump through the refCon */ |
/* Why, since DA's have they're own layer in 7.0? */ |
/* BECAUSE there are other people in the universe who will */ |
/* add things to your windowList.BalloonWriter, for example, */ |
/* so you still need to be careful */ |
if (tempKind == kMyModalKind || tempKind == kMyDocumentKind) { |
/* get the drawing proc from the refCon */ |
drawProc = (ProcPtr)GetWRefCon((WindowPtr)gERecord.message); |
/* jump to it */ |
drawProc((WindowPtr)gERecord.message); |
} |
break; |
case mouseDown: |
/* first see where the hit was */ |
switch (FindWindow(gERecord.where, &twindow)) { |
case inDesk: /* if they hit in desk, then the process manager */ |
break; /* will switch us out, we don't need to do anything */ |
case inMenuBar: |
/* let Help and Application menus happen always */ |
DoSelected(MenuSelect(gERecord.where)); |
break; |
case inSysWindow: |
/* pass to the system */ |
SystemClick(&gERecord, twindow); |
break; |
case inContent: |
/* Handle content and control clicks here */ |
/* If they clicked in the content region of a back window, */ |
/* bring that window forward */ |
if (twindow != FrontWindow()) { |
SelectWindow(twindow); /* select the window */ |
SetPort(twindow); |
} else { |
/* control tracking or whatever. */ |
/* Here we have a couple of lists, so we'll track */ |
/* them */ |
Rect boundRect; |
Point locPoint = gERecord.where; |
GlobalToLocal(&locPoint); |
/* first see if it's in eiher of our Lists */ |
boundRect = (*gMacList)->rView; |
/* expand to include the scroll bear */ |
boundRect.right += 15; |
if (PtInRect(locPoint, &boundRect)) { |
Cell currentCell = { |
0, 0 |
}; |
Cell theCell = { |
0, 0 |
}; |
/* first, get the current cell */ |
LGetSelect(true, ¤tCell, gMacList); |
if (LClick(locPoint, nil, gMacList)) { |
/* if it's in this list, switch port list */ |
if (LGetSelect(true, &theCell, gMacList)) { |
/* this is where you'd do something special for a double-click */ |
/* in this example I just fill the other list in agin */ |
DoIPCListAndFillList(&theCell, gPortsList); |
} |
} else { |
/* single click, but maybe they changed things */ |
LGetSelect(true, &theCell, gMacList); |
if (theCell.v != currentCell.v) |
DoIPCListAndFillList(&theCell, gPortsList); |
} |
} else { |
boundRect = (*gPortsList)->rView; |
/* expand to include the scroll bear */ |
boundRect.right += 15; |
if (PtInRect(locPoint, &boundRect)) { |
LClick(locPoint, nil, gPortsList); |
/* if it's in this list, I just don't care atall */ |
} else { |
/* normal control tracking goes here, commented out */ |
/* since I'm not using it today */ |
/* |
if (FindControl(locPoint, twindow, &returnedControl)) { |
if (TrackControl(returnedControl, locPoint, nil)) { |
} |
} */ |
} |
} |
} |
break; |
case inDrag: |
DragWindow(twindow, gERecord.where, &qd.screenBits.bounds); |
break; |
case inGrow: |
/* Call GrowWindow here if you have a grow box */ |
break; |
case inGoAway: |
/* Click in Close box */ |
break; |
} |
case mouseUp: |
/* don't care */ |
break; |
/* same action for key or auto key */ |
case keyDown: |
case autoKey: |
if (gERecord.modifiers & cmdKey) |
DoSelected(MenuKey(gERecord.message & charCodeMask)); |
break; |
case keyUp: |
/* don't care */ |
break; |
case diskEvt: |
/* I don't do anything special for disk events, this just passes them */ |
/* to a function that checks for an error on the mount */ |
DoDiskEvents(gERecord.message); |
break; |
case activateEvt: |
/* not doing anything on activates */ |
break; |
case networkEvt: |
/* don't care */ |
break; |
case driverEvt: |
/* don't care */ |
break; |
case app4Evt: |
/* If we're switching layers and I have my MModal up, I want to */ |
/* change the state of the control */ |
switch ((gERecord.message >> 24) & 0x0FF) { /* high byte of message */ |
case suspendResumeMessage: /* suspend/resume is also an activate/deactivate */ |
gInBackground = (gERecord.message & kResumeMask) == 0; |
/* set dim/enable on the control */ |
/* make sure hiliting is right */ |
SetContextSwitch(gInBackground); |
break; |
} |
break; |
/* This dispatches high level events (AppleEvents, for example) */ |
/* to our dispatch routine.This is NEW in the event loop for */ |
/* System 7 */ |
case kHighLevelEvent: |
DoHighLevel(&gERecord); |
break; |
default: |
break; |
} |
} |
while (gQuit != true); |
} |
/* DoDaCall opens the requested DA.It's here as a seperate routine if you'd */ |
/* like to perform some action or just know when a DA is opened in your */ |
/* layer.Can be handy to track memory problems when a DA is opened */ |
/* with an Option-open */ |
void DoDaCall(MenuHandle themenu, long theit) |
{ |
long qq; |
Str255 DAname; |
GetMenuItemText(themenu, theit, DAname); |
qq = OpenDeskAcc(DAname); |
} |
/* end DoDaCall */ |
/* DoDiskEvents just checks the error code from the disk mount, */ |
/* and puts up the 'Format' dialog (through DIBadMount) if need be */ |
/* You can do much more here if you care about what disks are */ |
/* in the drive */ |
void DoDiskEvents(long dinfo) /* hi word is error code, lo word is drive number */ |
{ |
short hival, loval, tommy; |
Point fredpoint = { |
40, 40 |
}; |
hival = HiWord(dinfo); |
loval = LoWord(dinfo); |
if (hival != noErr) /* something happened */ { |
tommy = DIBadMount(fredpoint, dinfo); |
} |
} |
/* draws my window.Pretty simple */ |
void DrawMain(WindowPtr drawIt) |
{ |
WindowPtr tempWP; |
Str255 words; |
Rect tempRect; |
GetPort(&tempWP); |
BeginUpdate(drawIt); |
SetPort(drawIt); |
EraseRect(&drawIt->portRect); |
LUpdate(drawIt->visRgn, gMacList); |
tempRect = (*gMacList)->rView; |
InsetRect(&tempRect, -2, -1); |
FrameRect(&tempRect); |
MoveTo(tempRect.left, tempRect.top - 2); |
GetIndString(words, kGenStrings, kSayMacs); |
DrawString(words); |
/* other list */ |
LUpdate(drawIt->visRgn, gPortsList); |
tempRect = (*gPortsList)->rView; |
InsetRect(&tempRect, -2, -1); |
FrameRect(&tempRect); |
MoveTo(tempRect.left, tempRect.top - 2); |
GetIndString(words, kGenStrings, kSayPorts); |
DrawString(words); |
EndUpdate(drawIt); |
SetPort(tempWP); |
} |
/* my menu action taker.It returns a Boolean which I usually ignore, but it */ |
/* mught be handy someday */ |
Boolean DoSelected(long val) |
{ |
short loval, hival; |
Boolean returnVal = false; |
loval = LoWord(val); |
hival = HiWord(val); |
switch (hival) { /* switch off the menu number selected */ |
case kAppleMenu: /* Apple menu */ |
if (loval != 1) { /* if this was not About, it's a DA */ |
DoDaCall(gAppleMenuHandle, loval); |
} else { |
Alert(kAboutBox, nil); /* do about box */ |
} |
returnVal = true; |
break; |
case kFileMenu: /* File menu */ |
switch (loval) { |
case kQuitItem: |
gQuit = true; /* onlyitem */ |
returnVal = true; |
break; |
default: |
break; |
} |
break; |
case kEditMenu: |
/* edit menu junk */ |
/* don't care */ |
break; |
case kToolsMenu: |
/* add all your test stuff here */ |
RefreshMacList(gMacList); |
break; |
case kHMHelpMenuID: /* Defined in Balloons.h */ |
/* I only care about this item.If anything else is returned here, I don't know what */ |
/* it is, so I leave it alone.Remember, the Help Manager chapter says that */ |
/* Apple reserves the right to add and change things in the Help menu */ |
if (loval == gHelpItem) |
SampleHelpDialog(); |
break; |
} |
HiliteMenu(0); |
return(returnVal); |
} |
/* InitAEStuff installs my appleevent handlers */ |
void InitAEStuff(void) |
{ |
OSErr aevtErr = noErr; |
long aLong = 0; |
Boolean gHasAppleEvents = false; |
/* Check this machine for AppleEvents. If they are not here (ie not 7.0) |
* then we exit */ |
gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr); |
/* The following series of calls installs all our AppleEvent Handlers. |
* These handlers are added to the application event handler list that |
* the AppleEvent manager maintains. So, whenever an AppleEvent happens |
* and we call AEProcessEvent, the AppleEvent manager will check our |
* list of handlers and dispatch to it if there is one. |
*/ |
if (gHasAppleEvents) { |
aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, |
NewAEEventHandlerProc(AEOpenHandler),0, false); |
aevtErr = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, |
NewAEEventHandlerProc(AEOpenDocHandler),0, false); |
aevtErr = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, |
NewAEEventHandlerProc(AEQuitHandler), 0, false); |
aevtErr = AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, |
NewAEEventHandlerProc(AEPrintHandler),0, false); |
if (aevtErr) ExitToShell(); |
} |
else ExitToShell(); |
} |
/* end InitAEStuff */ |
/* I'm not doing error handling in this sample for clarities sake, you should. Hah, */ |
/* easy for me to say, huh? */ |
void DoHighLevel(EventRecord *AERecord) |
{ |
AEProcessAppleEvent(AERecord); |
} |
/* end DoHighLevel */ |
/* This is the standard Open Application event.*/ |
pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
#pragma unused (messagein,reply,refIn) |
Rect lRect; |
Rect lRect2 = { |
0, 0, 0, 1 |
}; |
Point cp = { |
0, 0 |
}; |
short theSize; |
FontInfo theFont; |
typedef unsigned char Tuple[104]; |
extern Tuple myRetBuff[100]; |
WindowPtr myWindow; |
/* we of course don't do anything here in this simple app */ |
/* except open our window */ |
myWindow = GetNewWindow(128, nil, (WindowPtr)-1); |
((WindowPeek)myWindow)->windowKind = kMyDocumentKind; |
/* install drawing proc */ |
SetWRefCon(myWindow, (long)DrawMain); |
/* add two lists */ |
SelectWindow(myWindow); |
SetPort(myWindow); |
/* call the draw proc oncet */ |
GetFontInfo(&theFont); |
theSize = (theFont.ascent + theFont.descent + theFont.leading) * 10; |
SetRect(&lRect, 10, 30, (myWindow->portRect.right / 2) - 15, 30 + theSize); |
gMacList = LNew(&lRect, &lRect2, cp, nil, myWindow, true, false, false, true); |
LActivate(true, gMacList); |
LSetDrawingMode(false, gMacList); |
(*gMacList)->listFlags = lDoVAutoscroll; |
SetRect(&lRect, (myWindow->portRect.right / 2) + 15, 30, (myWindow->portRect.right) - 15, 30 + theSize); |
gPortsList = LNew(&lRect, &lRect2, cp, nil, myWindow, true, false, false, true); |
LActivate(true, gPortsList); |
LSetDrawingMode(false, gPortsList); |
(*gPortsList)->listFlags = lDoVAutoscroll; |
/* While we're here we may as well find and add all the PPC capable macs in my zone */ |
DrawMain(myWindow); |
RefreshMacList(gMacList); |
return(noErr); |
} |
/* end AEOpenHandler */ |
/* Open Doc, opens our documents.Remember, this can happen at application start AND */ |
/* anytime else.If your app is up and running and the user goes to the desktop, hilites one */ |
/* of your files, and double-clicks or selects Open from the finder File menu this event */ |
/* handler will get called. Which means you don't do any initialization of globals here, or */ |
/* anything else except open then doc.*/ |
/* SO-- Do NOT assume that you are at app start time in this */ |
/* routine, or bad things will surely happen to you. */ |
pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
#pragma unused (messagein,refIn,reply) |
/* we of course don't do anything here */ |
return(errAEEventNotHandled); /* we have no docs, so no odoc events should come to us */ |
} |
pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ /* no printing handler in yet, so we'll ignore this */ |
/* the operation is functionally identical to the ODOC event, with the additon */ |
/* of calling your print routine.*/ |
#pragma unused (messagein,refIn,reply) |
/* we of course don't do anything here */ |
return(errAEEventNotHandled); /* we have no docs, so no pdoc events should come to us */ |
} |
/* Standard Quit event handler, to handle a Quit event from the Finder, for example.*/ |
/* ¥¥¥¥¥ DO NOT CALL EXITTOSHELL HERE ¥¥¥¥¥ or you will never have a happy life.*/ |
pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
#pragma unused (messagein,refIn,reply) |
/* prepQuit sets the Stop flag for us.It does _NOT_ quit, you */ |
/* should NEVER quit from an AppleEvent handler.Calling */ |
/* ExitToShell here would blow things up */ |
gQuit = true; |
return(noErr); |
} |
/* This is my sample help dialog.Does not do anything, expand as you need */ |
void SampleHelpDialog(void) |
{ |
DialogPtr tdial = GetNewDialog(kSampHelp, nil, (WindowPtr)-1); |
short itemhit = 0; |
while (itemhit != 1) { |
ModalDialog(nil, &itemhit); |
} |
DisposeDialog(tdial); |
} |
/* myGetMyZone returns (oh, you guessed!) a zone name string */ |
OSErr myGetMyZone(char *nameBack) |
{ |
OSErr myErr = noErr; |
XPPParamBlock *theParamPtr = (XPPParamBlock *)NewPtrClear(sizeof(XPPParamBlock)); |
theParamPtr->XCALL.xppTimeout = 3; |
theParamPtr->XCALL.xppRetry = 4; |
theParamPtr->XCALL.zipBuffPtr = nameBack; |
theParamPtr->XCALL.zipInfoField[1] = 0; |
theParamPtr->XCALL.zipInfoField[2] = 0; |
myErr = GetMyZone(theParamPtr, false); |
DisposePtr((Ptr)theParamPtr); |
return(myErr); |
} |
/* RefreshMacList re-scans the current zone for all macs, and */ |
/* adds them to the list */ |
void RefreshMacList(ListHandle theList) |
{ |
register qq; |
Cell cp = { |
0, 0 |
}; |
/* This takes a while here at Apple (lotsa machines) so I'll put up a wait dialog */ |
DialogPtr theDial = GetNewDialog(kWaitDialog, nil, (WindowPtr)-1); |
DrawDialog(theDial); |
/* this takes a while */ |
SetCursor(*GetCursor(watchCursor)); |
/* Delete all the current list entries quickly */ |
LDelRow(32000, 0, theList); |
/* fill in the list of machines */ |
GetAllPPCAbleMachines(¶mblk); |
/* loop through all the machines in this zone and add 'em to the list */ |
for (qq = 0; qq < paramblk.NBP.parm.Lookup.numGotten; qq++) { |
EntityName myEntityName; |
AddrBlock myAddrBlock; |
LAddRow(1, qq, theList); /* a new item, add a row for it */ |
cp.v = qq; |
/* get the info out of the NBP record. It's easier than calculating the offsets */ |
/* yerself */ |
NBPExtract((Ptr)&myRetBuff, paramblk.NBP.parm.Lookup.numGotten, qq + 1, &myEntityName, &myAddrBlock); |
/* and add this name to the list */ |
LAddToCell((&myEntityName.objStr[1]), myEntityName.objStr[0], cp, theList); |
} |
/* kill my wait dialog */ |
DisposeDialog(theDial); |
InitCursor(); |
} |
/* DoIPCListAndFillList calls IPCListPorts for the machine name selected, and */ |
/* fills our list with the ports on the other machine */ |
void DoIPCListAndFillList(Cell *theCell, ListHandle theList) |
{ |
PortInfoArrayPtr thePorts; |
short returnedCount; |
OSErr myErr = noErr; |
Cell cp = { |
0, 0 |
}; |
EntityName myEntityName; |
AddrBlock myAddrBlock; /* myAddrBlock: AddrBlock; */ |
register qq; |
SetCursor(*GetCursor(watchCursor)); |
/* I want to get a maximum of 30 ports, so allocate a buffer that big */ |
thePorts = (PortInfoArrayPtr)NewPtrClear(sizeof(PortInfoRec) * 30); |
/* extract the machine name and zone name based on the cell they clicked */ |
/* on and the buffer we got from GetAllPPCAbleMachines */ |
NBPExtract((Ptr)&myRetBuff, paramblk.NBP.parm.Lookup.numGotten, theCell->v + 1, &myEntityName, &myAddrBlock); |
/* call our IPCList routine */ |
myErr = myIPCListPorts(0, 30, &returnedCount, myEntityName.objStr, myEntityName.zoneStr, thePorts); |
if(myErr == noErr){ |
/* now add the names to the list */ |
LDelRow(32000, 0, theList); |
for (qq = 0; qq < returnedCount; qq++) { |
LAddRow(1, qq, theList); |
cp.v = qq; |
LAddToCell(&(((PortInfoPtr)thePorts)->name.name[1]), thePorts->name.name[0], cp, theList); |
thePorts = thePorts + 1; |
} |
} |
DisposePtr((Ptr)thePorts); |
InitCursor(); |
} |
/* SetContextSwitch does what I need to do to go into/come out of */ |
/* the backgrounmd. In this example, all I do is set the lists */ |
void SetContextSwitch(Boolean how) |
{ |
how = (how ? false:true); /* don't ask, The how is kinda backwards */ |
LActivate(how,gMacList); |
LActivate(how,gPortsList); |
} |
#pragma segment Init |
void InitalizeApp(void) |
{ |
MenuHandle helpHandle; |
Handle myMenu; |
StringHandle helpString; |
short count; |
long vers; |
MaxApplZone(); |
InitGraf((Ptr)&qd.thePort); |
InitFonts(); |
InitWindows(); |
InitMenus(); |
TEInit(); |
InitDialogs(nil); |
InitCursor(); |
/* Check system version */ |
Gestalt(gestaltSystemVersion, &vers); |
vers = (vers >> 8) & 0xf; /* shift result over and mask out major version number */ |
if (vers < 7) { |
StopAlert(kBadSystem, nil); |
ExitToShell(); |
} |
PPCInit(); |
InitAEStuff(); |
/* set up my menu junk */ |
myMenu = GetNewMBar(kMBarID); |
SetMenuBar(myMenu); |
gAppleMenuHandle = GetMenuHandle(kAppleMenu); |
gFileMenuHandle = GetMenuHandle(kFileMenu); |
gEditMenuHandle = GetMenuHandle(kEditMenu); |
gToolMenuHandle = GetMenuHandle(kToolsMenu); |
AppendResMenu(gAppleMenuHandle, 'DRVR'); |
/* now install my Help menu item in the Help Manager's menu */ |
HMGetHelpMenuHandle(&helpHandle); /* Get the Hlpe menu handle */ |
count = CountMItems(helpHandle); /* How many items are there? */ |
helpString = GetString(kHelpString); /* get my help string */ |
DetachResource((Handle)helpString); /* detach it */ |
HNoPurge((Handle)helpString); |
MoveHHi((Handle)helpString); |
HLock((Handle)helpString); |
InsertMenuItem(helpHandle,*helpString, count + 1); /* insert my item in the Help menu */ |
gHelpItem = CountMItems(helpHandle); /* The number of the item */ |
DrawMenuBar(); |
GetCurrentProcess(&gOurSN); /* Get our process serial number for later use, if needed */ |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-14