eMbedded Visual Basic から Visual Basic .NET への移行

Microsoft Corporation

トピック

はじめに はじめに
開発の変更と向上の概要 開発の変更と向上の概要
ユーザー インターフェイス とアプリケーション ナビゲーション ユーザー インターフェイス とアプリケーション ナビゲーション
POCKET PC とスマートフォンの開発 POCKET PC とスマートフォンの開発
アプリケーション統合 アプリケーション統合
データベースでの動作 データベースでの動作
導入と配布 導入と配布
結論 結論

はじめに

このホワイト ペーパーでは、Microsoft® Windows® Pocket PC 2002 のソフトウェア開発を、Microsoft eMbedded Visual Basic® から Microsoft .NET Framework および Visual Basic .NET に移行する方法について説明します。

図 1 : 要素の関連性

開発基盤の関係. NET Compact Framework のリリースによって、サーバーおよびデスクトップ アプリケーションの開発で使用されるものと同じツールと言語を使用して、モバイル アプリケーションを開発できるようになります。

.NET Compact Framework は、.NET Framework 型と名前空間のサブセットで構成されています。また、Microsoft Visual Studio® .NET が持つスマートデバイス開発機能により環境の統合も行っています。この統合には、.NET Compact Framework で開発がサポートされているフォーム デザイナやデバイス エミュレータなどを含みます。ツールと言語の新しいプラットフォームと向上機能は、モバイル アプリケーションの開発、コード、実行、および導入の質を高める上で、有効な手段となります。 1 は、それぞれの開発基盤の関係を図示したものです。

基本的な変更

Microsoft eMbedded Visual Basic はリリース以降、アプリケーション開発環境として幅広く採用されてきました。Microsoft Visual Basic 6.0 との類似性、さらにその使いやすさで、多くの開発者に支持されています。しかし、本来の言語とプラットフォームへの依存性、複数の対処策やサードパーティ製品、さらには低レベルの Windows CE API 呼び出しが必要であるという制約がありました。新しい環境では、このような制約のほとんどが改善されていますが、一部に開発上の注意が必要な部分もあります。基本的な変更点として、Visual Basic .NET がオブジェクト指向のモダンな言語であることと、一般的な .NET Compact Framework のクラス ライブラリを使用してコードが構築されていることが挙げられます。このライブラリは、共通のメソッド、プロパティ、およびイベントを使った、Windows フォーム用の System.Windows.Forms やデータベース管理用の System.Data 等です。拡張された型などの共通タスクの固有サポート、クラスの使用、XML Web サービスの呼び出し、構造化された例外処理の実装により、従来、eMbedded Visual Basic の開発者側で効率改善が必要だった不足部分を解消しています。

アプリケーションのポーティング

既存の eMbedded Visual Basic コード ベースの自動的なアップグレード パスはありません。プラットフォームと言語の違いが大きすぎるので、このようなサポートをうまく効率的に設計および実装することができません。通常のポート作業の大半は、以下のようなものです

  • 言語文法 : eMbedded Visual Basic は、Visual Basic Script 言語なので、文法の違いも大小さまざまです。

  • 共通コードライブラリの実装 : ポートには、既存の eMbedded Visual Basic の共通コード ライブラリが必要です。現在では、クラスの使用がサポートされているので、コード ライブラリの実装および使用と異なる場合が多くなります。.NET Compact Framework は .NET Framework のサブセットなので、Pocket PC の開発に既存の Visual Basic .NET クラス ライブラリを利用できるようになります。

  • アプリケーションのナビゲーションと制御フロー : フォームの管理とアプリケーションのナビゲーションは、System.Windows.Forms の型によって処理され、eMbedded Visual Basic とは別に実装されます。

  • データベース : データ アクセスは、ADO.NET のサブセットによって処理されます。マイクロソフトは Microsoft SQL Server™ 2000 Windows CE Edition 2.0 (SQL Server CE 2.0 ) 用のマネージ データ プロバイダを提供しています。.NET Compact Framework には、eMbedded Visual Basic 開発者の間で広く使用されている、CEDB または Pocket Access とも呼ばれるローカル データ ストアにアクセスするためのマネージ型が含まれていません。

  • XML Web サービス : eMbedded Visual Basic は、リモート コンポーネントの呼び出しを組み込みサポートしていないため、リモート コンポーネントを呼び出して使用するには、サードパーティに頼る必要がありました。Web サービスのサポートは、.NET Compact Framework の中心となる型のひとつで、.NET Framework 全体の主要な統合メカニズムであると考えられます。通常、ほとんどの開発プロジェクトは、システム統合関連の作業が大半なので、システム統合コードの再記述は非常に有望です。

  • 例外処理 : eMbedded Visual Basic のエラー処理は、"On Error Resume Next" と、"If Err.Number <> 0 Then" ステートメントで構成されます。Try ... Catch ... Finally ブロックを使用した構造化され効率的な例外処理は、コードの堅牢性と耐障害性を高めます。

概要情報の詳細については、以下の英語ページをご覧ください。

開発の変更と向上の概要

プラットフォームの向上

eMbedded Visual Basic の開発は、eMbedded Visual Basic 専用のランタイム向けの独立した環境で行われます。.NET Compact Framework は、Visual Basic ランタイム環境を置き換えます。これは、開発者がプラットフォーム、言語、およびツール スキルを再学習する必要があることを意味します。ほとんどの変更の基本的なメリットは、「共通」という語に由来しています。.NET Compact Framework は完全な .NET Framework と共通した特徴を多数共有しています。

  •     共通言語ランタイム (CLR) : すべてのモバイル アプリケーションは同じ実行可能ファイル用ランタイム環境を使用します。CLR はプログラムのロード、メモリ管理、およびその他の中核オペレーティング システム機能を提供します (図 2 )。

  •     共通型システム (CTS) : CTS は、ランタイム内の型をどのように宣言、使用、および管理するかを定義し、すべての .NET Framework 言語からアクセスできるようにします。

  •     共通中間言語 (CIL) : Microsoft Intermediate Language (MSIL) とも呼ばれる CIL は、CPU に依存しない命令セットで、ネイティブ コードへの効率的な変換が可能です。

実際の Core Framework は、オペレーティング システムとハードウェアですが、このクロスプラットフォーム アプローチは、すべてのプログラミング面にわたる共通分母に少なからず影響を与えます。プラットフォーム呼び出し (図 3 ) は、Windows CE API などのダイナミック リンク ライブラリ (DLL) に実装されたアンマネージ関数をマネージ コードで呼び出せるサービスです。幸い、Visual Studio .NET の開発環境には、このような複雑な部分は表示されないので、適切な要素のみを開発者が利用できます。これが可能な理由は、開発者が新規プロジェクトの開始時にターゲットとするプラットフォームを選択できるからです。

開発されたアプリケーションは Just-In-Time (JIT) コンパイルされ、CLR がメモリ メンテナンス プロセスであるガベージ コレクション (GC) を処理します。このメモリ メンテナンス プロセス、またはそれが機能しないことは、CreateObject ステートメントとそれに続く潜在的なメモリ リークを使用する eMbedded Visual Basic 開発者にとっての問題でした。モバイル ソリューションから見て、何より最も重要なプラットフォーム拡張は、接続性に関するものです。.NET Compact Framework は、本来、主要なインターネット プロトコル (TCP IP や HTTP など) とドキュメント標準 (XML や SOAP など) をサポートし、モバイル アプリケーションを接続する基盤を提供します。

fromemb_image02.gif

2 : 多数ある共通部分の一例 : 共通言語ランタイム

fromemb_image03.gif

3 : Visual Studio .NET のターゲットプラットフォームの選択

開発環境の向上

eMbedded Visual Basic プログラミングは、独立した開発環境内ですべてが完結していました。.NET Compact Framework の開発は Visual Studio .NET 2003 内で行われるので、.NET Framework と開発環境を共有します。eMbedded Visual Basic の開発者は、Visual Studioが使い慣れたものであり、エディタ、ユーザー インターフェイス デザイナ、堅牢なデバッグ、ならびに直観的なコンパイル、実装、およびデバッギングに IntelliSense のような機能があり使いやすいことに気付くでしょう。Web サービスとその他の .NET Framework コンポーネントを使用した開発のサポートが組み込まれており、両方のツールと言語がシームレスに統合されています。

言語の大幅な向上

概念上、eMbedded Visual Basic と Visual Basic .NET のルーツは同じで、共に Basic を起源とします。主要な言語構造と要素が、現代の Visual Basic 開発者へ引き続き提供されていますが、より重要なのは、多数の新機能が採用されていることです。言語に関する大幅な向上点は以下のとおりです。

  •     .NET Compact Framework クラス ライブラリをベースとした開発

  •     オブジェクト指向設計のサポート

  •     構造化された例外処理

  •     マルチスレッド機能

  •     多言語との統合

