{--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} { } { GENERIC EVENTS } { ``````````````````````````` } { } { A Generic Utilities unit, for use by any program. Copyright İ by David Sinclair, 1990 ­ 2001. I am releasing these units to the Pascal community. Feel free to use them in whole or part in your Pascal programs. You are also welcome to modify these units to suit your needs. If you wish to re-distribute the sources with your changes, please clearly indicate that you have changed them. In all cases, you must leave these comments and the copyright notice intact. If you use a significant portion of these units, I would appreciate acknowledgement in your About dialog and/or documentation, e.g. ³Dejal Generic Utilities copyright İ by David Sinclair, 1990 - 2001.² Iıd appreciate it if you also e-mail me at if you find these units useful. If you have any questions about these units, you can e-mail me at that address and I will do my best to help, time permitting. However, these units are provided ³as is² and I do not guarantee their reliablity or suitability for any particular purpose. These units have been used extensively in my Dejal shareware and freeware products over the years. Most of the code was written many years ago, and the code and style may not be optimal in all cases, but unless otherwise noted all routines have been used in released software, so should work as described. Please visit and try out Dejal QuickEncrypt and/or my other shareware products. If you want to show your appreciation for these units financially, registrations for my shareware are always welcome! Or you can make a donation to me via my online order form: . I hope you find these units useful, and good luck in your Pascal endeavors! - David Sinclair, Dejal } { * * * } { UNIT HISTORY: (Reverse chronology) } { } { Start ­ finish dates: Comments / changes: } { } { 27 October 2001 Public release as source code. 5 January 2001 Added the EventGetCurrentProcessFileSpec routine. 25 April 1998 Added the EventOptionDown routine. 16 March 1997 Added the eventOpenDocumentAE and made } { eventOpenApplication generic. } { 9 March 1997 Added the eventGotRequiredParams function. } { 27 January 1997 Added the eventSendOpenURLAE function. } { 9 November 1994 Dusted off this old unit as a place to keep useful } { low-level or high-level event code, including } { Apple event stuff. Also added the } { eventSendOpenSelectionAE function. } { 20 December 1991 First public release, in library form. } { 30 March 1991 Added eventCapsDown. } { 23 February 1991 Started the unit off by copying the } { eventAnyQueued routine from my old } { Generic Utilities file. } {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} UNIT genEvents; INTERFACE USES genToolbox, genNumerics, genStrings; CONST kSpacebarKeyCode = $31; kCommandKeyCode = $37; kShiftKeyCode = $38; kCapsLockKeyCode = $39; kOptionKeyCode = $3A; kControlKeyCode = $3B; noAppFound = '••••'; noBrowserErr = 9701; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventAnyQueued: boolean; FUNCTION eventCapsDown: boolean; FUNCTION EventOptionDown: Boolean; FUNCTION EventKeyIsDown(keyCode: Integer): Boolean; FUNCTION eventGotRequiredParams (anAppleEvent: AppleEvent): OSErr; FUNCTION EventGetCurrentProcessFileSpec(VAR procSpec: FSSpec): OSErr; FUNCTION eventSendOpenSelectionAE (fileSpec: FSSpec): osErr; FUNCTION eventBringFinderToFront: OSErr; FUNCTION eventBringAppToFront (creator: OSType): OSErr; FUNCTION eventOpenApplication (creatorsRsrcID: Integer; VAR creator: OSType): OSErr; FUNCTION eventSendOpenURLAE (creatorsRsrcID: Integer; theURL: Str255): OSErr; FUNCTION eventSendOpenDocumentAE (creator: OSType; fileSpec: FSSpec): OSErr; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} IMPLEMENTATION USES UGenericNumerics; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventAnyQueued: boolean; { Look through the event queue (low-mem global) } { Converted from C by David Sinclair, 5 August 1991. } VAR more, any: boolean; evt: evQElPtr; BEGIN more:= true; any:= false; evt:= evQElPtr(getEvQHdr^.qHead); IF evt = NIL THEN more:= false; WHILE more DO BEGIN IF (evt = NIL) OR (evt = evQElPtr(getEvQHdr^.qTail)) THEN more:= false; IF evt^.evtQWhat <> nullEvent THEN BEGIN any:= true; more:= false END END; eventAnyQueued:= any END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} PROCEDURE DebugFindKeyMap; {Reads the keyboard and finds which key was held down. Call this using the debugger to find out what number to use with the GetKeys result.} {Written by David Sinclair, 25 April 1998.} VAR theKeyMap: KeyMap; index: Integer; BEGIN GetKeys(theKeyMap); index:= 1; WHILE (index < 500) & NOT BitTst(@theKeyMap, index) DO index:= index+1; END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventCapsDown: boolean; { Reads the keyboard and returns true if the Caps Lock key is down (pressed). } { Written by David Sinclair, 30 March 1991. } { NOTE: Ordering of KeyMap bits in Lisa Pascalıs packed array of boolean defines the } { high order bit in a byte as bit 7 and the low order bit as bit 0. Therefore, key number 57 } { (CAPS LOCK) corresponds to bit 62 in the KeyMap, when viewing the high order bit in } { the array as 0 and the low order bit 127. } CONST capsLockKey = 62; VAR theKeyMap: keyMap; BEGIN getKeys(theKeyMap); eventCapsDown:= bitTst(@theKeyMap, capsLockKey) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION EventOptionDown: Boolean; {Reads the keyboard and returns true if the Option key is down (pressed).} {Written by David Sinclair, 25 April 1998.} CONST kOptionKey = 61; VAR theKeyMap: KeyMap; BEGIN GetKeys(theKeyMap); EventOptionDown:= BitTst(@theKeyMap, kOptionKey) END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} (* ĥĥ This routine uses the method suggested by THINK Reference... but it isnıt necessary for Pascal! FUNCTION EventKeyIsDown(keyCode: Integer): Boolean; {Given a key code, this returns True if that key is down, otherwise False. See THINK Referenceıs Keyboard Layouts (linked from the GetKeys page) for details of key code values. Several constants are also available, including kSpacebarKeyCode, kOptionKeyCode, etc.} VAR theKeyMap: PACKED ARRAY[0..15] OF SignedByte; theByte: SignedByte; theBit: Integer; BEGIN GetKeys(KeyMap(theKeyMap)); theByte:= theKeyMap[keyCode DIV 8]; theBit:= (keyCode MOD 8); EventKeyIsDown:= BTST(theByte,theBit) END; *) {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION EventKeyIsDown(keyCode: Integer): Boolean; {Given a key code, this returns True if that key is down, otherwise False. See THINK Referenceıs Keyboard Layouts (linked from the GetKeys page) for details of key code values. Several constants are also available, including kSpacebarKeyCode, kOptionKeyCode, etc.} VAR theKeyMap: KeyMap; BEGIN GetKeys(theKeyMap); EventKeyIsDown:= theKeyMap[keyCode] END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventGotRequiredParams (anAppleEvent: AppleEvent): OSErr; { Checks for a keyMissedKeywordAttr attribute. } { From Inside Macintosh volume VI, p6­47-8. Typed in by David Sinclair, 25 } { October 1991; made generic, 9 March 1997. } VAR returnedType: descType; actualSize: size; myErr: osErr; BEGIN myErr:= AEGetAttributePtr(anAppleEvent, keyMissedKeywordAttr, typeWildCard, returnedType, NIL, 0, actualSize); IF myErr = errAEDescNotFound THEN { You got all the required parameters } myErr:= noErr ELSE IF myErr = noErr THEN { You missed a required parameter } myErr:= errAEEventNotHandled; { Else the call to AEGetAttributePtr failed } eventGotRequiredParams:= myErr END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION EventGetCurrentProcessFileSpec(VAR procSpec: FSSpec): OSErr; {This returns the fileSpec of the currently running application.} VAR tempInfo: ProcessInfoRec; psn: ProcessSerialNumber; err: OSErr; BEGIN err:= GetCurrentProcess(psn); ZeroData(@tempInfo,SizeOf(tempInfo)); tempInfo.processInfoLength:= SizeOf(ProcessInfoRec); tempInfo.processAppSpec:= @procSpec; IF err=NoErr THEN err:= GetProcessInformation(psn,tempInfo); EventGetCurrentProcessFileSpec:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION findAProcess (creatorToFind, typeToFind: osType; {} VAR processSN: ProcessSerialNumber): osErr; { This runs through the process list looking for the indicated application. Used by } { sendOpenSelectionAE, below. } { Written by C.K. Haun of Apple Developer Tech Support; converted from C to Pascal } { and modified by David Sinclair, 9 November 1994. } VAR tempInfo: ProcessInfoRec; procSpec: FSSpec; processName: str31; myErr: osErr; BEGIN myErr:= noErr; { Nul out the PSN so we're starting at the beginning of the list: } processSN.lowLongOfPSN:= kNoProcess; processSN.highLongOfPSN:= kNoProcess; { Initialize the process information record: } tempInfo.processInfoLength:= sizeOf(ProcessInfoRec); tempInfo.processName:= @processName; tempInfo.processAppSpec:= @procSpec; { Loop through all the processes until we } { 1) find the process we want, or } { 2) error out because of some reason (usually, no more processes): } REPEAT myErr:= GetNextProcess(processSN); IF myErr = noErr THEN myErr:= GetProcessInformation(processSN, tempInfo); UNTIL ((tempInfo.processSignature = creatorToFind) & (tempInfo.processType = longint(typeToFind))) | (myErr <> noErr); findAProcess:= myErr END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventSendOpenSelectionAE (fileSpec: FSSpec): osErr; { Causes the Finder to open the specified file (which may be a document or } { application). From the sample code comments: This routine will ³send a Finder } { OpenSelection event. A Finder OpenSelection allows you to have the Finder } { launch an Application, or open a document, which will of course cause the owning } { Application to launch and open that document. Kinda just like the user had } { double-clicked on the file from a Finder window.² } { Written by C.K. Haun of Apple Developer Tech Support; converted from C to Pascal } { and modified by David Sinclair, 9 November 1994. } CONST aeSelectionKeyword = 'fsel'; aeOpenSelection = 'sope'; kSystemCreator = 'MACS'; kFinderType = 'FNDR'; VAR aeEvent, replyEvent: AppleEvent; { The event to create & the reply (ignored) } myAddressDesc, aeDirDesc, listElem: AEDesc; { Some descriptors Iıll need } dirSpec: FSSpec; { FSSpec for the Œparentı directory of } { the file Iım opening } fileList: AEDesc; { My list } process: ProcessSerialNumber; { This will hold the process serial } { number of the Finder } DirAlias, FileAlias: AliasHandle; { Some aliases } PROCEDURE checkResult (err: osErr); { Subroutine to check if an error occured, and exit with the error code if so. } BEGIN IF err <> noErr THEN BEGIN eventSendOpenSelectionAE:= err; exit(eventSendOpenSelectionAE); exitToShell { Paranoia } END END; BEGIN { Go find the Finderıs process information, please: } checkResult(findAProcess(kSystemCreator, kFinderType, process)); { Create an address descriptor so the AppleEvent manager knows where to send } { this event: } checkResult(AECreateDesc(typeProcessSerialNumber, @process, sizeOf(process), myAddressDesc)); { Create the empty FinderEvent: } { Itıs a Finder ŒFNDRı, Open Selection Œsopeı event } checkResult(AECreateAppleEvent(kFinderType, aeOpenSelection, myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, aeEvent)); { Make a FSSpec for the parent folder (see the OpenSeletion description in the } { AE Registry) using the information in the document FSSpec: } checkResult(FSMakeFSSpec(fileSpec.vRefNum, fileSpec.parID, null, dirSpec)); checkResult(NewAlias(NIL, dirSpec, DirAlias)); { Create alias for file: } checkResult(NewAlias(NIL, fileSpec, FileAlias)); { Create the file list: } checkResult(AECreateList(NIL, 0, false, fileList)); { Create the folder descriptor: } HLock(Handle(DirAlias)); checkResult(AECreateDesc(typeAlias, ptr(DirAlias^), GetHandleSize(Handle(DirAlias)), aeDirDesc)); HUnlock(Handle(DirAlias)); DisposeHandle(Handle(DirAlias)); { Put the Directory Desc in the event as the direct object: } checkResult(AEPutParamDesc(aeEvent, keyDirectObject, aeDirDesc)); { Done with the desc, kill it: } checkResult(AEDisposeDesc(aeDirDesc)); { Create the file descriptor and add to aliasList: } HLock(Handle(FileAlias)); checkResult(AECreateDesc(typeAlias, ptr(FileAlias^), GetHandleSize(Handle(FileAlias)), listElem)); HLock(Handle(FileAlias)); DisposeHandle(Handle(FileAlias)); checkResult(AEPutDesc(fileList, 0, listElem)); checkResult(AEDisposeDesc(listElem)); { Add the file alias list to the event: } checkResult(AEPutParamDesc(aeEvent, aeSelectionKeyword, fileList)); checkResult(AEDisposeDesc(fileList)); { And now send the event! } checkResult(AESend(aeEvent, replyEvent, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, NIL, NIL)); { And kill the memory used: } checkResult(AEDisposeDesc(aeEvent)); eventSendOpenSelectionAE:= noErr { If an error occurred, it wouldnıt } END; { have reached here } {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventBringFinderToFront: OSErr; { Causes the Finder to be brought to the front when WaitNextEvent is next called. } { Written by David Sinclair, 17 August 1995. } CONST kSystemCreator = 'MACS'; kFinderType = 'FNDR'; VAR process: ProcessSerialNumber; { The process seria number of the Finder } err: OSErr; BEGIN err:= findAProcess(kSystemCreator, kFinderType, process); IF err = NoErr THEN err:= SetFrontProcess(process); eventBringFinderToFront:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventBringAppToFront (creator: OSType): OSErr; { Causes the specified application to be brought to the front when WaitNextEvent is next called, } { if it is currently running. If not, an error is returned. } { Written by David Sinclair, 27 January 1997. } VAR psn: ProcessSerialNumber; err: OSErr; BEGIN err:= FindAProcess(creator, 'APPL', psn); IF err = noErr THEN err:= SetFrontProcess(psn); eventBringAppToFront:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION SearchVolForApp (vRef: Integer; creatorsHdl: OSTypeHandle; searchCreator: OSType; {} numCreators: Longint; VAR fileSpec: FSSpec; VAR creator: OSType): OSErr; { Searches the specified volume for one of the specified applications. Only called by } { eventOpenApplication, below. } VAR i: Integer; dPB: DTPBRec; refNum: Integer; filename: Str255; fndrInfo: FInfo; err: OSErr; BEGIN filename:= null; creator:= noAppFound; dPB.ioNamePtr:= @filename; dPB.ioVRefNum:= vRef; err:= PBDTGetPath(@dPB); IF err = noErr THEN BEGIN refNum:= dPB.ioDTRefNum; dPB.ioNamePtr:= @filename; i:= 0; WHILE (creator = noAppFound) & (i < numCreators) DO BEGIN i:= i + 1; dPB.ioIndex:= 0; { Want the one with the latest creation date } IF creatorsHdl = NIL THEN dPB.ioFileCreator:= searchCreator ELSE dPB.ioFileCreator:= creatorsHdl^^[i]; err:= PBDTGetAPPLSync(@dPB); { Look for the creator in the desktop database } IF err = noErr THEN BEGIN { We got the application info, but it is possible that the application has been deleted without the desktop } { file being updated. Check to see that the file is still there: } err:= HGetFInfo(vRef, dPB.ioAPPLParID, filename, fndrInfo); IF err = noErr THEN err:= FSMakeFSSpec(vRef, dPB.ioAPPLParID, filename, fileSpec); IF err = noErr THEN creator:= dPB.ioFileCreator; END; END; END; IF err = afpItemNotFound THEN { Not found on this volume } err:= noErr; SearchVolForApp:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventOpenApplication (creatorsRsrcID: Integer; VAR creator: OSType): OSErr; { Finds and opens an application, and returns its creator, or the constant noAppFound if one canıt be } { found. The currently running applications are checked first, then if it isnıt running, the desktop } { database is scanned for the latest version of the app. Pass the ID of an ŒApp#ı resource containing a } { list of creator types, or zero to use a creator specified in the creator parameter. If a valid ID is passed, } { creator need not be initialised. } CONST appListRsrcType = 'App#'; timeoutTicks = 15*60; {Timeout after 15 seconds} VAR creatorsHdl: OSTypeHandle; searchCreator: OSType; i: Integer; numCreators: Longint; fileSpec: FSSpec; filename: Str31; vPB: ParamBlockRec; theEvent: EventRecord; startTicks: Longint; ignored: Boolean; err: OSErr; BEGIN err:= noErr; searchCreator:= creator; creator:= noAppFound; creatorsHdl:= NIL; numCreators:= 1; IF creatorsRsrcID > 0 THEN err:= numGetResource(creatorsHdl, appListRsrcType, creatorsRsrcID); IF err = noErr THEN BEGIN IF creatorsHdl <> NIL THEN BEGIN numBlindLockHandle(creatorsHdl); numCreators:= GetHandleSize(Handle(creatorsHdl)) DIV 4; END; i:= 0; WHILE (creator = noAppFound) & (i < numCreators) DO { Search the running processes for one we know about } BEGIN i:= i + 1; IF creatorsHdl <> NIL THEN searchCreator:= creatorsHdl^^[i]; err:= eventBringAppToFront(searchCreator); IF err = noErr THEN creator:= searchCreator; END; IF creator = noAppFound THEN { No applications currently running, so search the disks for one to launch } BEGIN filename:= null; vPB.ioVolIndex:= 1; vPB.ioNamePtr:= @filename; REPEAT err:= PBGetVInfoSync(@vPB); IF err = noErr THEN err:= SearchVolForApp(vPB.ioVRefNum, creatorsHdl, searchCreator, numCreators, fileSpec, creator); IF (err = noErr) & (creator <> noAppFound) THEN BEGIN err:= eventSendOpenSelectionAE(fileSpec); startTicks:= TickCount; IF err=noErr THEN REPEAT ignored:= WaitNextEvent(keyUpMask, theEvent, 120, NIL); { Give the application some time to start up } UNTIL (eventBringAppToFront(searchCreator)=noErr) | (TickCount > (startTicks+timeoutTicks)); END; vPB.ioVolIndex:= vPB.ioVolIndex + 1; UNTIL (err <> noErr) | (creator <> noAppFound); END; IF err = nsvErr THEN { Out of volumes to search, havenıt found any applications } err:= noErr; IF creatorsHdl <> NIL THEN numDisposeHandle(creatorsHdl); END; eventOpenApplication:= err END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventSendOpenURLAE (creatorsRsrcID: Integer; theURL: Str255): OSErr; { Sends the OpenURL AE to whatever browser the user uses: it first searches for an open browser, } { then if not found, it searches the desktop database. Returns noBrowserErr if no browser could be } { found, or some other error value. Note: this routine requires an ŒApp#ı resource, containing } { creators of known browsers. If you pass zero for creatorsRsrcID, only Netscape will be recognised. } { Written by David Sinclair, 27 January 1997. } VAR gurlEvt: AppleEvent; replyEvt: AppleEvent; creatorDesc: AEAddressDesc; urlDesc: AEDesc; creator: OSType; PROCEDURE CheckResult (err: osErr); BEGIN IF err <> noErr THEN BEGIN eventSendOpenURLAE:= err; Exit(eventSendOpenURLAE); ExitToShell { Paranoia } END END; BEGIN creator:= 'MOSS'; CheckResult(eventOpenApplication(creatorsRsrcID, creator)); IF creator = noAppFound THEN CheckResult(noBrowserErr); CheckResult(AECreateDesc(typeApplSignature, @creator, SizeOf(creator), creatorDesc)); CheckResult(AECreateDesc(typeChar, @theURL[1], Length(theURL), urlDesc)); IF creator = 'MOS!' THEN { NCSA Mosaic has its own ideas for AE URLs } CheckResult(AECreateAppleEvent('mos!', 'ourl', creatorDesc, kAutoGenerateReturnID, kAnyTransactionID, gurlEvt)) ELSE CheckResult(AECreateAppleEvent('GURL', 'GURL', creatorDesc, kAutoGenerateReturnID, kAnyTransactionID, gurlEvt)); CheckResult(AEDisposeDesc(creatorDesc)); CheckResult(AEPutParamDesc(gurlEvt, keyDirectObject, urlDesc)); CheckResult(AEDisposeDesc(urlDesc)); CheckResult(AESend(gurlEvt, replyEvt, kAEWaitReply + kAECanInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, NIL, NIL)); CheckResult(AEDisposeDesc(gurlEvt)); CheckResult(AEDisposeDesc(replyEvt)); eventSendOpenURLAE:= noErr { If an error occurred, it wouldnıt have reached here } END; {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} FUNCTION eventSendOpenDocumentAE (creator: OSType; fileSpec: FSSpec): OSErr; { Passes the specified fileSpec to the specified application. The application is opened first, if necessary } { (via eventOpenApplication). Use eventSendOpenSelectionAE instead of this for normal documents, } { but this routine can be used where the file has a different creator than the creator parameter, e.g. to } { simulate dropping another application on an app, or a foreign document type. } { Written by David Sinclair, 16 March 1997, based on the eventSendOpenSelectionAE routine. } CONST aeSelectionKeyword = 'fsel'; kAppType = 'APPL'; VAR aeEvent, replyEvent: AppleEvent; { The event to create & the reply (ignored) } myAddressDesc, listElem: AEDesc; { Some descriptors Iıll need } fileList: AEDesc; { My list } process: ProcessSerialNumber; { This will hold the process serial number of the application } FileAlias: AliasHandle; { An alias of the file } PROCEDURE checkResult (err: OSErr); { Subroutine to check if an error occured, and exit with the error code if so. } BEGIN IF err <> noErr THEN BEGIN eventSendOpenDocumentAE:= err; exit(eventSendOpenDocumentAE); ExitToShell { Paranoia } END END; BEGIN { Open the application first: } CheckResult(eventOpenApplication(0, creator)); { Go find the appıs process information, please: } CheckResult(FindAProcess(creator, kAppType, process)); { Create an address descriptor so the AppleEvent manager knows where to send } { this event: } CheckResult(AECreateDesc(typeProcessSerialNumber, @process, SizeOf(process), myAddressDesc)); { Create the empty Apple event: } CheckResult(AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID, aeEvent)); { Create alias for file: } CheckResult(NewAlias(NIL, fileSpec, FileAlias)); { Create the file list: } CheckResult(AECreateList(NIL, 0, false, fileList)); { Create the file descriptor and add to aliasList: } HLock(Handle(FileAlias)); CheckResult(AECreateDesc(typeAlias, Ptr(FileAlias^), GetHandleSize(Handle(FileAlias)), listElem)); HLock(Handle(FileAlias)); DisposeHandle(Handle(FileAlias)); CheckResult(AEPutDesc(fileList, 0, listElem)); CheckResult(AEDisposeDesc(listElem)); { Add the file alias list to the event: } CheckResult(AEPutParamDesc(aeEvent, keyDirectObject, fileList)); CheckResult(AEDisposeDesc(fileList)); { And now send the event! } CheckResult(AESend(aeEvent, replyEvent, kAENoReply + kAEAlwaysInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, NIL, NIL)); { And kill the memory used: } CheckResult(AEDisposeDesc(aeEvent)); eventSendOpenDocumentAE:= noErr { If an error occurred, it wouldnıt } END; { have reached here } {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} {--------------------------------|--------------------------------------------------------------------|---------------------------------------------------------|------------------------} END.