非構造化補助サービス データ (USSD) は、モバイル ネットワーク オペレーター (通常は単に "MO" と呼ばれます) と通信するために、モバイル通信用グローバル システム (GSM) デバイスで使用される通信プロトコルです。
USSD の理解には、最も密接に関連する兄弟であるショート メッセージ サービス (SMS) との比較が役立ちます。 USSD と SMS はどちらも GSM 標準であり、第 2 世代モバイル デバイスの機能として導入されました。 ただし、SMS とは違い、USSD はセッション ベースの接続です。 SMS は短いセッションレス メッセージングに使用されますが、USSD は通常、モバイル デバイスのコマンドと制御に使用されます。 セッションを維持する必要があるため、SMS でサポートされているストア アンド フォワード機能は、USSD ではサポートされていません。 USSD メッセージと SMS メッセージはどちらも 7 ビットの GSM 準拠文字で送信されますが、最大文字数は、SMS が 160 文字であるのに対し、USSD は 184 文字です。
USSD メッセージは、ダイヤラーを開いてコードを入力すると、携帯電話から送信できます。 すべての電話または MO ですべてのコードがサポートされているわけではありません。 場合によっては、電話のソフトウェアまたはオペレーティング システムによってコードの手動送信ができないことがあります。 実装する必要があるコードの 1 つが *#06# です。 このコードはモデムの国際移動体装置識別番号 (IMEI) を返しますが、電話によっては、これを直接ダイヤルできなくなります。 電話の設定を使用してモデムの IMEI を検索する従来の方法に従う場合、その番号はこのコードを使用して取得されることになります。
IMEI の例のように、電話のハードウェアがコードのコマンドを直接処理できる場合、ネットワーク セッションは開始されません。 ネットワーク通信を必要とするその他のコードでは、セッションが開き、コマンドと必要なパラメーター (該当する場合) で構成されるメッセージが送信されます。 この例の 1 つは、MO との現在の残高とプラン状態を確認するコードです。
Windows の USSD は、WinRT API サーフェスとして実装されます。 このインターフェイスの実装クラスは USSD セッションの状態機械として機能しますが、最終的には WWAN サービスに依存して高負荷の作業を行います。 これらの API はファクトリ パターンで実装されます。
USSD の実装
注意すべき重要な点は、公開されている API が IDL によって定義されていることです。 特にユーザーが WinRT に慣れていないと、実装で混乱するかもしれません。 混乱の一部は、「ファクトリ」という言葉の一見あいまいな使用に起因します。 ファクトリは、静的インターフェイスのクラス実装、またはランタイム クラスにアクティブ化可能なインターフェイスを提供する本当の工場に言及している可能性があります。
このトピックでは、WinRT の概念を確認したうえで、これらの概念に基づく実装について説明します。 さらに詳しい説明については、常に IDL を参照してください。
インターフェイス
インターフェイスは、アプリケーション バイナリ インターフェイス (ABI) を定義します。 インターフェイスを実装する任意のクラスで呼び出すことができる関数について説明します。
ランタイム クラス
これらは実際のクラスです。 これらは、最終的に ABI にクラス名として公開されるものを名前で表します。 各ランタイム クラスは、0 個以上のインターフェイス (ただし、1 つ以上のインターフェイスがある場合は、少なくとも 1 つの既定のインターフェイスを宣言する必要あり)、0 個以上の静的インターフェイス、およびアクティブ化可能なタグ (必要な場合) を持つことができます。 これらのインターフェイスはそれぞれ、異なる "Impl" クラスとして異なるファイルに実装されていますが、単一の統一されたクラスとして ABI に表示されます。
一般的なインターフェイスは、既存のオブジェクトのインスタンス メソッドとして表示されます。
静的インターフェイスは、ランタイム クラス自体の静的メソッドとしてクライアントに表示されます。
アクティブ化可能なタグは、ランタイム クラスのインスタンスを生成するファクトリ インターフェイスを定義します。 これはクライアントに対して完全に難読化され、そのランタイム クラスのコンストラクターとして表示されます。
USSD の実装
フロー: 開く、送信する、受信する、閉じる。
開く、送信する
クライアントは、UssdSession.CreateFromNetworkAccountId または UssdSession.CreateFromNetworkInterfaceId のいずれかの静的関数を使用して UssdSession オブジェクトを作成します。
呼び出される API に関係なく、UssdSession を初期化するにはネットワーク インターフェイス ID が必要です。 *NetworkAccountID の場合は、アカウント ID からネットワーク インターフェイス ID を取得する手順が実行されます。 CreateInternal() は、UssdSession のインスタンスを作成し、新規作成されたインスタンスで Initialize() を呼び出すために呼び出されます。 初期化手順中にワーカー スレッドがスピンアップされ、スレッドのイベントをトリガーするイベント ハンドルが作成されます。 手順 3 と 4 は、インスタンスの Initialize() 中にも実行されます。
Initialize() は、WwanWrapper メンバー オブジェクトで呼び出されます。 この関数は、静的コールバック関数と、静的関数がコールバックをオブジェクト コンテキストにマップできるようにするコンテキストを受け入れます。
WwanWrapper は、WwanService のハンドルを開き、インターフェイスを列挙し、静的コールバック関数ポインターと "this" をコンテキストとして提供して USSD 通知をサブスクライブします。
UssdSession オブジェクトがクライアントに返されます。
クライアントは、メッセージ文字列を使用してコンストラクターを呼び出して、新しい UssdMessage を構築します。 WinRT は、このプロセスで UssdMessageFactory を難読化します。
クライアントはセッション オブジェクトで SendMessageAndGetReplyAsync を呼び出し、UssdMessage インスタンスを渡します。
現時点では、SendMessageAndGetReplyAsync は UssdSendMessageAndGetReplyOperation と呼ばれる特殊な操作オブジェクトを作成します。 その名前から、オブジェクトはスタックに送信される (および応答を待機している) 1 つのメッセージの論理をカプセル化しているように思えますが、これはそうではありません。 WinRT には、非同期操作用の特別な out パラメーターが必要です。このパラメーターは、この関数の定義の 2 番目のパラメーターと見なすことができます。
HRESULT SendMessageAndGetReplyAsync( [in] UssdMessage* message, [out, retval] Windows.Foundation.IAsyncOperation<UssdReply>** asyncInfo);
これは、typedef を介した名前付きインターフェイスである IUssdSendMessageAndGetReplyOperation であり、この操作で UssdReply が必然的に返されることを約束することで、このパラメーターを満たします。 このインターフェイスは IDL では定義されていませんが、UssdSendMessageAndGetReplyOperationImpl クラスで実装されます。 このクラスのヘッダーには特別な拡張子があることにご注意ください。
class UssdSendMessageAndGetReplyOperationImpl : public Microsoft::WRL::RuntimeClass< Windows::Networking::NetworkOperators::IUssdSendMessageAndGetReplyOperation, Windows::Internal::AsyncBaseFTM<IUssdSendMessageAndGetReplyCompletedHandler, Microsoft::WRL::SingleResult>>
UssdSendMessageAndGetReplyOperation オブジェクトを使用すると、WinRT で、この非同期操作の複雑さと、それに伴うすべてのコンパートメント化とメモリ プロキシを難読化できます。 詳細については、SendMessageAndGetReplyAsync を参照してください。
現時点では、上記の非同期操作は、この操作の論理が実際に含まれている UssdSession オブジェクトにコールバックするだけであると理解してください。 単純化するために、ここで UssdSession 自体が作業をカプセル化していることを視覚化できます。 非同期の性質にもかかわらず、一度に送信できる UssdMessage は 1 つだけであることをアサートできるようになりました。
SendMessageAndGetReplyAsync 関数が実際に実行すること:
- UssdSession オブジェクトはビジー状態に変わり、UssdMessage の内容を格納して、非同期アクションを実行します。
- OnOperationStart() は、非同期ロジックのエントリ ポイントです。 このシナリオでは、アクティブなセッションがないと仮定します。 この関数は、RequestType=WwanUssdRequestInitiate を使用して WWAN_USSD_REQUEST オブジェクトを作成します。
- 手順 9 と 10 は、この関数によって実行されるアクションとして実行されます。
m_wwanWrapper.SendRequest は、WwanService にメッセージを渡す作業を処理するために呼び出されます。
WwanWrapper は、WwanService ハンドルを使用して WwanService API を呼び出し、アクションを実行します。
受入
手順 10 の後に、新しい USSD セッションを初期化し、そのセッションの中で USSD メッセージを送信する要求が WwanService に送信された状態になります。 しばらくすると、返信が表示されます。
- WwanService は、手順 4 で提供された静的コールバック関数を、同じくアタッチされたコンテキストと共に呼び出します。
- コンテキストは、WwanWrapper インスタンスを取得し、NotificationCallback() を呼び出すために使用されます。
- WwanWrapper は手順 11 と同じパターンに従い、UssdSession への静的コールバックを呼び出し、手順 3 で格納されたコンテキストを提供します。
- 手順 12 と同様に、コンテキストは UssdSession のインスタンスでコールバックを呼び出すために使用されます。
- UssdSession は WWAN_USSD_EVENT を (ロック状態で) 格納し、イベントを処理するようにワーカー スレッドに通知します。
- HandleOperationReply() は、既存の UssdSendMessageAndGetReplyOperationImpl オブジェクトを受け取り、イベント データをその内部ハンドラーに渡します。
- この操作により、UssdReply が構築され、FireCompletion() が呼び出されて、非同期アクションに完了のマークが付きます。
- WinRT は、クライアントに対して、非同期アクションの完了を難読化します。 (アクションを待っているか、コールバック ロジックを持っています)
同じセッションで、さらにメッセージを送信できます。 セッションが維持された場合、将来の RequestType は WwanUssdRequestContinue になります。
終
手順 18 の後、クライアントは UssdMessage への応答を受信しました。 追加のメッセージを送信するために、アクティブな UssdSession の使用を継続する場合もあれば、しない場合もあります。 将来のある時点で、クライアントが UssdSession で Close() を手動で呼び出すと仮定します。 クライアントが明示的に Close() を呼び出さない場合は、UssdSession のデストラクター中に呼び出されます。
- クライアントが UssdSession インスタンスで Close() を呼び出します。
- RequestType=WwanUssdRequestCancel でWWAN_USSD_REQUEST が作成されます。
- この要求は、手順 9 と同じように m_wwanWrapper に送信されます。
- この要求は、手順 10 と同じように WwanService に送信されます。
この要求の結果は重要ではありません。 すべての意図と目的のために、セッションは閉じられます。 どういうわけかメッセージが一切配信されない極端なエッジケースでも、新しい USSD セッションは常に既存のセッションをオーバーライドします。
Hardware Lab Kit (HLK) テスト
「HLK のインストール手順」を参照してください。
HLK では、Studio はデバイスの携帯ネットワーク モデム ドライバーに接続し、テスト (Win6_4.MB.GSM.Data.TestUssd) を実行します。
MB USSD トラブルシューティング ガイド
「MB ログの収集」の手順に従ってログを収集し、デコードします。
フィルター処理のキーワード:
- OID_WWAN_USSD
- NDIS_STATUS_WWAN_USSD
- WWAN_USSD_REQUEST
- WWAN_USSD_EVENT