自訂要擷取的SMS-Windows Mobile [1]

自訂要擷取的SMS-Windows Mobile

操作Windows Mobile的使用者都知道,不管來自於Email、SMS或MMS的訊息,都會統一進到訊息中心這個長的很像

Outlook的程式之中,你可以透過訊息中心讀取與控制與簡易版Outlook express差不多功能的操作,但是,它並沒有

辦法可以按照Outllook一樣幫你把特定的訊息處理到你想要的地方,或者說,如果你想要每次當你老婆傳過來的甜蜜

簡訊時,可以事先過濾出來顯示給你看,那麼你可能需要去找一下相關的軟體來安裝使用;如果你是特定公司的工程

師或學校的學生要做個產品,想要讓程式在手機收到特定簡訊時,可以做特別的事,例如:過濾只接收公司的簡訊等

那麼,你可以參考一下這一篇的說明,在.NET Compact Framework中,它提供了一個類例:MessageInterceptor

協助處理這樣的需求。

 

那麼在說明程式怎麼使用.NET Compact Framwork所提供的MessageInterceptor時,我們可以先了解一些事情:

透過程式發出SMS,可以參考Microsoft.WindowsMobile.PocketOutlook.SMSMessage這個Class,那麼當簡訊送達手機時,

訊息中心或系統應該會觸發那些事情呢?

(1) 訊息接收者的State會改變。(這關於SystemState)

(2) 系統發出Notification告訴訊息中心。(System.Notification)

(3) 訊息中心將訊息讀取成要顯示的標題列、日期,並儲存ROM中。(Microsoft.WindowsMobile.PocketOutlook)

 

上述的說明,主要提供大家了解在訊息處理的主要流程與相對於.NET Compact Framework中所使用的類別。接下來,

下方將詳細說明如何完成在擷取訊息內容,並且讀取出訊息的內容與來源。

要使用MessageInterceptor,主要在VS2008專案中需要加入2個重要的參考元件庫:Microsoft.WindowsMobile與

Microsoft.WindowsMobile.PocketOutlook。

在使用MessageInterceptor時,需要注意二個重要的開發概念:

1) Deciding Whether to Share the Message

    因為MessageInterceptor主要是協助我們開發程式,讓它觸發在訊息送到訊息中心或交給其他訊息處理程式處理之前,

    因此,我們必需在設計時,先思考清楚是否訊息的處理只要在我們自行建立的程式就好,還是也要傳到訊息中心做處理

    如果,建立一個Interceptor程式,而且允許讓訊息往下交由其他訊息處理程式的話,記得在Instance該MessageInterceptor

    時,記得加上InterceptionAction.Notify;相反的,如果不想再往下交出去,將傳入InterceptionAction.NotifyAndDelete

    在預設是使用InterceptionAction.Notify。

2) Filtering Messages

    建立過濾訊息的條件,透過建立一個MessageCondition類別的Instance,做為MessageInterceptor中MessageCondition

    屬性值,而MessageCondition類別需要4個重要的資訊來設定一個完整的條件:

    a. 必須設定要用訊息的那個部分做為辨識的依據(MessageProperty enumeration),例如:電話號碼、寄件者、內容值等方式。

    b. 設定要以那一種辨別的結果值當作擷取的依據(MessagePropertyComparisonType enumeration),例如:等於、大於等。

    c. 設定要識別的值。例如:人名:Pou、電號:0932111111或內容包括:Test。

    d. 設定要識別的值是否有大小寫之分。

針對MessageProperty與MessagePropertyComparsionType可用的值如下之列表:

‧MessageProperty enumeration values

Value

Description

Body

透過訊息內容做為完成識別的方式。

MessageClass

透過訊息類別來做為識別的方式,其所有標準的SMS訊息都是相同的MessageClass,IPX.SMSText。

Sender

使用Sender的資訊做為識別的方式,此Sender會參考該行動裝置中的通訊錄的人名為主。

Subject

透過訊息的主旨做為識別的方式。但SMS訊息通常沒有主旨所以這個值不常使用

‧MessagePropertyComparsionType enumeration values

ValueDescription
Equal代表訊息屬性與比較值必需完全一致,使用此類型的比較,要特別注意細微的變化都視為不同。
NotEqual代表訊息屬性與比較值不相同。
Contains代表比較值出現於訊息屬性中。
StartsWith代表比較值出現於訊息屬性中最開頭。
EndWith代表比較值出現於訊息屬性中結尾。

上述二個表格就可以清楚知道要怎麼設定條件來過濾訊息內容。

