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.
AppleEventCore.c
/*------------------------------------------------------------------------------ |
* |
* Apple Developer Technical Support |
* |
* AppleEvent specific routines |
* |
* Program: AEObject-Edition Sample |
* File: AppleEventCore.c - C Source |
* |
* by: C.K. Haun <TR> |
* |
* Copyright © 1990-1992 Apple Computer, Inc. |
* All rights reserved. |
* |
*------------------------------------------------------------------------------ |
* This file handles the generic AppleEvent handlers, as well as intialization |
* and installing the handlers I'll need for this application. |
* Also installs my coercion handlers and has the interaction Idle proc. |
* Other, more specific AE handling (like edition functions) are in the functional |
* area files. |
* Functions that deal specifically with AppleEventª Objects are in the |
* file AEObject.c. |
*----------------------------------------------------------------------------*/ |
/* AESample v1: Removed all ShowMe error notifications, replaced with macro to display */ |
/* errors non-intrusively in AESatus window */ |
#define __AEM__ |
#pragma segment Main |
/* DoHighLevel will be in main, just because */ |
#include "Sampdefines.h" |
/* DoHighLevel processes our high level events */ |
/* All the HLEs that come into my application get dispatched to here. */ |
/* All I do is call AEProcessAppleEvent, because I do not support any */ |
/* other types of High Level Events, justs AEs. */ |
void DoHighLevel(EventRecord AERecord) |
{ |
OSErr fred2; |
/* Process the event. */ |
/* Here's what happens; |
1) If this is an AppleEvent, and we have a handler installed for this event, |
AEProcessAppleEvent jumps to that handler |
else |
2) If there is a system handler for this event, AEProcessAppleEvent jumps to that |
else |
3) return errEventNotHandled. |
*/ |
/* ¥¥¥¥ NOTE: If you are sending AppleEvents to yourself (using a PSN of kCurrentProcess */ |
/* in the address AEDesc to AECreateAppleEvent) then events sent to yourself that */ |
/* way will NOT come here! They will be dispatched directly to the */ |
/* correct handler by the AppleEvent manager! Try it in this sample. */ |
fred2 = AEProcessAppleEvent(&AERecord); |
if ((fred2 != userCanceledErr) && (fred2 != noErr) && (fred2 != errAEEventNotHandled)) |
mAEErrorDisplay("\pAppleEvent Proccessing.", fred2) |
/* if it was a userCanceledErr (from the quit routine) and the reply has been */ |
/* sent from there already */ |
/* if it's a errAEEventNotHandled, then someone sent us an event we're not prepared for, */ |
/* that is not a reason to put up a dialog. Since anyone can send us events, then */ |
/* we could get all kinds of stray stuff, so just ignore it. */ |
/* you may want to check for debugging reasons */ |
} |
/* end DoHighLevel */ |
#pragma segment AppleEvents |
/*************************************************************************************** |
MissedAnyParameters |
Used to check for any unread required parameters. Returns true if we missed at |
least one. |
*****************************************************************************************/ |
Boolean MissedAnyParameters(AppleEvent *message) |
{ |
OSErr err; |
DescType ignoredActualType; |
AEKeyword missedKeyword; |
Size ignoredActualSize; |
EventRecord event; |
err = AEGetAttributePtr(message, keyMissedKeywordAttr, typeKeyword, &ignoredActualType, (Ptr)&missedKeyword, |
sizeof(missedKeyword), &ignoredActualSize); |
/* no error means that we found some more.*/ |
if (!err) { |
event.message = *(long *)&ignoredActualType; |
event.where = *(Point *)&missedKeyword; |
mAEErrorDisplay("\pMissedAnyParameters: got parameters I don't know what to do with.", err) |
err = errAEEventNotHandled; |
} |
/* errAEDescNotFound means that there are no more parameters. If we get */ |
/* an error code other than that, flag it. */ |
else if (err != errAEDescNotFound) { |
mAEErrorDisplay("\pMissedAnyParameters: after AEGetAttributeDesc.", err) |
} |
return(err != errAEDescNotFound); |
} |
/* This is the standard Open Application event. You'll get this as one of the (if not the ) */ |
/* first events in your application. So, we open up a blank document */ |
/* You will _NOT_ get this if you were launched with an event (like an 'odoc' or 'pdoc' ) */ |
/* so do _not_ do application initialiaztion things here! This routine may never */ |
/* get called! */ |
pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
OSErr myErr = noErr; |
#pragma unused (messagein,refIn) |
gCurrentReply = reply; |
ChangePlane(AddNewWindow(true)); /* open our initial, blank window */ |
/* and make sure it's the front window */ |
mAEErrorDisplay("\pOpen App Handler", myErr) |
gCurrentReply = nil; |
return(myErr); |
} |
/* 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) |
{ |
OSErr myErr = noErr; |
#pragma unused ( refIn) |
gCurrentReply = reply; |
/* In previous versions I was coming to the front on this message. This is _not_ */ |
/* the proper thing to do. I have changed things to call AEInteractWithUser. */ |
/* The user (or the AEm will bring us forward if appropriate). But we may _not_ be */ |
/*required to come forward, it may be perfectly reasonable to stay in the background */ |
/* so don't do anything unless you really need to, like to put up a dialog */ |
/* which we don't have to, so just press on */ |
myErr = processOpenPrint(messagein, false); |
gCurrentReply = nil; |
return(myErr); |
} |
/* Same logic as OpenDoc */ |
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 (refIn) |
gCurrentReply = reply; |
processOpenPrint(messagein, true); |
gCurrentReply = nil; |
return(noErr); |
} |
/* 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. */ |
/* OK, it's a few months after I wrote that comment, and I've seen a lot of code */ |
/* come through DTS that calls ExitToShell from quit handlers. Let me explain... */ |
/* When an AppleEvent Handler is called (like this quit handler) you are ALMOST */ |
/* 100% in your application world. A5 is right, you can call any toolbox function, */ |
/* you can call your own routines, everything _seems_ like you are in complete */ |
/* control. Well, almost but not quite. The routine has been dispatch to from the */ |
/* AppleEvent Manager's space, so you _must_ return to that at some point! */ |
/* Which is why you can't call ETS from here. When you call ExitToShell from an */ |
/* AE Handler, the most likely thing that happens is the FInder quits, and your */ |
/* application keeps running. Which ain't what you want, y'know? */ |
/* so, DON'T CALL EXITTOSHELL FROM AN APPLEEVENT HANDLER!!!!!!!!!!!!!! */ |
pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
#pragma unused (messagein,refIn) |
OSErr theErr; |
Str32 userCanx; |
gCurrentReply = reply; |
theErr = PrepQuit(); /* 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 */ |
if (!theErr){ |
gCurrentReply = nil; |
return(noErr);} |
if (theErr == (userCanceledErr)) { |
/* reply to the application that told us to quit */ |
GetIndString(userCanx,kGeneralStrings,kUCanxString); |
AEPutParamPtr(reply, keyErrorNumber, typeLongInteger, (Ptr)&theErr, sizeof(OSErr)); |
AEPutParamPtr(reply, keyErrorString, typeChar, (Ptr)&userCanx, userCanx[0]); |
} |
gCurrentReply = nil; |
return(theErr); |
} |
/* This is the 'ansr', or answer, handler. You need this if you ever want to */ |
/* use QueueReply as an option to AESend (which you will) since the reply */ |
/* is going to be coming in through your event loop like any other */ |
/* AppleEvent. So here it is */ |
pascal OSErr AEAnswerHandler(AppleEvent *messagein, AppleEvent *reply, long refIn) |
{ |
#pragma unused (refIn) |
OSErr myErr = noErr; |
gCurrentReply = reply; |
mVerboseOutput("\p\nGot an answer from an event") |
DisplayReturnedData((AEDesc *)messagein); |
gCurrentReply = nil; |
return(myErr); |
/* ¥¥¥¥ NOTE: One thing you may want to consider, and it's a side-effect of */ |
/* the AppleEvent manager's direct dispatching of events if you send them to yourself */ |
/* using the kCurrentProcess Process Serial Number constant. */ |
/* If you use kCurrentProcess, then the AppleEvent manager will directly dispatch */ |
/* to the AppleEvent handler, the event will _not_ go through WaitNextEvent. */ |
/* Normally, that's a very good thing. But there is one potential problem.... */ |
/* It means that kQueueReply doesn't quite work the way you think it will when sending to */ |
/* yourself. The reply will _not_ be put in the event queue, instead this Answer hander */ |
/* will be called directly. And if you reply from the answer handler, that will dispatch right */ |
/* back to itself. And so on. So be aware that Queued replies are _not_ really */ |
/* queued when you are using kCurrentProcess! */ |
} |
/* my routine to snatch a section handle out of an AppleEvent */ |
OSErr GetSectionHandleFromEvent(AppleEvent *AEin, SectionHandle *theSection) |
{ |
DescType thisType; |
Size returnedSize; |
return(AEGetParamPtr(AEin, keyDirectObject, typeSectionH, &thisType, (Ptr)theSection, sizeof(theSection), &returnedSize)); |
} |
/* processOpenPrint handles ODOC and PDOC events. Both events open a document, one prints it */ |
OSErr processOpenPrint(AppleEvent *messagein, Boolean printIt) |
{ |
OSErr err; |
OSErr err2; |
AEDesc theDesc; |
FSSpec theFSS; |
register qq; |
long numFilesToOpen; |
AEKeyword ignoredKeyWord; |
DescType ignoredType; |
Size ignoredSize; |
WindowPtr tWind; |
err = AEGetParamDesc(messagein, keyDirectObject, typeAEList, &theDesc); |
if (err) { |
mAEErrorDisplay("\pGetParamDesc error in Open/Print", err) |
} |
if (!MissedAnyParameters(messagein)) { |
/* Got all the parameters we need. Now, go through the direct object, */ |
/* see what type it is, and parse it up. */ |
if (err = AECountItems(&theDesc, &numFilesToOpen)) { |
mAEErrorDisplay("\pAECountItems error in Open/Print", err) |
} else { |
for (qq = 1; ((qq <= numFilesToOpen) && (!err)); ++qq) { |
if (err = AEGetNthPtr(&theDesc, qq, typeFSS, &ignoredKeyWord, &ignoredType, (Ptr)&theFSS, sizeof(theFSS), |
&ignoredSize)) { |
mAEErrorDisplay("\pAEGetNthPtr in Open/Print", err) |
} else { |
FInfo fileInfo; |
FSpGetFInfo(&theFSS, &fileInfo); /* make sure it's a data file */ |
if (fileInfo.fdCreator == kMySignature && fileInfo.fdType == kMyDocumentFileType) |
tWind = OpenFile(&theFSS); |
else |
tWind = nil; /* they may have double clicked on the prefs file */ |
} |
if (printIt && tWind != nil) { |
PrintIt(tWind, false); /* in Print.c. Does not yet print, but the idea is there */ |
CloseMyWindow(tWind); |
} |
} /* for qq = ... */ |
} /* AECountItems OK */ |
} /* Got all necessary parameters */ |
if (err2 = AEDisposeDesc(&theDesc)) { |
mAEErrorDisplay("\pAEDisposeDesc in Open/Print", err2) |
} |
return(err ? err : err2); |
} |
/* This is an AppleEvent Idle function. It can be passed to AEInteractWithUser */ |
/* or AESend. */ |
/* What it does is this; */ |
/* If some AppleEvent thing is taking a really long time, the AppleEvent manager */ |
/* will call WaitNextEvent FOR you (yeah, yeah, only one event loop per app, oh well) */ |
/* and give you a result (limited) if you need to do something. That something */ |
/* will only be an update,activate,OSevent, or null event */ |
pascal Boolean CommonIdleFunction(EventRecord *whatEvent, long *sleeping, RgnHandle *mouseRgn) |
{ |
extern Boolean gInBackground; |
extern RgnHandle mousergn; |
switch (whatEvent->what) { |
case updateEvt: |
DrawIt((WindowPtr)whatEvent->message); /* draw whatever window needs an update */ |
break; |
case activateEvt: |
if (whatEvent->modifiers & activeFlag) |
DrawIt((WindowPtr)whatEvent->message); |
break; |
case app4Evt: /* or kOSEvent, I'm old fashioned */ |
switch ((whatEvent->message >> 24) & 0x0FF) { /* high byte of message */ |
case suspendResumeMessage: /* suspend/resume is also an activate/deactivate */ |
gInBackground = (whatEvent->message & kResumeMask) == 0; |
if (gInBackground) { |
SpitClip(); /* export the clipboard please */ |
/* deactivate the current TextEdit record as necessary */ |
if (FrontWindow() != nil) { |
windowCHandle tempCH = (windowCHandle)GetWRefCon(FrontWindow()); |
if ((*tempCH)->boxHandle != nil) |
TEDeactivate((*tempCH)->boxHandle); |
} |
} else { |
if (FrontWindow() != nil) { |
windowCHandle tempCH = (windowCHandle)GetWRefCon(FrontWindow()); |
if ((*tempCH)->boxHandle != nil) |
TEActivate((*tempCH)->boxHandle); |
} |
} |
break; |
} |
break; |
case nullEvent: |
AdjustCursor(whatEvent->where, mousergn); |
*sleeping = 20; /* may as well sleep a while */ |
*mouseRgn = mousergn; |
break; |
} |
return(false); /* If it takes for-ever I will wait, for you... Sorry. */ |
} |
AEIdleUPP gCommonIdleFunctionUPP = NewAEIdleProc(CommonIdleFunction); |
/* This function sends a GetData AppleEvent to someone, and displays the */ |
/* results in the AEStatus window */ |
void SendGetData(short which) |
{ |
AEDesc thisAddress; |
AppleEvent theEvent; |
AEDesc reply; |
OSErr myErr = noErr; |
/* first make an address */ |
MakeAddress(&thisAddress); |
myErr = AECreateAppleEvent(kAECoreSuite, kAEGetData, &thisAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent); |
myErr = BuildGetDataEvent(&theEvent, which); /* in AEObjects.c */ |
if (!myErr) { |
/* reply may or may not be used, depending on the reply mode you have set */ |
myErr = DoSend(&theEvent, &reply); |
if (!myErr) { |
/* display the results, if we were in WaitReply */ |
if (gReplyMode == 1) |
DisplayReturnedData(&reply); |
} |
} |
} |
/* This function sends a SetData AppleEvent to someone, and displays the */ |
/* results in the AEStatus window */ |
void SendSetData(short which) |
{ |
AEDesc thisAddress; |
AppleEvent theEvent; |
AEDesc reply; |
OSErr myErr = noErr; |
/* first make an address */ |
MakeAddress(&thisAddress); |
myErr = AECreateAppleEvent(kAECoreSuite, kAESetData, &thisAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent); |
myErr = BuildSetDataEvent(&theEvent, which); /* in AEObjects.c */ |
if (!myErr) { |
DoSend(&theEvent, &reply); |
} |
} |
/* Dialog box handler for the Interaction Settings you want to use for this sample */ |
void SetInteractionLevels(void) |
{ |
/* call my common start routine and preset some buttons */ |
DialogPtr tdial = CommonDStart(kInteractionDialog, gLocalInteraction + 6, gAESendInteraction + 9); |
short hitItem = 0; |
/* save some stuff in case the user cancels */ |
short saveMode1 = gLocalInteraction; |
short saveMode2 = gAESendInteraction; |
short saveMode3 = gAESwitchLayer; |
/* one additial item to set */ |
SetControlValue(SnatchHandle(tdial, kSwitchLItem), gAESwitchLayer); |
/* run the dialog */ |
{ |
ModalFilterUPP upp = NewModalFilterProc(standardDialogFilter); |
while (hitItem != ok && hitItem != cancel) { |
ModalDialog(upp, &hitItem); |
switch (hitItem) { |
case kSelfIItem: |
case kLocalIItem: |
case kAllIItem: |
/* check boxes, just toggle them */ |
SetControlValue(SnatchHandle(tdial, gLocalInteraction + kSelfIItem), false); |
gLocalInteraction = hitItem - kSelfIItem; |
SetControlValue(SnatchHandle(tdial, gLocalInteraction + kSelfIItem), true); |
break; |
case kNeverIItem: |
case kCanIItem: |
case kAlwaysIItem: |
/* more toggleable checkboxes */ |
SetControlValue(SnatchHandle(tdial, gAESendInteraction + kNeverIItem), false); |
gAESendInteraction = hitItem - kNeverIItem; |
SetControlValue(SnatchHandle(tdial, gAESendInteraction + kNeverIItem), true); |
break; |
case kSwitchLItem: |
gAESwitchLayer = (gAESwitchLayer ? false : kAECanSwitchLayer); |
SetControlValue(SnatchHandle(tdial, kSwitchLItem), gAESwitchLayer); |
break; |
default: |
break; |
} |
} |
DisposeDialog(tdial); |
DisposeRoutineDescriptor(upp); |
} |
if (hitItem == cancel) { |
/* if they canceled, restore the old values */ |
gLocalInteraction = saveMode1; |
gAESendInteraction = saveMode2; |
gAESwitchLayer = saveMode3; |
} else { |
/* set interaction levels to what the user picked */ |
AESetInteractionAllowed(gLocalInteraction); |
} |
} |
/* Dialog box handler for the addressing mode you want to use for this sample */ |
void SetTargetAddress(void) |
{ |
/* bring up dialog and preset some stuff */ |
DialogPtr tdial = CommonDStart(kAddressingDialog, gAddressMode + kSelfAddressCurrItem, 0); |
short hitItem = 0; |
short saveMode = gAddressMode; |
/* if an address is already specified, draw it in the box */ |
ParamText(&targetName, "", "", ""); |
/* dim out the 'Select Target' button if the right check box is not set */ |
if (gAddressMode + kSelfAddressCurrItem != kOtherAppItem) |
HiliteControl(SnatchHandle(tdial, kSelectProcItem), 255); /* can't find the constant for dimmed, somebody tell me where it is,please */ |
{ |
ModalFilterUPP upp = NewModalFilterProc(standardDialogFilter); |
/* run the dialog */ |
while (hitItem != ok && hitItem != cancel) { |
ModalDialog(upp, &hitItem); |
switch (hitItem) { |
case kSelfAddressCurrItem: |
case kSelfAddressPSNItem: |
case kOtherAppItem: |
/* checkbox toggling, and also setting the hilite state of the 'Set Target' */ |
/* button as necessary */ |
SetControlValue(SnatchHandle(tdial, gAddressMode + kSelfAddressCurrItem), false); |
gAddressMode = hitItem - kSelfAddressCurrItem; |
SetControlValue(SnatchHandle(tdial, gAddressMode + kSelfAddressCurrItem), true); |
if (gAddressMode + kSelfAddressCurrItem != kOtherAppItem) |
HiliteControl(SnatchHandle(tdial, kSelectProcItem), 255); |
else |
HiliteControl(SnatchHandle(tdial, kSelectProcItem), 0); |
break; |
case kSelectProcItem: |
/* Call the PPC browser to select a target */ |
BrowseForTarget(&gTargetAddress); |
break; |
default: |
break; |
} |
} |
DisposeRoutineDescriptor(upp); |
} |
DisposeDialog(tdial); |
/* restore old mode if they canceled */ |
if (hitItem == cancel) |
gAddressMode = saveMode; |
} |
/* Dialog box handler for the Reply Settings you want to use for this sample */ |
void SetReplyMode(void) |
{ |
DialogPtr tdial = CommonDStart(kReplyModeDialog, gReplyMode + kNoReplyItem, 0); |
short hitItem = 0; |
short saveMode = gReplyMode; |
/* set up to gray out the 'no reply' button */ |
HiliteControl(SnatchHandle(tdial, kNoReplyItem), 255); |
{ |
ModalFilterUPP upp = NewModalFilterProc(standardDialogFilter); |
while (hitItem != ok && hitItem != cancel) { |
ModalDialog(upp, &hitItem); |
switch (hitItem) { |
case kNoReplyItem: |
case kWaitReplyItem: |
case kQueueReplyItem: |
SetControlValue(SnatchHandle(tdial, gReplyMode + kNoReplyItem), false); |
gReplyMode = hitItem - kNoReplyItem; |
SetControlValue(SnatchHandle(tdial, gReplyMode + kNoReplyItem), true); |
break; |
default: |
break; |
} |
} |
DisposeRoutineDescriptor(upp); |
} |
DisposeDialog(tdial); |
if (hitItem == cancel) |
gReplyMode = saveMode; |
} |
/* CoerceBooleanToChar creates a desc that says True or False. It's not a very */ |
/* interesting coercion, but it's a nice sample. I use it for my output window */ |
pascal OSErr CoerceBooleanToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result) |
{ |
#pragma unused (refCon) |
OSErr myErr = noErr; |
/* make sure everything is fine first */ |
if (origData != typeBoolean || toType != typeChar) { |
/* something is goofy here */ |
myErr = errAECoercionFail; |
} else { |
/* a boolean should be two bytes. if it isn't, I'm confused */ |
if (theSize == sizeof(short)) { |
short theBool = *((short *)inPtr); |
short index; |
Str32 theText; |
index = theBool ? kTrueWord : kFalseWord; |
GetIndString(theText, kGeneralStrings, index); |
myErr = AECreateDesc(typeChar, (Ptr)&theText[1], theText[0], result); |
} else { |
myErr = errAECoercionFail; |
} |
} |
return(myErr); |
} |
/* CoerceQDRectToChar is the same kinda thing */ |
pascal OSErr CoerceQDRectToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result) |
{ |
#pragma unused (theSize,refCon) |
OSErr myErr = noErr; |
/* make sure everything is fine first */ |
if (origData != typeQDRectangle || toType != typeChar) { |
myErr = errAECoercionFail; |
} else { |
short *myRect = (short *)inPtr; |
register qq; |
Str255 theString; |
Str32 tempString; |
Str32 spaceString = "\p "; |
theString[0] = 0; |
GetIndString(theString, kGeneralStrings, kSayRectangle); |
for (qq = 0; qq < kFour; qq++) { |
NumToString(*myRect, tempString); |
AppendString(theString, tempString); |
AppendString(theString, spaceString); |
myRect = myRect + 1; /* I have had trouble with MPW C doing a += on a pointer, so I'll do it this way */ |
} |
myErr = AECreateDesc(typeChar, (Ptr)&theString[1], theString[0], result); |
} |
return(myErr); |
} |
/* these next two I really do find useful, dealing with Toolbox strings */ |
pascal OSErr CoerceCharToPString(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result) |
{ |
#pragma unused (origData,toType,refCon) |
OSErr myErr = noErr; |
Str255 theString; |
theString[0] = theSize; |
BlockMove(inPtr, (Ptr)&theString[1], theSize); |
myErr = AECreateDesc(typeMyPString, (Ptr)&theString[0], theString[0] + 1, result); |
return(myErr); |
} |
pascal OSErr CoercePStringToChar(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *result) |
{ |
#pragma unused (origData,toType,refCon) |
OSErr myErr = noErr; |
myErr = AECreateDesc(typeChar, (Ptr)(inPtr + 1), theSize - 1, result); |
return(myErr); |
} |
/* CoerceAliasToTargetID takes an applicaiton alias and coerces it to a process target ID */ |
/* Of course, to do this is needs to find and launch the application */ |
/* This handler uses pointers to the data, since the AppleEvent managr can handle this type */ |
/* of manipulation more efficiently than passing descs. You can install a desc handler */ |
/* instead, if you'd like. */ |
/* I actually don't use this in this sample, but I left it in as an example */ |
/* of a coercion handler */ |
pascal OSErr CoerceAliasToTargetID(DescType origData, Ptr inPtr, Size theSize, DescType toType, long refCon, AEDesc *returnID) |
{ |
#pragma unused (origData,toType,refCon) |
OSErr myErr; |
LaunchParamBlockRec launchThis; |
FSSpec theSpec; |
Boolean changed; |
Handle theAlias = NewHandle(theSize); |
HLock(theAlias); |
BlockMove(inPtr, (Ptr)*theAlias, theSize); |
HUnlock(theAlias); |
launchThis.launchAppSpec = &theSpec; |
/* the caller may have already done this, but it doesn't hurt to do it again */ |
myErr = ResolveAlias(nil, (AliasHandle)theAlias, launchThis.launchAppSpec, &changed); |
if (myErr) |
return(myErr); |
/* launch the thing */ |
launchThis.launchBlockID = extendedBlock; |
launchThis.launchEPBLength = extendedBlockLen; |
launchThis.launchFileFlags = nil; |
/* launchdontswitch because we just want to use the service. Also, it may be a */ |
/* background only application, so like you don't want it to come up, y'know? */ |
launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchDontSwitch; |
launchThis.launchAppParameters = nil; |
myErr = LaunchApplication(&launchThis); |
if (myErr) { |
mAEErrorDisplay("\pLaunchApplication error", myErr) |
return(myErr); |
} |
/* it launched. the PSN has been stored in the launchProcessSN field, now we have to make */ |
/* that a target */ |
/* fill in all the details for the target */ |
/* we'll just use the PSN to communicate */ |
myErr = AECreateDesc(typeProcessSerialNumber, (Ptr)&launchThis.launchProcessSN, sizeof(ProcessSerialNumber), returnID); |
mAEErrorDisplay("\pCreateDesc error after launch", myErr) |
return(myErr); |
} |
#undef __AEM__ |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-01-14