2006年01月31日

UID

UID とは Symbian OS 上で動作するアプリケーションを特定するための ID です。各アプリケーションが一意の ID 保持しています。自作アプリの外部公開を目指す人はこの UID を取得する必要があります。uid AT symbiandevnet.com にメールで問い合わせます。
posted by シンビアン at 17:19| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

エミュと実機のビルド

エミュと実機でビルドの条件を少しだけ変えたい場合は以下のようにする。(NextTrain60 から引用)

#if __WINS__
_LIT(KTbls, "C:\\nexttrain60\\tbls\\");
#else
_LIT(KTbls, "E:\\nexttrain60\\tbls\\");
#endif

エミュレータのときは "_LIT(KTbls, "C:\\nexttrain60\\tbls\\");" がコンパイルされる。
posted by シンビアン at 17:15| Comment(1) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

UIDの変更箇所

本格的なアプリケーション開発を行うようになると UID が必要になってくる。アプリケーションを開発するときはサンプルコードを改造したり、Application Wizard を用いて開発することが多いと思う。どっちにしても UID を後から設定する必要がある。(ちなみに筆者は Application Wizard でうまく設定出来たためしがない…。)以下のファイルを編集する

* 〜Application.h
* 〜Aif.rss
* 〜.mmp
* 〜.pkg
posted by シンビアン at 17:12| Comment(1) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

日本語リソースの設定

Series60青本の230ページあたりに詳しい記述があるが、日本語(2バイト?)を取り扱うときは以下の点にも注意する必要がある。

* *.loc ファイル中に CHARACTER_SET UTF8 を記述する。*.loc ファイルそのものも UTF-8 形式にする
* 各言語のリソースを記述する *.l01 ファイルなども UTF-8 形式にする

ちなみに日本語の場合だと *.l32 になる。

*.pkg ファイルの記述を工夫すると各言語セットごとにファイル構成を変えることが出来る。これにより、各国に合わせたビットマップや音声などをセットアップすることが出来る。
posted by シンビアン at 17:11| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

ファイルの読み込み

# BOM の取り扱い

日本語を取り扱うときは UTF-8 形式のファイルを取り扱う必要がある。UTF-8 形式のファイルはファイルの先頭にBOMが付加されているのでファイルを読み込ませるときは予め、この部分を飛ばしてから読み込ませる必要がある。
# UTF-8 -> UNICODE

内部的には UNICODE で処理されているので UTF-8 を UNICODE に変換する必要がある。具体的には以下のAPIを使って変換する。

const TInt returnValue=CnvUtfConverter::
ConvertToUnicodeFromUtf8(unicodeOutputBuf, utf8Buf);
posted by シンビアン at 17:10| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

Designing C++ Applications for Series 60

用語集
このドキュメントでは、以下の用語および略語が使用されています。
用語 説明
Avkon Series 60 エクステンションおよび Uikon とその他 Symbian OS アプリケーションフレームワークへの変更
Uikon すべての Symbian OS デバイスに共通の UI およびコントロールのフレームワーク
posted by シンビアン at 17:05| Comment(1) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

Resource Struct RSS_SIGNATURE

RSS_SIGNATURE
Support

Supported from 6.0
Description

A utility struct that, used as the first resource in a resource file, provides a way to record what the resource offset is.

It contains two 32-bit fields: a version number and a self-referencing link. The RResourceFile::ConfirmSignatureL() function reads the signature resource and initialises the offset value from this resource.
See also:

* RResourceFile::ConfirmSignatureL()

LONG signature=EEikResourceSignatureValue;

A resource file version number.
SRLINK self;

A link to the current resource (i.e. itself). This should not be assigned a value.
posted by シンビアン at 17:01| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

Series 60 アプリケーションフレームワーク

オプションメニューの使用
4.1 オプションメニュー
Avkon オプションメニューは、 .rss ファイルに指定されているメニューバーとメニューペインから構築されます。メニューは、 EAknSoftkeyOptions ID によりバインドされている場合 WINS エミュレータの 'F1' キーまたは 'Options' ソフトキーの操作に応じて開きます。既存の 'Options' ソフトキーペインを使おうとするアプリケーションビューは、 R_AVKON_SOFTKEYS_OPTIONS_BACK CBA リソースを使用するべきです。
4.2 メニューセクションの定義
メニューペインセクションは MENU_PANE リソースストラクチャとして定義されます。メニューペインはそれぞれのメニューセクションに定義されるべきです。ひとつのセクションはそれぞれのメニューペイン領域:システム、アプリケーション、ビュー、コンテキストに使用されます。