ただし.NET Compact Framework は COM との相互運用をサポートしません。これは既存の COM と ActiveX コンポーネント関連のラッパーを開発し、プラットフォーム呼び出し (P / Invoke) を使用して呼び出す必要があることを意味します。対処策として、Odyssey Software から提供されているサードパーティ ツールによって、COM と ActiveX コンポーネントをマネージ コードからシームレスに使用できるようになります。

ユーザー インターフェイス とアプリケーション ナビゲーション

この新しい開発ツール (Visual Basic .NET) は、これまでにないコーディング環境をもたらします。Visual Basic と eMbedded Visual Basic の開発者であれば理解できる機能が継承されているので、移行はそれほど困難ではありません。ボタンをダブルクリックして、Click イベントのコードを入力するなど、多数の使い慣れた機能を引き続き利用できます。しかし、表面下では多数の変更が行われています。

eMbedded Visual Basic では、デザイン時プロパティやイベント定義など、開発者には見えないステップが多数あります。また、真のオブジェクト指向環境ではないため、最初の使用では一部のクラス (フォーム、コントロール) がインスタンス化されていました。Visual Basic .NET では、デザイナのすべてのフォーム操作が、コードに反映されます。フォームとコントロールはコード内に宣言およびインスタンス化しなければならないオブジェクトです。

フォームの基本

はじめに、サンプル フォームを見てみましょう (図 4 )。
これはデザイナが表示されているところです。(注 : フォームの上部のみ表示)

fromemb_image04.gif

4 : サンプルフォーム

このフォームをフォームデザイナを使用して作成する場合、フォームにコントロールを宣言する生成コードは次のようになります。

Friend WithEvents Label1 As System.Windows.Forms.Label
Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
Friend WithEvents Button1 As System.Windows.Forms.Button

コントロールを作成する生成コードは、次のようになります。

Me.Label1 = New System.Windows.Forms.Label
Me.TextBox1 = New System.Windows.Forms.TextBox
Me.Button1 = New System.Windows.Forms.Button

最後に、このコントロールにプロパティをセットアップする生成コードは、次のようになります。

Me.Label1.Location = New System.Drawing.Point(8,11)
Me.Label1.Size = New System.Drawing.Size(48,16)
Me.Label1.Text = “Label1”
Me.TextBox1.Location = New System.Drawing.Point(56,8)
Me.TextBox1.Size = New System.Drawing.Size(104,22)
Me.TextBox1.Text = “TextBox1”
Me.Button1.Location = New System.Drawing.Point(168,8)
Me.Button1.Size = New System.Drawing.Size(64,24)
Me.Button1.Text = “Button1”
Me.Controls.Add(Me.Button1)
Me.Controls.Add(Me.TextBox1)
Me.Controls.Add(Me.Label1)
Me.Text = “Form1”

各コントロールの場所、サイズ、および内容 (Text プロパティ) が設定されます。コードを生成すると、実際にフォームへコントロールが追加される点に注意します。重要なのは、すべてのコントロールが Text プロパティを持つようになることです (フォームとラベルの Caption プロパティではない)。

追加のメタデータを格納するコントロール (デザイン時コントロール プロパティと画像などのその他のリソース)と、フォームと同じ名前のリソース ファイルにデータを格納するコントロール (上記のサンプルの Form1.resx) は引き続き必要です。

フォーム用に生成されるコードの残りの部分は、フォームの基本構造を作成します。最初に、その他のクラス同様、フォームを宣言し、.NET Compact Framework の提供するベース ウィンドウのクラスを継承します。

Public Class Form1 : Inherits System.Windows.Forms.Form

上記のコードは、実際は 2 行で生成されますが、読みやすさのため、2 つのステートメントを同じ行に記載しています。このフォームを作成するときは、次のようにコンストラクタを呼び出します。

Public Sub New()
MyBase.New()
InitializeComponent()
End Sub

このコンストラクタは、基本クラスのコンストラクタを要求する呼び出しを行い、さらに生成されたプライベート関数 (Sub InitializeComponent) を要求する別の呼び出しを行います。この関数には、上記に示したようなコントロールを作成し、プロパティを設定するコードが保存されています。InitializeComponent 関数はフォーム デザイナが要求します。そこに含まれるコードの操作には注意を要します。

アプリケーション開発を始めるには、[ プロジェクトプロパティ ] ダイアログボックス ([Solution Explorer] のプロジェクトを右クリックし、[ プロパティ ] を選択) の "Startup object" として Form 1 フォームを定義します。これは、eMbedded Visual Basic での作業方法と非常に類似しています。

POCKET PC とスマートフォンの開発

イベント

アプリケーションのフォームを設計するときは、コントロールのイベント ハンドラを作成しなければなりません。eMbedded Visual Basic の場合と同様、コントロールをダブルクリックし、規定のイベント ハンドラを作成することができます。上記のサンプルの続きから、ボタンをダブルクリックすると、Click イベントのイベント ハンドラが生成されます。

Private Sub Button1_Click(ByVal sender As System.Object,
  ByVal e As System.EventArgs) Handles Button1.Click
MessageBox.Show("Text on button is: " & Button1.Text)
End Sub

イベント プロシージャのパラメータは常に同じように表示されます。“sender” パラメータはイベントを生成したオブジェクトを参照し、"e"パラメータは各種のイベントを指定します。通常、これには生成イベントに関するデータが含まれます。eMbedded Visual Basic では、これは個々のイベント パラメータとして指定されていました。このイベントに使用するコントロールを示す宣言の最後に、特別なキーワード (Handles) があります。重要なのは、キーワード Handles が複数の引数を承認することです。これは、同じイベント ハンドラを複数のコントロールの処理イベントとして使用できることを意味します。フォームにボタンを追加すると (Button 2 )、イベント ハンドラのコードが次のように変更されます。

Private Sub Button1_Click(ByVal sender As System.Object,
  ByVal e As System.EventArgs) Handles Button1.Click,
Button2.Click
MessageBox.Show("Text on button is: " & CType(sender,
Button).Text)
End Sub

これでイベント ハンドラは、両方のボタンからクリック イベントを処理します。イベントを生成するボタン オブジェクトの取得に、”sender” パラメータが使用されていることがわかります。

イベントの追加と削除は、eMbedded Visual Basic での処理方法と極めて類似しています。別のイベント ハンドラを追加するには、ドロップダウン リストからメソッド名を選択し、右上のコード ウィンドウに追加します。イベント ハンドラを削除するには、イベント ハンドラのコードを削除するだけです。eMbedded Visual Basic の場合と同様、ある場所から別の場所へコントロールをコピーするときは、イベント ハンドラ コードを手動でコピーする必要があります。

ルック & フィール

eMbedded Visual Basic から Visual Basic .NET へ移行する開発者の共通の問題は、タスク バーの右上ボタンの制御方法です。新規フォームを作成すると、規定の設定ではスマートな最小化ボタンが表示されます (X に似た外観)。この場合ウィンドウは閉じられず、背景に配置されます (非表示だが、実行は継続)。これは、フォームの Minimize プロパティが規定で True に設定されるためです。ControlBox プロパティも規定で True に設定されているので、OK ボタンを表示するために必要な変更手順は、Minimize プロパティを False に設定することだけです。さらに、OK ボタンが押されフォームが閉じられる前に、(確認などの) イベントを追加する必要がある場合、フォームに Closing イベント ハンドラを追加します。サンプルの続きで、フォームの Minimize プロパティを False に設定し、以下のイベント ハンドラを追加します。

Private Sub Form1_Closing(ByVal sender As Object,
   ByVal e As System.ComponentModel.CancelEventArgs)
   Handles MyBase.Closing
If TextBox1.Text <> "TextBox1" Then
   MessageBox.Show("Text in TextBox cannot be changed!")
   e.Cancel = True
  End If
End Sub

この例は、TextBox のテキストが変更された場合、フォームが閉じないようにする方法を示したものです。2 番目のパラメータ (e) が、イベント専用の値 (プロパティ) の処理に使用されていることがわかります。

さらに、下部のメニュー バーとソフト入力パネル (SIP) を表示するため、フォームに追加しなければならないメニュー コントロール (実際には MainMenu) について特に検討します。メニュー コントロールは常に、新規プロジェクト作成時に、最初に生成されたフォームへ追加されますが、新しいフォームを追加する場合、メニューは手動で追加しなければなりません。

