Qtアプリケーションからmail.appにエクスポートする

特定のファイルを電子メールにエクスポートする必要がありました(ユーザーは非常に尋ねています)。 問題は、Mac OS Xでそれを行う方法です。まあ、Mail.app以外のメーラーを想定していないと仮定します。 developer.apple.comで、Qtなしでこれを行う方法の説明を見つけました。 これを実装する最初の試みは、developer.apple.comでは答えられない多くの質問につながりました。 一般的に、私は多くの苦労をして、AppleScriptを使用してそのような機能を実装するための既製のレシピを投稿します。



1.ヘッダーファイルCarbonを接続します。

# include <Carbon/Carbon.h>
      
      







2. 2つの完全なAppleScriptテキストを含む2つの静的変数(定数) 宣言します。1つは添付ファイルの送信用、もう1つは2つの添付ファイルの送信用です。

 char sendMailScript_singAtt[] = "on send_email_message(subjectLine, messageText, fileAttachment)\n" " tell application \"Mail\"\n" " (* CREATE THE MESSAGE *)\n" " activate\n" " set newMessage to make new outgoing message at end of outgoing messages with properties {subject:subjectLine, content:messageText & return, visible:true}\n" " \n" " (* SPECIFY THE ATTACHMENT *)\n" " tell newMessage\n" " make new attachment with properties {file name:fileAttachment} at after last paragraph\n" " end tell\n" " (*set frontmost to true*)\n" " end tell\n" "end send_email_message"; char sendMailScript_doubAtt[] = "on send_email_message(subjectLine, messageText, fileAttachmentA, fileAttachmentB)\n" " tell application \"Mail\"\n" " (* CREATE THE MESSAGE *)\n" " activate\n" " set newMessage to make new outgoing message at end of outgoing messages with properties {subject:subjectLine, content:messageText & return, visible:true}\n" " \n" " (* SPECIFY THE ATTACHMENT *)\n" " tell newMessage\n" " make new attachment with properties {file name:fileAttachmentA} at after last paragraph\n" " make new attachment with properties {file name:fileAttachmentB} at after last paragraph\n" " end tell\n" " (*set frontmost to true*)\n" " end tell\n" "end send_email_message";
      
      







ご覧のとおり、スクリプトは、件名のテキスト、メッセージの本文、およびパラメーターとして1つまたは2つの添付ファイルを受け取る2つの関数です。 送信方法は、上記の記事で説明した方法とはほぼ完全に異なります。明らかに記事は古く、Appleは情報を更新することを気にしませんでした。 実際、スクリプト自体は非常に簡単であり、注意を払う必要があるのは、アクティベートの呼び出しだけです。 これがないと、Mail.appウィンドウがバックグラウンドで開きます。



3.最新のスクリプトパラメータに注意してください。これらは単なるファイルパスではなく、いわゆるエイリアスです。 したがって、次の関数は、これらの同じエイリアスをパスから取得するように設計されています。

 GetAliasHandleForFile(QString fname, AliasHandle * ahandle) { FSRef fref; if(FSPathMakeRef((const UInt8 *)fname.toLocal8Bit().data(), &fref, NULL) == noErr) if(FSNewAlias(0, &fref, ahandle) == noErr && (*ahandle)) return true; return false; }
      
      





タイプQStringの引数で渡されたファイルパスからエイリアスが正常に受信された場合、関数はtrueを返します。そうでない場合はfalse



4. AppleScriptを呼び出すには、スクリプトテキストからイベントオブジェクトを作成する必要があります。このオブジェクトに引数を渡して呼び出し、ファイルを電子メールにエクスポートします。 両方のスクリプトに対してこのようなイベントを作成するための関数は次のとおりです。



 OSStatus CreateEmailMessageEvent1(AppleEvent *theEvent, char* subjectLine, char* messageText, AliasHandle fileAttachment) { OSStatus err; ProcessSerialNumber PSN = {0, kCurrentProcess}; /* create the container list */ err = AEBuildAppleEvent( 'ascr', kASSubroutineEvent, typeProcessSerialNumber, (Ptr) &PSN, sizeof(PSN), kAutoGenerateReturnID, kAnyTransactionID, theEvent, NULL, "'----':[TEXT(@),TEXT(@),alis(@@)]," "'snam':TEXT(@)", subjectLine, messageText, fileAttachment, "send_email_message"); return err; } OSStatus CreateEmailMessageEvent2(AppleEvent *theEvent, char* subjectLine, char* messageText, AliasHandle fileAttachmentA, AliasHandle fileAttachmentB) { OSStatus err; ProcessSerialNumber PSN = {0, kCurrentProcess}; /* create the container list */ err = AEBuildAppleEvent( 'ascr', kASSubroutineEvent, typeProcessSerialNumber, (Ptr) &PSN, sizeof(PSN), kAutoGenerateReturnID, kAnyTransactionID, theEvent, NULL, "'----':[TEXT(@),TEXT(@),alis(@@),alis(@@)]," "'snam':TEXT(@)", subjectLine, messageText, fileAttachmentA, fileAttachmentB, "send_email_message"); return err; }
      
      