メニューペインは次のように定義されます。

RESOURCE MENU_PANE r_system_menu
{
items =
{
MENU_ITEM { command = ECmdCut; txt = "Cut"; },
MENU_ITEM { command = ECmdCopy; txt = "Copy"; },
MENU_ITEM { command = ECmdPaste; txt = "Paste"; }
};
}

サブメニューペインは、サブメニューペインのリソース名を使って cascade パラメータにより指定できます。

例:

MENU_ITEM { command = ESystemOptions; txt =
"System Options"; cascade = r_system_options_menu; }

4.3 メニューセクションの組合せ
メニューセクションは MENU_BAR リソースにより結合されます。 これはメニューを構成するために結合されるすべてのセクションを表示します。メニューペインは、最後のセクションから先頭のセクションの順で定義されます。

メニューバーは次の様に定義されます。

RESOURCE MENU_BAR r_menuapp_menu
{
titles =
{
MENU_TITLE { txt = "System"; menu_pane =
r_system_menu; },
MENU_TITLE { txt = "App"; menu_pane =
r_app_menu; },
MENU_TITLE { txt = "View"; menu_pane =
r_view1_options_menu; },
MENU_TITLE { txt = "Context"; menu_pane =
r_context1_menu; }
};
}

オプションの txt パラメータは、明確にすることのみを目的としており、画面上ではまったく表示されません。但し、これらパラメータはリソースファイルには保存されます。

デフォルトメニューバーは EIK_APP_INFO リソースにより参照されます。これはアプリケーションの起動時に提供されるメニューバーです。

ビューアーキテクチャが使用される場合は、ビューのリソースストラクチャ内に各ビューのメニューリソースを設定するオプションがあります。
4.4 メニューセクションの変更
アプリケーションが使用するメニューバーリソースを変更することによりアプリケーション内でいつでもメニューセクションを変更することができます。

iEikonEnv->AppUiFactory()->MenuBar()->
SetMenuTitleResourceId(MENU_BAR_RESOURCE_ID);

これは、セクションの中のどれかひとつの内容を変更する必要があるたびに実行されるべきです。従って、考えられるメニューセクションの組合せの数だけ MENU_BAR リソースが定義されているべきです。つまり、ひとつのメニューバーは、ビューとコンテキストオプションの各組み合わせごとに定義されるべきだからです。

なお、ビューアーキテクチャが使用されていて、そのビュー自体のメニューシステムが現在使用されている場合、それは変更が必要なメニューバーの内容となります。

iMyView->MenuBar()->SetMenuTitleResourceId
(MENU_BAR_RESOURCE_ID);

4.5 メニューアイテムの変更
個々のメニューアイテムは、メニューが表示されるたびに変更される可能性があります。これにより、アプリケーションはアプリケーションの状態に応じてメニューアイテムを追加したり、削除したりできます。

アプリケーションUIは下記の仮想関数をオーバーライドするべきです。

void DynInitMenuPaneL
(TInt aResourceId, CEikMenuPane* aMenuPane);

これは、セクションのそれぞれがメニューに追加された後にコールされます。そして、追加されたセクションとビルドされているメニューペインのリソース ID でコールされます。

アプリケーションUIは下記の仮想関数もオーバーライドできます。

void DynInitMenuBarL
(TInt aResourceId, CEikMenuBar* aMenuBar);

これは、どんなセクションがメニューに追加される場合でもその前にコールされます。これはメニューに追加されるセクションを動的に変更するのに使用できます。つまり、コンテキストメニューセクションのリソース ID をあるアプリケーションの状態のために変更するために使用できます。
posted by シンビアン at 13:51| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

Series 60 アプリケーションフレームワーク

ベースクラス
3.2.1 CAknDocument

このクラスはアプリケーションドキュメントのベースクラスとして提供されます。このクラスを使うことにより、アプリケーションドキュメントファイルへのアクセスは開始されません。これは、大多数の Avkon アプリケーションでは許容されます。
3.2.2 CAknAppUi

すべての Avkon アプリケーション( Eiksrv とは別)はこのクラスから派生しなければなりません。

