| ログイン | ご入会 |
ADC連絡先
|
|
Technote 1131Creating Desktop Printers on the Fly
|
|
ファイル |
タイプ |
クリエータ |
|
LaserWriter 8 |
'PRER' |
'vgrd' |
|
StyleWriter 1200 |
'PRER' |
'dblo' |
|
StyleWriter 2500 |
'PRER' |
'auro' |
// --------------------------------------------------------------
// “システム機能拡張”フォルダ内で指定された最小バージョン、タイプ、
// クリエータのプリンタドライバを見つけます。
// 注意: このルーチンはエラーコードを返しません。エラーが起こった場合、
// 呼び出し側に C++例外が返されます。
// 呼び出し側は eofErr を含むエラーを処理しなければなりません。
// eofErr はプリンタドライバが見つからなかったことを示します。
// パラメータは次の通りです。
// inMinVersion - プリンタドライバの最小バージョンを指定
// inFileType - プリンタドライバのファイルタイプを指定
// inCreator - プリンタドライバのクリエータを指定
// outPrinterDrvrFsSpec - プリンタドライバの FSSpec が見つかった場合、
// それを返す
// --------------------------------------------------------------
void FindPrinterDriver(unsigned short inMinVersion, OSType inFileType, OSType inCreator
void FSSpec& outPrinterDrvrFsSpec )
{
OSErr err;
const long kSearchBufSize = 16 * 1024;
short savedResFile = CurResFile();
short startupVRefNum;
long extDirID; // 拡張機能フォルダのID
CInfoPBRec targetPb;
CInfoPBRec maskPb;
CSParam catSearchPb;
FSSpec foundFsSpec;
StPointerBlock searchBuf(kSearchBufSize); // PBCatSearch のバッファ
Boolean foundOne = false;
err = FindFolder(-1, kExtensionFolderType, FALSE, &startupVRefNum, &extDirID);
ThrowIfOSErr_(err);
targetPb.hFileInfo.ioFlFndrInfo.fdType = inFileType;
targetPb.hFileInfo.ioFlFndrInfo.fdCreator = inCreator;
targetPb.hFileInfo.ioNamePtr = 0;
targetPb.hFileInfo.ioFlAttrib = 0x00; // ファイルのみ検索
targetPb.hFileInfo.ioFlParID = extDirID; // 機能拡張フォルダのみ
maskPb.hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
maskPb.hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
maskPb.hFileInfo.ioFlFndrInfo.fdFlags = 0;
maskPb.hFileInfo.ioFlFndrInfo.fdLocation.h = 0;
maskPb.hFileInfo.ioFlFndrInfo.fdLocation.v = 0;
maskPb.hFileInfo.ioFlFndrInfo.fdFldr = 0;
maskPb.hFileInfo.ioNamePtr = 0;
maskPb.hFileInfo.ioFlAttrib = 0x10; // ディレクトリビット
maskPb.hFileInfo.ioFlParID = extDirID; // 機能拡張フォルダのみ
Try_{
catSearchPb.ioCatPosition.initialize = 0;
while(!foundOne ){
catSearchPb.ioCompletion = 0;
catSearchPb.ioNamePtr = 0;
catSearchPb.ioVRefNum = startupVRefNum;
catSearchPb.ioMatchPtr = &foundFsSpec;
catSearchPb.ioReqMatchCount = 1;
catSearchPb.ioSearchBits = fsSBFlAttrib +
fsSBFlFndrInfo + fsSBFlParID;
catSearchPb.ioSearchInfo1 = &targetPb;
catSearchPb.ioSearchInfo2 = &maskPb;
catSearchPb.ioSearchTime = 0;
catSearchPb.ioOptBuffer = (Ptr)searchBuf;
catSearchPb.ioOptBufSize = kSearchBufSize;
err = PBCatSearchSync(&catSearchPb);
ThrowIfOSErr_(err);
// 指定のタイプのクリエータを持つものが見つかった
LFile thePrDrFile(foundFsSpec);
Try_{
thePrDrFile.OpenResourceFork(fsRdPerm);
// プリンタドライバのバージョン
StResource versRsrc('vers', 1, true, true);
// 最小バージョンと比較
if(**(unsigned short **)(Handle)versRsrc >= inMinVersion){
// バージョンの条件は合致
outPrinterDrvrFsSpec = foundFsSpec;
foundOne = true; // ループを抜ける
}
thePrDrFile.CloseResourceFork();
}Catch_(inErr){
thePrDrFile.CloseResourceFork();
// throw しない
}EndCatch_
} // while
}Catch_(inErr){
// デフォルトリソースファイルに戻す
UseResFile(savedResFile);
Throw_(inErr);
}EndCatch_
}
このセクションでは、LaserWriter 以外のプリンタタイプのプリンタドライバ、例えば、StyleWriter のプリンタドライバ用の DTP を作成する方法を紹介します。
// ---------------------------------------------------------------------------
// SetResource
// このルーチンは既存のリソースの内容を、inNewContentH が指す新しい
// 内容に変更します。このルーチンが呼び出される前に、ターゲットの
// リソースの入ったリソースファイルを開いて、現在のリソースファイルに
// 設定しなければなりません。
// ---------------------------------------------------------------------------
void
SetResource(ResType inResType, ResID inResID, Handle inNewContentH)
{
// 変更するリソースを取り出す
oldResH = Get1Resource(inResType, inResID);
// リソースがない場合 (oldResH == 0) はエラー処理をすること
char savedInHdlState = HGetState(inNewContentH);
char savedRsrcHdlState = HGetState(oldResH );
Size sz = GetHandleSize(inNewContentH);
HUnlock(oldResH );
SetHandleSize(oldResH, sz); // サイズを合わせる
ThrowIfMemError_();
HLock(oldResH );
HLock(inNewContentH);
BlockMove(*inNewContentH, *oldResH, sz); // 内容をコピー
HSetState(inNewContentH, savedInHdlState);
HSetState(oldResH , savedRsrcHdlState);
ChangedResource(oldResH); // 変更があったことを示す
WriteResource(oldResH);
ThrowIfResError_();
UpdateResFile(CurResFile());
}
// ---------------------------------------------------------------------------
// SetStrResource
// このルーチンは既存の 'STR ' リソースの内容を inStrP が指す、新しい内容に
// 変更します。ターゲットのリソースが入っているリソースファイルを、この
// ルーチンが呼び出される前に開いて、現在のリソースファイルに設定しなけ
// ればなりません。既存のリソースが小さくなるのを防ぐ方法に特に注意して
// 見てください。
// ---------------------------------------------------------------------------
void
SetStrResource(ResType inResType, ResID inResID, ConstStringPtr inStrP )
{
// 変更するリソースを取り出す
oldResH = Get1Resource(inResType, inResID);
// リソースがない場合 (oldResH == 0) はエラー処理をすること
Size sz = *inStrP + 1;
/* 文字列がハンドルより長ければ、ハンドルを大きくする */
if(sz > GetHandleSize(oldResH )){
char savedRsrcHdlState = HGetState(oldResH );
HUnlock(oldResH );
SetHandleSize(oldResH , sz);
ThrowIfMemError_();
HSetState(oldResH , savedRsrcHdlState);
}
BlockMoveData(inStrP, *oldResH , sz);
ChangedResource(oldResH );
WriteResource(oldResH);
ThrowIfResError_();
UpdateResFile(CurResFile());
}
“デスクトップ・プリンタ機能拡張”は“Finder 機能拡張”として実装されているため、通信を行うためには Finder に依頼しなければなりません。次のルーチンはこの目的を達成するために必要なものです。
// ---------------------------------------------------------------------------
// アップルイベントを送りたい Finder のアドレスを作成します。
// ここでの「Finder」は最も一般的な意味で使っていることに注意してください。
// 実際には、Finder と AtEase を意味します。
// ---------------------------------------------------------------------------
OSStatus getFinderAddress(AEAddressDesc *theDesc)
{
OSErr result = noErr;
ProcessInfoRec processInfo;
ProcessSerialNumber serialNumber;
serialNumber.highLongOfPSN = 0;
serialNumber.lowLongOfPSN = kNoProcess;
while ((result = GetNextProcess(&serialNumber)) == noErr)
{
processInfo.processInfoLength = sizeof(ProcessInfoRec);
processInfo.processName = nil;
processInfo.processAppSpec = nil;
result = GetProcessInformation(&serialNumber, &processInfo);
if (result == noErr){
if ( processInfo.processType == 'FNDR' ){
result = AECreateDesc(typeProcessSerialNumber, (Ptr)&serialNumber,
sizeof(ProcessSerialNumber), theDesc);
return(result);
}
}
}
return(result);
}
// ---------------------------------------------------------------------------
// アップルイベントを Finder に送ります。イベントデータは 'dataPtr' が指し、
// その長さは 'dataSize' バイトです。データは Finder が内容を解釈できるよう
// データにはサブタイプを与えます。
// ---------------------------------------------------------------------------
#define kFinderExtension 'fext'
static OSStatus sendAEToFinder( Ptr dataPtr, Size dataSize)
{
OSStatus err = noErr;
// アップルイベントデスクリプタに Finder のアドレスを指定
AEAddressDesc finderAddr;
AppleEvent theEvent;
AppleEvent replyEvent;
err = getFinderAddress(&finderAddr);
if (err == noErr) {
err = AECreateAppleEvent(
kCoreEventClass, // コアイベントを作成
kFinderExtension, // Finder 機能拡張のイベント
&finderAddr, // これを Finder に送る
kAutoGenerateReturnID, // 返り値は取得しない
kAnyTransactionID, // トランザクション番号は無視
&theEvent); // ここにすぐ作成
if (err == noErr)
{
err = AEPutParamPtr(
&theEvent, // 渡すイベント
keyDirectObject, // ダイレクトオブジェクトキーワード
kFinderExtension, // Finder 拡張機能に送る
dataPtr, // これがデータ
dataSize); // これがその長さ
if (err == noErr)
{
err = AESend(
&theEvent, // ステータスイベントを送る
&replyEvent, // リプライイベントはなし、なぜなら...
kAENoReply + // リプライは不要、
kAECanInteract + // 受信者はユーザと対話可能で、
kAEDontReconnect, // エラーが発生しても再接続しないから。
kAENormalPriority, // 通常イベント
kAEDefaultTimeout, // 一定時間待つ
nil, nil); // 動作の結果は無視
}
// ここでアップルイベントを解放
(void) AEDisposeDesc(&theEvent);
}
// ここで Finder アドレスを解放
(void) AEDisposeDesc(&finderAddr);
}
// ここまで来る。エラーを (あれば) 返す。
return(err);
}
“デスクトップ・プリンタ機能拡張”は新しく選択された現在のプリンタを自動的に検出できますが、これは空き時間に関連リソースをチェックすることによって行います。これに若干の時間がかかる場合があります。検出までの時間を短縮するには、次のルーチンで“デスクトップ・プリンタ機能拡張”にアップルイベントを送り、新しいプリンタの追加があったことを通知するとよいでしょう。
// ---------------------------------------------------------------------------
// nessieCreateDTP
// “デスクトップ・プリンタ機能拡張”にアップルイベントを送り、
// 現在のプリンタに対応する新しい DTP の作成を依頼します。
// ---------------------------------------------------------------------------
#define kPrintingExtension 'dtpx'
#define aePFECreateDTP 'pfcr'
typedef struct
{
OSType pfeCreator;
OSType extensionType;
} CreateDTPEvent;
// ---------------------------------------------------------------------------
// “デスクトップ・プリンタ機能拡張”/Finder に現在のプリンタが変更に
// なったことを通知します
// ---------------------------------------------------------------------------
OSStatus nessieCreateDTP()
{
OSStatus err;
CreateDTPEvent myEvent;
myEvent.pfeCreator = kPrintingExtension;
myEvent.extensionType = aePFECreateDTP;
// “デスクトップ・プリンタ機能拡張”は Finder 機能拡張であるため
err = sendAEToFinder((Ptr) &myEvent, sizeof(myEvent));
return err;
}
現在のプリンタを指定するリソースを正しく設定し、“デスクトップ・プリンタ機能拡張”への通知が行った後、さらに DTP が実際に作成されたかどうかを調べなければなりません。このため、DTPInfo データ構造体を使用します。
typedef struct DTPInfo{
short vRefNum; // DTP フォルダの vRefNum
long dirID; // DTP フォルダのディレクトリ ID
Str31 DTPName; // DTP フォルダの名前
OSType driverType; // この DTP のプリンタドライバのクリエータタイプ
Boolean current; // この DTP は現在デフォルトプリンタかどうか
Str32 printerName; // ネット上の実際のプリンタ名 (LW8.4 のみ)
Str32 zoneName; // プリンタのあるゾーン (LW8.4 のみ)
} DTPInfo, *DTPInfoPtr, **DTPInfoHdl;
DTP についての情報を取得する方法は、“デスクトップ・プリンタ機能拡張”への Gestalt 呼び出しを行うことです。Gestalt 呼び出しは DTPInfo のリストを返します。リスト内の各 DTPInfo レコードはそれぞれ 1 個の DTP を記述します。リストを辿って個々の DTPInfo の内容を調べ、希望の DTP が作成されているかを調べることができます。次のルーチンはその方法を説明したものです。
#define errDTPNotFound -1
#define kGestaltPFEInfo 'dtpx'
enum
{
kOldPFEGestaltStructVersion = 0x02008000, // バージョン 2.0f0 (Mac OS 8.0、8.1、7.x)
kPFEGestaltStructVersion = 0x03000000 // バージョン 3.0 (Allegro)
};
// GestaltDTPInfo
typedef struct
{
short vRefNum; // DTP フォルダの vRefNum
long dirID; // DTP フォルダのディレクトリ ID
Str31 dtpName; // DTP フォルダ
OSType driverType; // この DTP のプリンタドライバのクリエータタイプ
Boolean current; // この DTP は現在デフォルトプリンタか
Str32 printerName; // ネット上の実際のプリンタの名前 (LaserWriter 8 DTP のみ)
Str32 zoneName; // このプリンタのあるゾーン (LaserWriter 8 DTP のみ)
} GestaltDTPInfo, *GestaltDTPInfoPtr;
// data associated with the pfe gestalt
typedef struct
{
long version; // kPFEGestaltStructVersion
short numDTPs; // アクティブな DTP の個数
Handle theDTPList; // アクティブな DTP の GestaltDTPInfo リストへのハンドル
Handle theDTPDriverList; // ドライバのファイルスペックのリストへのハンドル
Handle theDTPMoreInfoList; // アップルの内部使用のみ
} GestaltPFEInfo, **GestaltPFEInfoHdl;
// ---------------------------------------------------------------------------
// DTP のリストを辿り、ネットワークアドレスが 'papaH'、
// ファイルスペックが *printerDrvrFsSpecP のプリンタドライバにあたる
// プリンタを記述する DTP を探します。
// papaH は NULL だと無視します。
// printerDrvrFsSpecP は NULL だと無視します。
//
// 一致するものが見つかったら、noErr を返します。
// 一致するものが見つからない場合は、エラーを返します。
// 呼び出し側が一致したプリンタについての情報がほしい場合は、
// *'DTPInfoP' には NULL 以外の値、つまり DTPInfo 構造体を割り当てて
// その領域を指すポインタを渡してください。
// ---------------------------------------------------------------------------
OSStatus
nessieFindDTP(Handle papaH, FSSpec *printerDrvrFsSpecP, DTPInfo *DTPInfoP)
{
DTPInfoPtr found = NULL;
GestaltPFEInfoHdl gestaltResponse;
char papaHState;
OSStatus err;
if(papaH){
papaHState = HGetState(papaH);
HLock(papaH);
}
err = Gestalt(kGestaltPFEInfo, (long *)&gestaltResponse);
if(!err && gestaltResponse != NULL){
int numDTPs = (*gestaltResponse)->numDTPs;
DTPInfoHdl DTPH = (*gestaltResponse)->theDTPList;
FSSpec** driverH = (*gestaltResponse)->theDTPDriverList;
err = errDTPNotFound;
if((numDTPs > 0) && (DTPH != NULL) && (driverH != NULL)){
DTPInfoPtr DTP;
FSSpec *driverP;
char DTPState = HGetState((Handle)DTPH);
char driverListState = HGetState((Handle)driverH);
HLock((Handle)DTPH);
HLock((Handle)driverH);
DTP = *DTPH;
driverP = *driverH;
if((DTP != NULL) && (driverP != NULL)){
StringPtr printerStr; // プリンタ名へのポインタ
StringPtr zoneStr; // ゾーン名へのポインタ
// (最初はオブジェクトタイプを除外)
int i;
if(papaH){
printerStr = (StringPtr)*papaH; // プリンタ名へのポインタ
zoneStr = printerStr + *printerStr + 1; // ゾーン名へのポインタ
// (最初はオブジェクトタイプを除外)
zoneStr += *zoneStr + 1; // ゾーン名を設定
}
for(i = 0; i < numDTPs && found == NULL;
++i, ++DTP, ++driverP){
// 探している DTP は、指定のプリンタドライバで作成されており、
// ゾーン名とプリンタ名が合致するもの
if(papaH){
if(((printerDrvrFsSpecP == NULL) ||
((printerDrvrFsSpecP->vRefNum == driverP->vRefNum) &&
(printerDrvrFsSpecP->parID == driverP->parID) &&
(EqualString(printerDrvrFsSpecP->name, driverP->name, false, false)))) &&
EqualString(printerStr, DTP->printerName, false, false) &&
EqualString(zoneStr, DTP->zoneName, false, false)){
found = DTP;
}
}else{
if((printerDrvrFsSpecP != NULL) &&
((printerDrvrFsSpecP->vRefNum == driverP->vRefNum) &&
(printerDrvrFsSpecP->parID == driverP->parID) &&
(EqualString(printerDrvrFsSpecP->name, driverP->name, false, false)))){
found = DTP;
}
}
}
if(found != NULL){
if(DTPInfoP) *DTPInfoP = *found;
}
}
HSetState((Handle)driverH, driverListState);
HSetState((Handle)DTPH, DTPState);
}
}
if(papaH)
HSetState(papaH, papaHState);
return found == NULL ? errDTPNotFound : noErr;
}
// ---------------------------------------------------------------------------
// このルーチンは、プリンタドライバの FSSpec を受け取り、
// 該当する DTP が存在するかどうかを調べます。
// ---------------------------------------------------------------------------
Boolean HasDTP(DTPInfo *DTPInfoP, FSSpec *prDriverFsSpecP)
{
OSStatus err;
err = nessieFindDTP(NULL, prDriverFsSpecP, DTPInfoP);
return(!err);
}
これまでに紹介したルーチンの助けを借りて、これから最初の DTP を作成します。このサンプルが示すのは、LaserWriter 以外のタイプのプリンタドライバ用 DTP の作成方法です。LaserWriter (LW) DTP の場合は、LaserWriterExtra() というルーチンを呼び出す必要があり、ここではコメントにして外してあります。(詳細については「LaserWriter」のセクションを参照してください。)
環境の確認後、プリンタドライバの場所を調べます。それから、“System”ファイル内の現在のプリンタドライバを指定する 2 つのリソースを変更し、“デスクトップ・プリンタ機能拡張”にその変更を通知し、新しい DTP が作成されるのを待ちます。待ちループでの動作に注目してください。ループ内では、EventAvail または WaitNextEvent で Finder に制御を渡す必要があります。これをしないと“デスクトップ・プリンタ機能拡張”/Finder は DTP を作成する機会を持つことができません。
#define kWaitForDTPTime (60 * 20)
// ---------------------------------------------------------------------------
// CreateDTP
// このルーチンは StyleWriter1200 用 DTP の作成方法を示します。
// ---------------------------------------------------------------------------
void
CreateDTP()
{
OSErr err;
short savedResFile = CurResFile();
FSSpec printerDriverFSSpec;
AliasHandle theAlias;
EventRecord eventRec;
unsigned long endTime = TickCount() + kWaitForDTPTime;
DTPInfo DTPInfo;
// 環境のチェック。
// “デスクトップ・プリンタ機能拡張”および
// “Finder スクリプティング機能拡張”があることを確認
if(HasDesktopExtension() && HasFinderScripting()){
Try_{
FindPrinterDriver(0x0120,
'PRER', 'dblo', FSSpec& // StyleWriter1200
printerDriverFSSpec);
/* LaserWriter タイプのプリンタドライバの DTP を作成するには、
ここにコードが書く必要がある。
その場合は次を呼び出す → LaserWriterExtra();
*/
UseResFile(0); // システムファイル
// プリンタドライバのエイリアスを作成
err = NewAlias(nil, &printerDriverFSSpec, &theAlias);
ThrowIfOSErr_(err);
// 現在のプリンタを該当のプリンタドライバに設定
SetResource('alis', -8192, theAlias);
SetStrResource('STR ', -8192, printerDriverFSSpec.name);
DisposeHandle(theAlias);
// “デスクトップ・プリンタ機能拡張”にデフォルト
// プリンタの変更を通知
err = nessieCreateDTP();
// DTP が作成されたかどうか確認
do{
// “デスクトップ・プリンタ機能拡張”に
// DTP 作成要求を処理する機会を与える
EventAvail(everyEvent, &eventRec);
newDTPMade = HasDTP(&DTPInfo, &printerDriverFSSpec);
}while((TickCount() < endTime) && (newDTPMade == FALSE));
// DTP が作成されるかタイムアウトするまで
}Catch_(inErr){
// エラー処理
}EndCatch_
}
UseResFile(savedResFile);
}
LaserWriter 用の DTP を作成するコードを書く場合は、CreateDTP() ルーチンに少し変更を加えるだけで大丈夫です。
FindPrinterDriver を呼び出すところで、StyleWriter 用のクリエータの代わりに、LaserWriter のクリエータを渡します。上のサンプルではコメントで除外してあった LaserWriterExtra() ルーチンも呼び出してください。LaserWriterExtra() は、LaserWriter プリンタドライバ内の 'PAPA' -8192 リソースを変更して、新しいプリンタを指すようにします。
LaserWriterExtra() ルーチンは、LaserWriter 8.5.1 とそれより前のバージョンでは異なります。8.5.1 の場合は DTP のタイプによってさらに違いがあります。
8.5.1 より前の LaserWriter では、AppleTalk (PAP) DTP しか作成することができません。ドライバがオリジナルの 103 バイト長の 'PAPA' しかサポートしないためです。LaserWriterExtra() ルーチンは次のようになります。
// ---------------------------------------------------------------------------
// 8.5.1 より前の LaserWriter 用 LaserWriterExtra
// 現在のプリンタをターゲットにします。
// ---------------------------------------------------------------------------
LaserWriterExtra(FSSpec *printerDrvrFsSpecP,
ConstStr32Param inZone,
ConstStr32Param inPrinterName)
{
OSErr err;
char papaState;
short refNum;
Handle papaH;
short savedResFile = CurResFile();
// プリンタドライバのリソースフォークを開く
err = FSpOpenResFile(printerDrvrFsSpecP, fsWrPerm);
// エラー処理
// プリンタドライバから PAPA リソースを取得
papaH= Get1Resource('PAPA' , -8192);
// エラー処理
papaState = HGetState(papaH);
HLock(papaH);
// PAPA リソースの内容を変更
NBPSetEntity(*papaH, (ConstStr32Param)StringPtr(inPrinterName),
(ConstStr32Param)("\pLaserWriter"),
(ConstStr32Param)inZone);
HSetState(papaH, papaState );
ChangedResource(papaH); // 変更があったことを示す
WriteResource(papaH); // リソースを更新
err = FSClose(refNum);
UseResFile(savedResFile);
}
LaserWriter 8.5.1 は拡張 PAPA (1024 バイト長) をサポートします。拡張 PAPA を使うと、オリジナルの AppleTalk「PAP」プリンタに加えて、異なるタイプの仮想または物理プリンタを表すデスクトッププリンタを作成することができます。異なるタイプの DTP に印刷すると違う結果を生じます。「保留」DTP はスプールファイルを受け付けるだけのプリンタです。「PostScript トランスレータ」DTP は印刷文書を PostScript 文書に変換するものです。「カスタム」DTP は、あらかじめ指定されたアプリケーションを起動し、変換済みの PostScript 文書を開くよう命じるものです。「LPR」DTP は LPR プロトコルを理解するプリンタ/スプーラに印刷を行います。「赤外線」DTP は赤外線通信ポートを持つ LaserWriter に印刷します。拡張 PAPA の詳細については「TECHNOTE 1115: 拡張 'PAPA' リソース」を参照してください。
PrintingLib には、プログラマが内部構造を理解しなくても拡張 PAPA を作成できるルーチンがあります。詳細については「TECHNOTE 1129: プリンタ設定ライブラリ」を参照してください。
LaserWriter ドライバの PAPA リソースを変更して DTP を作成する前に、DTP を完全に記述する追加のパラメータを設定する必要もあります。現在定義されている DTP 用のパラメータの例は、すべてのタイプの DTP で必要な PPD ファイル、LPR DTP のドメインアドレス、トランスレータ DTP の格納先フォルダ、カスタム DTP の後処理アプリケーションがあります。
パラメータは次の表の通りです。
|
Collection Tag |
Tag ID |
DTP Type |
parameter |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ドメインアドレス |
|
|
|
|
の設定 |
|
|
|
|
エイリアス |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
これらのパラメータはコレクション内にヒントとして保管され、後に LaserWriter の設定ファイルに保存されます。ヒントはコレクションタグと ID によって識別されます。各パラメータの意味とデータ構造はこれらを使用するセクションで詳しく説明します。
PrintingLib にはこれらのコレクションにアクセスするルーチンがあります。詳細については、設定ライブラリ (SettingsLib) のドキュメントを参照してください。コレクションにアクセスする場合は必ずこれらのルーチンを使用してください。ルーチンのなかにはプリンタドライバの設定ファイルの名前を必要とするものがあります。LaserWriter の場合、設定ファイルの名前は LaserWriter ファイルの 'STR ' リソース、ID -8185 に保存されています。
DTP のコレクションにヒントを追加するルーチンは、次のようになります。
#define kNoCollection -2
OSErr psStorePrinterName(Collection prInfo, Handle papa);
/* コレクション prInfo に正規化した EntityName を保存する */
/*
DTP のコレクションにヒントを追加します。
長さが 'size' で 'bufP' の指すメモリブロックを、'tag' と 'id' を持つヒントとして、
'papaH' の指定する PAPA を持つ DTP に追加します。
注意: このルーチンを呼び出す前に、LaserWriter のリソースフォークを開いておかなくてはなりません。
*/
OSErr addHint(Handle papaH, CollectionTag tag, long id, long size, void *bufP){
Handle lwPrefFileNameH;
char savedHandleState;
Collection DTPCollection;
// LW の設定ファイルの名前が必要
lwPrefFileNameH= GetString(-8185 );
// エラー処理を忘れないように
savedHandleState = HGetState(inHandle);
HLock(lwPrefFileNameH);
// SettingsLib のルーチンでコレクションを取得し項目を追加する
DTPCollection= psGetPrefsPrinterInfo((StringPtr)(*lwPrefFileNameH), papaH);
if(DTPCollection== nil)
// エラー処理を忘れないように
err = kNoCollection;
err = psStorePrinterName(DTPCollection, papaH);
// エラー処理
err = AddCollectionItem(DTPCollection, tag, id, size, bufP);
// エラー処理
err = psUpdatePrefsPrinterInfo(*lwPrefFileNameH, papaH, DTPCollection);
DisposeCollection(DTPCollection);
// 後始末
HSetState(lwPrefFileNameH, savedHandleState );
ReleaseResource(lwPrefFileNameH);
return (err);
}
すべてのタイプの DTP に対して PPD ファイルを指定することができます。次のルーチンはその方法です。
OSStatus psGetPPDInfo(FSSpecPtr driver, Handle papaH,
long structVersion, PrinterPPDInfo *ppdInfo);
/* 'driver' や 'papaH' で指定されたプリンタの PPD 情報を返します。
PPD 情報は *'ppdInfo' に返します。
呼び出し側は使用する PrinterPPDInfo 構造体のバージョンを渡さなければなりません。
これは定数の 'kPPDInfoStructVersion' でなければなりません。
呼び出し側の構造体のバージョンが合わないと 'errWrongStructVersion' を返します。
*/
OSStatus psSetPPDInfo(FSSpecPtr driver, Handle papaH,
long structVersion, PrinterPPDInfo *ppdInfo);
/* PPD ファイルと、'driver' や 'papaH' で指定されたプリンタの
解析済み PPD ファイルを設定します。
PPD ファイルの FFSpec と解析済み PPD ファイルは、汎用の PPD を使うべきかどうかを指示
するフラグとともに、ppdinfo の指す構造体で渡されます。
汎用 PPD フラグが設定されている場合は、解析 PPD の FFSpec だけが有効であれば十分です。
structVersion は呼び出し側が使用している PrinterPPDInfo 構造体のバージョンを示します。
呼び出し側は定数を渡さなければなりません。
*/
OSErr ppdGetParseFolder(FSSpecPtr parseFolder);
/*
parseFolder が指す FFSpec に解析済み PPD フォルダの 'vRefNum' と 'parID' を設定します。
クライアントは解析済み PPD ファイル名を FFSpec の 'name' フィールドに設定し、ファイル
マネージャの Open 呼び出しで解析済み PPD を開くことができます。
*'parseFolder' は解析済み PPD フォルダの FFSpec ではないことに注意してください。
*/
OSErr ppdParseFile (const FSSpec *ppdFileSpec, short compiledRef, short compiledResFRef,
PPDParseErr *errInfoP);
/* PPD ファイルおよびすべての include を解析します。
FFSpecPtr は終了時にクローズされます。
PDD ファイルの解析結果はファイル参照の 'compiledRef' で開いたファイルに出力されます。
compiledResFRef が -1 でないと、PPD ファイルのリソースフォークをそこにコピーします。
'errInfoP' が NULL 以外だと、エラー情報があれば、*'errInfoP' に返します。
*/
enum PPDPresetSource {
kPPDSourceUnknown = -1,
kPPDSourceRSRC = 0,
kPPDSourceGeneric = 1,
kPPDSourceCustom = 2
};
typedef enum{
kTriFalse = 0,
kTriTrue,
kTriUnknown
} TriState;
struct CustPPDInfo {
Boolean usePPD;
FSSpec fileSpec;
};
typedef struct CustPPDInfo CustPPDInfo, **CustPPDHandle;
typedef struct {
short presetSource; /* enum PPDPresetSource */
TriState isSetup;
CustPPDInfo customPPD;
} WhatPPD;
typedef struct PrinterPPDInfo{
long structVersion; // 構造体のバージョンを示す
Boolean useGenericPPD; // 汎用 PPD を使用する場合は True
FSSpec ppdFile; // 現在の PPD ファイルの FSSpec
FSSpec parsedPPDFile; // プリンタの解析済み PPD ファイルの FSSpec
}PrinterPPDInfo;
/*
このルーチンは、ppdFsSpec によって指定された ppd ファイルを解析し、
対応するヒントを papaH によって指定された DTP に追加します。
*/
OSErr SetPPD(FSSpec* ppdFsSpecP, Handle papaH, FSSpec* laserWriterFsSpecP)
{
OSErr err = noErr;
FSSpec parsedPPD;
WhatPPD whatPPD;
short savedResFile = ::CurResFile();
Boolean isGeneric = false;
short dataForkRefNum, resourceForkRefNum;
PrinterPPDInfo ppdInfo;
// デフォルト
whatPPD.presetSource = kPPDSourceCustom;
whatPPD.isSetup = kTriTrue;
whatPPD.customPPD.usePPD = TRUE;
whatPPD.customPPD.fileSpec = *ppdFsSpecP;
// 解析済み PPD の FSSpec の準備
err = ppdGetParseFolder(&parsedPPD);
ThrowIfOSErr_(err);
CopyPStr(ppdFsSpecP->name, parsedPPD.name, sizeof(parsedPPD.name));
// 解析済みファイルを作成し、リソース/データフォークを開く
FSpCreateResFile(&parsedPPD, 'vgrd', 'Pref', smSystemScript);
err = SpOpenDF(&parsedPPD, fsRdWrPerm, &dataForkRefNum);
resourceForkRefNum = ::FSpOpenResFile(&parsedPPD, fsRdWrPerm);
// PPD の解析
err = ppdParseFile (ppdFsSpecP, dataForkRefNum, resourceForkRefNum, NULL);
// リソース/データフォークを閉じる
CloseResFile(resourceForkRefNum);
err = FSClose(dataForkRefNum);
UseResFile(savedResFile);
// PPD をプリンタと結合
err = addHint(papaH, 'pppd', 1, sizeof(parsedPPD), &parsedPPD);
err = addHint(papaH, 'ppd ', 1, sizeof(whatPPD), &whatPPD);
// デフォルトヒントを設定
err = psGetPPDInfo(laserWriterFsSpecP, papaH, 2, &ppdInfo);
if(!err) err = psSetPPDInfo(laserWriterFsSpecP, papaH, 2, &ppdInfo);
return (err);
}
PAP DTP 用 LaserWriterExtra ルーチンは次のようになります。
// ---------------------------------------------------------------------------
// LaserWriter 8.5.1 用 LaserWriterExtra
// 現在のプリンタをターゲットにします。
// ---------------------------------------------------------------------------
LaserWriterExtra(FSSpec *printerDrvrFsSpecP,
ConstStr32Param inZone,
ConstStr32Param inPrinterName)
{
OSErr err;
short refNum;
Handle papaH;
short savedResFile = CurResFile();
SSpec ppdFsSpec;
// プリンタドライバのリソースフォークを開く
err = FSpOpenResFile(printerDrvrFsSpecP, fsWrPerm, &refNum);
// エラー処理
// プリンタドライバから PAPA リソースを取得
papaH= Get1Resource('PAPA' , -8192);
// エラー処理
// PAPA リソースの内容を変更
// SettingsLib 仕様書の psSetPapPapa を参照
err = psSetPapPapa(papaH, inPrinterName,
(const Byte *)("\pLaserWriter"), inZone, 0);
// エラー処理
// PPD ファイルを ppdFsSpec で指定
err = FSMakeFSSpec(vRefNum,dirID,fileName,&ppdFsSpec);
err = SetPPD(&ppdFsSpec, papaH, printerDrvrFsSpecP);
ChangedResource(papaH); // 変更があったことを示す
WriteResource(papaH); // リソースを更新
err = FSClose(refNum);
UseResFile(savedResFile);
}
LPR DTP にはドメインアドレスとキューを指定しなければなりません。これらは 'LpIa' ヒントとして指定します。'LpIa' のフォーマットは、プリンタのドメインアドレス (パスカル文字列) に続けてキューの名前 (パスカル文字列) をつなげた形式です。
LPR DTP 用 LaserWriterExtra ルーチンは次のようになります。
// ---------------------------------------------------------------------------
// LaserWriter 8.5.1 用 LaserWriterExtra
// 現在のプリンタをターゲットにします。
// inTcpAddr は LPR プリンタのネットワークアドレスです。
// このアドレスは、名前の形式でもドット形式でも指定できます。
// 例えば "\plaser.rbi.com" または "\p204.188.109.155" となります。
// inQName は inTcpAddr のスプーラに割り当てられたプリントキューの
// 名前です。inQName が NULL だと、プリンタ/スプーラのデフォルトの
// キューを使用します。
// ---------------------------------------------------------------------------
LaserWriterExtra(FSSpec *printerDrvrFsSpecP,
ConstStr32Param inTcpAddr,
ConstStr32Param inPrinterName,
ConstStr32Param inQName)
{
OSErr err;
short refNum;
Handle papaH;
Handle ipAddrQueueH;
short savedResFile = CurResFile();
// プリンタドライバのリソースフォークを開く
err = FSpOpenResFile(printerDrvrFsSpecP, fsWrPerm, &refNum);
// エラー処理
// プリンタドライバから PAPA リソースを取得
papaH= Get1Resource('PAPA' , -8192);
// エラー処理
// PAPA リソースの内容を変更
// SettingsLib 仕様書の psSetLprPapa を参照
err = psSetLprPapa(papaH, inPrinterName, (const Byte *)("\p=LPR"),
(const Byte *)(*inTcpAddr), (const Byte *)inQName);
// エラー処理
// PPD ファイルを ppdFsSpec で指定
err = FSMakeFSSpec(vRefNum,dirID,fileName,&ppdFsSpec);
err = SetPPD(&ppdFsSpec, papaH, printerDrvrFsSpecP);
// プリンタのドメインアドレスとキューを指定
err = PtrToHand(inTcpAddr, &ipAddrQueueH, inTcpAddr[0] + 1);
err = PtrAndHand(inQName, ipAddrQueueH, inQName[0] + 1);
HLock(ipAddrQueueH);
err = addHint(papaH, 'LpIa', 1, GetHandleSize(ipAddrQueueH), *ipAddrQueueH);
HUnlock(ipAddrQueueH);
DisposHandle(ipAddrQueueH);
ChangedResource(papaH); // 変更があったことを示す
WriteResource(papaH); // リソースを更新
err = FSClose(refNum);
UseResFile(savedResFile);
}
// ---------------------------------------------------------------------------
// LaserWriter 8.5.1 用 LaserWriterExtra
// 現在のプリンタをターゲットにします。
// ---------------------------------------------------------------------------
LaserWriterExtra(FSSpec *printerDrvrFsSpecP,
ConstStr32Param inPrinterName)
{
OSErr err;
short refNum;
Handle papaH;
short savedResFile = CurResFile();
// プリンタドライバのリソースフォークを開く
err = FSpOpenResFile(printerDrvrFsSpecP, fsWrPerm, &refNum);
// エラー処理
// プリンタドライバから PAPA リソースを取得
papaH= Get1Resource('PAPA' , -8192);
// エラー処理
// PAPA リソースの内容を変更
// SettingsLib仕様書のpsSetInfraredPapaを参照
err = psSetInfraredPapa(papaH, inPrinterName, ("\p=Ird"));
// エラー処理
// PPD ファイルを ppdFsSpec で指定
err = FSMakeFSSpec(vRefNum,dirID,fileName,&ppdFsSpec);
err = SetPPD(&ppdFsSpec, papaH, printerDrvrFsSpecP);
ChangedResource(papaH); // 変更があったことを示す
WriteResource(papaH); // リソースを更新
err = FSClose(refNum);
UseResFile(savedResFile);
}
// ---------------------------------------------------------------------------
// LaserWriter 8.5.1 用 LaserWriterExtra
// 現在のプリンタをターゲットにします。
// ---------------------------------------------------------------------------
LaserWriterExtra(FSSpec *printerDrvrFsSpecP,
ConstStr32Param inPrinterName)
{
OSErr err;
short refNum;
Handle papaH;
short savedResFile = CurResFile();
// プリンタドライバのリソースフォークを開く
err = FSpOpenResFile(printerDrvrFsSpecP, fsWrPerm, &refNum);
// エラー処理
// プリンタドライバから PAPA リソースを取得
papaH= Get1Resource('PAPA' , -8192);
// エラー処理
// PAPA リソースの内容を変更
// See SettingsLib Spec for psSetHoldPapa
err = psSetHoldPapa(papaH, inPrinterName, ("\p=Hld"));
// エラー処理
// PPD ファイルを ppdFsSpec で指定
err = FSMakeFSSpec(vRefNum,dirID,fileName,&ppdFsSpec);
err = SetPPD(&ppdFsSpec, papaH, printerDrvrFsSpecP);
ChangedResource(papaH); // 変更があったことを示す
WriteResource(papaH); // リソースを更新
err = FSClose(refNum);
UseResFile(savedResFile);
}
PostScript トランスレータ DTP の場合、変換済のファイルを保存するデフォルトの格納先フォルダを 'Pdka' ヒントとして指定しなければなりません。「ファイルに印刷」することを示すため、'Svap' も指定する必要があります。
struct SaveAsFilePrefs{
Boolean saveToFile; // ファイルに印刷する場合は True
Boolean restricted; // ファイルに印刷する場合は True
};
// ---------------------------------------------------------------------------
// LaserWriter 8.5.1 用 LaserWriterExtra
// 現在のプリンタをターゲットにします。
// ---------------------------------------------------------------------------
LaserWriterExtra(FSSpec *printerDrvrFsSpecP,
ConstStr32Param inPrinterName,
FSSpec* destinationFolderP)
{
OSErr err;
short refNum;
Handle papaH;
SaveAsFilePrefs saveToFilePref;
AliasHandle printToDiskAliasH;
short savedResFile = CurResFile();
// プリンタドライバのリソースフォークを開く
err = FSpOpenResFile(printerDrvrFsSpecP, fsWrPerm, &refNum);
// エラー処理
// プリンタドライバから PAPA リソースを取得
papaH= Get1Resource('PAPA' , -8192);
// エラー処理
// PAPA リソースの内容を変更
// SettingsLib 仕様書の psSetFilePapa
err = psSetFilePapa(papaH, inPrinterName, "\p=Fil");
// エラー処理
// PPD ファイルを ppdFsSpec で指定
err = FSMakeFSSpec(vRefNum,dirID,fileName,&ppdFsSpec);
err = SetPPD(&ppdFsSpec, papaH, printerDrvrFsSpecP);
// ディスクヒントへ印刷
saveToFilePref.saveToFile = TRUE;
saveToFilePref.restricted = TRUE;
prefCollection.AddItem('Svap', 1, sizeof(saveToFilePref), &saveToFilePref);
// ディスクのデフォルトフォルダに印刷するよう設定
err = NewAliasMinimal(destinationFolderP, &printToDiskAliasH);
HLock((Handle)printToDiskAliasH);
err = addHint(papaH, 'Pdka', 1,
GetHandleSize((Handle)printToDiskAliasH), *printToDiskAliasH);
HUnlock((Handle)printToDiskAliasH);
DisposeHandle((Handle)printToDiskAliasH);
// PAPA リソースの内容を変更
ChangedResource(papaH); // 変更があったことを示す
WriteResource(papaH); // リソースを更新
err = FSClose(refNum);
UseResFile(savedResFile);
}
デベロッパがカスタム DTP を使用する方法と、アップルのデスクトッププリンタユーティリティを変更して特定の後処理アプリケーションの実行をサポートする方法の詳細については「TECHNOTE 1113: デスクトッププリンタユーティリティのカスタマイズ」を参照してください。
カスタム DTP にはそれぞれ、LaserWriter が起動する後処理アプリケーションを指定する必要があります。後処理アプリケーションは AliasHandle として、'TGap' ヒント内に指定します。
現在サポートされているカスタム DTP のヒントは、'PSlv'、'BNok'、'JObt'、'FOnt' です。これらのヒントの意味とデータ構造体については「TECHNOTE 1113: デスクトッププリンタユーティリティのカスタマイズ」で説明しています。
次のルーチンはこうしたパラメータをカスタム DTP のコレクションに追加する方法を示したものです。FOntHint および CustomAppDesc 構造体の詳細については「TECHNOTE 1113: デスクトッププリンタユーティリティのカスタマイズ」を参照してください。
typedef struct{ // 「カスタム DTP」の説明を参照
long flag; // kIncludeAllFontsBut または kIncludeAllFontsBut
unsigned char name[1]; // フォント名
}FOntHint;
struct CustomAppDesc{
OSType appSignature; // 後処理アプリケーションのシグネチャ
Str255 docType; // 新規メニューの文書リストに出す名前
Str255 helpText; // lin43 - このタイプの DTP が選択されたときに出す
Str255 usage; // ウィンドウに出す DTP 利用状況
Str255 appFileName; // エラーメッセージなどで使われるデフォルトアプリケーションファイル名
short numOfHintsFollow; // 1 から始まる
HintRsrcSpec hintRsrc[1]; // 可変長
};
typedef struct CustomAppDesc CustomAppDesc;
typedef struct CustomAppDesc* CustomAppDescPtr;
typedef struct CustomAppDesc** CustomAppDescHdl;
/*
このルーチンはカスタム DTP のヒントを DTP を指定する papaH に追加します。
ppApp は後処理アプリケーションの FSSpec を指します。
後処理アプリケーションの AliasHandle の生成法と、'TGap' ヒントとして追加する方法に注目してください。
*/
OSErr addCustomDtpParameters(FSSpec* ppApp, Handle papaH)
{
OSErr err;
long psLevel = 1; // PostScript レベル 1
Byte binaryOK = 0; // false
char job = 0; // psJobPostScript
FOntHint fontHint;
AliasHandle targetAppAliasH;
CustomAppDesc customAppDesc;
// PostScript レベル 1
err = addHint(papaH, 'PSlv', 1, siezof(psLevel ), &psLevel ){
// バイナリは使用しない
err = addHint(papaH, 'BNok', 1, siezof(binaryOK ), &binaryOK ){
// PostScript ジョブ
err = addHint(papaH, 'JObt', 1, siezof(job ), &job ){
// includeAllFonts
fontHint.flag = 1;
fontHint.name [0] = 0;
err = addHint(papaH, 'FOnt', 1, siezof(fontHint), &fontHint){
// ターゲットアプリケーションの場所を保存
err = ::NewAliasMinimal(ppApp, &targetAppAliasH);
// エラー処理
::HLock((Handle)targetAppAliasH);
err = addHint('TGap', 1,
GetHandleSize((Handle)targetAppAliasH), *targetAppAliasH);
::HUnlock((Handle)targetAppAliasH);
::DisposeHandle((Handle)targetAppAliasH);
// アップルのデスクトッププリンタユーティリティに DTP を認識してもらい、
// 開いてもらうためには、'CsDs' ヒントを追加しなければならない
// 後処理アプリケーションの customAppDesc 構造体のフィールドを設定
customAppDesc.appSignature = 'xxxx'; // 後処理アプリケーションのシグナチャ
/* その他のフィールドもすべて
*/
// カスタムアプリケーションの説明を保存
err = addHint(('CsDs', 1, sizeof(customAppDesc), &customAppDesc);
return err;
}
// ---------------------------------------------------------------------------
// LaserWriter 8.5.1 用 LaserWriterExtra
// 現在のプリンタをターゲットにします。
// ---------------------------------------------------------------------------
LaserWriterExtra(FSSpec *printerDrvrFsSpecP,
ConstStr32Param inPrinterName)
{
OSErr err;
FSSpec postProcessAppFsSpec;
short refNum;
Handle papaH;
short savedResFile = CurResFile();
// プリンタドライバのリソースフォークを開く
err = FSpOpenResFile(printerDrvrFsSpecP, fsWrPerm, &refNum);
// エラー処理
// プリンタドライバから PAPA リソースを取得
papaH= Get1Resource('PAPA' , -8192);
// エラー処理
// SettingsLib 仕様書の psSetCustomPapa を参照
err = psSetCustomPapa(papaH, inPrinterName, "\p=Cst");
// エラー処理
// PPD ファイルを ppdFsSpec で指定
err = FSMakeFSSpec(vRefNum,dirID,fileName,&ppdFsSpec);
err = SetPPD(&ppdFsSpec, papaH, printerDrvrFsSpecP);
// 後処理アプリケーションと他のパラメータを指定
err = FSMakeFSSpec(vRefNum, dirID, "\pYourPostProcessAppName", &postProcessAppFsSpec);
err = addCustomDtpParameters(&postProcessAppFsSpec, papaH);
// PAPA リソースの内容を変更
ChangedResource(papaH); // 変更があったことを示す
WriteResource(papaH); // リソースを更新
err = FSClose(refNum);
UseResFile(savedResFile);
}
この TECHNOTE で概説したように、プログラムの実行中にデスクトッププリンタを作成するにはちょっとした作業が必要です。しかし、ここで示した注意を守って行えば、多くのアプリケーションにとって、価値ある作業となるはずです。がんばってください。