前のページ次のページ上に戻るホーム SophiaFramework UNIVERSE 5.3

21.1. ラッパークラスの使用方法

BREW API プログラミングでは、BREW が提供するインターフェースを使用してシステムにアクセスします。 しかし、BREW API は C 言語で記述されているので、プログラムの作成に C++ 言語を使用する場合でも、 C 言語的な記述しかできません。また、参照カウントを正確に管理しなければならないため、コーディングに負担がかかります。

SophiaFremwork UNIVERSE では、 BREW SDK に含まれるすべての BREW インターフェースに対応する C++ ラッパークラスを提供することによって、 C++ のオブジェクト指向構文で BREW API を呼び出すことを可能にしました。 また、C++ ラッパークラスとスマートポインタを組み合わせることによって、 BREW インターフェースの参照カウント管理が自動化されています。

これ以外にも、SophiaFremwork UNIVERSE のクラスを渡せるようにした便利な拡張関数も用意しています。 詳細はクラスリファレンスを参照してください。

21.1.1. インターフェースの生成と呼び出し

ISHELL_CreateInstance 関数でインスタンスを生成するインターフェースと、 IQI_QueryInterface 関数でインスタンスを生成するインターフェースのラッパークラスの使い方をそれぞれ説明します。

21.1.1.1. ISHELL_CreateInstance 関数でインスタンスを生成するインターフェースの場合

IHash インターフェースのラッパークラス SFBHash の使用方法について説明します。

[Tip] IHash インターフェース

IHash インターフェースは、ISHELL_CreateInstance 関数を使用してそのインスタンスを生成するインターフェースです。

例 21.1. インターフェースの生成

// SFBHash::NewInstance 関数呼び出しで返されるエラー値
SFCError error;
// SFBHashSmp は SFBHash インターフェースを管理するスマートポインタ
// SFBHash::NewInstance 関数を使用して新しいインターフェースを生成する
SFBHashSmp hash(SFBHash::NewInstance(AEECLSID_MD5, &error));

例 21.2. インターフェースの呼び出し

// インターフェースの呼び出し
hash->Restart();

例 21.3. インターフェースの利用後の処理

// インターフェースは自動的に解放されるので、何もしなくてよい

// インターフェースを明示的に解放する場合
// hash.Release(); とする

21.1.1.2. IQI_QueryInterface 関数でインスタンスを生成するインターフェースの場合

IBitmapDev インターフェースのラッパークラス SFBBitmapDev の使用方法について説明します。

[Tip] IBitmapDev インターフェース

IBitmapDev インターフェースは、IQI_QueryInterface 関数を使用してそのインスタンスを生成するインターフェースです。

例 21.4. インターフェースの生成

SFCError      error;  // SFBBitmapDev::NewInstance 関数呼び出しで返されるエラー値
SFBBitmapSmp  bmp;    // SFBBitmapDev::NewInstance 関数に渡すビットマップ
SFBShellSmp   shell = SFBShell::GetInstance();

// リソースファイルからビットマップを取得する
bmp = shell->LoadResBitmap(MYRESOURCE_RES_FILE, IDB_MY_PICTURE);

// SFBBitmapDevSmp は SFBBitmapDev インターフェースを管理するスマートポインタ
// SFBBitmapDev::NewInstance 関数を使用して新しいインターフェースを生成する
SFBBitmapDevSmp bitmap_dev(SFBBitmapDev::NewInstance(bmp, AEEIID_BITMAPDEV, &error));

例 21.5. インターフェースの呼び出し

Bool result;  // SFBBitmapDev::IsEnabled 関数の結果が返される Bool 値
// インターフェースの呼び出し
result = bitmap_dev->IsEnabled();

例 21.6. インターフェースの利用後の処理

// インターフェースは自動的に解放されるので、何もしなくてよい

// インターフェースを明示的に解放する場合
// bitmap_dev.Release(); とする

21.1.2. スマートポインタ

スマートポインタを使うと、使われなくなったインターフェースは自動的に解放されます。 参照カウントの管理は不要です。

例 21.7. スマートポインタの使い方

// SFBHashSmp は SFBHash インターフェースを管理するスマートポインタ
// SFBHash::NewInstance 関数を使用して新しいインターフェースを作成する
SFBHashSmp hash(SFBHash::NewInstance(AEECLSID_MD5));

// インターフェースの呼び出し
hash->Restart();

// 使われなくなったインターフェースは自動的に解放される

21.1.3. コールバック関数

BREW インターフェースのラッパークラスで使用するコールバック関数は、独自に宣言・実装・登録する必要があります。

BREW インターフェースのラッパークラスで使用するコールバック関数は静的関数でなければならないという制限があります。 そのため、以下のサンプルコードのように、 静的メンバ関数または freind 関数で定義されるダミーのコールバック関数を経由して、実際のコールバック関数を呼び出します。