このクラスはいくつかの Avkon 固有の機能をサポートしています。これら機能については、 SDK 説明書で詳しく解説されています。

* KeySound サポート
* CBA ペインと ステータスペインのアクセサリー
* TextResolver - CAknAppUi::HandleError() から報告される Avkon 特有のエラー
* Avkon ビューアーキテクチャインテグレーション
* コントロールダンピング- デバッグ機能

3.2.3 CAknViewAppUi

すべてのビューアーキテクチャに基づくアプリケーションは、このクラスから派生しなければなりません。詳細は SDK 説明書に記載されています。
posted by シンビアン at 13:48| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

Series 60 アプリケーションフレームワーク

CEikApplication から派生する CAknApplication クラスが提供されます。このクラスは再実装により CEikApplication を特化させます。

* PreDocConstructL()
* OpenIniFileLC(RFs& aFs)

PreDocConstructL はまず構築中のアプリケーションのインスタンスが既に存在していないかどうかチェックするために実装されます。もしもそのインスタンスが既に存在する場合は、アプリケーションは存在するインスタンスに切り替え、その後終了します。このチェックは非埋め込みアプリケーションに対して行われます。

デフォルトでは、 Series 60 アプリケーションは、 .ini ファイルをサポートしていません。 OpenIniFileLC は、コールされるとただリーブする単純な実装によりオーバーライドされます。 .ini ファイルが使用される場合、アプリケーションはそのアプリケーションクラス内でこのメソッドを実行することを強制され、 CEikApplication::OpenIniFileLC をコールします。
posted by シンビアン at 13:45| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

2006年01月14日

デストラクタ

C++言語などのオブジェクト指向言語で作成したプログラムにおいて、オブジェクトが破棄される時に呼び出される特殊な関数。そのオブジェクトのために確保した占有メモリ領域を開放して再利用できるようにする処理などを行なう。Java言語ではオブジェクトの破棄は実行環境(Java仮想マシン)が自動的に行なうので、デストラクタは必要ない。
posted by シンビアン at 17:20| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

メモリリーク

コンピュータの動作中に、使用可能なメモリ容量がだんだん減っていく現象。OSやアプリケーションソフトが処理のために占有したメモリ領域を、なんらかの理由で解放しないまま放置してしまうために起きる。多くの場合、OSのメモリ管理方法に問題があったり、アプリケーションソフトに不具合(バグ)が残っていたりすることが原因である。メモリリークにより利用可能なメモリ領域が減少すると、システムの性能が低下したり、不安定になったりする。これを解消するには、システムを再起動する必要がある。
posted by シンビアン at 17:15| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

has-a関係

複合オブジェクトとそれを構成する部品オブジェクトとの関係をpart-of関係と呼ぶことがあります。部分は全体の一部なので「部分はpart-of全体」という表現方法が自然にできるからです。

 「Aはpart-of B」かつ「Bはpart-of C」ならば「A はpart-of C」なので、part-of関係は推移律が成立します。またis-a関係と同様、part-of関係も階層構造を持つことができます。この関係はhas-a関係と呼ぶこともあります。この場合、part-of関係と主語が反対になり「全体has-a部分」と表現することができます。全体が部分を保有しているという意味です。

【複合オブジェクトの例】

 例えば、車はボディ、シャーシ、エンジンなどさまざまな部品で構成されています。さらに、ボディは運転装置、内装、照明などで構成されています。つまり、車というオブジェクトは複合オブジェクトであり、車を構成する部品自体も、より小さな部品で構成される複合オブジェクトであると考えることができます
posted by シンビアン at 17:13| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

オーバーロード

プログラミングにおいて、戻り値や引数の数やデータ型(シグネチャ)が異なる同名の関数やメソッドを多重定義すること。

 オーバーロードにより、引数の型が異なる関数を複数定義することができ、多重定義された関数が呼び出される際には呼び出し側の引数の型に応じて適切な関数が呼び出すことができる。

 これは、関数を呼び出す立場から見ると関数に与えるデータ型を変えることで関数の挙動が変化するように見える。例えば、関数の引数が10個定義してあるものの、最低限必要なものは4個であり、それ以外の変数は必要に応じて用いる、といった状況に対応できる。
posted by シンビアン at 17:08| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

クリーンアップスタック

コンストラクション(Cクラス)

 次に、Cクラスのオブジェクトのコンストラクションに話を移しましょう。オブジェクトのコンストラクションに絡めて、クリーンアップスタックについて見ていきます。