他の Pocket PC アプリケーションと同じ外観にするには、以下のような追加ガイドラインに従います。

  •     すべてのフォーム キャプションに必ずアプリケーション名を付けます (フォームの Text プロパティ)。

  •     サブフォームでは、左上隅のフォーム (X = 8、Y = 5 が最適な位置) に、ダイアログボックスの名前を付けた Label コントロールを追加します。そのラベルの下に、フォームと同じ幅の 1 ポイントの線を追加します。高さ 1、幅 240 に設定された Panel コントロールを使用することを推奨します (X = 0、Y = 23 が最適な位置)。

  •     Label コントロールを TextBox コントロールのテキストに揃えるには、Label を TextBox の 3 ピクセル下に置きます (Y は TextBox + 3 )。

その他のユーザー インターフェイスについては、Visual Basic .NET のヘルプファイルと、Pocket PC デザイン ガイドライン (英語 / pdf) を 参照 してください。

フォーム ナビゲーションと対話

1 つのフォームだけで構成されているアプリケーションは非常にまれなので、異なるフォーム間のナビゲーションを効率化することが使いやすさの向上に繋がります。上記のサンプルの続きを構築するにあたり、別のフォームを追加します (メニュー オプションから [ プロジェクト ][Windows フォームの追加 ] を選択し、規定どおり Form 2 と名前を付けます)。最初の手順は、下部のメニュー バーが表示されるように MainMenu コントロールを追加することです。次に、右上の OK ボタンが表示されるよう、フォームの Minimize プロパティをFalse に変更します。デバッグ時間を節約するため、子フォームを作成するときはこれを習慣付けておきます。

新規フォームを構築する最もシンプルな方法は、最初のフォームのボタンにこのコードを追加することです。

Dim secondForm As Form2
secondForm = New Form2
secondForm.ShowDialog()

先に述べたように、eMbedded Visual Basic での作業方法とは対照的に、フォームを含むすべてのクラス インスタンスを、使用する前に作成しなければなりません。

ロードするフォームのサイズによっては、フォームのロード中に待機カーソルを表示することをお勧めします。その場合、ShowDialog 呼び出しの前に、以下のコード行を配置します。

Cursor.Current = Cursors.WaitCursor 

待機カーソルは、フォームがロードされると削除されねばなりません。これは、2 番目のフォームのコンストラクタで、以下のコードを使うと実行できます。

Public Sub New()
MyBase.New()
InitializeComponent()
Cursor.Current = Cursors.Default
End Sub

ただし、2 番目のフォーム (Form2_Load) の Load イベント ハンドラで、コントロールのロード値など、かなりの量の初期化が行われる場合、代わりに Load イベント ハンドラの最後で、カーソルを復元することをお勧めします。

フォーム間の通信は、よくある問題です。最もシンプルな通信方式は、ShowDialog を呼び出す方法です。ShowDialog は事前定義された結果コードのいずれか (OK、Cancel、Yes、No、Abort、Retry、Ignore、None) を返します。最初のフォームのコードを次のように変更できます。

MessageBox.Show (“You selected: ” +
secondForm.ShowDialog().ToString())

これは、2 番目のフォームによって返される結果コードを示しています。2 番目のフォームからこの値を返す方法は 2 種類あります。ボタンの DialogResult プロパティを設定するか、またはフォーム自体の DialogResult プロパティを設定する方法です。ボタンを 2 番目のフォーム (btnCancel) に追加する場合、次のコードをコンストラクタに追加し、このプロパティを設定します。

btnCancel.DialogResult = DialogResult.Cancel 

このプロパティはデザイナから利用できないので、コードで設定する必要があります。2 番目のフォームの Minimize プロパティを False に変更した場合、2 つの結果コードをフォームから返すことができます。右上の OK ボタンを押すと OK が、btnCancel ボタンを押すと Cancel が返されます。

通常の Pocket PC ユーザー インターフェイスのガイドライン (上記参照) によると、アプリケーションの Running Programs (Memory Setting のタブ) 一覧には 1 つのインターフェイスのみ表示される必要があります。最初のフォームが ( 2 番目の下に) 表示された状態で 2 番目のフォームを開いた場合、各フォームが Running Programs 一覧に表示されます。したがって、2 番目のフォームが表示されると、最初のフォームを非表示にする方法が必要になります。最初のフォームで Hide メソッド呼び出しを使うと、フォームは非表示になります。ShowDialog と Me.Show() を呼び出す前に、Me.Hide() を呼び出すと、最初のフォームに対してこの操作が実行されます。ただし、このアプローチには問題があります。2 番目のフォームのロード時間が長くなると、フォーム間の移行時にフォームが何も表示されなくなります (アプリケーション ユーザーにとって不自然に見えます)。先のサンプルの構築例では、何もフォームが表示されずに、"You selected..." メッセージ ボックスが表示されます。これを処理する有効な方法は、2 番目のフォームによって最初のフォームを隠すことです。これを実行するには、2 番目のフォームが最初のフォームから何らかのインスタンスを受信する必要があります。この情報を渡す最も明白な方法は、2 番目のフォームのコンストラクタを使用することです。2 番目のフォームに、最初のフォームのインスタンスを持つプライベート クラス変数を追加します。

Private firstForm As Form1 

新規パラメータと、そのパラメータをプライベート変数に保存するコードを使って、コンストラクタを更新します。

Public Sub New(ByVal firstForm As Form1)
   Me.firstForm = firstForm
   ‘ other code...
End Sub

これで、2 番目のフォームをインスタンス化する最初のフォームのコード行が以下に変更されます。

secondForm = New Form2(Me) 

この方法によって、2 番目のフォームに最初のフォームの情報が伝達され、以下を呼び出すことができます。

firstForm.Hide() 

最良の方法は、フォームの Load イベント (Form2_Load) の最後に使用することです。フォームの Closing イベント (Form2_Closing) で、次のコードを使用すると、再度最初のフォームが表示されます。

firstForm.Show() 

結果、フォーム間の移行が円滑になると共に、2 番目のフォームのロード時間または閉じる時間といった、パフォーマンス上の問題に依存しない移行が可能になります。

これは、フォーム間を通信する優れた方法です。2 番目のフォームのコンストラクタに、いくつパラメータを追加しても問題ありません。そのため、最初のフォームから 2 番目のフォームに、いくらでもデータを流し込むことができます。では、2 番目のフォームから最初のフォームへデータを戻す場合はどうでしょう。結果コードを使って最初のフォームに通知できることはわかっていますが (上記参照)、それを渡すには別の手段が必要になります。先のコードでは、firstForm 変数 (およびパラメータ) が、ベース型の Form ではなく Form1 として宣言されていることがわかります。Hide と Show メソッドは、これが可能なベース型 Form の一部です。しかし、firstForm 変数が Form1 型として宣言された場合、Form1 のクラスは、最初のフォームへデータを渡すため、2 番目のフォームによって呼び出されたパブリックな (正確にはフレンドな) メソッド を実装できます。

先の同じサンプルで続きを構築するには、次のメソッドを最初のフォームに追加します。

Friend Sub Form2Data(ByVal text As String)
   textFromForm2 = text
End Sub

textFromForm2 はプライベートに宣言された Form1 のクラス変数です。以下は、2 番目のフォームをロードするよう、ボタンの Click イベントのコードを修正したものです。

Dim secondForm As Form2
Dim result As DialogResult
Cursor.Current = Cursors.WaitCursor
secondForm = New Form2(Me)
result = secondForm.ShowDialog()
MessageBox.Show(“You selected: “ + result.ToString())
If result = DialogResult.OK Then
   txtFromForm2.Text = textFromForm2
End If

2 番目のフォームからのデータを表示する TextBox コントロールは、txtFromForm2 という名前です。次のコードを 2 番目のフォームの Closing イベントに追加します (Form2_Closing)。

firstForm.Form2Data(TextBox1.Text) 

このアプローチによって、2 番目のフォームから最初のフォームへどんなデータでも転送することができます。

アプリケーションのナビゲーションは、アプリケーションの利便性向上に不可欠です。先に示した推奨事項によって、フォーム間を効率的にナビゲートし、それぞれのデータを通信する方法がわかります。

アプリケーション統合

ほとんどの企業 モバイル ソリューションは、既存システムを拡張したものです。したがって、既存の IT システムをどのように統合するかということは、ソリューション アーキテクチャに欠かせない側面となっています。

統合戦略

統合には、統合パターン (方法) と接続回数 (頻度) の 2 つの局面があります。

統合パターン

