リファレンスに記載されていないエラー番号の内容は … ?
SophiaFramework が返すエラー ( SFCError 型 ) に関して、その番号が [ 0x0000 〜 0x3FFF ] の範囲にあるものでリファレンスに記載のないものは BREW プラットフォームが返したエラーです。
これらのエラーの詳細内容については、BREW SDK に含まれる AEEError.h というファイルをご覧になってください。
C++ で作成されたBREW アプリで、アプリ終了や例外処理などのプログラム全般の処理を行う方法です。
SophiaFramework を用いています。
SophiaFramework が返すエラー ( SFCError 型 ) に関して、その番号が [ 0x0000 〜 0x3FFF ] の範囲にあるものでリファレンスに記載のないものは BREW プラットフォームが返したエラーです。
これらのエラーの詳細内容については、BREW SDK に含まれる AEEError.h というファイルをご覧になってください。
SFXBrewPointer クラスは BREW インターフェースのインスタンスを自動管理するためのスマート ポインター クラスです。このクラスはテンプレート クラスとなっており、ラッパー クラスの種類だけ自動的に型が生成されます。
ラッパー クラスのインスタンスは、スマート ポインターで自動的に管理されますので、 SFXBrewPointer クラスを明示的に使用する必要はありません。
以下のようにして、明示的に型を生成することも可能です。
■ SFXBrewPointer クラスの使用方法Void SFXPointerExplainer::_SFXBrewPointer(Void) const { // 以下の 2 種類の変数宣言は同等 // ( 通常、記述しやすい Smp バージョンを利用する ) SFXBrewPointer<SFBDisplay> display1; SFBDisplaySmp display2; // ラッパー クラスのインスタンスの生成は、 // 各ラッパー クラスの NewInstance() 関数または // GetInstance() 関数を利用する // ( スマート ポインターがインスタンスを管理するので、解放処理は不要 ) SFBGraphicsSmp graphics; SFBGraphicsPtr raw_graphics; if ((graphics = SFBGraphics::NewInstance()) != null) { // インスタンスの取得成功 } // 管理しているインスタンスの生ポインターの取得 raw_graphics = graphics.Get(); // スマート ポインターの比較 if (display1 == display2) { } if (display1 != display2) { } // スマート ポインターと生ポインターの比較 if (graphics == raw_graphics) { } // null ポインターとの比較 if (graphics != null) { } // 他の型を表すスマート ポインター同士の比較 // ( 推奨されないが、設計上可能 ) if (graphics != display1) { } // スマート ポインターが管理するインスタンスのポインターのキャストは、 // static_pointer_cast 演算子などを利用する // ( static_cast 演算子を利用してはいけない ) SFBBaseSmp base; SFBBitmapSmp bitmap; base = bitmap; bitmap = static_pointer_cast<SFBBitmap>(base); // 空インスタンスの取得 // ( 関数の戻り値として空のインスタンスへの参照を返す場合に便利 ) SFBFileSmpConstRef file(SFBFileSmp::EmptyInstance()); unused(file); // 管理しているインスタンスの明示的な解放 SFBFileMgrSmp filemgr; if ((filemgr = SFBFileMgr::NewInstance()) != null) { // SFXBrewPointer クラスの Release() 関数を呼び出す filemgr.Release(); // SophiaFramework 3.0 以上では // SFBBase (IBase) クラスの AddRef(), Release() 関数を呼び出せない /* filemgr->Release(); */ } return; }
SophiaFramework には AEEApplet 構造体が存在しません。
SophiaFramework で AEEApplet に相当するクラスは、SFCApplet クラスですが、このクラスは IApplet クラスを独自に拡張した変数の並びとなっています。
そのため、SFBApplet::GetInstance() 関数や SFXHelper::getinstance() 関数を利用しても SFCApplet 構造体へのポインタが返ってくるので互換性はありません。
例えば、BREW エクステンション側が単純に IDisplay へのポインタを必要としているのであれば、以下の例のようにアプリ内で自前の AEEApplet 構造体を確保し、メンバを初期化した後、その AEEApplet 構造体へのポインタを渡すという方法が考えられます。
AEEApplet _brew_applet; _brew_applet.m_pIDisplay = interface_cast(SFXGraphics::GetSFBDisplay().Get()); 3d_function(3d, &_brew_applet, ...); // 必要に応じて他のメンバも初期化して渡します。
※ この方法は、エクステンション側がインターフェースへのポインタを単純に参照するだけの場合は有効ですが、アプレット自身の参照カウンタを変更するような特殊な場合には正常に動作しない可能性があります。
SophiaFramework 4.1.7 から atomic_cast 演算子が利用可能になりました。
atomic_cast 演算子は、図形と色など AtomRec 構造体が定義されるクラスのポインターと、そのクラスの AtomRec 構造体のポインターを相互に変換するための型変換演算子です。
atomic_cast 演算子により、クラスのポインターは AtomRec 構造体のポインターへ、AtomRec 構造体のポインターはクラスのポインターへそれぞれ型変換されます。
以下は、atomic_cast 演算子を使ったサンプル コードです。
Void my_func(SFXRectangle rects[2]) { // 何らかの処理 ...... } SFXRectangle::AtomRec rects[] = { {0, 0, 100, 100}, {0, 0, 50, 50} }; my_func(atomic_cast(rects));
SophiaFramework 4.1.7 から、BREW SDK 4.0.0 用新規プロジェクトを作成できるようになりました。CheckAvail 関数が BREW SDK 4.0.0 では正常に動作しないため、BREW SDK 4.0.0 を使う場合、サンプルコードで CheckAvail 関数が呼び出されないように変更しました。また、BREW SDK 4.0.0 ではモジュール名が 21 文字を超えると発生するエラーとなるため、すべてのサンプルコードのモジュール名を 21 文字以下としました。
※制約事項:
BREW SDK 4.0.0 API のラッパーは提供されていません。SophiaFramework 4.1.8 以降で、提供する予定です。
■ BREW SDK 4.0.0 で開発する手順
Step 1 : Qualcomm 社サイトから BREW 4.0.0 SDK をダウンロードし、インストールします。
Step 2 : SophiaFramework 4.1.7 をインストールします。
Step 3 : 環境変数を更新するため、再起動します。
Step 4 : SophiaFramework のリンカのファイルを変更します。
Visual C++ 6.0 の場合 :
[プロジェクト] -> [設定] -> [リンク] -> [オブジェクト / ライブラリ モジュール] で [SophiaFrameworkBrew310VC6.lib] を [SophiaFrameworkBrew400VC6.lib] に変更します。
.NET の場合 :
[プロジェクト] -> [(プロジェクト名)のプロパティ] -> [リンカの入力] -> [追加の依存ファイル] で [SophiaFrameworkBrew310NET.lib] を [SophiaFrameworkBrew400NET.lib] に変更します。
Step 5 : アプリをコンパイルします。
※ AEEIramCache および AEEIRecordStore に関してコンパイラ エラーが発生します。このエラーは、BREW SDK 4.0.0 の不具合です。
以下のように変更すれば、コンパイラ エラーを回避できます。
■変更前
static __inline int IRAMCACHE_Find(IRamCache* piRamCache,
const char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRamCache,IRamCache)
->Find(piRamCache,
cpKey, nKeyLen,
pVal, pnValLen);
}
■変更後
static __inline int IRAMCACHE_Find(IRamCache* piRamCache,
const char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRamCache,IRamCache)
->Find(piRamCache,
cpKey, nKeyLen,
static_cast<char *>(pVal), pnValLen);
}
■変更前
static __inline int IRECORDSTORE_Find(IRecordStore* piRecordStore,
const char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRecordStore,IRecordStore)
->Find(piRecordStore,
cpKey, nKeyLen,
pVal, pnValLen);
}
■変更後
static __inline int IRECORDSTORE_Find(IRecordStore* piRecordStore,
char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRecordStore,IRecordStore)
->Find(piRecordStore,
cpKey, nKeyLen,
static_cast<char *>(pVal), pnValLen);
}
Step 6 : もう一度、コンパイルします。
【注意事項】
1) SophiaFramework 4.1.7 では BREW 4.0.0 API ラッパーは提供されていません。
[対策] SophiaFramework 4.1.8 以降で提供される予定です。
2) BREW 4.0.0 SDK には KDDI_FONT_FIXED16X16 が含まれないため、pclock アプリはコンパイルできません。
SophiaFramework 4.1.6 では、一部 BREW SDK 4.0.0 に対応しています。BREW SDK 3.1 以前の環境で開発した SophiaFramework アプリをコンパイルし実行できます。
※制約事項:
BREW SDK 4.0.0 用の新規プロジェクトは作成できません。また、BREW SDK 4.0.0 API のラッパーも提供されていません。SophiaFramework 4.1.7 以降で、提供する予定です。
■ BREW SDK 4.0.0 で開発する手順
Step 1 : Qualcomm 社サイトから BREW 4.0.0 SDK をダウンロードし、インストールします。
Step 2 : SophiaFramework 4.1.6 をインストールします。
Step 3 : 環境変数を更新するため、再起動します。
Step 4 : SophiaFramework のリンカのファイルを変更します。
Visual C++ 6.0 の場合 :
[プロジェクト] -> [設定] -> [リンク] -> [オブジェクト / ライブラリ モジュール] で [SophiaFrameworkBrew310VC6.lib] を [SophiaFrameworkBrew400VC6.lib] に変更します。
.NET の場合 :
[プロジェクト] -> [(プロジェクト名)のプロパティ] -> [リンカの入力] -> [追加の依存ファイル] で [SophiaFrameworkBrew310NET.lib] を [SophiaFrameworkBrew400NET.lib] に変更します。
Step 5 : アプリをコンパイルします。
※ AEEIramCache および AEEIRecordStore に関してコンパイラ エラーが発生します。このエラーは、BREW SDK 4.0.0 の不具合です。
以下のように変更すれば、コンパイラ エラーを回避できます。
■変更前
static __inline int IRAMCACHE_Find(IRamCache* piRamCache,
const char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRamCache,IRamCache)
->Find(piRamCache,
cpKey, nKeyLen,
pVal, pnValLen);
}
■変更後
static __inline int IRAMCACHE_Find(IRamCache* piRamCache,
const char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRamCache,IRamCache)
->Find(piRamCache,
cpKey, nKeyLen,
static_cast<char *>(pVal), pnValLen);
}
■変更前
static __inline int IRECORDSTORE_Find(IRecordStore* piRecordStore,
const char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRecordStore,IRecordStore)
->Find(piRecordStore,
cpKey, nKeyLen,
pVal, pnValLen);
}
■変更後
static __inline int IRECORDSTORE_Find(IRecordStore* piRecordStore,
char* cpKey, int nKeyLen,
void* pVal, int* pnValLen)
{
return AEEGETPVTBL(piRecordStore,IRecordStore)
->Find(piRecordStore,
cpKey, nKeyLen,
static_cast<char *>(pVal), pnValLen);
}
Step 6 : もう一度、コンパイルします。
【注意事項】
1) SophiaFramework 4.1.6 では、BREW 4.0.0 用の新規プロジェクトを作成できません。
[対策] SophiaFramework 4.1.7 以降で対応いたします。
2) SophiaFramework 4.1.6 では BREW 4.0.0 API ラッパーは提供されていません。
[対策] SophiaFramework 4.1.8 以降で提供される予定です。
3) BREW 4.0.0 用シミュレータでアプリ起動すると Unknown Error(1) が発生します。
以下のサンプルアプリで発生します。
−SyncScheduler
−psec
−Recog
−pself_dom
−pself_sax
[原因] CheckAvail 関数が BREW 4.0.0 では正常に動作しないためです。
[対策] CheckAvail 関数を使わなければ正常に動作します。
4) BREW 4.0.0 用シミュレータでアプリ起動すると Unknown Error(14) が発生します。
以下のサンプルコードで発生します。
−SFXCollectionExplainer
−SFXMathematicsExplainer
[原因] モジュール名が 21 文字を超えると発生するエラーです。
[対策] BREW 4.0.0 SDKでは、モジュール名は 21 文字以下にします。
5) BREW 4.0.0 SDK には KDDI_FONT_FIXED16X16 が含まれないため、pclock アプリはコンパイルできません。
SFRアプリは複雑なUIを構築するとき、SFCアプリは既存の BREW 標準のコードを流用するときに、それぞれ効果を発揮します。
■ SFRアプリのメリットとデメリット
<メリット>
・SophiaFramework独自の標準UIコンポーネントを利用できます。
・イベント処理はハンドラ形式になり、コードがすっきりします。
<デメリット>
・BREW 標準の UI クラスと相性が悪い部分があります。
( IHtmlViewer などはそのままでは使えません。 )
■ SFCアプリのメリットとデメリット
<メリット>
・UI の構築方法やイベントの処理方法が、BREW 標準のものとほぼ同じ構造です。
( IHtmlViewer などのインターフェースもラッパークラス経由でそのまま使えます。 )
<デメリット>
・SophiaFramework 付属の UI コンポーネントを利用できません。
・イベント処理がハンドラ形式ではなく、BREW 標準の分岐形式になり、コードが煩雑になります。
尚、文字列やコレクションなどのユーティリティクラスは SFR・SFC アプリとも利用可能です。
1.SFU??? で始まる SophiaFramework 2.x, SophiaFramework 3.x に関するクラスが利用されていないことを確認する。
※利用されている場合は、先にバージョン3.0 のコードを 4.0 に対応 させておく必要があります。
2.IndexOf() 関数を利用している個所を FirstIndexOf() 関数に置き換える。
3.引数を指定せずに利用している SFXArray , SFXStack , SFXList クラスの GetIterator() 関数と GetEnumerator() 関数を、GetFirstIterator() 関数と GetFirstEnumerator() 関数に置き換える。
4.コンパイルを行い、エラーを確認する。
エラーが発生しなければバージョン 4.1 への対応は完了です。
5.手順4でクラス、マクロや関数が見つからない旨のエラーが発生する場合は、下記表の非推奨 API を利用していないか確認する。
6.すべて修正できたら手順4へ
さらに、バージョン 4.1 に最適化するためには、SFXHashmap クラスを利用している個所を確認します。
バージョン 4.1 ではキーイテレータと値イテレータが搭載されましたので、従来独自に管理しなければいけなかった値オブジェクトのリストをこれらのイテレータを利用して管理できます。
非推奨 API 一覧
/*** クラス ***/ ・SFRBrewTextControl クラスは SFREditboxControl クラスに置き換え /*** マクロ ***/ #define alignof(type) align64of(type) #define clusterof(type) cluster64of(type) macro TYPE_<コンポーネント名> => TYPE_SFR<コンポーネント名> macro ATTRIBUTE_<コンポーネント名> => ATTRIBUTE_SFR<コンポーネント名> macro BEHAVIOR_<コンポーネント名> => BEHAVIOR_SFR<コンポーネント名> ・SFRBREWTEXTCONTROL に関するマクロは、すべて SFREDITBOXCONTROL に置き換え /*** 関数 ***/ ・以下の関数は非推奨 API です。それぞれの実装を参考に置換してください。 /*** SFXBuffer ***/ inline SFXBuffer Slice(UInt32 begin, UInt32 end) const { SFXBuffer result(*this); result.Slice(begin, end); return result; } /*** SFXRingBuffer ***/ inline VoidPtr LockWrite(UInt32Ptr size = null) { return GetWritableBuffer(size); } inline VoidPtr LockRead(UInt32Ptr size = null) { return const_cast<VoidPtr>(GetReadableBuffer(size)); } inline SFCError UnlockWrite(UInt32 size) { return SeekWrite(size); } inline SFCError UnlockRead(UInt32 size) { return SeekRead(size); } /*** SFXAscii ***/ inline static AChar ToUpper(AChar param) { return AsUpper(param); } inline static WChar ToUpper(WChar param) { return AsUpper(param); } inline static AChar ToLower(AChar param) { return AsLower(param); } inline static WChar ToLower(WChar param) { return AsLower(param); } /*** SFXAnsiString ***/ inline SInt32 ToSInt32(SInt32 substitute = 0) const { return AsSInt32(substitute); } inline UInt32 ToUInt32(UInt32 substitute = 0) const { return AsUInt32(substitute); } /*inline Void Rotate(SInt32 shift) { => removed }*/ /*** SFXWideString ***/ inline SInt32 ToSInt32(SInt32 substitute = 0) const { return AsSInt32(substitute); } inline UInt32 ToUInt32(UInt32 substitute = 0) const { return AsUInt32(substitute); } /*inline Void Rotate(SInt32 shift) { => removed }*/ /*** SFXShiftJIS ***/ inline static UInt16 WCharToUInt16(WChar param) { return AsUInt16(param); } inline static UInt16 UInt16ToWChar(WChar param) { return AsWChar(param); } /*** SFXRGBColor ***/ inline RGBVAL ToRGBVAL(Void) const { return AsRGBVAL(); } /*** SFXGraphics ***/ inline SFBGraphicsSmpConstRef GetGraphics(Void) const { return GetSFBGraphics(); } inline SFBDisplaySmpConstRef GetDisplay(Void) const { return GetSFBDisplay(); } /*** SFXDirectory ***/ inline static SFCError GetTemporaryPath(SFXPathConstRef path, SFXAnsiStringConstRef prefix, SFXAnsiStringConstRef suffix, SFXPathPtr result) { return GetUniquePath(path, prefix, suffix, result); } /*** SFXFile ***/ inline static SFCError GetTemporaryPath(SFXPathConstRef path, SFXAnsiStringConstRef prefix, SFXAnsiStringConstRef suffix, SFXPathPtr result) { return GetUniquePath(path, prefix, suffix + ".tmp", result); } /*** SFXConfig ***/ inline SFCError Load(SFXAnsiStringConstRef file) { return Load(SFXPath(file)); } inline SFCError Save(SFXAnsiStringConstRef file) { return Save(SFXPath(file)); } /*inline SFCError GetEntry(SInt32 index, UInt16Ptr tag, VoidConstHandle value, UInt16Ptr length) const { => removed }*/ /*** SFXDate ***/ inline UInt32 ToUInt32(Void) const { return AsUInt32(); } inline JulianType ToJulianType(Void) const { return AsJulianType(); } /*** SFXDateDuration ***/ inline SInt32 ToSInt32(Void) const { return static_cast<SInt32>(AsSInt64()); }
アプリ全体からアクセスする変数は、アプリクラスのメンバ変数として定義します。
例
class AppliClass : public SFRApplication { private: SInt32 _data; // アプリ全体からアクセスする変数 ... public: Void SetData(SInt32 data) { _data = data; } SInt32 GetData() { return _data; } };
データは任意の場所で取得、設定できます。
// アプリのインスタンスの取得 AppliClassPtr app; app = (AppliClassPtr)SFRApplication::GetInstance(); app->SetData(1); // データの設定 app->GetData(); // データの取得
バージョン 3.0 のコードを 4.0 に書き換えるときの手順は
1.ヘッダファイル中の HANDLER_DECLARE_??? マクロの第1引数 (クラス名) を削除する (変更後の引数は1つになる)。
// 修正前 HANDLER_DECLARE_VOIDVOID(CHelloWorld, OnKey) // 修正後 HANDLER_DECLARE_VOIDVOID(OnKey)
2.SFUIPEndpoint クラスを SFXSocketAddress クラスに置き換える。
3.SFUHostResolver クラスを SFXInetAddress クラスに置き換える。
4.コンパイルしてコンパイルが通るか確認する。
この時点で、 3.0 のクラスと 4.0 のクラスが共存した状態になっている。さらに 4.0 のクラスだけを利用する場合は、次へ進む。
5.コンパイラの設定やメイクファイルに
TARGET_COMPATIBILITY_ONLY400
マクロを設定する。
(SophiaFramework.hpp ファイルを読み込む前に #define してもよい。)
6.コンパイルしてエラーを確認する。
エラーが出力されず、正常に終了した場合は、すでに 4.0 のクラスに対応している。
7.alignof, clusterof マクロを align64of , cluster64of マクロに置き換える。
8.ToSInt32() 関数などが存在しないとエラーが出る場合は、AsSInt32() 関数などに適切に置き換える。(該当クラスのクラス定義ヘッダファイル *.h.hpp 中に新しい関数との対応関係が記述されています。)
例:SFXAnsiString::ToSInt32 関数は SFXAnsiString::AsSInt32 関数に変更する。
9.SFUHttpConnection クラスを SFXHTTPConnection クラスに置き換える。
10.SFUStream 系のクラス(SFUFileStream, SFUNetworkStream, SFUMemoryStream, SFUSourceStream)を SFXFile , SFXTCPSocket , SFXMemory , SFXSource クラスに置き換える。
BREW 環境では C++ 言語の例外を利用することができず、
コンストラクタ内部のエラーや演算子内部のエラーを外部で検知することができません。
SophiaFramework では static_exception クラスを利用して、統一的なエラー処理を行います。
static_exception クラスは、継承して使用します。
SFMTYPEDEFCLASS(myclass) class myclass : public static_exception{ public: explicit myclass(Void) static_throws; // static_throws キーワードは // この関数(コンストラクタ)の中でエラーが起こるかもしれないと // いうことを示す目印(実際には何もしない) private: SFCError Function(Void); // エラー値を返す関数 }; myclass::myclass(Void) { // 親クラスでエラーが発生してないかチェック if (static_try()) { // Function() 関数の戻り値(エラー値)を設定 static_throw(Function()); // エラーが発生していないかチェック if (static_try()) { ... } } return; }
このクラスの使い方
myclass my; // コンストラクタの中でエラーが起きているかもしれないので…
// エラーが起きているかを調べる
if (my.static_catch() == SFERR_NO_ERROR) {
// エラーは起きていない
...
} else {
// エラーが起きている
// my.static_catch() の戻り値でエラーの種類を知ることができる
}
参照 static_exception | static_exception::static_try | static_exception::static_throw
static_exception::static_catch
関数の引数に定数の構造体を渡す場合(例えば、SFXGraphics::SetForeColor 関数などに
SFXRGBColor クラスのインスタンスを渡す場合)、以下のように記述できます。
SFXGraphicsPtr graphics = SFXGraphics::GetInstance(); graphics->SetForeColor(SFXRGBColor(0xFF, 0x00, 0x00, 0x00));
この方法では、SFXRGBColor クラスのコンストラクタの分がオーバーヘッドになります。
SFXRGBColor クラスのコンストラクタを起動させずに、
定数を直接渡すには以下のように記述します。
static SFXRGBColor::AtomRecConst color = { 0x00, 0xFF, 0x00, 0x00 // 左から順に α、R、G、B }; SFXGraphicsPtr graphics = SFXGraphics::GetInstance(); graphics->SetForeColor(color);
このような構造体として、カラーの他にシェイプ クラスなどがあります。
参照 SFXGraphics::GetInstance | SFXGraphics::SetForeColor |
SFXRGBColor::AtomRecConst
SFXDate::CurrentDate 関数で取得できる時刻は秒単位です。
時間をミリ秒単位で取得するには、SFXHelper::gettimems を使用します。
UInt32 startms = SFXHelper::gettimems(); func(); // 測定したい処理 UInt32 endms = SFXHelper::gettimems(); SInt32 milisecTime = endms - startms; // milisecTime は // 測定した時間(ミリ秒単位)
画面のサイズを取得するには、SFXGraphics::GetDeviceRectangle 関数、または
SFXGraphics::GetDeviceSize 関数を使用します。
// 画面サイズが 横 240、縦 290 の場合 SFXRectangle rect = SFXGraphics::GetDeviceRectangle(); // rect は (x, y) = (0, 0), 幅 240, 高さ 290 となる SFXSize size = SFXGraphics::GetDeviceSize(); // size は 幅 240, 高さ 290 となる
参照 SFXGraphics::GetDeviceRectangle | SFXGraphics::GetDeviceSize
アプリを終了させるには、SFRApplication::Terminate 関数
(GUI フレームワークを使わない場合は SFCApplication::Terminate 関数)を使用します。
引数が true の場合、全ての BREW アプリケーションを終了し、 待ち受け画面に戻ります。
false の場合は現在アクティブなアプリケーションのみを終了し、 BREW アプリケーション センター画面に戻ります。
SFRApplication::Terminate(false); // アプリを終了させる SFCApplication::Terminate(false); // GUI フレームワークを使わない場合