前回の記事でも多少触れさせていただきましたが、クラスのインスタンスを作成する時は通常、「2フェーズコンストラクション」を行います。2フェーズコンストラクションは、具体的には

* new(ELeave)演算子を用いてクラスのインスタンスが必要とするメモリを確保する。この新たにオーバーロードされている演算子はリーブを発生させる可能性がある。

* 作成したインスタンスが他のオブジェクトを所有する場合(つまりhas-aポインタを持つ場合)は、概ねConstructLという名前の関数でポインタの参照先インスタンスの生成とポインタの値の設定を行う。

という流れになります。若干厄介に見えますが、これはメモリリーク対策になります。またまた繰り返しになりますが「メモリの確保が最もリソース不足によるエラーを起こしやすい」に注意してください。

携帯環境ですから、非常にリソースが限られています。ですから、小さなオブジェクトの確保でも失敗をする可能性があるわけです。小さなコードで、初期化に失敗する可能性を考えるのであれば(これは携帯環境では十分に考えられる)、各々のポインタに対して、nullチェックを行う必要があります。これでは、プログラムを書くのが手間になってしまいます。また、リーブの機構があるのですからこれを使わない手はありません。

そこで、例外処理をすっきりさせるため、先ほど出てきたリーブの仕組みを使うことを考えます。つまり、new(ELeave)を用いてメモリの確保を行います。このオペレータは先述の通り、メモリ確保に失敗するとリーブを発生させます。

つまり、リーブが発生した時点でTRAPマクロやTRAPDマクロで処理される箇所までスタックを遡るわけです。後のコードでリーブが発生した場合、前のコードが一時的な作業用のauto変数(コンストラクタの中であったとしても十分にあり得る)であれば、そのポインタが永遠に失われ、結果としてメモリリークの原因になります。

そこで、次のような対策を講じます。

1. CBaseクラスを継承したクラス(ClassA(前のコード))の使用するメモリのみを確保する(コンストラクタでは何も行わない)。メモリの確保に失敗すれば、リーブを発生させる。

2. ClassAによって所有される他のクラス(has-aポインタでの参照先)は、他のコンストラクション用の関数(一般にConstructL)で初期化する。ここでもリーブが発生する可能性がある。

3. 1または2でリーブが発生した場合、構築途中のオブジェクトへのポインタが失われないようにグローバルな領域(スタック)にポインタの値をコピーしておく(このスタックをクリーンアップスタックと呼ぶ)。

それでは、2フェーズコンストラクションのサンプルを見てみましょう

CMyObj* CMyObj::NewL(CConstructionContainer* aContainer )
{
CMyObj* ptr = new(ELeave)CMyObj; // インスタンスが使用するメモリの確保
CleanupStack::PushL( ptr );
// (1)以下の処理でリーブが発生したときに備えクリーンアップスタックにpush
ptr->ConstructL(aContainer); // インスタンスのメンバの初期化
CleanupStack::Pop();
// リーブの可能性がなくなったので、クリーンアップスタックからpop
return ptr ;
}

void CMyObj::ConstructL(CConstructionContainer* aContainer)
{
this->iContainer = aContainer ;
TInt reason = KErrNoMemory; // 勝手にメモリがないことにする
User::Leave(reason); // リーブを発生(2)
aContainer->UpdateMessage(_L("初期化完了") ); // この行は実行されない
}

CMyObj::~CMyObj()
{
this->iContainer->UpdateMessage(_L("CMyObj 削除完了"));
}

ここでは(1)にて構築途中のオブジェクトをクリーンアップスタックにプッシュし、第二フェーズのコンストラクションの(2)において意図的にリーブを発生させています。ここでクリーンアップスタックの重要な動作として、
リーブが発生したとき、クリーンアップスタックに詰まれた
全てのオブジェクトのデストラクタが呼び出される
という点に注意してください。つまり、2フェーズ目で構築に失敗し、リーブが発生しても、クリーンアップスタックにメモリ確保時に取得したポインタを積んでおけば、自動的にデストラクタが呼び出されるということです。そして、リーブ時にデストラクタを呼び出すためにCBaseクラスに仮想デストラクタが定義されているわけです。

ただし注意点として、リーブ発生時にはクリーンアップスタックに詰まれた全てのオブジェクトがデストラクトされます。つまり、