現在出荷されている多くの商用 Pocket PC アプリケーションは、ネットワーク接続を必要としないため、「スタンドアロン」アプリケーションと見なされ、統合機能を持ちません。しかし、デバイスの接続が進むにつれ、統合の重要性も高まっています。解決すべき問題はその方法です。最も一般的な統合のアーキテクチャ パターンは以下のとおりです。

  •     デバイスデータとサーバーデータ : デバイス上のデータベースをサーバー データベースと直接同期します。パフォーマンスが非常に優れているので、このオプションは、データ同期に関するロジックが余りない場合に適しています。

  •     デバイスロジックとサーバーロジック : デバイス アプリケーションをサーバー上のコンポーネントと接続します。ほとんどの同期はビジネス ロジックを伴うので、これは最も一般的なオプションです。

  •     デバイスロジックとサーバーデータ : デバイスをサーバー データベースと直接接続します。あまり多くのロジックが関与していない場合で、利用可能な帯域幅が十分ある場合に、このオプションをお勧めします。

  •     サーバーのみ : サーバー側 Web アプリケーションとの接続にデバイス ブラウザを使用します。すべてのシンクライアント ベース (Web) のアプリケーションと同じ理由で魅力的なオプションですが、デバイスをサーバーへ常時接続する必要があります。

最後のオプションは、実際には統合オプションではありませんが、常時接続アプリケーションで十分な帯域幅を利用できることを示すため含まれています。率直に言って、このオプションはあまり有効な方法ではありません。上記のそれぞれのパターンに適用されるテクノロジは以下のとおりです。

  •     デバイスデータとサーバーデータ : SQL Server for Windows CEリモートデータアクセスとマージレプリケーション

  •     デバイスロジックとサーバーロジック : Web サービス

  •     デバイスロジックとサーバーデータ : SQL Server .NET Provider

  •     サーバーのみ : Visual Studio .NET 2003(モバイルデバイス開発機能)

先の図に示したような実装に必要なテクノロジの大半が提供されています。

接続頻度

もうひとつの重要な面が、ソリューションに必要なネットワーク依存性です。従来のようなオフラインかオンラインかという選択肢では、もはや不十分です。特定のシナリオに応じて、オフラインとオンラインの中間に位置する選択もより多く使用されるようになっています。

最も重要な接続頻度は以下のとおりです。

  •     ほとんどなし : 大半の時間、アプリケーションがオフラインで動作しており、同時性がほとんどない、または全くない場合に特定の間隔でのみ同期が必要です (多数のユーザーが同じデータで作業)。非常に低い帯域幅を必要とするか、または時により高帯域幅が必要となる場合 (オフィスなど) です。

  •     自動 : これは Seldom (前項目参照) と非常に類似していますが、同期の必要な時期を判断するロジックがアプリケーションに含まれます。

  •     多い : アプリケーションが頻繁にサーバーを呼び出し、データを送受信します。継続的な接続は必要ありません。アプリケーションはデータを転送するだけなので、比較的低い帯域幅しか必要としません。帯域幅のコストが、送信するバイトと関連性がある場合、これは非常に魅力的なオプションです。

  •     常時 : 有効な接続が必要なオンライン (ほとんどの場合 Web) アプリケーションです。

特定のシナリオで転送できるデータ量を特定するには、異なる時間での利用可能な帯域幅も重要です。最も一般的なオプションは以下のとおりです。

  •     広い (WLAN / Wi-Fi = 11 Mb 以上)

  •     狭い (WAN / PHS = 64 - 128 Kb)

  •     極めて狭い (WAN / PDC = 28.8 / 9.6 Kb)

選択

すべてのシナリオに適したオプションを 1 つに決めることはできませんが、先のオプションを考慮して、各シナリオを評価する必要があります。eMbedded Visual Basicの場合、先に述べた同期オプションのほとんどを実現できました (ほとんどの場合一部のミドルウェアを使用)。SQL Server for Windows CE の リモートデータアクセスまたは マージレプリケーション を使用したデータベース同期は、Visual Basic .NET を使用した場合と非常に類似しています。サーバー データベースへの直接接続は、デスクトップ上で Visual Basic .NET を使用した場合と類似しています。またオンライン (Web) アプリケーションの作成は、eMbedded Visual Basic とはあまり関係ありません。したがって、最適なオプションは、サーバー コンポーネントとの接続方法として、Web サービスを使用する方法です。

XML ベースの Web サービス

簡単に言うと、Web サービスは拡張マークアップ言語 (XML)、または多くの場合 HyperText 転送プロトコル (HTTP) を使ってメソッドを呼び出す (要求/応答) 方法です。Web サービスの最大の目標は、アプリケーション統合です。Web サービスの使用は、異なる企業のシステム接続方法に、社内アプリケーションを準拠させることから始まります。Web サービスの成功には、2 つの重要な理由があります。まず、定評のある標準規格 (HTTP、XML、SOAP、WSDL、UDDI など) を使って簡単に構築できること、次に、主要企業 (IBM、マイクロソフト、Sun、Oracle、その他多数) のほとんどが参加していることです。

Global XML Architecture (GXA) と呼ばれる機能を使って、Web サービスのSimple Object Access Protocol (SOAP) を拡張するため、多大な努力が払われています。GXA は製品ではなく、Web サービスの検索、安全な呼び出し (WS-Inspection)、メッセージと代替パスの定義 (WS-Routing/WS-Referral)、トランザクションのサポート (WS-Transaction)、およびバイナリ添付ファイルの送信 (WS-Attachments) のような多数のアプリケーション仕様の一般名です。GXA の初の具体的なテストが、Web Services Enhancements (英語) で、この仕様の一部が .NET Framework に実装されています。

サーバーコンポーネントとの接続

eMbedded Visual Basic では、サーバー コンポーネントへ簡単に接続するネイティブな方法がなく、開発者はサードパーティのミドルウェアに頼らねばなりませんでした。このようなミドルウェア製品は複数ありますが、最も便利なのは、ネイティブのコンポーネントの使用方法が類似している製品です。例えばOdyssey Software の CEfusion のような製品を使って、サーバー上にオブジェクトを作成し、デスクトップの DCOM (Distributed Component Object Model ) を使った場合と同じような形で利用することができます。CEfusion では、デスクトップとほとんど同じレコードセットを使用して、データが転送されます。Visual Basic .NET には、Web サービスを使用してアプリケーションを統合するネイティブな方法があります。サーバー上のコンポーネントは、XML や HTTP などのシンプルなプロトコルを使用して機能を公開することができます。Visual Basic .NET と .NET Compact Framework は、Web サービスの使用を既定でサポートしています。このサポートによって、単に可能になるというだけでなく、非常に強力な方法でアプリケーションを統合できることがわかります。

Web サービスの公開

サーバー上で Visual Studio .NET を使って、Web サービスを作成する方法は極めてシンプルです。Web サービスは、.NET Framework と Component Object Model (COM) コンポーネントの両方を発行する場合にも使用することができます。Active Server Pages (ASP) の .NET Framework Web プロジェクトを作成する既製のテンプレートがあります。MSDN (英語) には Web サービス作成に役立つ多数のリソースが用意されています。

クライアントの基本

*最初に、*Visual Basic .NET を使ってクライアント実装された非常にシンプルな Web サービスについて説明します。このサンプルは無償の Web サービスを使用して既存の機能を実行します。新規プロジェクトに、Web 参照を追加します (メニュー オプションの [ プロジェクト ] から [Web 参照の追加 ] を選択) 。このサンプルは無料の Web サービスを使用してクレジット カード番号の妥当性を確認します。図 5 はフォームの外観を示したものです ( : フォームの上部のみ表示)。

fromemb_image05.gif

5 : Web サービスのサンプルフォーム

新しい Visual Basic .NET プロジェクトを作成したら、フォームとコントロールの 名前と テキスト プロパティを操作するだけです。これは、より適した値を反映するよう変更されます。Web サービスの参照を作成するには、メニュー オプションの [ プロジェクト ] から [Web 参照の追加 ] を選択し、Web サービスの URL を追加します (サンプル URL 社外サイトへのリンク )。

ボタンの Click イベントに、次のコードを追加します。

Dim CreditCardWS As New cdyne.LUHNChecker
Dim Result As cdyne.ReturnIndicator
Result = CreditCardWS.CheckCC(txtCreditCardNumber.Text)
MessageBox.Show("Card type: " & Result.CardType &
 Microsoft.VisualBasic.vbCrLf &
 "Card valid: " & IIf(Result.CardValid, "Yes", "No"))

Web 参照の名前が "cdyne" に変更されていることがわかります (提案される名前は、実際にはドメイン URL を逆引きするため、あまり便利ではありません)。 Web サービスの参照を設定するときは、アプリケーションで Web サービスの型をその他の型 (クラス) と同様に処理できるようにします。

