[comp.sys.mac.programmer] TN 126, last part

Alan.Michelson@f141.n102.z1.FIDONET.ORG (Alan Michelson) (03/19/90)

 
A Sublaunch from C 
 
To sublaunch from MPW C, we need to have a small assembly language routine 
that calls _Launch, since MPW C currently will not allow either inline
assembly or multiple word extern declarations: 
 
; OSErr Launchit(pLaunch) 
; pLaunchStruct pLaunch; 
; extern; 
 INCLUDE 'traps.a' 
 CASE ON ; so C can C Launchit 
Launchit PROC EXPORT 
 
 MOVE.L 4(SP),A0 ; get pointer to parameter block 
 _Launch ; call launch 
 
 ; note that now we can return from _Launch (under MultiFinder) so
 ; we'd better be prepared to continue. 
 
 ; we've returned from Launch, we now have the return address on the
 ; stack, but first we need to clean up the address of our parameter 
 MOVE.L (SP)+,A0 ; get the return address in A0 
 ADDQ #4,SP ; get rid of the paramter 
 JMP (A0) ; we need to be prepared to come back
          ; from a launch 
 ENDP 
 END 
 
 
Now heres the MPW C source: 
 
typedef struct LaunchStruct { 
 char *pfName; /* pointer to the name of launchee */ 
 short int param; 
 char LC[2]; /*extended parameters:*/ 
 long int extBlockLen;/*number of bytes in extension == 6*/ 
 short int fFlags; /*Finder file info flags (see below)*/ 
 long int launchFlags; /*bit 31,30==1 for sublaunch, others reserved*/ 
} *pLaunchStruct; 
 
extern OSErr Launchit(); 
 
 
OSErr DoLaunch() 
 
{ /* DoLaunch */ 
 
 struct LaunchStruct myLaunch; 
 Point wher; /*where to display dialog*/ 
 SFReply reply; /*reply record*/ 
 SFTypeList myFileTypes;/* we only want APPLs */
 short int numFileTypes=1; 
 HFileInfo myPB; 
 char *dirNameStr; 
 OSErr err; 
 
 wher.h = 80; 
 wher.v = 90; 
 myFileTypes[0] = 'APPL'; /* we only want APPLs */ 
 /*Let the user choose the file to Launch*/ 
 SFGetFile(wher, "", nil, numFileTypes, myFileTypes, nil, &reply); 
 
 if (reply.good) 
 { 
 dirNameStr = &reply.fName; /*initialize to file selected*/ 
 
 /*Get the Finder flags*/ 
 myPB.ioNamePtr= dirNameStr; 
 myPB.ioVRefNum= reply.vRefNum; 
 myPB.ioFDirIndex= 0; 
 myPB.ioDirID = 0; 
 err = PBGetCatInfo(&myPB,false); 
 if (err != noErr) 
 return err; 
 
 /*Set the current volume to where the target application is*/ 
 err = SetVol(nil, reply.vRefNum); 
 if (err != noErr) 
 return err; 
 
 /*Set up the launch parameters*/ 
 myLaunch.pfName = &reply.fName; /*pointer to our fileName*/ 
 myLaunch.param = 0; /*we dont want alternate screen or sound buffers*/ 
 
 /*set up LC so as to tell Launch that there is non-junk next*/ 
 myLaunch.LC[0] = 'L'; myLaunch.LC[1] = 'C'; 
 myLaunch.extBlockLen = 6; /*length of param. block past this long word*/ 
 /*copy flags; set bit 6 of low byte to 1 for RO access:*/ 
 myLaunch.fFlags = myPB.ioFlFndrInfo.fdFlags; /*from GetCatInfo*/ 
 myLaunch.launchFlags = 0xC0000000; /*set BOTH hi bits for a sublaunch*/ 
 
 err = Launchit(&myLaunch); /* do the sublaunch */ 
 if (err < 0) 
 { 
 /* the launch failed, so put up an alert to inform the user */ 
 DoLaunchFailed(); 
 return err; 
 } 
 else 
 return noErr; 
 } /*if reply.good*/ 
} /*DoLaunch*/ 
 
Working directories 
 
Putting aside the compatibility issue for the moment, the only problem
this creates under the current system is one of Working Directory Control
Blocks, or WDCBs. Unless the application you are launching is at the root
or on an MFS volume, a new WDCB must be created so that it may be set as
the current directory when the program is run. 
 
In the example procedure above, the new working directory is opened
(allocated) by Standard File and its WDRefNum is returned in
reply.vRefNum. If you werent using Standard File and couldnt assume, for
instance, that the application was in the blessed folder or root then you
would have to open a new working directory explicitly via OpenWD. The new
WDCB should have a WDProcID of 'ERIK' so the Finder or another shell which 
saw that the WDCB had been allocated by a"sublaunchee would know to
de-allocate it. 
 
The sublaunching process is recursive; you may sublaunch a program which
then sublaunches another, and so on, and when each application exits it
may return to the one that called it. The problem is that there is a limit 
to the number of WDCBs that can be created; currently (and probably
forever) the limit is 40. You can see how quickly these might be used up
if many programs were playing the shell game or neglecting to de-allocate
WDCBs they had created. Make sure that you check for all errors after
calling PBOpenWD. A tMWDOErr (121) means that all available WDCBs have
been allocated. 
 

--  
Alan Michelson via cmhGate - Net 226 fido<=>uucp gateway Col, OH
UUCP: ...!osu-cis!n8emr!cmhgate!102!141!Alan.Michelson
INET: Alan.Michelson@f141.n102.z1.FIDONET.ORG