[Note] コールバック関数を登録する関数のプロトタイプ

コールバック関数を登録する関数のプロトタイプは、BREW インターフェースのラッパークラスによって異なります。

詳細情報 : 「 BREW API リファレンス 」

例 21.8. コールバック関数を静的メンバ関数として定義・実装し、登録する方法

SFMTYPEDEFCLASS(Camera)
class Camera {
SFMSEALCOPY(Camera)

private:
    SFBCameraSmp _camera; // ICamera インターフェースのラッパークラス

public:
    SFCError Resume(Void);  // レジューム処理
    Void OnCamera(AEECameraNotify* notify);  // コールバック関数の実体
    static Void OnCameraSHP(VoidPtr reference, AEECameraNotify* notify);  // ダミーのコールバック関数 : 静的メンバ関数として定義する
};

#endif

// レジューム処理: カメラの基本的な初期化処理
SFCError Camera::Resume(Void)
{
    SFCError error(SFERR_NO_ERROR);
 
    // SFBCamera のインスタンスを取得する
    if ((_camera = SFBCamera::NewInstance()) != null) {     
    
        // ダミーのコールバック関数を登録する
        error = _camera->RegisterNotify(OnCameraSHP, this); 
        
        if (error == SFERR_NO_ERROR) {

            ...

        }
        
    // カメラのインスタンスを取得できなかった場合
    } else {
    
        error = SFERR_NO_MEMORY;   
    }
    
    if (error != SFERR_NO_ERROR) {
	
       // エラーが発生したとき
	   ...
    }
    return error;
}

// ダミーのコールバック関数
Void Camera::OnCameraSHP(VoidPtr reference, AEECameraNotify* notify)
{
    // 実際のコールバック関数を呼び出す
    static_cast<CameraPtr>(reference)->OnCamera(notify); 
    return;
}

// 実際のコールバック関数
Void Camera::OnCamera(AEECameraNotify* notify)
{
    switch (notify->nStatus) {
        case CAM_STATUS_START:  // カメラの起動が完了したとき
            ...
            break;
        case CAM_STATUS_FRAME:  // 新たなフレームを取得したとき
            ...
            break;
        case CAM_STATUS_DONE:   // 処理が完了したとき
            ...
            break;
        case CAM_STATUS_FAIL:   // 処理が失敗したとき
            ...
            break;
        case CAM_STATUS_ABORT:  // 処理を中止したとき
            ...
            break;
    }
    return;
}
[Caution] SFBCameraSmp インスタンス変数

ダミーのコールバック関数を登録する SFBCameraSmp インスタンス変数 _camera は、Camera クラスのクラス変数として定義します。

_cameraを Camera::Resume 関数のローカル変数として定義した場合、 Camera::Resume 関数を終了した段階でスコープから外れるので、スマートポインタである _camera は解放されてしまいます。 その結果、ダミーのコールバック Camera::OnCameraSHP 関数は呼び出されなくなります。

例 21.9. コールバック関数を friend 関数として定義・実装し、登録する方法

SFMTYPEDEFCLASS(jpegreader)
class jpegreader : public SFYApplication {
    SFMSEALCOPY(jpegreader)

private:
    SFBImageSmp _image;  // IIMage インターフェースのラッパークラス

public:
    static SFCInvokerPtr Factory(Void);

private:
    explicit jpegreader(Void) static_throws;
    virtual ~jpegreader(Void);
    SFCError LoadImage(SFXPathConstRef path);
    SFCError ExampleDirectFile(SFXFilePtr file);  // ファイルストレージからイメージを読み込む
    SFCError ExampleThroughMemory(SFXFilePtr file, UInt32 size);  // メモリストレージからイメージを読み込む
    XANDLER_DECLARE_BOOLEVENT(OnKey)
    Void OnImage(Void);  // コールバック関数の実体
    friend Void read_finished(VoidPtr, IImage*, AEEImageInfo*, SIntN);  // ダミーのコールバック関数 : friend 関数として定義する
};


// コンストラクタ
jpegreader::jpegreader(Void) static_throws
{
    if (static_try()) {
        static_throw(RegisterHandler(
            SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END),
            XANDLER_INTERNAL(OnKey)
        ));
    }
    if (static_try()) {
        static_throw(LoadImage(SFXPath("version.jpg")));
    }
}

// デストラクタ
jpegreader::~jpegreader(Void)
{
}


// パスから JPEG 画像の読み込み
SFCError jpegreader::LoadImage(SFXPathConstRef path)
{
    SFXFile   file;
    UInt32    size;
    SFCError  error(SFERR_NO_ERROR);

    // SFBImage のインスタンスを取得する
    if ((_image = SFBImage::NewInstance(AEECLSID_JPEG, &error)) != null) {

        if ((error = file.OpenReadOnly(path)) == SFERR_NO_ERROR) {

            if ((error = file.GetSize(path, &size)) == SFERR_NO_ERROR) {

                // ファイルストレージからイメージを読み込む場合 
                // ExampleDirectFile(&file);

                // メモリストレージからイメージを読み込む場合 
                ExampleThroughMemory(&file, size); 
            }
        }
    }
    return error;
}