リーブが発生する可能性が無くなった時点でクリーンアップスタックから取り除く

必要があります。将来、全く別の理由でリーブが発生した場合、問題のないオブジェクトまでデストラクションする可能性があるためです。
posted by シンビアン at 17:01| Comment(0) | TrackBack(0) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

例外処理(リーブ)

例外処理を見ていきましょう。また、例外処理に関連して2フェーズコンストラクションについて見ていきたいと思います。このセクションをお読みになるにあたり、しつこいですが「携帯環境のリソースは非常に限られたものを想定している」というのを頭の片隅において置いてください。

 Series60では通常のC++によるtry-catch構文とは異なる例外処理の機構を利用します。これは通常のtry-catchによる例外処理が結果としてコードサイズの肥大化を招くためです。ですから、通常のtry-catchによる例外処理は採用されていません。

 そこで、try-catchの代用として出てくるのが「リーブ(Leave)」という考え方(機構、仕組みといっても良いかもしれません)です。リーブは、従来の例外と概念的にはほぼ同一です。以下にリーブについて概略をまとめます。

* C++の例外の代わりに使用される
* リソースエラー等が発生すると、コードはリーブする
* トラップハーネス(TRAPマクロやTRAPDマクロ)でリーブが処理されるまで関数のスタックをさかのぼる

リーブによる例外処理の例
次のサンプルを見てみましょう。このサンプルでは、メニューから「リーブのテスト」を選ぶと、意図的にメモリ不足のリーブが発生するようになってます。

// コード例(A)
void CLeaveSampleAppUi::HandleCommandL(TInt aCommand)
{
switch ( aCommand )
{
/// 中略….
case ELeaveSampleCmdAppTest:
{
// 次の関数の呼び出しはリーブを発生させる
this->iAppContainer->TestLeaveL();
break;
}
// 後は省略….

このTestLeaveL()関数の実装は次の通りです。

// コード例(B)
void CLeaveSampleContainer::TestLeaveL()
{
TInt reason = KErrNoMemory; // 勝手にメモリがないことにする
User::Leave(reason); // (1)例外を発生
this->iToDoLabel->SetTextL(_L("問題なく終了しました"));
// 上の一行は実行されない
}
このサンプルでは、(1)においてメモリ不足のリーブを意図的に発生させています(User::Leave関数でリーブを発生)。
それでは、このアプリケーションに対して例外処理のコードを加えたいと思います。上記コード例(A)を次のように書き換えてみてください。
// コード例(C)
void CLeaveSampleAppUi::HandleCommandL(TInt aCommand)
{
switch ( aCommand )
{
/// 中略….
case ELeaveSampleCmdAppTest:
{
// TRAPDマクロで例外を捕捉
// error に例外コードが入ってくる
TRAPD( error,
this->iAppContainer->TestLeaveL(); );
if( error != KErrNone ){ // 例外が発生しているかを検査
this->iAppContainer->UpdateMessage();
}
break;
}
// 後は省略…
TRAPDマクロの第一引数にあるerrorに例外が発生した理由が格納されます。これをKErrorNone(つまり例外が発生しなかったことを表す)と比較しているわけです。

 もう少しリーブについて見ていきましょう。例外処理自体は、このような形で行うことができます。次に残る問題は「作成した関数、またはAPIで提供されている関数がリーブを発生させるか否か、コンパイラレベルでは判断できない」点にあります。リーブの機構はC++の言語ではなく、Series60で採用されているものです。つまり、例外を適切に処理するのであれば、先のコード例(A)を本来はコード例(C)のようにしなくてはいけません。しかし、コード例(A)のままでも問題なくコンパイルが可能ですし、警告も表示しません。

 そこで出てくるのが関数のコードコンベンションです。今回はコード例(B)で定義した関数は最後に「L」の付く関数になっていますが、一般にリーブを発生させる可能性のある関数はその名前の最後に「L」を付ける習慣になっています。このような「L」の付く関数に関しては(製品としてプログラムを出す場合は)必ずTRAPマクロや今回の様にTRAPDで処理をする必要があります。

補足:今回はリーブによる例外処理を見ていきましたが、一部のAPIには戻り値によって正常/異常終了を表すもあります。
posted by シンビアン at 16:05| Comment(0) | TrackBack(1) | Series60プログラミングテクニック | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は1年以上新しい記事の投稿がないブログに表示されております。