自訂要擷取的SMS-Windows Mobile [2]
上一篇[自訂要擷取的SMS-Windows Mobile [1] ]介紹了透過MessageInterceptor配合本身MessageCondition屬性,
實作MessageCondition類別提供二個重要參數MessageProperty與MessagePropertyComparsion做為SMS過濾條件,
並且實作委派MessageRecived事件,執行有效地擷取符合條件的訊息內容、寄件者或是電話號碼等。
接下來這一篇主要說明,如何把建立好的MessageInterceptor範例程式,加到Windows Mobile中,讓它在啟動後
就長駐於系統中,讓他可以在背景裡執行像服務一般。因此,下方將透過二個主題分別說明:
(1)如何建立一個持久性的訊息攔截程式(Persistent Message Notifications);
(2)如果將訊息欄截程式處理的Thread獨立出來(Message Notifications and Threading)。
Persistent Message Notifications
我們在上一篇[]所建立的MessageInterceptor範例程式,其實是一種暫時性的訊息截取程式,當我們關閉該程式後,即便傳送
符合我們截取條件的訊息來,也不會觸發到我們所實作的Event Handler裡,所以針對要提供持久性的訊息截取,要了解一下
Windows Mobile針對訊息處理的概念:
【針對訊息的攔截,在Windows Mobile中,擷取、通知、發佈訊息統一透過一個device messaging subsystem來管理了,為了
讓我們實作的messageinterceptor範例可以有效的攔截我們要的資訊,就需要透過上一篇所提到一些設定條件,並且產生成
register entry放置於註冊表中,當訊息抵達時,messaging subsystem會去決定該訊息是否符合那一個messageinterceptor
所設定的攔截條件,如果找到符合的,messaging subsystem會去辨識該攔截條件所屬的application(如messageinterceptor
程式)是否已經啟動:如果該application正在啟動的話,messaging subsystem直接轉送訊息到該程式;如果程式未啟動,
messaging subsystem呼叫該application讓它啟動和轉送訊息到它身上。由此可見,device messaging subsystem的特性,
包括:識別符合攔條的程式、啟動程式和通知程式。為了讓我們的範例程式可以跟device messaging subsystem結合,
所以要做一點修改。】
在建立一個持久性的訊息截取程式之前,我們先了解一下MessageInterceptor類例的一些重要的屬性與方法:
Catelogy | Name | Description |
Properties | ApplicationArguments | Gets any optional parameters to pass to the intercepting application. |
ApplicationLaunchId | Gets the Identifier of the intercepting application. | |
ApplicationToLaunch | Gets the name of the intercepting application. | |
InterceptionAction | Gets or sets the action performed on the intercepted SMS message.此屬性用來設定該截取程式收到訊息時,是否要複製一份出來使用並往下傳送至下一個截取程式或直接讀取並刪除,例如:Notify與NotifyAndDelete。 | |
MessageCondition | Gets or sets a value indicating the condition an arriving SMS message must satisfy to be intercepted. | |
Method | DisableApplicationLauncher | Disables an already enabled application from launching if an arriving SMS message satisfies the interception rule condition. If your application is still running and consuming the MessageReceived event, then you will still receive the event. |
EnabledApplicationLauncher | 提供多載的方法,讓你可以為所建立的訊息攔截程式,根據一個唯一的識別值(如GUID)加入到Persistent Message Notifications中。 | |
IsApplicationLauncher | Get a value indicating if a message interceptor application launcher with the give identifier has already been enabled. | |
Event | MessageReceived | Occurs when an arriving SMS message satisfies the interception rule condition. |
Creating Persistent Message Notifications
透過使用MessageInterceptor.EnableApplicationLauncher,讓我們實作的MessageInterceptor範例程式可以轉變成持久型的訊息
攔截程式。EnabledApplicationLauncher提供多載的方式(包括:指定識別字串、程式名稱或直接下達Command指令等)為攔截程式
建立於訊息通知中,然而常見的是指定一個識別的字串值作為識別不同的MessageInterceptor,該字串可以是任何值,只要它不會
與其他的識別字串重覆即可。另外,二個重點要提醒大家:
a) 一個重要的Method用於確認識別值是否有相對應的MessageInterceptor程式使用。可以透過IsApplicationLauncher(識別值)
確認。建議IsApplicationLauncher最好是用於當訊息攔截程式啟動時就進行判斷,避免重覆設定造成Exception。
b) 使用EnableApplicationLauncher設定訊息攔截程式,由於該程式被儲存於註冊表之中變成持久型程式,它不會因為你設備軟
開機而消失,如果要禁用它的話,必需明確指示:MessageInterceptor.DisableApplicationLauncher才能真正移除它。
Message Notifications and Threading
預設MessageInterceptor類別的MessageReceived事件處理程式(Thread)是同屬於Main Thread之中,這樣的方式在只過濾少量的
訊息內容對主要程序的處理影響不太大,但如果針對大量的訊息處理的時候,那將會嚴重影響整個處理的程序,在這個情形下,
建議是將訊息處理獨立一個新的Thread來運作會是比較好的。MessageInterceptor建構子中提供這樣的做法如下:
1: public MessageInterceptor(
2: InterceptionAction interceptionAction, bool useFormThread
3: );
預設useFormThread為true,代表預設使用Main Thread;相反地False代表獨立一個新的Thread。雖然說獨立Thread可以解決上
述的情境,但如果你的設備中有多個MessageIntercetor程式的話,其實他們都是共用同一個Thread的,這要特別注意。因此,
盡可能不要讓一個MessageInterceptor程式處理占用太長時間的處理序,以免其他程式都在等待。
Interacting with the User Interface
當我們獨立訊息攔截程序的時候,要怎麼回去跟畫面中的UI Thread進行互動呢?可以直接透過匿名委派(anonymous delegate)
的方式,使用Control.Invoke與Control.BeginInvoke這二個方式與UI Thread進行互動,如果不這樣的話,會出現Exception。
Disposing Message Notifications
最後在補充一下,MessageInterceptor類別實作了IDisposable介面,因此,當你不使用或長時間不用該MessageInterceptor時,
要記得執行Dispose(),雖然.NET Compact Framework會自動幫你回收不用的物件資源,但如上述所提到的,如果您是建立成
持久型訊息攔截程式的話,它是一直活在註冊檔裡,不會因為你關閉程式或軟開機而消息,因此,一定要記得養好習慣,加上
Dispose(),就像我們使用SQLConnection的時候一樣的道理。
以上是補充說明如果建立持久性訊息攔截程式的方法(透過EnabledApplicatonLauncher方法)與獨立一個新的訊息處理Thread的
方式並且能與UI Thread互動(透過MessageInterceptor架構子設定與匿名委派的方式),那麼以下將提供二個範例分別說明:
(A) 說明如何透過MessageInterceptor架構設定參數方式獨立一個Thread與互動UI Thread
1: MessageInterceptor _smsInterceptor = null;
2:
3: private void frmExample2_Load(object sender, EventArgs e)
4: {
5: // InterceptionAction.NotifyAndDelete代表當訊息抵達時,通知攔截應用程序進行處理,
6: // 當此應用程序處理完訊息後,Pocket Outlook直接刪除原來的message.Note。任何其他攔截應用程序,不會再截獲此消息。
7: // false代表:該程式獨立執行在自己的訊息攔截程序上,不是在主應用程式程序上。
8: _smsInterceptor = new MessageInterceptor(InterceptionAction.NotifyAndDelete, false);
9:
10: // 設定MessageCondition:判斷寄件者是否包含電話號碼為+14254448851。
11: _smsInterceptor.MessageCondition =
12: new MessageCondition(MessageProperty.Sender,
13: MessagePropertyComparisonType.Contains, "+14254448851");
14: _smsInterceptor.MessageReceived += SmsInterceptor_MessageReceived_OnThread;
15: }
16:
17: // Notification runs on the message-interceptor thread, not the main
18: // application thread
19: void SmsInterceptor_MessageReceived_OnThread(object sender, MessageInterceptorEventArgs e)
20: {
21: SmsMessage newMessage = e.Message as SmsMessage;
22: if (newMessage != null)
23: {
24: // 使用匿名委派的方式BeginInvoke method 去控制主應用程式中的元件,並且更新它的值。
25: statusBar1.BeginInvoke((MethodInvoker)delegate
26: {
27: statusBar1.Text = "From:" + newMessage.From.Address;
28: });
29: textBox1.Text=string.Format("Sender:{0} - Body:{1}", newMessage.From.Address, newMessage.Body);
30: }
31: }
32:
33: private void frmExample2_Closed(object sender, EventArgs e)
34: {
35: if (_smsInterceptor != null)
36: {
37: // 當程式關閉時,移除該MessageInterceptor的MessageReceived的Event Hander,
38: // 並且進行Dispose(),回收該實作的物件。
39: _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived_OnThread;
40: _smsInterceptor.Dispose();
41: }
42: }
43:
44: #if PocketPC || Smartphone
45: // MethodInvoker is a delegate with no arguments and no return value
46: // MethodInvoker is part of the full .NET Framework but not the
47: // .NET Compact Framework so must declare explicitly
48: delegate void MethodInvoker();
49: #endif
要特別注意第44~第49行,這是建立委派的方式,必需透過明確的宣告方式,才能讓Message-Interceptor thread可以呼叫
處理UI Thread中的物件。
(B) 建立Persistent Message Interceptor與獨立Thread
1: MessageInterceptor _smsInterceptor = null;
2: //宣告一個常式代表要註冊於Persistent Message Notifications中識別MessageInterceptor的識別值。
3: const string _persistentIdentifier = "Contoso.Pharmaceuticals.MessageHandlerApp";
4:
5: private void frmExample3_Load(object sender, EventArgs e)
6: {
7: // 透過IsApplicationLauncherEnabled判斷是否有符合該常式的MessageInterceptor存在
8: if (!MessageInterceptor.IsApplicationLauncherEnabled(_persistentIdentifier))
9: {
10: // 如果該MessageInterceptor不存在要明確實例化,並且設定false代表不同的Thread
11: _smsInterceptor = new MessageInterceptor(InterceptionAction.NotifyAndDelete, false);
12: _smsInterceptor.MessageCondition = new MessageCondition(MessageProperty.Body,
13: MessagePropertyComparisonType.StartsWith, "Contoso Data:", false);
14: // 將MessageInterceptor加入Persistent Message Notifications
15: _smsInterceptor.EnableApplicationLauncher(_persistentIdentifier);
16: }
17: else
18: {
19: // 如果恐MessageInterceptor已存在,直接使用相同的常式取代現有的MessageInterceptor
20: _smsInterceptor = new MessageInterceptor(_persistentIdentifier, false);
21: }
22:
23: _smsInterceptor.MessageReceived += SmsInterceptor_MessageReceived_OnThread;
24: }
25:
26: // Notification runs on the message-interceptor thread, not the main
27: // application thread
28: void SmsInterceptor_MessageReceived_OnThread(object sender, MessageInterceptorEventArgs e)
29: {
30: try
31: {
32: SmsMessage newMessage = e.Message as SmsMessage;
33: if (newMessage != null)
34: {
35: // 使用匿名委派的方式BeginInvoke method 去控制主應用程式中的元件,並且更新它的值。
36: statusBar1.BeginInvoke(
37: (MethodInvoker)delegate
38: {
39: statusBar1.Text = "From:" + newMessage.From.Address;
40:
41: textBox1.Text = string.Format("Sender:{0} - Body:{1}", newMessage.From.Address, newMessage.Body);
42: });
43: }
44: }
45: catch (NotSupportedException ex)
46: {
47: Console.WriteLine(ex.Message);
48: }
49: catch (Exception ex)
50: {
51: if (ex is ArgumentException)
52: {
53:
54: }
55: }
56: }
57:
58: private void frmExample3_Closed(object sender, EventArgs e)
59: {
60: if (_smsInterceptor != null)
61: {
62: // Remove event handler to assure proper registry cleanup
63: _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived_OnThread;
64: _smsInterceptor.Dispose();
65: }
66: }
67:
68: // Remove persistent notification
69: private void menuDisablePersistentNotification_Click(object sender, EventArgs e)
70: {
71: // 確認_smsInterceptor是否已經實作化、而且該_smsInterceptor的識別值是否相等於
72: // 上述的_persistentIdentifier,最後確認_persistentIdentifier所對應的MessageInterceptor
73: // 是否已經被啟動了。如果有的話,要把它DisableApplicationLauncher()。
74: if (_smsInterceptor != null &&
75: _smsInterceptor.ApplicationLaunchId == _persistentIdentifier &&
76: MessageInterceptor.IsApplicationLauncherEnabled(_persistentIdentifier))
77: {
78: _smsInterceptor.DisableApplicationLauncher();
79: }
80: }
81:
82: etPC || Smartphone
83: // MethodInvoker is a delegate with no arguments and no return value
84: // MethodInvoker is part of the full .NET Framework but not the
85: // .NET Compact Framework so must declare explicitly
86: delegate void MethodInvoker();
87: #endif
以上是詳細介紹MessageInterceptor類別針對自訂訊息攔截、使用匿名委派、獨立不同的Thread與Thread間之間的互動,
希望對大家能有所幫助。如果有寫錯或不清楚的話,希望大家可以一起討論,分享學習經驗。
範例程式:
References:
http://msdn.microsoft.com/en-us/library/bb932385.aspx