呼び出される関数の詳細については、Appleのドキュメントを参照してください(詳細については詳しく説明しませんでしたが、インターネット上のさまざまな例からそれらを引き出しました)。



5.上記の機能を使用して作成されたイベントの実際の呼び出し:



 OSStatus ExecuteAppleScriptEvent(const void* text, long textLength, AppleEvent *theEvent, AEDesc *resultData) { ComponentInstance theComponent; AEDesc scriptTextDesc; OSStatus err; OSAID contextID, resultID; /* set up locals to a known state */ theComponent = NULL; AECreateDesc(typeNull, NULL, 0, &scriptTextDesc); contextID = kOSANullScript; resultID = kOSANullScript; /* open the scripting component */ theComponent = OpenDefaultComponent(kOSAComponentType, typeAppleScript); if(theComponent != NULL) { /* put the script text into a Apple event descriptor record */ err = AECreateDesc(typeChar, text, textLength, &scriptTextDesc); if(err == noErr) { /* compile the script into a new context. The flag 'kOSAModeCompileIntoContext' is used when compiling a script containing a handler into a context. */ err = OSACompile(theComponent, &scriptTextDesc, kOSAModeCompileIntoContext, &contextID); if(err == noErr) { /* run the script */ err = OSAExecuteEvent( theComponent, theEvent, contextID, kOSAModeNull, &resultID); /* collect the results - if any */ if(resultData != NULL) { AECreateDesc(typeNull, NULL, 0, resultData); if(err == errOSAScriptError) OSAScriptError(theComponent, kOSAErrorMessage, typeChar, resultData); else if(err == noErr && resultID != kOSANullScript) OSADisplay(theComponent, resultID, typeChar, kOSAModeDisplayForHumans, resultData); } } } } else err = paramErr; AEDisposeDesc(&scriptTextDesc); if(contextID != kOSANullScript) OSADispose(theComponent, contextID); if(resultID != kOSANullScript) OSADispose(theComponent, resultID); if(theComponent != NULL) CloseComponent(theComponent); return err; }
      
      







ご覧のとおり、関数はAEDesc型のオブジェクトを介して呼び出しの結果を返すことができます。 スクリプトテキストとその長さは関数に渡されます。 この関数では、スクリプトのコンパイル(OSACompile)と起動(OSAExecuteEvent)が発生し、イベントを作成するための以前の関数は、スクリプトの実行時に使用されるパラメーターの呼び出し説明とコンテナーのみを作成します。



6.さて、今ではすべてをまとめています。



 void SendSingleFileToEmail(QString subj, QString body, QString attPath) { AliasHandle ahandle; AppleEvent theEvent; if(!GetAliasHandleForFile(attPath, &ahandle)) return; if(CreateEmailMessageEvent1(&theEvent, subj.toLocal8Bit().data(), body.toLocal8Bit().data(), ahandle) == noErr) ExecuteAppleScriptEvent(sendMailScript_singAtt, strlen(sendMailScript_singAtt), &theEvent, NULL); } void SendDoubleFileToEmail(QString subj, QString body, QString attPathA, QString attPathB) { AliasHandle ahandleA, ahandleB; AppleEvent theEvent; if(!GetAliasHandleForFile(attPathA, &ahandleA) || !GetAliasHandleForFile(attPathB, &ahandleB)) return; if(CreateEmailMessageEvent2(&theEvent, subj.toLocal8Bit().data(), body.toLocal8Bit().data(), ahandleA, ahandleB) == noErr) ExecuteAppleScriptEvent(sendMailScript_doubAtt, strlen(sendMailScript_doubAtt), &theEvent, NULL); }
      
      







ここには、1つの添付ファイルと2つの添付ファイルを送信するための、それぞれ2つの関数があります。 最後に、このコードはファイルを送信せず、新しいメッセージを作成し、編集、受信者アドレスの入力、またはキャンセルのために開きます。

まあ、別の重要なポイント。 AppleScriptを実際に実行できないため、特権モードで(つまり、rootとして)作業している場合、このコードを使用することはできません。

今日は以上です。



All Articles