It works, but I patched InitDialogs instead of InitMenus because it comes after the other initializations.
As a simple exercise, I draw an L over every oval in AppleWorks.
First I make a 'C68K' code resource 128 which will install the FrameOval patch.
//========================================
// File: FrameOvalCR.h
//========================================
#pragma once
void main();
pascal void New_FrameOval(const Rect* const r);
//========================================
// File: FrameOvalCR.cp
//========================================
#include "FrameOvalCR.h"
// Rem: The next include may not be precompiled
// because it contains inline assembler.
#include <SetupA4.h>
FrameOvalProcPtr old_FrameOval;
void main()
{
ProcPtr old_address;
ProcPtr new_address;
old_address=::GetToolTrapAddress(_FrameOval);
old_FrameOval=reinterpret_cast<FrameOvalProcPtr>(old_address);
new_address=reinterpret_cast<ProcPtr>(New_FrameOval);
::SetToolTrapAddress(new_address,
_FrameOval);
}
pascal void New_FrameOval(const Rect* const r)
{
EnterCallback();
old_FrameOval(r);
const SInt16 top=r->top;
const SInt16 left=r->left;
const SInt16 bottom=QD(r->bottom-1);
const SInt16 right=QD(r->right-1);
::MoveTo(left,
top);
::LineTo(left,
bottom);
::LineTo(right,
bottom);
ExitCallback();
}
I link this into my extension.
Its patch verifies whether we are in AppleWorks.
Then it copies 'C68K' resource 128 into AppleWorks's zone.
Then it executes 'C68K' resource 128's main.
//========================================
// File: FrameOvalBOBO68KINIT.h
//========================================
#pragma once
int main();
Bool Run();
void InstallPatch();
pascal void New_InitDialogs(void *ignored);
Bool TryToInstallPatch();
bool IsTargetApName();
Bool SearchExtension(FSSpec &spec);
Bool LoadCodeResource(const FSSpec &spec,
Handle &h);
Bool LoadCodeResource(OSType type,
SInt16 id,
Handle &h);
//========================================
// File: FrameOvalBOBO68KINIT.cp
//========================================
#include "FrameOvalBOBO68KINIT.h"
// Rem: The next includes may not be precompiled
// because they contain inline assembler.
#include <A4Stuff.h>
#include <SetupA4.h>
InitDialogsProcPtr old_InitDialogs;
int main()
{
EnterCodeResource();
PrepareCallback();
NoGuiError::Init_class();
const SInt16 iconID=Run() ? INIT::goodIconID : INIT::badIconID;
if (!INIT::DrawINITIcon(iconID))
{
Error::Show("\pDrawINITIcon fails");
}
ExitCodeResource();
return 0;
}
Bool Run()
{
// 1. Me.
Handle me;
if (!INIT::GetINITHandle(me))
{
Return_false("\pGetINITHandle fails");
}
// 2. Patch.
InstallPatch();
return True;
}
void InstallPatch()
{
ProcPtr old_address;
ProcPtr new_address;
old_address=::GetToolTrapAddress(_InitDialogs);
old_InitDialogs=reinterpret_cast<InitDialogsProcPtr>(old_address);
new_address=reinterpret_cast<ProcPtr>(New_InitDialogs);
::SetToolTrapAddress(new_address,
_InitDialogs);
}
pascal void New_InitDialogs(void* const ignored)
{
EnterCallback();
old_InitDialogs(ignored);
if (!TryToInstallPatch())
{
Error::Show("\pTryToInstallPatch fails");
}
ExitCallback();
}
Bool TryToInstallPatch()
{
if (!IsTargetApName())
{
return True;
}
FSSpec spec;
if (!SearchExtension(spec))
{
Return_false("\pSearchExtension fails");
}
Handle h;
if (!LoadCodeResource(spec,
h))
{
Return_false("\pLoadCodeResource fails");
}
typedef pascal void (*MainProcPtr)();
MainProcPtr const proc=reinterpret_cast<MainProcPtr>(*h);
proc();
return True;
}
bool IsTargetApName()
{
static ConstStringPtr const targetApName="\pAppleWorks";
ConstStringPtr x=targetApName;
ConstStringPtr const last=x+*x;
ConstStringPtr y=LMGetCurApName();
while (x<=last)
{
if (*x!=*y)
{
return false;
}
x++;
y++;
}
return true;
}
Bool SearchExtension(FSSpec &spec)
{
SInt16 vRefNum;
SInt32 dirID;
OSErr err=::FindFolder(kOnSystemDisk,
kExtensionFolderType,
false,
&vRefNum,
&dirID);
if (err==fnfErr)
{
Return_false("\pExtension folder doesn't exist");
}
if (err)
{
Return_false_err("\pFindFolder fails",err);
}
bool exists;
if (!MakeSpec(vRefNum,
dirID,
"\pFrame oval BOBO 68K",
spec,
exists))
{
Return_false("\pMakeSpec fails");
}
if (!exists)
{
// Rem: The extension was moved, renamed or deleted.
Return_false("\pExtension doesn't exist");
}
return True;
}
Bool LoadCodeResource(const FSSpec &spec,
Handle &h)
{
const SInt16 refNum=::FSpOpenResFile(&spec,
fsRdPerm);
OSErr err=::ResError();
if (err)
{
Return_false_err("\pFSpOpenResFile fails",err);
}
const Bool ok=LoadCodeResource('C68K',
128,
h);
::CloseResFile(refNum);
err=::ResError();
if (err)
{
Return_false_err("\pCloseResFile fails",err);
}
if (!ok)
{
Return_false("\pLoadCodeResource fails");
}
return True;
}
Bool LoadCodeResource(const OSType type,
const SInt16 id,
Handle &h)
{
if (!Resource::Get1(type,
id,
h))
{
Return_false("\pGet1 fails");
}
if (!Resource::Detach(h))
{
Return_false("\pDetach fails");
}
// Rem: Because we are now in a program,
// we can move the handle to the end,
// which cannot be done in a normal extension.
::HLockHi(h);
const OSErr err=::MemError();
if (err)
{
Return_false_err("\pHLockHi fails",err);
}
return True;
}
Instead of IsTargetApName I tried also the following, but it crashed when Finder started:
bool isBOBO;
if (!CheckProcess(isBOBO))
{
Return_false("\pCheckProcess fails");
}
if (!isBOBO)
{
return True;
}
Bool CheckProcess(bool &isBOBO)
{
ProcessSerialNumber psn;
OSErr err=::GetCurrentProcess(&psn);
if (err)
{
Return_false_err("\pGetCurrentProcess fails",err);
}
ProcessInfoRec info;
err=::GetProcessInformation(&psn,
&info);
if (err)
{
Return_false_err("\pGetProcessInformation fails",err);
}
isBOBO=(info.processSignature=='BOBO');
return True;
}