ホームページ開発ツール>Xojo / Real Studio Trial and Error・レガシーAPIを延命する・絶対パスへの変換

 Xojo / Real Studio Trial and Error

レガシーAPIを延命する・絶対パスへの変換

目次
 はじめに

 以下は、Xojo Cocoaビルドについての話題です。

 Xojo 2015 Release 3から、Inline68KがRemovalsとなってしまいました。
 この影響を受けるのが、例えば、エイリアスパスから絶対パスを取得する場合なのですが、試しにInline68K部分を削除してみたところ、特に問題はなさそうでした。
 が、そもそもInline68Kの役割がよく分かっていない(文字通り、最初期のCPUである68Kシリーズ用?)こともあって、なんとなく気持ち悪いので、前回と同様のコマンドラインツールによる対応を考えてみました。

 参考サイト(1):Deprecations - Xojo Documentation

 なお検証には、Xojo 2015 Release 4.1を用いています。(Mac mini + OS X 10.11.3 El Capitan)


 エイリアスパス>絶対パスの実装
  1. Xcode7.2.1を起動し、File > New > Project...メニューを選択
  2. ダイアログのリストから「OS X > Application」と選択し、「Command Line Tool」をクリックしてNextボタンを押す
  3. プロジェクト名を「absCommand」として保存
  4. プロジェクトの設定を変更
    OS X Deployment Target > OS X 10.7
    Objective-C Automatic Reference Counting > No
  5. main.mを開き、中身を全文削除後に、以下をペースト(より厳密なエラーチェックが必要なら追加して下さい。)
    #import <Foundation/Foundation.h>
    
    static int GetAbsPath(const char* ahds, const char* sizeC);
    static unsigned char* string2char(const char* ahds, int size);
    static Handle char2handle(unsigned char* str, int size);
    
    int main (int argc, const char * argv[]) {
    	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    	
    	// insert code here...
    	
    	// Get POSIX Path
    	int ret = GetAbsPath(argv[1], argv[2]);
    	
    	[pool drain];
    	return ret;
    }
    
    int GetAbsPath(const char* ahds, const char* sizeC) {
    	int size = atoi(sizeC);
    	unsigned char *ahdc = string2char(ahds, size);  // call string2char
    	if (ahdc == NULL) return 1;
    	
    	OSStatus err;
    	FSRef theRef;
    	Boolean changed;
    	UInt8 absPath[4096];
    	AliasHandle ahd = (AliasHandle)char2handle(ahdc, size);  // call char2handle
    	if (ahd == NULL) return 2;
    	err = FSResolveAlias(NULL, ahd, &theRef, &changed);
    	DisposeHandle((Handle)ahd);
    	if (err != 0) return err;
    	err = FSRefMakePath(&theRef, (UInt8 *)absPath, size);
    	if (err != 0) return err;
    	printf("%s", absPath);  // Result
    	
    	free(ahdc);
    	return err;
    }
    
    unsigned char* string2char (const char* ahds, int size) {
    	unsigned char *ahdc;
    	ahdc = (unsigned char *)malloc(size*sizeof(unsigned char));
    	if (ahdc == NULL) return NULL;
    	UInt16 v1, v2, v3;
    	unsigned char c1, c2;
    	for (int i=0; i<size; i++) {
    		c1 = ahds[i*2];
    		c2 = ahds[i*2+1];
    		if ((c1<'0')||(c1>'9')) v1 = (UInt16)(c1-'a'+10);
    		else			v1 = (UInt16)(c1-'0');
    		if ((c2<'0')||(c2>'9')) v2 = (UInt16)(c2-'a'+10);
    		else			v2 = (UInt16)(c2-'0');
    		v3 = v1*16+v2;
    		ahdc[i] = (unsigned char)v3;
    	}
    	return ahdc;
    }
    
    Handle char2handle(unsigned char* str, int size) {
    	Handle hndl = NewHandle(size+1);
    	if (hndl != NULL) {
    		int state = HGetState(hndl);
    		HLock(hndl);
    		OSStatus err = PtrToHand(str, &hndl, size);
    		HSetState(hndl, state);
    		if (err != 0) return NULL;
    		SetHandleSize(hndl, size);
    	}
    	return hndl;
    }
    
  6. ビルド
  7. 出来上がったツールを、(ひとまず)Xojoプロジェクトと同じ場所に置く
  8. Xojo側の、ツールを起動して結果を受け取るメソッドは、以下の通り
    メソッド名: GetAbsPath
    引数: aliasPath As String
    戻り値型: String
    
    // パスが空なら戻る
    if aliasPath="" then
      return ""
    end if
    
    Dim f2 As FolderItem
    // absCommandの取得(アプリケーションパッケージ内)
    f2=App.ExecutableFile.Parent.Parent.Child("Applications").Child("absCommand")
    if f2=nil or f2.Exists=false then
      // なければ、プロジェクトファイルの場所から取得(デバッグ時)
      f2=App.ExecutableFile.Parent.Parent.Parent.Parent.Child("absCommand")
      if f2=nil or f2.Exists=false then
        msgBox "not found."
        return ""
      end if
    end if
    Dim appPath As String = f2.NativePath
    
    // パスのバイナリ(16進)表現を、そのまま文字列に
    Dim binst, s2 As String
    Dim i As Integer
    Dim mb As MemoryBlock
    mb=new MemoryBlock(2)
    for i=1 to LenB(aliasPath)
      mb.StringValue(0,1)=MidB(aliasPath,i)
      s2=Hex(mb.Byte(0))
      if LenB(s2)=1 then
        s2="0"+s2
      end if
      binst=binst+s2
    next
    binst=Lowercase(binst)  // absCommandが小文字を前提とした処理をしているので、小文字に変換
    
    // absCommand実行
    Dim s As Shell
    s = New Shell
    s.Execute(""""+appPath+""" """+binst+""" """+Str(LenB(binst)/2)+"""")
    if s.ErrorCode <> 0 Then
      MsgBox("Error code: " + Str(s.ErrorCode))
      return ""
    end if
    
    return s.Result
    
  9. Xojo側で、CarbonのDeclareメソッドコールと上記メソッドコールを差し替え
 結果、エイリアスパスを絶対パスに復元できることを確認しました。


 おわりに

 開発時はいいとして、ビルド時はその都度手作業で、パッケージ内のApplicationsフォルダにコマンドラインツールをコピーする必要があり、面倒ではあります。
 やはりプラグイン化した方がいいかも。


 お世話になったサイト

 貴重な情報をご提供頂いている皆様に、お礼申し上げます。(以下、順不同)

 参考サイト(1):Deprecations - Xojo Documentation
 参考サイト(2):C言語 文字(char型)を数字(int型)に変換。。。 - char型の変数、cNum に'1'(←... - Yahoo!知恵袋


 更新履歴

 2016.02.27 新規作成


[Home]  [MacSoft]  [Donation]  [History]  [Privacy Policy]  [Affiliate Policy]