Web サービスは、基本の型 (文字列、整数など) を返しますが、このサンプルに示したように、Visual Basic .NET のクラスに変換される complex 型を返すこともできます。このサンプルでは、2 つのメンバ (CardType と CardValid) を持つ ReturnIndicator がこのクラスに相当します。

このアプリケーションの背景を見たい場合、[ ソリューションエクスプローラ ][ すべてのファイルを表示 ] ボタンをクリックし、Reference.vb ファイル (Reference.map ファイルの下) を探します。このファイルのコードを開くと、実際に Web サービスと complex型がいかに純粋な .NET Framework クラスとして宣言されているかがわかります。

Chatty な対話と Chunky な対話

このサンプルには、Web サービスと共に動作する興味深いパターンも示されています。戻り値は complex 型なので、単独の呼び出しで複数の値を返すことができます。多くの場合、各値の取得に複数の呼び出しを行う前のパフォーマンスに最適なソリューションです。ただし、一度の呼び出しで返されるデータの量があまりに大きい場合、問題が生じる場合があります。この問題は、chatty な対話と chunky な対話によく例えられます。「chatty な」対話とは、特定のタスクを実行する呼び出しが多数あることを意味します。一方、「chunky な」対話は、各呼び出しに大容量のデータが含まれることを意味します。モバイル アプリケーションの多くは、通常、帯域幅に限界があります。帯域幅が低い場合、最適なソリューションの選択にとりわけ注意を払わねばなりません。

DataSet 統合

eMbedded Visual Basic でデータを処理するときに便利なコンストラクトが、ActiveX Data Objects (ADO) Recordset です。同じには程遠いものの、これと対応する Visual Basic .NET のコンストラクトが DataSet です (Recordset と DataSet の違いに関する詳細情報については、以下の「データベースでの動作」のセクションを参照)。簡単に言うと、DataSet は、XML としてデータを抽出する機能を持つ切断されたデータ コンテナで、Web サービスとの統合に非常に有益です。

Web サービスと DataSet を使用した、サーバー コンポーネントとの統合方法を示すにあたり、最初に .NET Framework ツールを使用した Web サービスを作成します。Visual Studio .NET で、型「ASP .NET Web Service」、名前「DataSetWS」の新規プロジェクトを作成します。.NET Framework で使用される言語に依存しないことを明らかにするため、C# プロジェクトとして Web サービスを作成します。以前に C# の経験がない人でも読める程度の簡単なコードが望ましいです。新規プロジェクトを作成するときは、以下のコードを追加します。

[WebMethod]
public DataSet GetEmployees(int EmployeeID)
{
SqlConnection con;
SqlDataAdapter da;
DataSet ds;
con = new SqlConnection("data source=(local);initial
catalog=Northwind;" +
"uid=sa;pwd=");
 con.Open();
 if (EmployeeID > 0)
 da = new SqlDataAdapter("SELECT EmployeeID,LastName,
FirstName, " +
 "HomePhone FROM Employees WHERE EmployeeID="
+
 EmployeeID.ToString(),con);
else
da = new SqlDataAdapter("SELECT EmployeeID,LastName,
FirstName, " +
"HomePhone FROM Employees",con);
 ds = new DataSet("Employees");
 da.Fill(ds,"Employees");
 return ds;
}

図 6 : サンプル

DataSet Web サービスのサンプルこ のサンプルに使用するデータベースは、Northwind の SQL Server サンプルデータベースです。Web サービス メソッド (GetEmployees) は 1 つのパラメータ (EmployeeID) を取得し、DataSet を返します。接続を作成して開くときは、確認を行い、従業員の提供した ID が有効 (ゼロ以上) であるかを判断します。有効な場合、特定の従業員がデータベースから選択され、有効でない場合は、すべての従業員が取得されます。クエリ結果が DataSet のテーブルに格納され (いずれも名前は "Employees")、DataSet は呼び出し元に返されます。データをできる限り小さくするため、データベース クエリからは必要なフィールドのみが返されることがわかります。プロジェクトを構築するときは「サーバー」(大抵は開発 PC) から従業員情報を取得する Web サービスが必要です。

先のサンプルを拡張し、フォームへ多数のアイテムを追加すると、最終的にこのような外観になります (図 6 )。

新しいアイテム は、従業員の ID を入力するラベルとテキストボックス (txtEmployeeID)、Web サービス呼び出しを行うボタン、および返された従業員データを保存する ListView (lvwEmployees) です。テキストボックスに、従業員 ID が何も入力されていない場合、すべての従業員のデータが返されます。ListView には 3 つのコラム (Name、Phone、ID) が追加され、最後のコラムは非表示 (幅 = 0 ) です。

Web 参照を追加すると (新たに作成された Web サービスの URL を使用)、次のコードが Get button Click イベントに追加されます。

Dim DataSetWS As New server.NETCF
Dim ds As DataSet
Dim iEmployeeID As Integer = 0
Dim dr As DataRow
Dim lvi As ListViewItem
If IsNumeric(txtEmployeeID.Text) Then
 iEmployeeID = Convert.ToInt32(txtEmployeeID.Text)
End If
ds = DataSetWS.GetEmployees(iEmployeeID)
If ds.Tables(0).Rows.Count < 1 Then
 MessageBox.Show("No Employee(s)found!")
Else
 lvwEmployees.Items.Clear()
 For Each dr In ds.Tables(0).Rows
 lvi = New ListViewItem(dr("FirstName").ToString() & " " &
 dr("LastName").ToString())
lvi.SubItems.Add(dr("HomePhone").ToString())
lvi.SubItems.Add(dr("EmployeeID").ToString())
lvwEmployees.Items.Add(lvi)
Next
End If

最初に、Web サービスを作成し (このサンプルでは “server” と呼ぶ。サーバーの Web サービス クラスの名前は "NETCF")、他の宣言後に、従業員 ID が TextBox (txtEmployeeID) に追加されたかどうか確認します。ID が供給されない場合、Web サービスの呼び出しに規定の値 (0) を使用します。返された DataSet (ds) に、行が含まれているか確認し、含まれている場合、その行を ListView に追加します。3 番目の段は、従業員 ID を取得していることがわかります。これは ListView の特定の行の従業員情報を追加で取得する場合に役立ちます。

これは、サーバーとクライアント間でリレーショナル データを転送する便利な方法です。.NET Framework であれば少ないコード数で実現することができます。転送されたデータを調べると、データだけでなく、メタデータ (フィールド型や長さなど) も転送されていることがわかります。

非同期の Web サービス呼び出し

“chatty” と “chunky” を比較した考察によると、XML 形式のデータは明らかに “chunky” になりやすいと言えます。したがって、送信されるデータを最小化するよう注意を払う必要があります (上記のサンプルに示したように必要な列のみを選択する)。場合によって、デバイスをロックアップせずに、大量のデータを転送する必要があります。この場合、非同期の Web サービス呼び出しが必要になります。

別のボタン (btnGetAsync) と次のコードを Click イベントに追加し、先のサンプルの続きを構築します。

Dim DataSetWS As server.NETCF = New server.NETCF
Dim iEmployeeID As Integer = 0a
Dim cb As AsyncCallback
btnGetAsync.Enabled = False
lvwEmployees.Items.Clear()
If IsNumeric(txtEmployeeID.Text) Then
iEmployeeID = Convert.ToInt32(txtEmployeeID.Text)
End If
cb = New AsyncCallback(AddressOf GetAsyncReturn)<
DataSetWS.BeginGetEmployees(iEmployeeID,cb,DataSetWS)

このコードの大半は、先に示した同期呼び出しと極めて類似していますが、ここでは呼び出し中にボタンが無効になります。これは、この操作がアクティブであることをユーザーに知らせる場合に便利な方法です。最も重要なのは、Web サービスの非同期呼び出し (BeginGetEmployees) に使用される非同期コールバック変数 (cb) が追加されていることです。

コールバック変数 (cb) は、基本的に次のようなパブリック関数に対する関数ポインタです。

Public Sub GetAsyncReturn(ByVal ar As IAsyncResult)
 Dim DataSetWS As server.NETCF
 Dim ds As DataSet
 Dim i As Integer = 0
 Dim dr As DataRow
 Dim lvi As ListViewItem
DataSetWS = ar.AsyncState
ds = DataSetWS.EndGetEmployees(ar)
If ds.Tables(0).Rows.Count < 1 Then
 MessageBox.Show("No Employee(s) found!")
Else
For Each dr In ds.Tables(0).Rows
lvi = New ListViewItem(dr("FirstName").ToString() & " "
&
 dr("LastName").ToString())
lvi.SubItems.Add(dr("HomePhone").ToString())
lvi.SubItems.Add(dr("EmployeeID").ToString())
lvwEmployees.Items.Add(lvi)
 Next
 End If
 btnGetAsync.Enabled = True
