适用于:
Microsoft® .NET Compact Framework
Microsoft Visual Studio® .NET
Microsoft Windows® Powered Pocket PC Phone
摘要:作為行動電話家族的進階成員,具有内置電話功能的 Windows Powered Pocket PC Phone 有多個連接配接選項。核心功能為可連接配接至 Internet,除此之外,還有其他可用選項。在所有的全球移動通信系統 (GSM) 網絡中,一種常用的通信方式便是使用短消息伺服器 (SMS) 消息。在設計連接配接行動電話應用程式時,這是一個不容忽視的選項,本文将對其原因進行解釋。(本文還包含英文連結。請注意,在示例檔案中,程式員的注釋使用的是英文,本文中将其譯為中文是為了便于讀者了解。)
下載下傳 sms_apps.exe
目錄
什麼是 SMS?
為什麼使用 SMS?
SMS API
SMS Anyplace 示例
代碼演練
小結
什麼是 SMS?
短消息伺服器使行動電話(包括 Pocket PC Phone)能夠使用 GSM 網絡發送短消息,它具有許多有趣的功能:
- 一個 SMS 消息最長可包括 160 個字元(偶數二進制)。
- SMS 是一種存儲和轉發服務。也就是說,短消息并不是直接從發送人發送到接收人,而始終通過 SMS 中心進行轉發。如果接收人處于未連接配接狀态(可能電話已關閉),則消息将在接收人再次連接配接時發送。
- SMS 具有消息發送确認的功能。這意味着 SMS 與尋呼不同,使用者不是簡單地發出短消息然後相信消息已發送成功;而是短消息發送人可以收到傳回消息,通知他們短消息是否已發送成功。
- SMS 消息的發送和接收可以和 GSM 語音同步進行。
- SMS 消息按消息收費,是以要比通過基于 IP 的網絡(例如,使用 GPRS [通用分組無線業務])發送的資料昂貴得多(每位元組)。
要使用 SMS,使用者需要預訂支援 SMS 的移動網絡,并且必須為該使用者啟用 SMS 的使用。使用者需要有發送短消息或接收短消息的目的地。該目的地通常是其他的行動電話,但也可以是伺服器。最後,使用者還需要有支援 SMS 的行動電話,并需要了解如何使用其特定型号的行動電話發送或閱讀短消息。
為什麼使用 SMS?
對于應用程式開發人員來說,将 Pocket PC Phone 連接配接至伺服器的即時解決方案可能是通過基于 IP 的網絡,例如 Internet。這種做法的優勢包括:已經存在公用标準協定,而且通信工具也是現成的。
但是,在某些情況下,基于 IP 的網絡并非是最有效的傳輸方式。主動甚至自動地進行連接配接需要占用寶貴的時間,而且在通話時不能進行連接配接。如果存在一種即使是在通話時也能即時連接配接至伺服器的方法,那會是什麼呢?既然 Pocket PC Phone 可以發送 SMS 消息,它也許是一種實作辦法。
通常在四處走動的從業人員需要向業務流程應用程式通知重要事件時,即時連接配接非常有用。可能是通知伺服器有新訂單的推銷員,也可能是剛剛送完貨的卡車司機。
在伺服器方面,有多種解決方案可用于接收 SMS 消息并将其轉發給其他系統。例如 MobileSys, Inc. 和 Smartserv Online, Inc. 的産品。在本文中,我們将進一步探讨 Pocket PC Phone 的 SMS 性能。
SMS API
在 Pocket PC Phone 上,您可以使用大量的 Microsoft® Windows® CE API 調用來通路 SMS 消息功能:
函數 | 說明 |
---|---|
SmsOpen | 打開用于發送和/或接收通路的 SMS 消息元件。 |
SmsSendMessage | 發送 SMS 消息。 |
SmsGetMessageStatus | 檢索已發送消息的狀态報告。 |
SmsReadMessage | 閱讀先前收到的 SMS 消息。 |
SmsGetMessageSize | 确定緩沖區大小的上限。 |
SmsGetSMSC | 讀取預設的短消息服務中心 (SMSC) 位址。 |
SmsSetSMSC | 設定預設的 SMSC。 |
SmsGetPhoneNumber | 擷取與 SMS 持有者相關聯的裝置的電話号碼。 |
SmsGetTime | 擷取由 SMSC 時鐘粗略估計的目前時間。 |
SmsGetBroadcastMsgRanges | 擷取行動電話可以偵聽的廣播消息的範圍。 |
SmsSetMessageNotification | 在 SMS 消息到達時啟動應用程式。 |
SmsClearMessageNotification | 取消對 SMS 通知的注冊。 |
SmsSetBroadcastMsgRanges | 設定行動電話可以偵聽的廣播消息的範圍。 |
SmsClose | 關閉現有的 SMS 消息句柄。 |
會話以調用 SmsOpen 開始,這将傳回一個 SMS 句柄,此後,在調用 SMS API 函數時均需要此句柄。通過将此句柄傳遞給 SmsClose 來終止會話。本文将着重說明使用 .NET CF 中平台調用功能的 SmsSendMessage API,類似的技術也可用于通路其他 API。
SMS Anyplace 示例
該示例是使用 Microsoft Visual Studio® .NET、C# 和 .NET Compact Framework 建立的 Pocket PC Phone 的示例應用程式。它示範了如何使用 SMS API 發送 SMS 消息。該應用程式包含一個表單:
圖 1:SMS Anyplace 示例本示例的構思為:送貨的卡車司機無需連接配接至任何基于 IP 的網絡(例如 Internet)即可将通知即時發送給伺服器上的業務流程應用程式。
請想象一下,在貨物清單中作出選擇,随後的螢幕将顯示選中的貨物辨別以及目前的日期和時間。隻需敲擊“發送”按鈕即可。
敲擊“發送”按鈕後,發送資訊将被編譯成 XML 消息字元串,您可以在螢幕下半部分看到該字元串。該資訊可能不會顯示在實際應用程式中,在此處顯示隻是為了便于說明。XML 格式可以確定接收伺服器能夠以标準方式通路資訊。然後無需任何連接配接,甚至無須打斷正在進行的語音對話,便可使用 SMS 将 XML 發送至伺服器。
代碼演練
讓我們從“發送”按鈕所表示的代碼開始:
// 建立 XML 消息
MemoryStream ms = new MemoryStream();
XmlTextWriter xmlw = new XmlTextWriter(ms, System.Text.Encoding.UTF8);
xmlw.WriteStartDocument();
xmlw.WriteStartElement("Delivery");
xmlw.WriteElementString("PackageID", lblPackageID.Text);
xmlw.WriteElementString("Delivered", txtDelivered.Text);
xmlw.WriteEndElement();
xmlw.WriteEndDocument();
xmlw.Flush();
ms.Seek(0, SeekOrigin.Begin);
StreamReader sr = new StreamReader(ms);
txtMessage.Text = sr.ReadLine();
lblMessage.Text = "Message (" + txtMessage.Text.Length.ToString() + "
chars):";
this.Refresh();
xmlw.Close();
sr.Close();
// 發送消息
if (0 == SMSHelper.SendSMS("+15555550123", txtMessage.Text))
MessageBox.Show("Message sent!", this.Text, MessageBoxButtons.OK,
MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
else
MessageBox.Show("Could not send message!", this.Text);
貨物辨別和發送時間将被轉換成 XML。.NET CF 具有對 XML 的本地支援,并且具有若幹可以使用的類。在本示例中,選擇了 XMLTextWriter 類。使用簡單的方法将 XML 寫入到記憶體流。然後,該流被重置至開始,并由 StreamReader 讀入到消息文本控制。消息标簽也随消息長度而更新。建立消息後,消息将被發送(第二個參數)至 SMSHelper 類的靜态 SendSMS 方法。第一個參數為國際格式的目标位址(電話号碼)。
SMSHelper 類以多個聲明開始:
private const string SMS_MSGTYPE_TEXT = "Microsoft Text SMS Protocol";
private const int SMS_MODE_SEND = 2; // 以發送模式打開
private const int SMSDE_GSM = 1; // 使用 GSM 編碼
private const int SMSAT_INTERNATIONAL = 1; // 國際格式
private const int PS_MESSAGE_OPTION_NONE = 0; // 沒有消息選項
private const int PS_MESSAGE_CLASS0 = 0; // 顯示但不存儲
private const int PS_MESSAGE_CLASS1 = 1; // 存儲并顯示
private const int PSRO_NONE = 0; // 沒有替換項
private const int SMS_OPTION_DELIVERY_NONE = 0; // 沒有發送選項
[DllImport("sms.dll")]
private static extern int SmsOpen(
string ptsMessageProtocol,
int dwMessageModes,
ref IntPtr psmshHandle,
int phMessageAvailableEvent);
[DllImport("sms.dll")]
private static extern int SmsSendMessage(
IntPtr smshHandle,
int psmsaSMSCAddress,
IntPtr psmsaDestinationAddress,
int pstValidityPeriod,
IntPtr pbData,
int dwDataSize,
IntPtr pbProviderSpecificData,
int dwProviderSpecificDataSize,
int smsdeDataEncoding,
int dwOptions,
int psmsmidMessageID);
[DllImport("sms.dll")]
private static extern int SmsClose(IntPtr smshHandle);
首先,聲明某些 SMS API 特定常數。這隻是可用常數的一部分,要參考所有常數,請參閱 Windows CE API 文檔。然後從 System.Runtime.InteropServices 命名空間中使用指向在其中執行函數的 DLL(動态連結庫)的 DllImport 屬性(在此示例中為 sms.dll)來聲明每個 SMS API。
SendSMS 方法的核心内容如下所示:
// 獲得句柄
if (0 != SmsOpen(SMS_MSGTYPE_TEXT, SMS_MODE_SEND, ref smsHandle, 0))
returnValue = -1; // 無法打開
// 發送消息
if (0 != SmsSendMessage(smsHandle, 0, smsAddress, 0,
smsMessage, smsMessageTag.Length,
smsProviderData, smsProviderDataTag.Length,
SMSDE_GSM, SMS_OPTION_DELIVERY_NONE, 0))
returnValue = -2;
// 釋放句柄
if (0 != SmsClose(smsHandle))
returnValue = -3; // 無法關閉
對 SmsOpen API 的調用将設定 SMS API 句柄 (smsHandle),并指定消息的類型以及發送模式。句柄及其他一些必需參數(smsAddress、smsMessage 和 smsProviderData)作為 IntPtr 進行聲明。IntPtr 是一個結構,可以確定指針的長度(32 位或 64 位)與目前平台的本地指針大小相适應。最後,通過調用 SmsClose API 釋放 SMS API 句柄。
小結
由于 Pocket PC Phone 是行動電話家族的重要成員,是以我們可以利用其功能,例如 SMS 消息。在設計連接配接應用程式時,不要忘了這個有趣的選項。