diff --git a/mac-cpp-source/Iomega Zip Tester.cpp b/mac-cpp-source/Iomega Zip Tester.cpp index b69c10d..adb4cb3 100644 --- a/mac-cpp-source/Iomega Zip Tester.cpp +++ b/mac-cpp-source/Iomega Zip Tester.cpp @@ -47,6 +47,7 @@ bool process_command() { printf("\n"); char *arg_str = strchr(cmd, ' '); + while(*arg_str == ' ') arg_str++; if(arg_str) arg_val = atoi(arg_str); switch( tolower(cmd[0]) ) { @@ -60,6 +61,7 @@ bool process_command() { case 'u': mac_unmount(arg_val); break; case 't': run_tip(arg_val); break; case 'q': return false; + case 'o': SetRichEditText(arg_str); break; } return true; } diff --git a/mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin b/mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin new file mode 100644 index 0000000..84dace8 Binary files /dev/null and b/mac-cpp-source/Iomega Zip Tester.rsrc.sit.bin differ diff --git a/mac-cpp-source/macos/mac_vol.h b/mac-cpp-source/macos/mac_vol.h index 21a50db..7d971f8 100644 --- a/mac-cpp-source/macos/mac_vol.h +++ b/mac-cpp-source/macos/mac_vol.h @@ -1,4 +1,4 @@ void mac_list_volumes(); void mac_unmount(int id); OSErr mac_get_drive_volumes(int driveNum, Str255 str); -OSErr mac_unmount_drive(int driveNum); \ No newline at end of file +OSErr mac_unmount_drive(int driveNum); diff --git a/mac-cpp-source/tip-doc.sit.bin b/mac-cpp-source/tip-doc.sit.bin new file mode 100644 index 0000000..deabd67 Binary files /dev/null and b/mac-cpp-source/tip-doc.sit.bin differ diff --git a/mac-cpp-source/tip/tip.cpp b/mac-cpp-source/tip/tip.cpp index 5273e4e..29e7f90 100644 --- a/mac-cpp-source/tip/tip.cpp +++ b/mac-cpp-source/tip/tip.cpp @@ -85,10 +85,13 @@ void WndProc(long iMessage, long wParam) { case DISK_Z_TRACK_FAILURE: case DISK_TEST_FAILURE: case DISK_PROTECTED: - //EjectIomegaCartridge(); + EjectIomegaCartridge(); break; case DISK_LOW_SPARES: + SetRichEditText(szNotRunning); + SetWindowText(hTestButton, szPressToStart); PrepareToBeginTesting(); + InvalidateRect(hTestMonitor); break; } break; diff --git a/mac-cpp-source/tip/tip.h b/mac-cpp-source/tip/tip.h index e0d3a8a..006b6df 100644 --- a/mac-cpp-source/tip/tip.h +++ b/mac-cpp-source/tip/tip.h @@ -37,6 +37,11 @@ extern long SingleTransferLBA; // ----------------------- Macintosh Compatibility ----------------------- +enum AlertTypes { + ERR_DLG, + YN_DLG +}; + enum { BACK_COLOR = -1, BLACK_COLOR = 0x000000, @@ -57,6 +62,8 @@ void SetColor(long color); void SetColor(long color, long monoColor); void DrawLed(int x, int y, long color); void StrToPascal(Str255 pStr, const char *str); +int ShowAlert(AlertTypes type, const char* format, ...); +void SetRichEditText(const char *name); long GetTextExtent(const char *str, unsigned long len); void TextOut(int x, int y, Str255 str); void TextOut(int x, int y, const char *str); @@ -137,6 +144,25 @@ extern const char *szPressToSpin; extern const char *szPressToEject; extern const char *szPressToProceed; +/************* Filenames *************/ + +extern const char *szInstructions; +extern const char *szNoASPI; +extern const char *szASPITrouble; +extern const char *szPPAVersion; +extern const char *szDefectList; +extern const char *szLocked; +extern const char *szNoSpares; +extern const char *szOutOfSpares; +extern const char *szFewSpares; +extern const char *szNotRunning; +extern const char *szRunning; +extern const char *szInterrupted; +extern const char *szPerfectResult; +extern const char *szExplainResult; +extern const char *szBadResult; +extern const char *szIomegaQuote; + /************* Cartridge Status Text *************/ typedef struct {long code; char *str;} ErrorTypeList; @@ -227,7 +253,8 @@ long GetSpareSectorCounts(char); void HandleDriveChanging(); void SetCartridgeStatusToEAX(long eax); long PerformRegionTransfer(short XferCmd, void *pBuffer); -long TestTheDisk(); +void TestTheDisk(); long GetElapsedTimeInSeconds(); void PrepareToBeginTesting(); void BumpErrorCounts(long ErrorCode); +void EjectIomegaCartridge(); diff --git a/mac-cpp-source/tip/tip_aspi.cpp b/mac-cpp-source/tip/tip_aspi.cpp index 5beaa44..c40ddec 100644 --- a/mac-cpp-source/tip/tip_aspi.cpp +++ b/mac-cpp-source/tip/tip_aspi.cpp @@ -92,15 +92,6 @@ struct DEFECT_LIST_HEADER { #define CHECK_CONDITION 0x02 -enum { - szBadResult, - szInterrupted, - szExplainResult, - szPerfectResult, - szNoSpares, - szOutOfSpares -}; - long CurrentDevice = 0; long DriveCount = 0; @@ -454,11 +445,12 @@ long GetSpareSectorCounts(char checkPassword) { if(!Side_0_SparesCount && !Side_1_SparesCount) { NoSpares: CartridgeStatus = DISK_TEST_FAILURE; - eax = szNoSpares; + const char *eax = szNoSpares; // if were running give them a different error message if(TestingPhase) { eax = szOutOfSpares; } + SetRichEditText(eax); goto ErrorExit; } @@ -470,6 +462,7 @@ long GetSpareSectorCounts(char checkPassword) { // show the richedit control for the trouble if (eax == DEFECT_LIST_READ_ERROR) { CartridgeStatus = DISK_Z_TRACK_FAILURE; + SetRichEditText(szDefectList); ErrorExit: return -1; } @@ -533,6 +526,7 @@ void SetCartridgeStatusToEAX(long eax) { esi = szPressToStop; break; case DISK_NOT_PRESENT: + SetRichEditText(szNotRunning); goto DisableActions; case DISK_AT_SPEED: eax = GetSpareSectorCounts(true); // update the Cart Condition @@ -556,6 +550,7 @@ void SetCartridgeStatusToEAX(long eax) { } if(Side_1_SparesCount < MINIMUM_ZIP_SPARES) { InsufficientSpares: + SetRichEditText(szFewSpares); CartridgeStatus = DISK_LOW_SPARES; esi = szPressToProceed; goto EnableTestBtn; @@ -656,6 +651,23 @@ void BumpErrorCounts(long ErrorCode) { HardErrors++; } +/******************************************************************************* + * EJECT IOMEGA CARTRIDGE + *******************************************************************************/ +void EjectIomegaCartridge() { + // Could NOT do it through the IOCTL layer ... so eject with SCSI + // make sure the media is not locked... + char Scsi[6] = {0}; + Scsi[0] = SCSI_Cmd_PreventAllow; + SCSICommand(CurrentDevice, Scsi, 0, 0); + // issue an Asynchronous STOP command to induce spindown and ejection + memset(Scsi, 0, sizeof(Scsi)); + Scsi[0] = SCSI_Cmd_StartStopUnit; + Scsi[1] = 1; // Set the IMMED bit for offline + Scsi[4] = 2; // eject a Jaz disk after stopping + SCSICommand(CurrentDevice, Scsi, 0, 0); +} + /******************************************************************************* * PERFORM REGION TRANSFER *******************************************************************************/ @@ -775,18 +787,19 @@ Exit: * TEST THE DISK *******************************************************************************/ -long TestTheDisk() { +void TestTheDisk() { void *pPatternBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR); void *pUserDataBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR); if(pPatternBuffer == NULL || pUserDataBuffer == NULL) { printf("Allocation error\n"); - return -1; + return; } StopApplicationTimer(); PreventProgramExit(); + SetRichEditText(szRunning); CartridgeStatus = DISK_TEST_UNDERWAY; TestingPhase = TESTING_STARTUP; // inhibit stopping now SetWindowText(hTestButton, szPressToStop); @@ -869,7 +882,8 @@ GetOut: AllowProgramExit(); // compute the number of serious troubles - long eax, errors = FirmErrors + HardErrors; + const char *eax; + long errors = FirmErrors + HardErrors; if (errors >= BADNESS_THRESHOLD) { eax = szBadResult; } @@ -885,8 +899,8 @@ GetOut: eax = szPerfectResult; } } - + SetRichEditText(eax); InvalidateRect(hTestMonitor); + Exit: StartApplicationTimer(); - return eax; } diff --git a/mac-cpp-source/tip/tip_main.cpp b/mac-cpp-source/tip/tip_main.cpp index 2515c59..4ba2cb9 100644 --- a/mac-cpp-source/tip/tip_main.cpp +++ b/mac-cpp-source/tip/tip_main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -7,6 +8,8 @@ #include #include +#include "pstring.h" +#include "LaunchLib.h" #include "mac_vol.h" #include "tip.h" @@ -30,7 +33,10 @@ void run_tip(int id) { WinMain(id); RgnHandle cursorRgn = NewRgn(); + SetRichEditText(szInstructions); NewTipWindow(); + EnableWindow(hTestButton, false); + gDone = false; do { EventRecord event; @@ -195,17 +201,15 @@ void DoDiskEvent(EventRecord &event) { mac_get_drive_volumes(driveNum, volumes); // Ask the user whether they want to unmount the disk - ParamText(volumes, "\p", "\p", "\p"); if (CautionAlert(128, NULL) == 1) { // The user wishes to unmount the disk OSErr err = mac_unmount_drive(driveNum); if(err != noErr) { if(err == fBsyErr) { - ParamText("\pFailed to unmount. One or more files are open.", "\p", "\p", "\p"); + ShowAlert(ERR_DLG, "Failed to unmount. One or more files are open."); } else { - ParamText("\pFailed to unmount.", "\p", "\p", "\p"); + ShowAlert(ERR_DLG, "Failed to unmount. Error Code: %d", err); } - StopAlert(129, NULL); } } } @@ -217,6 +221,69 @@ void StrToPascal(Str255 pStr, const char *str) { strncpy((char*)pStr + 1, str, 255); } +/******************************************************************************* + * SHOW ALERT BOX + *******************************************************************************/ + +int ShowAlert(AlertTypes type, const char* format, ...) { + Str255 pStr; + va_list argptr; + va_start(argptr, format); + vsprintf((char*)pStr + 1, format, argptr); + va_end(argptr); + pStr[0] = strlen((char*)pStr + 1); + ParamText(pStr, "\p", "\p", "\p"); + switch(type) { + case ERR_DLG: return StopAlert(129, NULL); + case YN_DLG: return NoteAlert(130, NULL); + } + return 0; +} + +/******************************************************************************* + * SET RICH EDIT TEXT + * + * This routine will open one of the TIP explanation files using SimpleText + * + * This uses code from Thomas Tempelmann's C libraries + * + * http://www.tempel.org/macdev/index.html + *******************************************************************************/ + +void SetRichEditText(const char *name) { + static const char *lastName = 0; + if(name == lastName) return; + + if(ShowAlert(YN_DLG, "Would you like to read the document \"%s\" now?", name) == 2) { + return; + } + Str255 docName; + StrToPascal(docName, name); + + Str255 pathName; + pstrcpy(pathName, "\p:tip-doc:"); + pstrcat(pathName, docName); + + FSSpec docSpec; + FSSpec appSpec; + OSErr err = FSMakeFSSpec(0, 0, pathName, &docSpec); + if(err) { + ShowAlert(ERR_DLG, "Can't find the \"%s\" file. Make sure it is inside the \"tip-doc\" folder.", name); + return; + } + + err = FindApplicationFromDocument(&docSpec, &appSpec); + if(err) { + ShowAlert(ERR_DLG, "Can't find an application to open \"%s\". Is \"SimpleText\" installed?", name); + return; + } + err = LaunchApplicationWithDocument(&appSpec, &docSpec, false); + if(err) { + ShowAlert(ERR_DLG, "Can't open \"%s\". If \"%#s\" is already running, please close it.", name, appSpec.name); + return; + } +} + /******************************************************************************* * SET COLOR *******************************************************************************/ diff --git a/mac-cpp-source/tip/tip_text.cpp b/mac-cpp-source/tip/tip_text.cpp index e1d3bf3..77c0085 100644 --- a/mac-cpp-source/tip/tip_text.cpp +++ b/mac-cpp-source/tip/tip_text.cpp @@ -26,6 +26,25 @@ const char *szPressToSpin = "Press to Spin Up"; const char *szPressToEject = "Press to Eject"; const char *szPressToProceed = "Press to Proceed"; +// Filenames + +const char *szInstructions = "Instructions"; +const char *szNoASPI = "No ASPI"; +const char *szASPITrouble = "No Drives"; +const char *szPPAVersion = "Parallel Port"; +const char *szDefectList = "Z-Track Failure"; +const char *szLocked = "Cartridge Locked"; +const char *szNoSpares = "No Spares"; +const char *szOutOfSpares = "Out of Spares"; +const char *szFewSpares = "Few Spares"; +const char *szNotRunning = "Not Running"; +const char *szRunning = "Test Running"; +const char *szInterrupted = "Test Interrupted"; +const char *szPerfectResult = "Perfect Result"; +const char *szExplainResult = "Good Result"; +const char *szBadResult = "Bad Result"; +const char *szIomegaQuote = "Iomega Quote"; + /************* Cartridge Status Text *************/ const char *szUnknownStat = "Ejecting Cartridge"; diff --git a/mac-cpp-source/utils/.finf/FileLib.c b/mac-cpp-source/utils/.finf/FileLib.c new file mode 100644 index 0000000..c13d137 Binary files /dev/null and b/mac-cpp-source/utils/.finf/FileLib.c differ diff --git a/mac-cpp-source/utils/.finf/FileLib.h b/mac-cpp-source/utils/.finf/FileLib.h new file mode 100644 index 0000000..d9cb0d5 Binary files /dev/null and b/mac-cpp-source/utils/.finf/FileLib.h differ diff --git a/mac-cpp-source/utils/.finf/LaunchLib.c b/mac-cpp-source/utils/.finf/LaunchLib.c new file mode 100644 index 0000000..6807105 Binary files /dev/null and b/mac-cpp-source/utils/.finf/LaunchLib.c differ diff --git a/mac-cpp-source/utils/.finf/LaunchLib.h b/mac-cpp-source/utils/.finf/LaunchLib.h new file mode 100644 index 0000000..9325bba Binary files /dev/null and b/mac-cpp-source/utils/.finf/LaunchLib.h differ diff --git a/mac-cpp-source/utils/.finf/PascalLib.c b/mac-cpp-source/utils/.finf/PascalLib.c new file mode 100644 index 0000000..0547fd1 Binary files /dev/null and b/mac-cpp-source/utils/.finf/PascalLib.c differ diff --git a/mac-cpp-source/utils/.finf/PascalLib.h b/mac-cpp-source/utils/.finf/PascalLib.h new file mode 100644 index 0000000..0f9350b Binary files /dev/null and b/mac-cpp-source/utils/.finf/PascalLib.h differ diff --git a/mac-cpp-source/utils/.finf/TrapAvail.c b/mac-cpp-source/utils/.finf/TrapAvail.c new file mode 100644 index 0000000..8c9746a Binary files /dev/null and b/mac-cpp-source/utils/.finf/TrapAvail.c differ diff --git a/mac-cpp-source/utils/.finf/TrapAvail.h b/mac-cpp-source/utils/.finf/TrapAvail.h new file mode 100644 index 0000000..5340d55 Binary files /dev/null and b/mac-cpp-source/utils/.finf/TrapAvail.h differ diff --git a/mac-cpp-source/utils/.finf/pstring.h b/mac-cpp-source/utils/.finf/pstring.h new file mode 100644 index 0000000..42eba35 Binary files /dev/null and b/mac-cpp-source/utils/.finf/pstring.h differ diff --git a/mac-cpp-source/utils/.rsrc/FileLib.c b/mac-cpp-source/utils/.rsrc/FileLib.c new file mode 100644 index 0000000..090b269 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/FileLib.c differ diff --git a/mac-cpp-source/utils/.rsrc/FileLib.h b/mac-cpp-source/utils/.rsrc/FileLib.h new file mode 100644 index 0000000..1b2c2f5 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/FileLib.h differ diff --git a/mac-cpp-source/utils/.rsrc/LaunchLib.c b/mac-cpp-source/utils/.rsrc/LaunchLib.c new file mode 100644 index 0000000..62e03d0 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/LaunchLib.c differ diff --git a/mac-cpp-source/utils/.rsrc/LaunchLib.h b/mac-cpp-source/utils/.rsrc/LaunchLib.h new file mode 100644 index 0000000..8178a02 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/LaunchLib.h differ diff --git a/mac-cpp-source/utils/.rsrc/PascalLib.c b/mac-cpp-source/utils/.rsrc/PascalLib.c new file mode 100644 index 0000000..845a837 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/PascalLib.c differ diff --git a/mac-cpp-source/utils/.rsrc/PascalLib.h b/mac-cpp-source/utils/.rsrc/PascalLib.h new file mode 100644 index 0000000..a806bdc Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/PascalLib.h differ diff --git a/mac-cpp-source/utils/.rsrc/TrapAvail.c b/mac-cpp-source/utils/.rsrc/TrapAvail.c new file mode 100644 index 0000000..e7f16a0 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/TrapAvail.c differ diff --git a/mac-cpp-source/utils/.rsrc/TrapAvail.h b/mac-cpp-source/utils/.rsrc/TrapAvail.h new file mode 100644 index 0000000..a296974 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/TrapAvail.h differ diff --git a/mac-cpp-source/utils/.rsrc/pstring.h b/mac-cpp-source/utils/.rsrc/pstring.h new file mode 100644 index 0000000..dcb17c3 Binary files /dev/null and b/mac-cpp-source/utils/.rsrc/pstring.h differ diff --git a/mac-cpp-source/utils/FileLib.c b/mac-cpp-source/utils/FileLib.c new file mode 100644 index 0000000..e8578ec --- /dev/null +++ b/mac-cpp-source/utils/FileLib.c @@ -0,0 +1,184 @@ +/* + * File Utilities (System 7 and above) + * + * by Thomas Tempelmann, macdev@tempel.org + */ + + +#include +#include +#include +#include +#include +#include +#include +//#include + +#define CALL_NOT_IN_CARBON 1 // for Universal Headers 3.3 +#include + +#include "FileLib.h" +#include "TrapAvail.h" + +#pragma push +#pragma cplusplus on + +static Boolean inited = false; +static FSSpec ThisPath = {0,1,"\p"}; // 27.3.96: dirID mu§te von 0 auf 1 geŠndert werden, weil sonst u.U. ResolveAlias einen Endlos-Loop machte + +static OSErr getInfo (CInfoPBPtr pb, FSSpec &fs) +{ + pb->hFileInfo.ioVRefNum = fs.vRefNum; + pb->hFileInfo.ioNamePtr = fs.name; + pb->hFileInfo.ioFDirIndex = 0; + pb->hFileInfo.ioDirID = fs.parID; + return PBGetCatInfoSync (pb); +} + +OSErr FSpResolveAlias (FSSpec &spec) +// PrŸft, ob die Datei ein Alias ist und lšst den ggf. auf. +// Liefert Fehlercode, z.B., wenn ein Login-Dialog vom User abgebrochen wurde. +{ + Boolean isFolder, wasAlias; + return ResolveAliasFile (&spec, true, &isFolder, &wasAlias); +} + + +DrvQElPtr FindDrvQ (short drvNum) +{ + DrvQElPtr qep = (DrvQElPtr)(GetDrvQHdr()->qHead); + while (qep) { + if (qep->dQDrive == drvNum) return qep; + qep = (DrvQElPtr)qep->qLink; + } + return nil; +} + +short FindVolByDriveNum (short drvNum) +{ + HVolumeParam pb; + short err, idx; + + idx = 1; + do { + pb.ioVolIndex = idx; + pb.ioNamePtr = NULL; + err = PBHGetVInfoSync ((HParamBlockRec*)&pb); + if (err) break; + if (pb.ioVDrvInfo == drvNum) { + return pb.ioVRefNum; + } + ++idx; + } while (true); + return 0; +} + +OSErr GetSysVolume (short *vRefNum) +// returns the boot volume +{ + long dir; + OSErr err = FindFolder (kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir); + if (err) *vRefNum = -1; + return err; +} + + +OSErr FindInFolderByCreator (short vRefNum, long dirID, OSType creator, OSType fileType, FSSpec *foundSpec) +{ + OSErr err; + HFileParam pb; + short idx = 1; + do { + pb.ioVRefNum = vRefNum; + pb.ioDirID = dirID; + pb.ioFDirIndex = idx++; + pb.ioNamePtr = foundSpec->name; + pb.ioFVersNum = 0; + err = PBHGetFInfoSync ((HParmBlkPtr)&pb); + if (!err) { + if (pb.ioFlFndrInfo.fdCreator == creator && (fileType == 0 || pb.ioFlFndrInfo.fdType == fileType)) { + foundSpec->vRefNum = vRefNum; + foundSpec->parID = dirID; + return noErr; + } + } + } while (!err); + return err; +} + +OSErr FindOnDiskByCreator (short vRefNum, OSType creator, OSType fileType, FSSpec *foundSpec) +{ + OSErr err; + CSParam pb; + CInfoPBRec info1; + CInfoPBRec info2 = {0}; + + pb.ioVRefNum = vRefNum; + pb.ioNamePtr = nil; + pb.ioMatchPtr = foundSpec; + pb.ioReqMatchCount = 1; + pb.ioCatPosition.initialize = 0; + pb.ioOptBuffer = nil; + pb.ioOptBufSize = 0; + pb.ioSearchTime = 0; + pb.ioSearchBits = fsSBFlAttrib | fsSBFlFndrInfo; + pb.ioSearchInfo1 = &info1; + pb.ioSearchInfo2 = &info2; + if (fileType) { + info1.hFileInfo.ioFlFndrInfo.fdType = fileType; + info2.hFileInfo.ioFlFndrInfo.fdType = (UInt32) -1; // mask + } + info1.hFileInfo.ioFlFndrInfo.fdCreator = creator; + info2.hFileInfo.ioFlFndrInfo.fdCreator = (UInt32) -1; // mask + info1.hFileInfo.ioFlAttrib &= ~ioDirMask; // looking for files, not dirs + info2.hFileInfo.ioFlAttrib |= ioDirMask; // set the mask for files/dirs + err = PBCatSearchSync (&pb); + if (!err && pb.ioActMatchCount > 0) { + return noErr; + } + return fnfErr; +} +#if 0 // Disable by MLT +EXTERN_API(Ptr) GetFCBSPtr(void) TWOWORDINLINE(0x2EB8, 0x034E); + +OSErr FindOpenFileByTypeAndCreator (OSType type, OSType creator, FSSpec *itsSpec) +// type = 0 -> don't care +{ + OSErr err; + short idx = 1; + Boolean hasFSM = TrapAvailable(0xA824); + do { + FCBPBRec pb; + pb.ioFCBIndx = idx++; + pb.ioVRefNum = 0; // means: index through all volumes + pb.ioNamePtr = itsSpec->name; + err = PBGetFCBInfoSync (&pb); + if (!err) { + FCBRecPtr fcb; + if (hasFSM) { + UTResolveFCB (pb.ioRefNum, &fcb); + } else { + fcb = (FCBRecPtr) ((Ptr)GetFCBSPtr() + pb.ioRefNum); + } + if (type == 0 || type == fcb->fcbFType) { + if (creator) { + itsSpec->vRefNum = pb.ioVRefNum; + itsSpec->parID = pb.ioFCBParID; + FInfo fi; + err = FSpGetFInfo (itsSpec, &fi); + if (!err) { + if (creator == fi.fdCreator) { + return noErr; + } + } + } + } + } + } while (!err); + return err; +} +#endif + +#pragma pop + +// EOF diff --git a/mac-cpp-source/utils/FileLib.h b/mac-cpp-source/utils/FileLib.h new file mode 100644 index 0000000..754c10a --- /dev/null +++ b/mac-cpp-source/utils/FileLib.h @@ -0,0 +1,27 @@ +/* + * File Utilities (System 7 and above) + * + * by Thomas Tempelmann, macdev@tempel.org + */ + +#include + +#pragma push +#pragma cplusplus on + +Boolean FSpIsAlias (FSSpec &spec); +OSErr FSpResolveAlias (FSSpec &spec); // Lšst ggf. Aliase auf + +DrvQElPtr FindDrvQ (short drv); +short FindVolByDriveNum (short drvNum); + +OSErr GetSysVolume (short *vRefNum); // gets the boot volume + +OSErr FindInFolderByCreator (short vRefNum, long dirID, OSType creator, OSType fileType, FSSpec *foundSpec); +OSErr FindOnDiskByCreator (short vRefNum, OSType creator, OSType fileType, FSSpec *foundSpec); + +OSErr FindOpenFileByTypeAndCreator (OSType type, OSType creator, FSSpec *itsSpec); + +#pragma pop + +// EOF diff --git a/mac-cpp-source/utils/LaunchLib.c b/mac-cpp-source/utils/LaunchLib.c new file mode 100644 index 0000000..2874f72 --- /dev/null +++ b/mac-cpp-source/utils/LaunchLib.c @@ -0,0 +1,684 @@ +/* + * Functions for launching apps with documents + * + * by Thomas Tempelmann, macdev@tempel.org + * + * some of these routines are not from me (TT), but from some DTS sample code. + * here's a link to it: + */ + + +//#include +#include +#include +#include +#include +#include +#include +#include "PascalLib.h" +#include "FileLib.h" +#include "LaunchLib.h" + + +#pragma cplusplus on + +/* + Korrekturen: + TT 23.2.95: foundFlag wurde nicht auf "false" initialisiert. + TT 5.11.96: LaunchAppl() neu, OpenSpecifiedDocument() kann auch APPLs direkt starten + TT 30.1.99: FindApplicationFromDocument() stellt nun sicher, da§ die App wirklich existiert (das + ist nicht der Fall, wenn das Volume not mounted ist oder wenn die App verschoben + oder gelšscht wurde, oder wenn die Datei nicht vom Typ 'APPL' ist). + TT 13.2.99: FindApplicationFromDocument() updated to use the proper algorith that the Finder + uses. For that, the code has been largely rewritten (reordered) + Note: it is not perfectly like the Finder: The Finder orders remote vols by their + speed, thru the parm "volumeGrade", while I ignore this information, since most + vols are having a grade of 0, anyways. + Attention: It does not use the "fopn" Finder interception AE that has been introduced + in Mac OS 8! + TT 16.2.99: LaunchAppl(): launchNoFileFlags was set in wrong field (in launchFileFlags instead + launchControlFlags) + TT 23.3.99: added: FindApplicationByCreator(), OpenWithFinder(), FindRunningAppBySignature(), + SendFSSEventToProcess(). + TT 15.4.99: added the file type 'APPD' to the list of launchable apps in checkThisVolume(). + (APPD is used for apps routed to the Apple Menu Items folder) + TT 31.7.99: added "Boolean inBackground" parm to OpenSpecifiedDocument() and LaunchAppl(), + and added SetFrontProcess() in OpenSpecifiedDocument() and in LaunchApplicationWithDocument() + in order to bring the app to the front when it was already running. + TT 24.4.00: added the file type 'appe' to the list of launchable apps in checkThisVolume(), + added types 'APPC', 'APPD' and 'appe' to +*/ + +// OpenSpecifiedDocument searches to see if the application which +// created the document is already running. If so, it sends +// an OpenSpecifiedDocuments Apple event to the target application +// (remember that, because of puppet strings, this works even +// if the target application is not Apple event-aware.) + +OSErr OpenSpecifiedDocument(const FSSpec * documentFSSpecPtr, Boolean inBackground) +{ + OSErr retCode; + ProcessSerialNumber currPSN; + ProcessInfoRec currProcessInfo; + FSSpec applicationSpec; + FInfo documentFInfo; + Boolean foundRunningProcessFlag; + + // verify the document file exists and get its creator type + + retCode = FSpGetFInfo(documentFSSpecPtr, &documentFInfo); + if (retCode != noErr) goto Bail; + + // check the current processes to see if the creator app is already + // running, and get its process serial number (as currPSN) + + currPSN.lowLongOfPSN = kNoProcess; + currPSN.highLongOfPSN = 0; + + currProcessInfo.processInfoLength = sizeof(ProcessInfoRec); + currProcessInfo.processName = nil; + currProcessInfo.processAppSpec = &applicationSpec; + + foundRunningProcessFlag = false; + while (GetNextProcess(&currPSN) == noErr) { + if (GetProcessInformation(&currPSN, &currProcessInfo) == noErr) { + if (currProcessInfo.processSignature == documentFInfo.fdCreator) { + foundRunningProcessFlag = true; + break; + } + } + } + + if (foundRunningProcessFlag) { + // if the creator is running, send it an OpenDocuments Apple event + // since there is no need to launch it + + if (currProcessInfo.processType != documentFInfo.fdType) { // this would be the case if the doc is an app + retCode = SendOpenDocumentEventToProcess(&currPSN, documentFSSpecPtr); + } + if (retCode == noErr) { + if (!inBackground) { + SetFrontProcess (&currPSN); + } + } + + } else if (documentFInfo.fdType == 'APPL' || documentFInfo.fdType == 'APPC' || documentFInfo.fdType == 'APPD' || documentFInfo.fdType == 'appe') { + // else if the creator is not running and if the document to be opened is a application, + // then launch it directly. + + retCode = LaunchAppl (documentFSSpecPtr, inBackground); + + } else { + // else if the creator is neither running nor an application, find it on disk and launch + // it with the OpenDocuments event included as a part of the launch parameters + + retCode = FindApplicationFromDocument(documentFSSpecPtr, &applicationSpec); + + if (retCode == noErr) { + retCode = LaunchApplicationWithDocument(&applicationSpec, documentFSSpecPtr, inBackground); + } + } + +Bail: + return retCode; +} + +OSErr LaunchAppl (const FSSpec * applicationFSSpecPtr, Boolean inBackground) +{ + LaunchParamBlockRec launchParams; + launchParams.launchAppParameters = nil; + launchParams.launchBlockID = extendedBlock; + launchParams.launchEPBLength = extendedBlockLen; + launchParams.launchFileFlags = 0; + launchParams.launchControlFlags = launchContinue | launchNoFileFlags; + if (inBackground) launchParams.launchControlFlags |= launchDontSwitch; + launchParams.launchAppSpec = (FSSpecPtr)applicationFSSpecPtr; + return LaunchApplication (&launchParams); +} + +// given an application and a document, LaunchApplicationWithDocument +// launches the application and passes the application an +// OpenDocuments event for the document +// if the app is already running, then it simply gets the open event + +OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr, + const FSSpec * documentFSSpecPtr, Boolean inBackground) +{ + OSErr retCode; + LaunchParamBlockRec launchParams; + ProcessSerialNumber myPSN; + AppleEvent theAppleEvent; + AEDesc myAddrDesc, launchParamDesc, docDesc; + AEDescList docDescList; + AliasHandle docAlias; + ProcessSerialNumber currPSN; + ProcessInfoRec currProcessInfo; + FSSpec applicationSpec; + Boolean foundRunningProcessFlag; + + // to simplify cleanup, ensure that handles are nil to start + theAppleEvent.dataHandle = nil; + launchParamDesc.dataHandle = nil; + docDescList.dataHandle = nil; + docDesc.dataHandle = nil; + docAlias = nil; + + // check if the app is already running + currPSN.lowLongOfPSN = kNoProcess; + currPSN.highLongOfPSN = 0; + currProcessInfo.processInfoLength = sizeof(ProcessInfoRec); + currProcessInfo.processName = nil; + currProcessInfo.processAppSpec = &applicationSpec; + foundRunningProcessFlag = false; + while (GetNextProcess(&currPSN) == noErr) { + if (GetProcessInformation(&currPSN, &currProcessInfo) == noErr) { + if (applicationSpec.vRefNum == applicationFSSpecPtr->vRefNum + && applicationSpec.parID == applicationFSSpecPtr->parID + && pstrcmp (applicationSpec.name, (const StringPtr)applicationFSSpecPtr->name) == 0) { + foundRunningProcessFlag = true; + break; + } + } + } + if (foundRunningProcessFlag) { + retCode = SendOpenDocumentEventToProcess (&currPSN, documentFSSpecPtr); + if (retCode == noErr) { + if (!inBackground) { + SetFrontProcess (&currPSN); + } + } + return retCode; + } + + // the Apple event will need a valid address descriptor (even though its + // contents will not matter since we will not be calling AESend) so make + // one using my own serial number + + (void) GetCurrentProcess(&myPSN); + retCode = AECreateDesc(typeProcessSerialNumber, (Ptr) &myPSN, + sizeof(ProcessSerialNumber), &myAddrDesc); + if (retCode != noErr) goto Bail; + + // make a descriptor list containing just a descriptor with an + // alias to the document + + retCode = AECreateList(nil, 0, false, &docDescList); + if (retCode != noErr) goto Bail; + + retCode = NewAlias(nil, documentFSSpecPtr, &docAlias); + if (retCode != noErr) goto Bail; + + HLock((Handle) docAlias); + retCode = AECreateDesc(typeAlias, (Ptr) *docAlias, + GetHandleSize((Handle) docAlias), &docDesc); + HUnlock((Handle) docAlias); + if (retCode != noErr) goto Bail; + + retCode = AEPutDesc(&docDescList, 0, &docDesc); + if (retCode != noErr) goto Bail; + + // now make the 'odoc' AppleEvent descriptor and insert the + // document descriptor list as the direct object + + retCode = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, + &myAddrDesc, kAutoGenerateReturnID, kAnyTransactionID, + &theAppleEvent); + if (retCode != noErr) goto Bail; + + retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDescList); + if (retCode != noErr) goto Bail; + + // this Apple event will not be sent but rather will be used + // as a parameter to the LaunchApplication call, so coerce it + // to the magic type typeAppParamters + + retCode = AECoerceDesc(&theAppleEvent, typeAppParameters, &launchParamDesc); + if (retCode != noErr) goto Bail; + + // finally, fill in the launch parameter block, including the + // Apple event, and make the launch call + + HLock((Handle) launchParamDesc.dataHandle); + launchParams.launchAppParameters = + (AppParametersPtr) *(launchParamDesc.dataHandle); + + launchParams.launchBlockID = extendedBlock; + launchParams.launchEPBLength = extendedBlockLen; + launchParams.launchFileFlags = launchNoFileFlags; + launchParams.launchControlFlags = launchContinue; + if (inBackground) launchParams.launchControlFlags |= launchDontSwitch; + launchParams.launchAppSpec = (FSSpecPtr) applicationFSSpecPtr; + + retCode = LaunchApplication(&launchParams); + +Bail: + // dispose of everything that was allocated + + if (theAppleEvent.dataHandle != nil) (void) AEDisposeDesc(&theAppleEvent); + if (launchParamDesc.dataHandle != nil) (void) AEDisposeDesc(&launchParamDesc); + if (docDescList.dataHandle != nil) (void) AEDisposeDesc(&docDescList); + if (docDesc.dataHandle != nil) (void) AEDisposeDesc(&docDesc); + if (launchParamDesc.dataHandle != nil) (void) AEDisposeDesc(&launchParamDesc); + if (docAlias != nil) + DisposeHandle((Handle) docAlias); + + return retCode; + +} + + +OSErr SendFSSEventToProcess (ProcessSerialNumber *targetPSN, OSType aeClass, OSType aeCmd, const FSSpec *documentFSSpecPtr) +{ + OSErr retCode; + AppleEvent theAppleEvent = {typeNull, nil}, theReplyEvent = {typeNull, nil}; + AEDesc targetAddrDesc = {typeNull, nil}, docDesc = {typeNull, nil}; + //AEDescList docDescList; + AliasHandle docAlias; + + // to simplify cleanup, ensure that handles are nil to start + theAppleEvent.dataHandle = nil; + //docDescList.dataHandle = nil; + docDesc.dataHandle = nil; + docAlias = nil; + + // create an address descriptor based on the serial number of + // the target process + + retCode = AECreateDesc(typeProcessSerialNumber, (Ptr) targetPSN, + sizeof(ProcessSerialNumber), &targetAddrDesc); + if (retCode != noErr) goto Bail; + + /* I see no reason to make a list here, it's always just one item anyway + // make a descriptor list containing just a descriptor with an + // alias to the document + retCode = AECreateList(nil, 0, false, &docDescList); + if (retCode != noErr) goto Bail; + */ + + retCode = NewAlias(nil, documentFSSpecPtr, &docAlias); + if (retCode != noErr) goto Bail; + + HLock((Handle) docAlias); + retCode = AECreateDesc(typeAlias, (Ptr) *docAlias, + GetHandleSize((Handle) docAlias), &docDesc); + HUnlock((Handle) docAlias); + if (retCode != noErr) goto Bail; + + /* I see no reason to make a list here, it's always just one item anyway + retCode = AEPutDesc(&docDescList, 0, &docDesc); + if (retCode != noErr) goto Bail; + */ + + // now make the AppleEvent descriptor and insert the + // document descriptor list as the direct object + + retCode = AECreateAppleEvent(aeClass, aeCmd, + &targetAddrDesc, kAutoGenerateReturnID, kAnyTransactionID, + &theAppleEvent); + if (retCode != noErr) goto Bail; + + // retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDescList); + retCode = AEPutParamDesc(&theAppleEvent, keyDirectObject, &docDesc); + if (retCode != noErr) goto Bail; + + // finally, send the Apple event + retCode = AESend (&theAppleEvent, &theReplyEvent, kAENoReply, + kAEHighPriority, 2*60 /* timeout: 2 seconds */, nil, nil); + +Bail: + // dispose of everything that was allocated + + if (theAppleEvent.dataHandle != nil) (void) AEDisposeDesc(&theAppleEvent); + //if (docDescList.dataHandle != nil) (void) AEDisposeDesc(&docDescList); + if (docDesc.dataHandle != nil) (void) AEDisposeDesc(&docDesc); + if (docAlias != nil) DisposeHandle((Handle) docAlias); + + return retCode; +} + + +// given an application's serial number and a document, +// SendOpenDocumentEventToProcess passes +// the application an OpenDocuments event for the document + +OSErr SendOpenDocumentEventToProcess(ProcessSerialNumber *targetPSN, const FSSpec * documentFSSpecPtr) +{ + return SendFSSEventToProcess (targetPSN, kCoreEventClass, kAEOpenDocuments, documentFSSpecPtr); +} + + +static Boolean HasCatSearch (short vRefNum) +{ + IOParam pb; + GetVolParmsInfoBuffer buf; + pb.ioVRefNum = vRefNum; + pb.ioBuffer = (Ptr)&buf; + pb.ioReqCount = 6; + pb.ioNamePtr = nil; + if (PBHGetVolParmsSync ((HParmBlkPtr)&pb) == noErr) { + if (pb.ioActCount >= 6 && (buf.vMAttrib & (1L<= 14 && buf.vMLocalHand != 0) return true; + } + return false; +} + +static OSErr checkThisVolume (short currVRefNum, OSType creator, FSSpecPtr applicationFSSpecPtr, Boolean *foundRef) +{ + OSErr retCode; + Boolean foundFlag = false; + + // find the path refNum for the desktop database for + // the volume we're interested in + + DTPBRec desktopParams; + desktopParams.ioVRefNum = currVRefNum; + desktopParams.ioNamePtr = nil; + retCode = PBDTGetPath(&desktopParams); + + if (retCode == noErr) { + if (desktopParams.ioDTRefNum == 0) { + // oops?! + retCode = -1; // !TT new 30 Jan 99 + } else { + + // iterate over all possible creators on one volume + + short idx = 0; + do { + // use the GetAPPL call to find the preferred application + // for opening any document with this one's creator + + desktopParams.ioIndex = idx++; // this is the way the Finder in OS 7.6.1 does it: starts with idx 0, then comes 1, 2, ... + desktopParams.ioFileCreator = creator; + desktopParams.ioNamePtr = applicationFSSpecPtr->name; + retCode = PBDTGetAPPLSync(&desktopParams); + + if (retCode == noErr) { + + // okay, found it; fill in the application file spec + // and set the flag indicating we're done + + applicationFSSpecPtr->parID = desktopParams.ioAPPLParID; + applicationFSSpecPtr->vRefNum = currVRefNum; + + // However, we have to make sure that the app + // really still exists and that it is a APPL in deed. + // If not, we have to continue to search + + CInfoPBRec ci; + HFileInfo &fi = (HFileInfo&)ci; + fi.ioNamePtr = applicationFSSpecPtr->name; + fi.ioVRefNum = currVRefNum; + fi.ioDirID = applicationFSSpecPtr->parID; + fi.ioFDirIndex = 0; + if (PBGetCatInfoSync (&ci) == noErr) { + if (/* do not check the creation date, because the Finder doesn't do it either: fi.ioFlCrDat == desktopParams.ioTagInfo && */ + fi.ioFlFndrInfo.fdCreator == desktopParams.ioFileCreator && + fi.ioFlFndrInfo.fdType == 'APPL' || fi.ioFlFndrInfo.fdType == 'APPC' || fi.ioFlFndrInfo.fdType == 'APPD' || fi.ioFlFndrInfo.fdType == 'appe' // +++ add more types or use a better detection? + ) { + foundFlag = true; + } + } + } + } while (!foundFlag && retCode == noErr); + } + } + *foundRef = foundFlag; + return retCode; +} + +// FindApplicationByCreator uses the Desktop Database to +// locate the creator application for the given document +// +// this routine will first check the desktop database of the disk +// containing the document, then the desktop database of all local +// disks, then the desktop databases of all server volumes +// (so up to three passes will be made) +// exception (13.2.99): when the file is located on a remote vol, +// the boot vol is searched first +// now returns fnfErr if app is not found + +// Attention: It does not support the "fopn" Finder interception AE that has been introduced +// in Mac OS 8! + +OSErr FindApplicationByCreator (OSType creator, short firstVol, FSSpec *applicationFSSpecRef) +{ + short volumeIndex; + OSErr err; + Boolean found = false; + short vRefNum, skipThisVol = 0; + + if (IsRemoteVolume (firstVol)) { + // first, check the boot vol + GetSysVolume (&vRefNum); + checkThisVolume (vRefNum, creator, applicationFSSpecRef, &found); + if (found) return noErr; + skipThisVol = vRefNum; + } + + // check the vol the doc is on + checkThisVolume (firstVol, creator, applicationFSSpecRef, &found); + if (found) return noErr; + + for (int remotePass = 0; remotePass <= 3; ++remotePass) { + volumeIndex = 0; + do { + HParamBlockRec pb; + HVolumeParam &vp = (HVolumeParam&)pb; + + vp.ioNamePtr = nil; + vp.ioVRefNum = 0; + vp.ioVolIndex = ++volumeIndex; + err = PBHGetVInfoSync (&pb); + if (err != nsvErr) { + if (err != noErr) return err; + if (vp.ioVRefNum != firstVol && vp.ioVRefNum != skipThisVol) { + // prio: 0 & 1 for local, 2 & 3 for remote; 0 & 2 with CatSearch, 1 & 3 without CatSearch + int volumePrio = IsRemoteVolume (vp.ioVRefNum) * 2 + (HasCatSearch (vp.ioVRefNum)?0:1); + if (remotePass == volumePrio) { + checkThisVolume (vp.ioVRefNum, creator, applicationFSSpecRef, &found); + if (found) { + return noErr; + } + } + } + } + } while (err != nsvErr); + } + if (err == nsvErr) err = fnfErr; + return err; +} + + +OSErr FindApplicationFromDocument (const FSSpec * documentFSSpecPtr, FSSpec *applicationFSSpecRef) +{ + OSErr err; + OSType creator; + + // verify the document file exists and get its creator type + { + FInfo documentFInfo; + err = FSpGetFInfo(documentFSSpecPtr, &documentFInfo); + if (err != noErr) return err; + creator = documentFInfo.fdCreator; + } + + return FindApplicationByCreator (creator, documentFSSpecPtr->vRefNum, applicationFSSpecRef); +} + +OSErr OpenWithFinder (const FSSpec *spec) +{ + ProcessSerialNumber finderPSN; + FSSpec finderSpec; + OSErr err = FindRunningAppBySignature ('FNDR', 'MACS', &finderPSN, &finderSpec); + if (!err) { + err = SendFSSEventToProcess (&finderPSN, kCoreEventClass, kAEOpenDocuments, spec); + } + return err; +} + +OSErr FindRunningAppBySignature (OSType fileType, OSType creator, ProcessSerialNumber *psn, FSSpec *fileSpec) +// from: "SignatureToApp.c", by Jens Alfke, DTS, Apple Computer 1991 +{ + OSErr err; + ProcessInfoRec info; + psn->highLongOfPSN = 0; + psn->lowLongOfPSN = kNoProcess; + do{ + err = GetNextProcess(psn); + if (!err) { + info.processInfoLength = sizeof (info); + info.processName = NULL; + info.processAppSpec = fileSpec; + err = GetProcessInformation (psn, &info); + } + } while (!err && info.processSignature != creator && info.processType != fileType); + if (!err) *psn = info.processNumber; + return err; +} + + +static long CountItems (AEDesc *d) +{ + long items = 1; + if(d->descriptorType == typeNull) { + items = 0; + } else if((d->descriptorType == typeAEList) || (d->descriptorType == typeAERecord)) { + AECountItems(d, &items); + } + return items; +} + +static void ae_dispose (AEDesc &d) +{ + if (d.dataHandle) AEDisposeDesc (&d); +} + +OSErr FindOpenCDEVInFinder (Boolean shouldUseAEs, OSType creator, FSSpec *itsSpec) +// algorithm: either uses AppleEvents to get list of all windows, coercing the results to FSSpecs +// The FSSpecs can then be used for both getting the creator code and for closing the window +// returns: 0 if not open in Finder, 1 if open, neg. value if error occured +{ + long theTimeout = 5*60; // wait no more than 5 seconds for Finder to respond + + if (!shouldUseAEs) { + return FindOpenFileByTypeAndCreator ('cdev', creator, itsSpec); + } + + Boolean found = false; + OSErr err; + + AEDesc dataDescriptor = {typeNull,0}; + AppleEvent reply = {typeNull,0}; + AEDesc allCreators = {typeNull,0}; + AEDesc targetAddrDesc = {typeNull,0}; + AppleEvent ae = {typeNull,0}; + AEDesc allWinsSpecifier = {typeNull,0}, keyData = {typeNull,0}; + AEDesc keyData2 = {typeNull,0}; + AEDesc directObjectSpecifier = {typeNull,0}, nullDesc = {typeNull,0}; + + ProcessSerialNumber finderPSN, frontPSN; + FSSpec finderSpec; + err = FindRunningAppBySignature ('FNDR', 'MACS', &finderPSN, &finderSpec); + if (err) goto Bail; + + GetFrontProcess (&frontPSN); + Boolean finderIsFrontProcess; + SameProcess (&frontPSN, &finderPSN, &finderIsFrontProcess); + + if (finderIsFrontProcess) { + // oops, we will not be successful sending the AE (a timeout would occur). + // So fall back to the other method. + err = FindOpenFileByTypeAndCreator ('cdev', creator, itsSpec); + return err; // no cleanup necessary here yet + } + + err = AECreateDesc (typeProcessSerialNumber, (Ptr)&finderPSN, sizeof(ProcessSerialNumber), &targetAddrDesc); + if (err) goto Bail; + + err = AECreateAppleEvent(kAECoreSuite, kAEGetData, &targetAddrDesc, kAutoGenerateReturnID, kAnyTransactionID, &ae); + + // want:type(cwin), from:'null'(), form:indx, seld:abso('all ') + OSType all = 'all '; + err = AECreateDesc (typeAbsoluteOrdinal, &all, sizeof(all), &keyData); + if (err) goto Bail; + + err = CreateObjSpecifier (cWindow, &nullDesc, formAbsolutePosition, &keyData, true, &allWinsSpecifier); + if (err) goto Bail; + + // want:type(prop), from:, form:prop, seld:type(cobj) + OSType cobj = cObject; + err = AECreateDesc (typeType, &cobj, sizeof(cobj), &keyData2); + if (err) goto Bail; + + err = CreateObjSpecifier (cProperty, &allWinsSpecifier, formPropertyID, &keyData2, true, &directObjectSpecifier); + if (err) goto Bail; + + err = AEPutParamDesc (&ae, keyDirectObject, &directObjectSpecifier); + if (err) goto Bail; + AEDisposeDesc (&directObjectSpecifier); + + // core,getd,'----':<>, rtyp:type(list)" + OSType list = 'list'; + err = AECreateDesc (typeType, &list, sizeof(list), &dataDescriptor); + if (err) goto Bail; + + err = AEPutParamDesc (&ae, keyAERequestedType, &dataDescriptor); + if (err) goto Bail; + AEDisposeDesc (&dataDescriptor); + + err = AESend (&ae, &reply, kAEWaitReply, kAEHighPriority, theTimeout, nil, nil); + if (err) goto Bail; + + ae_dispose (ae); + + err = AEGetParamDesc (&reply, keyAEResult, typeWildCard, &allCreators); + if (err) goto Bail; + + long n = CountItems (&allCreators); + for (int i = 1; i < n; ++i) { + AEDesc w; + AEKeyword ignoreKey; + if (AEGetNthDesc (&allCreators, i, typeFSS, &ignoreKey, &w) == noErr) { + FSSpec spec; + spec = *(FSSpec*)*w.dataHandle; + AEDisposeDesc (&w); + FInfo fi; + if (FSpGetFInfo (&spec, &fi) == noErr && fi.fdCreator == creator) { + // we found it + *itsSpec = spec; + found = true; + break; + } + } + } + err = found; + +Bail: + ae_dispose (keyData); + ae_dispose (keyData2); + ae_dispose (targetAddrDesc); + ae_dispose (dataDescriptor); + ae_dispose (allWinsSpecifier); + ae_dispose (directObjectSpecifier); + ae_dispose (allCreators); + ae_dispose (reply); + ae_dispose (ae); + + return err; +} + +// EOF diff --git a/mac-cpp-source/utils/LaunchLib.h b/mac-cpp-source/utils/LaunchLib.h new file mode 100644 index 0000000..6e8ac2f --- /dev/null +++ b/mac-cpp-source/utils/LaunchLib.h @@ -0,0 +1,36 @@ +/* + * Functions for launching apps with documents + * + * by Thomas Tempelmann, macdev@tempel.org + * + * some of these routines are not from me (TT), but from some DTS sample code + * here's a link to it: + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + -> also see "SignatureToApp.c" as a demo (comes from Apple and does some things differently) +*/ +OSErr OpenWithFinder (const FSSpec * applicationFSSpecPtr); // uses AppleEvent to open the file +OSErr LaunchAppl (const FSSpec * applicationFSSpecPtr, Boolean inBackground); // starts APPLs only +OSErr OpenSpecifiedDocument(const FSSpec * documentFSSpecPtr, Boolean inBackground); // starts APPLs or opens docs with its APPLs +OSErr LaunchApplicationWithDocument(const FSSpec * applicationFSSpecPtr, const FSSpec * documentFSSpecPtr, Boolean inBackground); +OSErr SendOpenDocumentEventToProcess(ProcessSerialNumber *targetPSN, const FSSpec * documentFSSpecPtr); +OSErr FindApplicationFromDocument(const FSSpec * documentFSSpecPtr, FSSpec *applicationFSSpecRef); +OSErr FindApplicationByCreator (OSType creator, short firstVol, FSSpec *applicationFSSpecRef); +OSErr FindRunningAppBySignature (OSType fileType, OSType creator, ProcessSerialNumber *psn, FSSpec *fileSpec); +OSErr SendFSSEventToProcess (ProcessSerialNumber *targetPSN, OSType aeClass, OSType aeCmd, const FSSpec *documentFSSpecPtr); +OSErr FindOpenCDEVInFinder (Boolean shouldUseAEs, OSType creator, FSSpec *itsSpec); + +#ifdef __cplusplus +} +#endif + +// EOF diff --git a/mac-cpp-source/utils/PascalLib.c b/mac-cpp-source/utils/PascalLib.c new file mode 100644 index 0000000..da92221 --- /dev/null +++ b/mac-cpp-source/utils/PascalLib.c @@ -0,0 +1,261 @@ +/* + * Library for handling Pascal-Strings + * + * by Thomas Tempelmann, macdev@tempel.org + * + * Originally by Markus Fritze. + * Changes and additions by Thomas Tempelmann: + * - pstrlen neu + * - BlockMoveData statt BlockMove + * - pstrcmp liefert nicht Boolean sondern short, wie bei strcmp. + * - pstrupper neu + * 28.12.95 TT: + * - alle Zugriffe auf s[0] und d[0] word-expandiert, bevor mit ihnen gerechnet wird, + * um zu verhindern, da§ bei der LŠnge 255 ein †berlauf nach 0 passiert. + * 08.04.95 TT: + * - pstrcmp() lieferte "C"<"BB", da das LŠngenbyte mit verglichen wurde. Korrigiert. + * - BlockMoveData() durch copyBytes() ersetzt, da vermutlich i.d.R. schneller. + * 09.04.95 TT: + * - Geschw-optimiert: pfindchar, pstrupper, pdelchars + * - pstrextract() neu + * 30.4.96 TT: + * - copyBytes kopierte falsch, wenn source und dest sich Ÿberlagern und dest>source war. + * 18.7.96 TT: + * - strcatc neu + * 14.8.96 TT: + * - sicherheitshalber 'far' accesses eingefŸhrt. + * 23.07.00 TT: + * - disabled the "far" pragmas + * - changed "StringPtr" into "unsigned char*" so that it can be compiled for Windows, too. + */ + +#include + +#include +#include "PascalLib.h" + +#pragma push +#pragma cplusplus on + +/* + * We need far data access in this module + * (alternatively we could setup A5 appropriately): + */ +/* !TT July 23, 2000 - removed this +#ifndef __powerc +#pragma far_data on +#pragma far_strings on +#pragma far_vtables on +#endif +*/ + +static void copyBytes (const unsigned char* s0, unsigned char* d, unsigned short len) +{ + const unsigned char* s = s0; + if (d > s) { + // rŸckwŠrts kopieren + if (len) { + d += len; + s += len; + do { *--d = *--s; } while (--len); + } + } else { + if (len) do { *d++ = *s++; } while (--len); + } +} + +void pstrcpy (unsigned char* d, const unsigned char* s) +{ + copyBytes (s, d, ((unsigned short)s[0])+1); +} + +void pstrncpy (unsigned char* d, const unsigned char* s, short n) +// n: dest buffer size including length char +{ + if (n) { + if (n > ((unsigned short)s[0])+1) n = ((unsigned short)s[0])+1; + copyBytes (s, d, n); + if (n < ((unsigned short)d[0])+1) d[0] = n-1; + } +} + +void pstrcat (unsigned char* d, const unsigned char* s) +{ + copyBytes (s + 1, d + ((unsigned short)d[0]) + 1, s[0]); + d[0] += s[0]; +} + +void pstrcatc (unsigned char* d, const char* s) +{ + short n = strlen(s); + copyBytes ((unsigned char*)s, d + ((unsigned short)d[0]) + 1, n); + d[0] += n; +} + +void pstrcatchar (unsigned char* d, const unsigned char c) +{ + d[++d[0]] = c; +} + +short pfindchar (const unsigned char* d, const unsigned char c) +{ + short i, dlen = d[0]; + for (i = 1; i <= dlen; i++) { + if (d[i] == c) return i; + } + return 0; +} + +void pstrextract (unsigned char* d, const unsigned char* s, short offset, short len) +{ + short slen; + if (offset < 1 || offset > (slen = s[0])) { + d[0] = 0; + return; + } + if (((offset-1) + len) > slen) { + len = slen - offset + 1; + } + if (len <= 0) { + d[0] = 0; + return; + } + copyBytes (s + offset, d + 1, len); + d[0] = len; +} + +void pdelchars (unsigned char* d, short offset, short len) +{ + short dlen; + if (offset > (dlen = d[0])) return; // Offset zu gro§ + if (len <= 0) return; // LŠnge zu klein + if ((offset + len) > (dlen + 1)) { // LŠnge zu gro§? + d[0] = offset; // String zurechtstutzen + return; + } + copyBytes (d + offset + len, d + offset, dlen - len - offset + 1); + d[0] -= len; +} + +void pstrins (unsigned char* d, const unsigned char* s, short offset) +{ + short slen, dlen; + if ((slen = s[0]) == 0) return; // einzufŸgender String = 0 Bytes => raus + if (offset > (dlen = d[0])) { // ggf. an den String anhŠngen + offset = dlen + 1; + } + copyBytes (d + offset, d + offset + slen, dlen + 1 - offset); // String nach hinten + copyBytes (s + 1, d + offset, slen); // String einfŸgen + d[0] += slen; // und die LŠnge updaten +} + +short pstrcmp (const unsigned char* s10, const unsigned char* s20) +{ + const unsigned char* s1 = s10; + const unsigned char* s2 = s20; + unsigned char l1 = *s1++, l2 = *s2++; + unsigned char len = (l1 < l2)? l1:l2; + + if (len) do { + if (*s1++ != *s2++) { + return (s1[-1] < s2[-1])? -1: +1; + } + } while (--len); + if (l1 == l2) { + return 0; + } else { + return (l1 < l2)? -1: +1; + } +} + +short pstrlen (const unsigned char* s1) +{ + return s1[0]; +} + +void pstrupper (unsigned char* d) +{ + short i, dlen = d[0]; + for (i = 1; i <= dlen; i++) { + d[i] = toupper (d[i]); + } +} + +typedef unsigned char byte; + +/* +short pfindstr (const unsigned char* target, const unsigned char* search) +{ + unsigned char* s = search; + unsigned char* d = target; + short slen = s[0]; + if (slen) { + short i; + short iend = d[0] - slen + 1; + for (i = 1; i <= iend; i++) { + if (d[i] == s[1]) { + short len = slen - 1; + if (len) { + unsigned char* s1 = &s[2], d1 = &d[i+1]; + do { + if (*s1++ != *d1++) { + break; + } + } while (--len); + } + if (len == 0) return i; + } + } + } + return 0; +} +*/ + +short pfindstr (const unsigned char* d, const unsigned char* s0) +{ + const unsigned char* s = s0; + short slen = *s++; + if (slen == 0) return 0; + --slen; + { + byte c = *s++; + short i; + short end = d[0] - slen; + for (i = 1; i <= end; i++) { + if (d[i] == c) { + const byte *sp = s, *dp = &d[i+1]; + byte len = slen; + do { + if (len-- == 0) return i; // gefunden + } while (*sp++ == *dp++); + } + } + } + return 0; +} + +void pstrnins (unsigned char* d, short destSize, const unsigned char* s, short offset) +// TT 25 Sep 97: does no write over end of dest string +// 'destSize': size of dest string including length byte +{ + short slen, dlen; + if (offset < 1) return; + if ((slen = s[0]) == 0) return; // einzufŸgender String = 0 Bytes => raus + if (offset > (dlen = d[0])) { // ggf. an den String anhŠngen + offset = dlen + 1; + } + if (offset >= destSize) return; + if (offset + slen > destSize) { + slen = destSize - offset; + dlen = offset - 1; + } else { + if (slen + dlen >= destSize) { + dlen = destSize - 1 - slen; + } + copyBytes (d + offset, d + offset + slen, dlen + 1 - offset); // String nach hinten + } + copyBytes (s + 1, d + offset, slen); // String einfŸgen + d[0] = dlen + slen; // und die LŠnge updaten +} + +#pragma pop diff --git a/mac-cpp-source/utils/PascalLib.h b/mac-cpp-source/utils/PascalLib.h new file mode 100644 index 0000000..ebfd270 --- /dev/null +++ b/mac-cpp-source/utils/PascalLib.h @@ -0,0 +1,27 @@ +/* + * Library for handling Pascal-Strings + * + * by Thomas Tempelmann, macdev@tempel.org + */ + +#pragma push +#pragma cplusplus on + +//#include + +void pstrcpy (unsigned char* d, const unsigned char* s); +void pstrcat (unsigned char* d, const unsigned char* s); +void pstrcatc (unsigned char* d, const char* s); +void pstrcatchar (unsigned char* d, unsigned char c); +short pfindchar (const unsigned char* d, const unsigned char c); +void pdelchars (unsigned char* d, short offset, short len); +void pstrins (unsigned char* d, const unsigned char* s, short offset); +short pstrcmp (const unsigned char* s1, const unsigned char* s2); +short pstrlen (const unsigned char* s1); +void pstrncpy (unsigned char* d, const unsigned char* s, short n); // n: dest buffer size including length char +void pstrupper (unsigned char* d); +void pstrextract (unsigned char* d, const unsigned char* s, short offset, short len); +short pfindstr (const unsigned char* d, const unsigned char* s); +void pstrnins (unsigned char* d, short destSize, const unsigned char* s, short offset); + +#pragma pop diff --git a/mac-cpp-source/utils/TrapAvail.c b/mac-cpp-source/utils/TrapAvail.c new file mode 100644 index 0000000..c30cf73 --- /dev/null +++ b/mac-cpp-source/utils/TrapAvail.c @@ -0,0 +1,43 @@ +/* + * TrapAvail.c + * by Thomas Tempelmann, macdev@tempel.org + */ + +#include +#include +#include "TrapAvail.h" + +Boolean TrapAvailable (short theTrap); + +#define TrapMask 0x0800 + +static short NumToolboxTraps( void ) +{ + if (NGetTrapAddress(_InitGraf, ToolTrap) == + NGetTrapAddress(0xAA6E, ToolTrap)) + return 0x0200; + else + return 0x0400; +} + +static TrapType GetTrapType(short theTrap) +{ + if ((theTrap & TrapMask) > 0) + return ToolTrap; + else + return OSTrap; +} + +Boolean TrapAvailable (short theTrap) +{ + TrapType tType; + + tType = GetTrapType(theTrap); + if (tType == ToolTrap) + theTrap = theTrap & 0x07FF; + if (theTrap >= NumToolboxTraps()) + theTrap = _Unimplemented; + return NGetTrapAddress(theTrap, tType) != NGetTrapAddress(_Unimplemented, ToolTrap); +} + +// EOF diff --git a/mac-cpp-source/utils/TrapAvail.h b/mac-cpp-source/utils/TrapAvail.h new file mode 100644 index 0000000..f539703 --- /dev/null +++ b/mac-cpp-source/utils/TrapAvail.h @@ -0,0 +1,16 @@ +/* + * TrapAvailable.c + * by Thomas Tempelmann, macdev@tempel.org + */ + +#ifdef __cplusplus +extern "C" { +#endif + +Boolean TrapAvailable (short theTrap); + +#ifdef __cplusplus +} +#endif + +// EOF