另外,在處理訊息抵達時要做的事情時, 由MessageInterceptor該類別公開提供一個事件:MessageReceived,讓它可以

接收來自MesseageInterceptorEventHandler的委派,換句話說,當SMS訊息送達時,MessageReceived這個Event會被啟動,

並且丟出MessageInterceptorEventArgs的Reference到我們要處理的Method之中(或是直接Override本身的MessageReceived

事件),而MessageInterceptor只有一個公開的屬性:Message,代表收到訊息的內容,但Message屬性是來自於Message Class

而不是SmsMessage Class,所以必需做轉型才能取得SMS Body。

以下將舉一個簡單的例子說明實作MessageInterceptor:

   1: using Microsoft.WindowsMobile;
   2: using Microsoft.WindowsMobile.PocketOutlook;
   3:  
   4: MessageInterceptor _smsInterceptor = null;
   5:  
   6: private void Form1_Load(object sender, EventArgs e)
   7: {
   8:     // 實例化MessageInterceptor類別,並且設定過濾條件為:
   9:     // 判斷訊息內容的傳送者為Smith, John的訊息。
  10:     _smsInterceptor = new MessageInterceptor();
  11:     _smsInterceptor.MessageCondition = 
  12:         new MessageCondition(MessageProperty.Sender, 
  13:         MessagePropertyComparisonType.Contains, "Smith, John", false);
  14:     // 修改MessageInterceptor類別中MessageReceived所要處理的事件內容。
  15:     _smsInterceptor.MessageReceived += SmsInterceptor_MessageReceived;
  16: }
  17:  
  18: void SmsInterceptor_MessageReceived(object sender, MessageInterceptorEventArgs e)
  19: {
  20:     // 轉換Message內容為SmsMessage,才能取得訊息內容
  21:     SmsMessage newMessage = e.Message as SmsMessage;
  22:     if (newMessage != null)
  23:     {
  24:         statusBar1.Text = "From:" + newMessage.From.Address;
  25:         Debug.WriteLine(string.Format("Sender:{0} - Body:{1}", _
  26:           newMessage.From.Address, newMessage.Body));
  27:     }
  28: }
  29:  
  30: private void Form1_Closed(object sender, EventArgs e)
  31: {
  32:     if (_smsInterceptor != null)
  33:     {
  34:         // 移除MessageInterceptor.MessageReceived的事件處理,並且清除註冊的服務,避免重覆開啟。
  35:         _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived;
  36:         _smsInterceptor.Dispose();
  37:     } 
  38: }

從上述的程式,你可以看到第10~15段主要實作該MessageInterceptor、設定MessageCondition條件,並且提供MessageReceived

事件一個Event Hander:SmsInterceptor_MessageReceived;第21~27行則是該Event Handler要做的事情;最後第32行到37行,

則是Dispose該MessageInterceptor實作物件。接著下方將詳細說明這個範例的一些重要概念:

首先,當我們實作化一個MessageInterceptor類別時,除了擁有該類別的屬性與方法之外,該MessageInterceptor一個重要的事件

:MessageReceived,當我們實作他的Event Handler時,它會讓MessageInterceptor類別產生一個temporary registry entry(臨時

的註冊實體)並儲存於註冊表之中:HKLM\Software\Microsoft\Inbox\Rules,這個register entry包含關於該實作MessageInterceptor

的相關資訊,用來當訊息抵達系統時,Messaging Subsystem(你可以把他當成訊息中心)根據該register entry通知MessageInterceptor

可以執行它的活動。但是這裡要提及一個重點,在上一篇[]範例中,最後在Form_Close的事件時,執行了下面二段程式內容:

   1: _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived;
   2: _smsInterceptor.Dispose();

 

這二段程式內容,主要是透過取消針對該MessageInterceptor中MessageReceiveed事件的Event Handler,讓MessageInterceptor

移除該register entry,並且通知GC(垃圾回收)回收該MessageInterceptor實例。這二段的原因在於,register entry不會因為關閉

程式後,MesageInterceptor就自動真的從註冊表中清除掉,而這些保留下來的register entry會一直存在,甚至接下來重覆執行的

MessageInterceptor都不會在用到它們,因此,這將會造成註冊表的混亂影響效能。這是要特別注意的。

 

針對這篇文章寫到最後,我發現,應該補充怎麼把寫好的App變成可以Background也可以執行,甚至變成一個服務的方式。

因此,接下來下一篇希望可以整理出相關的這篇文章後續處理MessageInterceptor註冊到註冊表與啟動時就要載入的方式,

繼續分享並且做為自己學習的筆記。

 

References:

http://msdn.microsoft.com/en-us/library/bb932385.aspx