End Sub

宣言のほとんどは、同期呼び出しと似通っていますが、Web サービス (DataSetWS) は宣言内でインスタンス化されていないことがわかります。代わりに、非同期状態パラメータ (ar) からインスタンスが取得されます。返された DataSet (ds) は、Web サービス (EndGetEmployees) の最終呼び出しによって取得されます。先と同じ方法で ListView を入力すると、ボタンが再度有効になります。

興味深いことに、ボタンの Click イベントの実行と GetAsyncReturn 呼び出しの間、ユーザーは通常どおりアプリケーションと対話できます。これにより、取得されるデータが同じ場合でも、より快適なユーザー体感がもたらされます。

統合の最適化

Web サービスの非同期呼び出し機能によって、ユーザー体感がはるかに快適になりますが、転送されるデータ量は使用可能な帯域幅 (費用) の割に大きいままです。純粋なデザイン指向のアクションに加え (転送データを細かく分割するなど)、データの圧縮能力を調査することができます。ただし、このトピックを説明するには、個別の記事またはホワイト ペーパーが必要です。詳細は Web services Developer Center (英語) をご覧ください。

データベースでの動作

このセクションでは、先に説明した「デバイス データとサーバー データ」の統合パターンの詳細を示します。ほとんどのモバイル アプリケーションはリモート データベースからのデータ取得、収集したデータの保存、およびリモート データベースへのデータ返送を行います。eMbedded Visual Basic は、サーバー側の ADO オブジェクト モデルに似た ADOCE をベースとするプログラミング モデルを提供していました。同様に、.NET Compact Framework は、System.Data 名前空間を通じて ADO.NET のサブセットを公開します。表面上新しいプログラミング モデルは ADOCE と違いがないように見えます。実際、接続の取得、レコードとフィールド収集、および接続オブジェクト経由のトランザクションの利用などの基本タスクは、非常に似通った方法で機能します。

しかし、データ アクセスの面で 2 つの顕著な違いがあります。第一に、CEDB または Pocket Access とも呼ばれるローカル データ ストアのマネージ プロバイダがありません。代わりに、SQL Server CE 2.0、およびサーバー側 SQL Server とのリモート接続用のマネージ プロバイダを提供しています。次に、ローカル ファイルとして格納される XML を、ボリュームの少ないデータ シナリオのデータ ストアとして使用することができます。言い換えると、SQL Server CE 2.0 を必要としない場合があるということです。ADOCE Recordset に相当する DataSet は、両方の状況で使用されます。次の表は、利用可能な 3 つのデータベース戦略の概要を示したものです。

 

ローカル ファイルのXML である DataSet

ローカルの SQL Server CE データベース

リモートの SQL Server データベース

データ
ボリューム

ボリュームの少ないデータ

中間のボリュームのデータ

ボリュームの大きいリモート データ。
デバイスは小規模な結果セットを使用する

クエリ

単純、オフライン

豊富、オフライン

豊富、(常時) オンライン

主要な利点

最も安価

最も堅牢なローカル データソリューション、
効率的な帯域幅の利用

リアルタイム、複製処理はなし

7 : System.Data の中核部分

DataSet

DataSet クラスは ADOCE Recordset の代わりになるだけでなく、より多くの機能を追加します。DataSet には、DataTable オブジェクトと呼ばれる複数の結果セットを含めることができます。そのため、DataRelation オブジェクトおよび DataRelationCollection オブジェクトと相互に関連付けることができます。

次のコードは、eMbedded Visual Basic を使用して SQL Server CE データベースのコレクションとレコードセットを開く方法を示しています。

'変数
Dim provider As String
Dim datasource As String
Dim rs As ADOCE.Recordset
Dim cn As ADOCE.Connection
 'ADOCE オブジェクトを作成する
Set cn = CreateObject("ADOCE.Connection.3.1")
Set rs = CreateObject("ADOCE.Recordset.3.1")
 'プロバイダとデータソース文字列を設定する
provider = "Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0"
datasource = "Data Source=\SQL\sample.sdf"
 '接続を開く
cn.Open provider & "; " & datasource
 'レコードセットを開く
rs.Open "SELECT SupplierID, CompanyName FROM Suppliers ORDER
BY CompanyName",cn,adOpenDynamic,adLockOptimistic

以下は、それに相当する Visual Basic .NET のコードです。

'変数
Dim cn As New SqlServerCe.SqlCeConnection
Dim ds As New DataSet
Dim da As New SqlServerCe.SqlCeDataAdapter
Dim cmd As New SqlServerCe.SqlCeCommand
 '接続文字列を設定し、接続を開く
cn.ConnectionString = "Data Source=\SQL\sample.sdf"
cn.Open()
 'コマンド プロパティを設定する
cmd.CommandText = "SELECT SupplierID,CompanyName FROM
Suppliers ORDER BY CompanyName"
cmd.Connection = cn
 'データ アダプタのコマンドを設定する
da.SelectCommand = cmd
 'アダプタからデータセットをデータテーブルに格納する
da.Fill(ds,"Suppliers")

クラスのインスタンス化の際に、コンストラクタ パラメータを介してプロパティ値を設定することで、Visual Basic .NET コードをよりコンパクトにすることができます。これは eMbedded Visual Basic では不可能です。以下はその実行方法を示したものです。