// ファイルストレージからイメージを読み込む
SFCError jpegreader::ExampleDirectFile(SFXFilePtr file)
{
    // ダミーのコールバック関数を登録する
    _image->Notify((PFNIMAGEINFO)read_finished, this);

    // ファイルストレージのストリームを設定する
    return _image->SetStream(*file);
}

// メモリストレージからイメージを読み込む
SFCError jpegreader::ExampleThroughMemory(SFXFilePtr file, UInt32 size)
{
    SFXBuffer  buffer;
    VoidPtr    ptr;
    SFXMemory  memory;
    SFCError   error(SFERR_NO_ERROR);

    if (size > 0) {

        if ((error = buffer.SetSize(size)) == SFERR_NO_ERROR) {

            ptr = buffer.Detach();

            if ((error = file->Read(ptr, &size)) == SFERR_NO_ERROR) {

                if ((error = buffer.Attach(ptr, size)) ==SFERR_NO_ERROR) {

                    if ((error = memory.Open(buffer)) == SFERR_NO_ERROR) {

                        // ダミーのコールバック関数を登録する
                        _image->Notify((PFNIMAGEINFO)read_finished, this);

                        // メモリストレージのストリームを設定する
                        error = _image->SetStream(memory);
                    }
                }
            }
        }
    }
    else {
        error = SFERR_FAILED;
    }
    return error;
}

// 実際のコールバック関数(実体: イメージを描画する)
Void jpegreader::OnImage(Void)
{
    SFXRectangle  rx;
    AEEImageInfo  info;

    rx.Set(GetLocalBound());

    _image->GetInfo(&info);

    // イメージを描画する
    _image->Draw((rx.GetWidth() - info.cx) / 2, (rx.GetHeight() - info.cy) / 2);

    return;
}

// ダミーのコールバック関数(PFNIMAGEINFO 型)
Void read_finished(VoidPtr reference, IImage* /* image*/, AEEImageInfo* /* info*/, SIntN /* error*/)
{
    // 実際のコールバック関数を呼び出す
    static_cast<jpegreaderPtr>(reference)->OnImage();

    return;
}

// キー ハンドラ
XANDLER_IMPLEMENT_BOOLEVENT(jpegreader, OnKey, invoker, event)
{
    unused(invoker);
    switch (event.GetP16()) {
        case AVK_SELECT:
            Terminate();
            return true;
    }
    return false;
}

[Caution] SFBImageSmp インスタンス変数

ダミーのコールバック関数を登録する SFBImageSmp インスタンス変数 _image は、jpegreader クラスのクラス変数として定義します。

_image を jpegreader::LoadImage 関数のローカル変数として定義した場合、 jpegreader::LoadImage 関数を終了した段階でスコープから外れるので、スマートポインタである _image は解放されてしまいます。 その結果、ダミーのコールバック read_finished 関数は呼び出されません。

[Note] コールバック関数

上の例では、ダミーのコールバック read_finished関数は freind 関数として定義され、 実際に JPEG 画像を描画する処理(コールバック関数の実体)は、read_finished 関数から呼び出される jpegreader::OnImage 関数内に実装します。

全体のサンプルコードはこちら ( jpegreader.zip : 99.7kb ) にあります。

21.1.4. ラッパーの実行速度

ラッパークラスには、BREW インターフェースを C++ で単純にラップしたインライン関数と SophiaFramework UNIVERSE のクラスを引数とする関数があります。

インライン関数はコンパイル時にインライン展開されるので、実行時に速度が低下することはありません。

例 21.10. IShell インターフェースの ISHELL_GetAppCopyright 関数

// BREW ネイティブ API
int ISHELL_GetAppCopyright(IShell* pIShell, AECHAR* pBuff, int nSize);

// BREW API 関数を単純にラップしたインライン関数
SInt32 SFBShell::GetAppCopyright(WCharPtr buf, SInt32 size);

// SophiaFramework UNIVERSE のクラスを引数とする関数
SInt32 SFBShell::GetAppCopyright(SFXWideStringPtr string);

この関数は引数として WChar 型文字列を格納するバッファへのポインタを与えます。

インライン関数はネイティブ BREW API を単にラップしたものです。 この関数をソースコード中で使用しても、コンパイル段階でネイティブ BREW API 呼び出しに展開されるため、速度低下は発生しません。

SophiaFramework UNIVERSE のクラスを引数とする関数では、SFXWideString などが使えるように拡張されています。 この場合、引数に指定された SFXWideString クラスで指定されたサイズのバッファを内部的に確保するなどのオーバーヘッドが発生するため、 速度はその分だけ遅くなります。