'変数
Dim cn As New SqlServerCe.SqlCeConnection("Data
Source=\SQL\sample.sdf")
Dim ds As New DataSet
Dim da As New SqlServerCe.SqlCeDataAdapter("SELECT SupplierID,
CompanyName FROM Suppliers", cn)
 '接続を開く
cn.Open()
 'アダプタから DataSet を DataTable に格納する
da.Fill(ds, "Suppliers")

DataAdapter は、データベースからのデータの挿入、更新、および削除に使用されます。必要なコマンドの作成を開始する最も簡単な方法は、デスクトップの Windows Forms アプリケーションを構築し、[ データアダプタ構成ウィザード ] を使用してデータ アダプタを作成することです。ウィザードによって、適切なコードとコマンドが作成されます。

DataSet はデータとスキーマを XML ドキュメントとして管理し、データとスキーマの両方を読み書きするメソッド (WriteXml、ReadXml、WriteXmlSchema、ReadXmlSchema) を実行します。そのため、DataSet 自体は低ボリュームのデータ用のローカル データ ストアの物理実装であると認識できます。

次の 2 行のコードは、DataSet をベースにした XML スキーマとデータを記述したものです。

ds.WriteXmlSchema("\SuppliersSchema.xsd")
ds.WriteXml("\Suppliers.xml")

XML スキーマは、以下のようになります。

<?xml version="1.0" standalone="yes" ?>
- <xs:schema id="NewDataSet" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
- <xs:element name="NewDataSet" msdata:IsDataSet="true"
msdata:Locale="sv-SE">
- <xs:complexType>
- <xs:choice maxOccurs="unbounded">
- <xs:element name="Suppliers">
- <xs:complexType>
- <xs:sequence>
  <xs:element name="SupplierID" type="xs:int" minOccurs="0" />
  <xs:element name="CompanyName" type="xs:string"
minOccurs="0" />
  </xs:sequence>
  </xs:complexType>
  </xs:element>
  </xs:choice>
  </xs:complexType>
  </xs:element>
  </xs:schema>

データ ファイルの最初の数行の XML は以下のとおりです。

<?xml version="1.0" standalone="yes" ?>
- <NewDataSet>
- <Suppliers>
  <SupplierID>1</SupplierID>
  <CompanyName>Aux joyeux ecclesiastiques</CompanyName>
  </Suppliers>
- <Suppliers>
  <SupplierID>2</SupplierID>
  <CompanyName>New Orleans Cajun Delights</CompanyName>
  </Suppliers>
- <Suppliers>
  <SupplierID>3</SupplierID>
  <CompanyName>Grandma Kelly’s Homestead</CompanyName>
  </Suppliers>
- <Suppliers>
  <SupplierID>4</SupplierID>
  <CompanyName>Tokyo Traders</CompanyName>
  </Suppliers>
  </NewDataSet>

DataSet の XML 機能は、eMbedded Visual Basic が提供する機能を大きく上回ると言えます。DataSet を使用した、データベースからユーザー インターフェイスへのデータ移動は極めて簡単です。次のコードは、コンボ ボックスの内容を削除し、それを DataSet に格納する方法を示しています。

'DataSet をコンボ ボックスにバインドし、最初のアイテムを選択する
With cboSuppliers
  .Items.Clear()
  .DataSource = ds.Tables("Suppliers")
  .ValueMember = "SupplierID"
  .DisplayMember = "CompanyName"
  .SelectedIndex = 0
End With

DataReader

DataSet が、接続されていない結果セットを生成するのに対して、DataReader は読み取りと転送専用カーソルの接続された結果セットなので、より高いパフォーマンスを提供します。

rs.CursorType = adOpenForwardOnly
rs.LockType = adLockReadOnly
rs.ActiveConnection = cn
rs.Open "SELECT SupplierID, CompanyName FROM Suppliers ORDER
BY CompanyName"

変数 "cn" が ADOCE コネクションオブジェクトであることがわかります。Visual Basic .NET の相当するコードは、このようになります (コネクションオブジェクトのインスタンス化を含む)。

Dim cn As New SqlServerCe.SqlCeConnection("Data
Source=\SQL\sample.sdf")
cn.Open()
Dim dc As New SqlServerCe.SqlCeCommand("SELECT SupplierID,
CompanyName FROM Suppliers ORDER BY CompanyName", cn)
Dim dr As SqlServerCe.SqlCeDataReader = dc.ExecuteReader()

次のコードは、DataReader データをループし、コンボ ボックスを実装する方法を示したものです。このコードは、ComboBox 参照と SQL 文字列という 2 つのパラメータを受け取る汎用的なプロシージャを実行します。このプロシージャは、オープンな接続 (cn) を利用できることを前提とします。.NET Compact Framework の新しいクラスである ArrayList を使用すると、非表示の一意な ID と記述的な表示名を持つコンボ ボックスを実装する場合の一般的な問題が解決されます。

Private Sub PopulateComboBox(ByRef ComboBox As ComboBox, ByVal
SQL As String)
    'ID/Name でコンボを埋める汎用的なSUB
    '宣言
  Dim IDNameArray As ArrayList = New ArrayList
    'コンボ ボックスを削除する
  With ComboBox
        .Visible = False
        .DataSource = Nothing
        .Items.Clear()
End With
Try
  Dim dc As New SqlServerCe.SqlCeCommand(SQL, cn)
  Dim dr As SqlServerCe.SqlCeDataReader = dc.ExecuteReader()
    'このリーダーをループする
    While dr.Read()
        IDNameArray.Add(New IDName(Trim(dr("ID")),
Trim(dr("Name"))))
      End While
    'コンボ ボックスのプロパティを設定する
  With ComboBox
      .DataSource = IDNameArray
      .DisplayMember = "Name"
      .ValueMember = "ID"
      .SelectedIndex = 0
  End With
  Catch ex As Exception
    MessageBox.Show(ex.Message)
  Finally
    ComboBox.Visible = True
  End Try
End Sub

コンボ ボックスは ArrayList によって実装されます。ArrayList は ID と Name の 2 つの汎用プロパティを実装する、カスタム クラスからのアイテム データを使用して構築されます。このクラスは以下のようになります。

Class IDName
  Private _ID As String
  Private _Name As String
  Public Sub New(ByVal ID As String, ByVal Name As String)
    MyBase.New()
      ID = ID
      Name = Name
  End Sub
  Public ReadOnly Property ID() As String
    Get
      Return (_ID)
    End Get
  End Property
  Public ReadOnly Property Name() As String
    Get
      Return _Name
    End Get
  End Property
  Public Overrides Function ToString() As String
    Return _ID + " - " + _Name
  End Function
End Class

ローカルデータベースの管理

デバイス上に SQL Server CE のデータベースを配置するには、以下の 2 通りの方法があります。

  •     セットアップ時にデータベース ファイルを配布する

  •     実行時にデータベースを作成する

eMbedded Visual Basic を使用して、新しいデータベースを作成するには、以下を実行します。

'変数
Dim provider As String
Dim datasource As String
Dim ct As ADOXCE.Catalog
 'エラーを処理する
On Error Resume Next
 'ADOXCE カタログを作成する
Set ct = CreateObject("ADOXCE.Catalog.3.1")
 'プロバイダとデータソース文字列を設定する
provider = "Provider=Microsoft.SQLSERVER.OLEDB.CE.2.0"
datasource = "Data Source=\SQL\sample.sdf"
 'データベースを作成する
ct.Create provider & "; " & datasource
 'エラーを確認する
If Err.Number <> 0 Then
 'ここに処理コードを配置する!
End If

実行時の作成の場合、データベースが事前に存在していることがわかります。この状況を処理するには 2 つの方法があります。最初に、データベース ファイルの有無をコードで確認できます。存在している場合、コードは新しいデータベースの作成を試みません。さらに、すでに存在するデータベースの作成を試みた場合に生じるエラーをコードで処理できます。eMbedded Visual Basic のコードでは、前述の “On Error Resume Next” を使用して、Create メソッドの後に、Err オブジェクトの Number プロパティ (Err.Number) を確認することで実行されます。Visual Basic .NET で同じことを行うには、より構造的な Try ... Catch ... Finally の例外処理を使用します。

'変数
Dim db As String = "\sample2.sdf"
Dim sqlEngine As New SqlServerCe.SqlCeEngine("Data Source=" +
db)
Try
 'データベースを作成する
  sqlEngine.CreateDatabase()
Catch ex As SqlServerCe.SqlCeException
 'ここに処理コードを配置する!
Finally
 'CreateDatabase の成功と失敗両方の場合に実行するコードをここに配置する!
  cn.Open()
End Try

以下は、既存データベースを最初に確認し、次に Visual Basic .NET を使用して、新規データベースを作成する場合です。

'変数
Dim db As String = "\sample.sdf"
Dim sqlEngine As New SqlServerCe.SqlCeEngine("Data Source=" +
db)
‘ すでに存在している場合、データベースを削除する
If File.Exists(db) Then
  File.Delete(db)
End If
0
‘ データベースを作成する
sqlEngine.CreateDatabase()

データベースを作成した後は、テーブルを作成し、データを使った動作を開始します。次のコードは、以下を実行します。

  •     テーブル Suppliers の作成

  •     2 つのレコードの挿入

  •     1 つのレコードの更新と削除

  •     トランザクションのデータ変更の管理

‘ 変数
Dim db As String = "\sample.sdf"
Dim sqlEngine As New SqlServerCe.SqlCeEngine("Data Source=" +
db)
Dim cn As New SqlServerCe.SqlCeConnection("Data Source=" + db)
Dim cmd As New SqlServerCe.SqlCeCommand
‘ すでに存在している場合、データベースを削除する
If File.Exists(db) Then
  File.Delete(db)
End If
Try
‘ データベースを作成する
    sqlEngine.CreateDatabase()
Catch
    ‘ ここに処理コードを配置する!
Finally
‘ CreateDatabase の成功と失敗両方の場合に実行するコードをここに配置する!
    cn.Open()
End Try
‘ Command オブジェクトを使用してテーブルを作成する
cmd.Connection = cn
cmd.CommandText = "CREATE TABLE Suppliers(SupplierID int
PRIMARY KEY, CompanyName nvarchar(50))"
cmd.ExecuteNonQuery()
Try
  ‘ テーブルを実装する
  cmd.CommandText = "INSERT INTO Suppliers(SupplierID,
CompanyName) VALUES (1, ‘Best Foods’)"
  cmd.ExecuteNonQuery()
  cmd.CommandText = "INSERT INTO Suppliers(SupplierID,
CompanyName) VALUES (2, ‘Best Clothes’)"
  cmd.ExecuteNonQuery()
Catch ex As SqlServerCe.SqlCeException
  cn.Close()
  MsgBox("Could not insert data!" + ex.Message)
  Exit Sub
Finally
End Try
Try
  ‘ 更新と削除!
  cmd.CommandText = "UPDATE Suppliers SET CompanyName = ‘Good
Foods’ WHERE SupplierID = 1"
  cmd.ExecuteNonQuery()
  cmd.CommandText = "DELETE FROM Suppliers WHERE SupplierID =
2"
  cmd.ExecuteNonQuery()
Catch ex As SqlServerCe.SqlCeException
  MsgBox("Could not modify data!" + ex.Message)
Finally
  cn.Close()
End Try

リモートデータベースの使用

.NET Compact Framework を使用して、Pocket PC からリモート データベースにアクセスするには、主に 2 種類の方法があります。

  •     多層 Web サービスアプリケーション : サービスに渡し、リモート データベースに接続することができます。またはサーバー側 SQLXML マネージ クラスを使用して、SQL Server 2000 のビルトイン XML サポートを活用できます。

  •     リモートデータベースアプリケーション : リモート データベース アプリケーションの開発は、次のいずれかによって実行できます。1 つ目は、.NET Compact Framework の SQL マネージプロバイダ を使用して、直接データベースに問い合わせる方法です。これは eMbedded Visual Basic では利用できません。もうひとつは、.NET Compact Framework の SQL Server CE マネージプロバイダ を使用して、リモート データベース テーブルのプッシュとプル、および複製との結合を可能にします。密なデータベース間の統合は、パフォーマンスを向上させますが、Web サービスで実装されるビジネス ロジックを使用する機能は、ほとんどまたは一切提供されません。

MSDN 記事 : administration (英語) もご参照ください。

fromemb_image08.gif

8 : SQL Server CE 仮想ディレクトリ作成ウィザード

SQL Server CE 1.x の接続構成の経験のある eMbedded Visual Basic の開発者は、SQL Server CE 接続管理コンソールと SQL Server CE 仮想ディレクトリ作成ウィザード (図 8) を快適に使いこなせるでしょう。

データベースの直接クエリ

System.Data.SqlClient 名前空間のコンポーネントは、リモート SQL Server との接続、コマンドの実行、および結果の取得に使用されます。以下のコードは、DataReader を使用してこれを実行する方法を示したものです。サンプル コードによって企業名の部分が入力されます。これは、Northwind データベースの Suppliers テーブルに対するクエリに使用されます。
 SqlCommand オブジェクトが、リモート SQL Server にあるストアド プロシージャを参照していることがわかります。

‘ 変数
Dim cmd As SqlClient.SqlCommand
Dim dr As SqlClient.SqlDataReader
Dim cn As New System.Data.SqlClient.SqlConnection("user
id=sa;password=;initial
catalog=northwind;server=192.168.100.100")
Dim CompanyName As String
‘ 検索する企業名を取得する
CompanyName = txtCompanyName.Text
Try
  ‘ リモート サーバーへの接続を開く
    cn.Open()
  ‘ サプライヤを取得する
    cmd = New System.Data.SqlClient.SqlCommand("getSuppliers " +
CompanyName, cn)
    dr = cmd.ExecuteReader()
    ‘ コンボ ボックスを実装する
      cboSuppliers.Items.Clear()
      While dr.Read()
        cboSuppliers.Items.Add(dr("CompanyName"))
      End While
    ‘ 最初のサプライやを表示する
      cboSuppliers.SelectedIndex = 0
Catch ex As SqlClient.SqlException
  MsgBox(ex.Message)
Finally
  dr.Close()
  cn.Close()
End Try

ストアド プロシージャ getSuppliers は次のようになります。

CREATE PROCEDURE getSuppliers
@CompanyName NVARCHAR(50)
AS
SELECT SupplierID, CompanyName
FROM Suppliers
WHERE CompanyName LIKE ‘%’ + @CompanyName + ‘%’

eMbedded Visual Basic を使用して構築されたアプリケーションの多くが、SQL Server CE COM コンポーネントの Remote Data Access (RDA) と マージレプリケーション (MR) を使用して、デバイスとリモート サーバー間のデータを同期しています。.NET Compact Framework の SqlCeRemoteDataAccess と SqlCeReplication 名前空間には、同じ機能セットが実装されています。詳細は Microsoft SQL Server 2000 Windows® CE Edition Home (SQL Server CE) (英語) をご参照ください。

導入と配布

アプリケーションを構築するときは、便利な方法で導入および配布できるようにしておく必要があります。eMbedded Visual Basic には、プロジェクトと必要なリソースをインストール実行ファイル (setup.exe) にパッケージしたアプリケーション インストール ウィザードがあります。Visual Basic .NET の場合には違った方法をとります。

導キャビネット ファイルの作成

アプリケーション インストール ウィザード (eMbedded Visual Basic 付属) でインストールを作成した場合、デバイス上で動作するキャビネット ファイル (.cab) が常に追加され、これが実際のインストールを行います。生成されたファイル (Setup.exe、Setup.ini、およびキャビネット ファイル) は、最終的に CD 1 という名前のフォルダに保存されます。Visual Basic .NET の場合、完全な PC インストールを作成する方法はありませんが、キャビネット ファイルの作成がビルトイン サポートされています。Visual Basic .NET で、プロジェクトをロードおよび構築するときは (多くはリリース構成を使用)、メニュー オプション [ ビルド ] からサブメニューの [Cab ファイルの生成 ] を選択し、多数のプロセッサ種類のキャビネットファイルを生成します。キャビネット ファイルは、プロジェクト フォルダ下位のフォルダ (/cab/Release) に生成されます。

Pocket PC のインストールの場合、"PPC.ARM.CAB" サフィックスの付いたキャビネット ファイルを使用します。これは Pocket PC のインストール プログラムで、このファイルがデバイスにコピーされ、(デバイスの) ファイル エクスプローラ内からタップされると、アプリケーションがインストールされます。これは Web ページ上でも利用可能なファイルなので、接続された Pocket PC ユーザーは、Pocket PC の Pocket Internet Explorer から直接インストールを開始することもできます。

ただし、生成されたキャビネット ファイルをデバイスに取得してインストールした場合、アプリケーション名が Visual Basic .NET.で使用するプロジェクト名とまったく同じになることがわかります。また、企業名が "My Company," に設定され、自社の社名が適用されない場合があります。キャビネット ファイルの作成をカスタマイズするには、プロジェクト フォルダ下位に位置する別のフォルダ (/obj/Release) を見てみる必要があります。そこにキャビネット ファイルの作成に使用されたセットアップ情報ファイル (.inf) があります。このファイルには、使用されるアプリケーションと企業名のエントリが含まれます。以下はこのようなファイルから抜粋したサンプルです (ピリオド記号のあるセクションは除く)。

[Version]
Signature="$Windows NT$"
Provider="CompanyName"
CESignature="$Windows CE$"
[CEStrings]
AppName="ApplicationName"
InstallDir=%CE1%\%AppName%
.
.
[DefaultInstall]
CEShortcuts=Shortcuts
CopyFiles=Files.Common
.
.
[SourceDisksFiles]
ProjectName.exe=1
.
.
[Files.Common]
ProjectName.exe,,,0
.
.
[Shortcuts]
ApplicationName,0,ProjectName.exe,%CE11%

このファイルを生成する Visual Basic .NET のプロジェクト名は、"ProjectName" です。生成されたファイルでは、Version セクションの プロバイダ値が "My Company" から "CompanyName" に変更されています。また、CEStrings セクションの AppName 値は "ProjectName" から "ApplicationName" に変更されました。最後の Shortcuts セクションでも同様の変更が行われています (一覧の最初の値が、生成するショートカット名です)。これは概要を簡潔にご紹介したにすぎません。実際の .inf ファイルのトピックは極めて広範にわたります (詳細情報については、Visual Basic .NET ヘルプ ファイルの目次「デバイス プロジェクトの inf ファイル」を参照)。

.inf ファイルを更新すると、.inf ファイルと同じフォルダにあるバッチ ファイル (BuildCab.bat) を実行して、キャビネット ファイルのセットを新たに生成することができます。

ActiveSync のセットアップ

先に述べたように、eMbedded Visual Basic 付属のアプリケーション インストール ウィザードによって、インストール ファイルを含むフォルダ (CD 1 ) が作成されます。このフォルダに含まれるファイルは、PC 上で実行するインストール アプリケーション (Setup.exe) と構成設定ファイル (Setup.ini) です。eMbedded Visual Basic がインストールされている場合、この 2 つのファイルを使用して、Visual Basic .NET プロジェクトから PC インストールを作成することができます。上記のサンプルに基づいて構築すると、setup.ini ファイルは次のようになります。

[General]
Component=ProjectName
DefaultDirectory=ApplicationName
CabCount=1
Cab0=ProjectName_PPC.ARM.CAB
Description=CompanyName ApplicationName

Pocket PC のインストールの場合、必要なキャビネット ファイルは "_PPC.ARM.CAB” サフィックスのあるものだけです。ActiveSync を介して PC からアプリケーションをインストールするには、3 つのファイル (Setup.exe、Setup.ini、ProjectName_PPC.ARM.CAB) をユーザーに送信する必要があります。3 つのファイルは、エンド ユーザーの利便性を高めるため、解凍するとインストール アプリケーション (Setup.exe) を開始する自己解凍アーカイブ ファイル化されている場合もあります。これは、ほとんどの商用アーカイブ ツール (WinZip や WinRAR など) を使用して実行できます。

結論

eMbedded Visual Basic から Visual Basic .NET for Pocket PC 開発への移行は、重大な進歩です。ユーザー インターフェイス、アプリケーション ナビゲーション、システム統合、データベース管理、およびソリューション導入に関連した開発が向上しています。環境、言語、およびプラットフォームが一から再設計されるので、堅牢な機能とコードの効率化に繋がります。そのため、開発が容易になり、モバイル アプリケーションの接続性も向上します。