Important: |
---|
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. |
Jim Wilson,
November 2007
Summary
Short Message System (SMS) messaging provides a convenient way to communicate between applications running on separate devices; the MessageInterceptorclass allows you to easily incorporate SMS message handling in your application. This paper provides a description of the MessageInterceptorclass' capabilities and includes samples of the class' most common uses. Samples are shown in both C# and Microsoft® Visual Basic® .NET.
Applies To
Microsoft Windows Mobile® 6 Professional
Microsoft Windows Mobile 6 Standard
Microsoft Windows Mobile 6 Classic
Microsoft Windows Mobile 5.0 for Pocket PC Phone Edition
Microsoft Windows Mobile 5.0 for Smartphone
Microsoft Windows Mobile 5.0 for Pocket PC
Introduction
Exchanging Short Message System (SMS) messages, also known as "texting," is a simple, easy, and convenient way to communicate between mobile devices. In addition to being a great way for people to communicate, SMS can be a useful way for applications to exchange simple messages between devices. SMS doesn't require a direct connection between devices, the infrastructure for the system is already in place, and it works across most cellular service providers. One aspect of SMS that makes it especially useful for mobile applications is that it relies on a devices fixed identity, the phone number; this provides a distinct benefit over other technologies that rely on IP addresses because a device's IP address varies depending on its current network.
When it comes to working with SMS messages, there are of course two sides: sending messages and receiving messages. To send an SMS message using the .NET Compact Framework you simply use the SmsMessageClass and the class' Sendmethod. Sending SMS messages is reasonably easy; there's little information to add beyond what's covered in the documentation. To receive or more appropriately, to intercept, SMS messages you use the MessageInterceptorclass. The MessageInterceptorclass is also simple to use but there are a few nuances that are worth discussing.
How to use the MessageInterceptorclass to receive incoming SMS messages and the associated nuances is the subject of this paper. This paper includes several examples of using the MessageInterceptorclass. The examples are provided in both C# and Visual Basic .NET, and are located at the end of the paper.
Message Interception
If you've ever worked with the State and Notifications Broker API's primary class SystemState, you'll find working with the MessageInterceptorclass to be very similar. In both cases, you create an instance of the class, associate a filtering condition, and provide an event handler that the system calls each time an event or message meeting the criteria occurs. Unlike the SystemStateclass, which monitors a variety of different values, the MessageInterceptormonitors only arriving SMS messages.
Note: |
---|
Like the SystemStateclass, the MessageInterceptorclass must remain in-scope otherwise it may stop monitoring. For this reason, you rarely, if ever, create an instance of the MessageInterceptorclass as a local variable. Instead, you'll almost always create instances of the MessageInterceptorclass as a class-level field |
To use the MessageInterceptorclass you must add references to the Microsoft.WindowsMobileand Microsoft.WindowsMobile.PocketOutlookassemblies. The classes are all contained within the "Microsoft.WindowsMobile.PocketOutlook" and "Microsoft.WindowsMobile.PocketOutlook.MessageInterception" namespaces. C# developers need to include the appropriate usingstatements; Visual Basic .NET developers need to include the namespaces in the Microsoft Visual Studio® Imported namespacelist.
Note: |
---|
The topics discussed in the following subsections are demonstrated in Examples 1 and 2 located near the end of this paper. |
Deciding Whether to Share the Message
When you create an instance of the MessageInterceptorclass, the first thing you need to decide is whether you would like the intercepted messages to be available to other interceptor applications including the Windows Mobile Text Message reader. If you would like the message to be available to other interceptor applications, create the MessageInterceptorinstance passing the InterceptionAction.Notifyenumeration value to the MessageInterceptorconstructor. In this case, the messaging system passes a copy of the message to your application and continues notifying other interceptor applications. If you instead pass InterceptionAction.NotifyAndDelete, the messaging system deletes the message when your application finishes with it. If you create an instance of the MessageInterceptorclass with a constructor that does not accept a InterceptionActionparameter, the value defaults to InterceptionAction.Notify.
Note: |
---|
Setting the InterceptionActionto InterceptionAction.NotifyAndDeleteprevents the Windows Mobile Text Message reader from receiving the message but does not guarantee that no other message interceptor receives the message. An InterceptionActionvalue of InterceptionAction.NotifyAndDeletedoes not affect any interceptors that process the message prior to the messaging subsystem notifying your application. |
Filtering Messages
In most situations, the user's mobile device is not used exclusively for your application. The user likely uses the device for a variety of work and personal purposes. For this reason, when registering to intercept SMS messages, you should provide a filter condition. Creating a copy of the message and routing the copy to your application consumes device resources, therefore you should register your SMS interceptor so that it receives only those messages that meet a specific criteria. Allowing the messaging system to filter the incoming messages is much more efficient than performing the filtering in your application.
To create a filter condition you simply assign an instance of the MessageConditionclass to the MessageInterceptorinstance's MessageConditionproperty. The MessageConditionclass requires four pieces of information for a complete condition. First you must identify the part of the message to which the condition applies; you specify this value with the MessagePropertyenumeration. Second is the type of comparison to perform such as equal, contains, starts-with, and so on; you specify the comparison using the MessagePropertyComparisonTypeenumeration. Finally, the condition needs the value to use for the comparison and whether the comparison should be case-sensitive. Tables 1 and 2, respectively, show the values for the MessagePropertyand MessagePropertyComparisonTypeenumerations.
Table 1. MessageProperty enumeration values
Value | Description |
---|---|
Body |
Perform the comparison using the message body contents. |
MessageClass |
Perform the comparison using the message class. For all standard SMS messages the MessageClassvalue is the same, IPX.SMSText; an application would normally only check this value when working with a custom message type. |
Sender |
Perform the comparison using the sender information. When working with SMS messages, this value always includes the sender's phone number as consecutive digits with no separators such as a period, hyphen, or parenthesis. If the sender is contained in your Contacts list, the sender will also contain the sender's name as it appears in the Contact FileAsfield. |
Subject |
Perform the comparison using the message subject field. SMS messages do not have a subject therefore this value is not normally used. |
Table 2. MessagePropertyComparisonType enumeration values
Value | Description |
---|---|
Equal |
The message property and the comparison value must be an exact match. Use this comparison type with caution as any small change in the message property or the comparison value will result in a failed comparison. |
NotEqual |
The message property and comparison value must be different. |
Contains |
The comparison value appears within the message property. |
StartsWith |
The message property starts with the comparison value. |
EndsWith |
The message property ends with the comparison value. |
By default, the comparisons are case-sensitive. You can specify a case-insensitive comparison by passing false to the caseSensitiveparameter of the MessageConditionconstructor that accepts four parameters.
Handling Message Notifications
The MessageInterceptorclass exposes a single event named MessageReceivedthat accepts a MessageInterceptorEventHandlerdelegate. The MessageInterceptorclass signals the MessageReceivedevent when the device receives an SMS message meeting the condition associated with the MessageInterceptorinstance.
When the MessageReceivedevent signals, it passes a MessageInterceptorEventArgsreference to your event handler method. The MessageInterceptorEventArgsclass has only one public member: the Messageproperty that returns a reference to the received SMS message. The Messageproperty return type is the base class Message,which does not provide a reference to the message body; therefore, to access the message body you must cast the Messagereference to a SmsMessagereference.
Once your application associates an event handler with the MessageReceivedevent, you cannot make any modifications to the MessageInterceptorinstance; therefore, you must associate the MessageConditionwith the MessageInterceptorinstance before associating the event handler. For this reason, Visual Basic .NET developers cannot use the WithEventsdeclaration modifier. The WithEventsdeclaration modifier automatically associates an event handler when the MessageInterceptorinstance is created, which does not give you an opportunity to associate a MessageCondition. To associate a MessageConditionwith the MessageInterceptorclass in Visual Basic .NET, you must declare the MessageInterceptorreference without the WithEventskeyword and use the AddHandlerkeyword to attach an event handler to the MessageInterceptorinstance after you assign the MessageCondition.
Handling Message Notification Cleanup
When you create an instance of the MessageInterceptorclass and attach a delegate to the MessageReceivedevent, the MessageInterceptorclass creates a temporary registry entry under HKLM\Software\Microsoft\Inbox\Rules. The registry entry contains information about the MessageInterceptorinstance, which the messaging subsystem uses to notify the MessageInterceptorinstance when a message arrives. Once you are done with the MessageInterceptorinstance, the registry entry should be removed. Unfortunately, the MessageInterceptorclass does not always clean up the registry properly. As a result, the registry entry may remain in the registry indefinitely even though the MessageInterceptorclass will never use that entry again. These excess entries clutter the registry and over time, as the number of these unused entries grows, they may negatively impact message processing performance.
The MessageInterceptorclass creates the registry entry when you attach an event handler to the MessageReceivedevent; the MessageInterceptorwill also delete the entry if you remove the event handler from the MessageReceivedevent. Most applications do not explicitly remove event handlers and instead just let the .NET Compact Framework garbage collector remove them. Due to the problem in the MessageInterceptorclass' cleanup process, you must explicitly remove the event handlers to assure that the MessageInterceptorclass properly removes its registry entries.
Persistent Message Notifications
The discussion of message interception to this point focuses on transient message interception, message interception that begins and ends with a given program. Although transient message interception is appropriate for many situations, there will undoubtedly be other situations where you would like message interception to be in effect any time that the device is turned on without regard for whether your application is running. Persistent message notifications make this possible.
A persistent message notification stores the MessageInterceptorcharacteristics and the message handling application's information in the device registry; these registry entries remain even after your application exits. When a message arrives, the device messaging subsystem determines whether the message meets the persistent condition; when it does, the messaging subsystem identifies whether the application associated with the persistent condition is running. If the application is running, the messaging subsystem sends the message to the application just as the messaging subsystem normally does; if the application is not running, the messaging subsystem launches the application and then sends the message to the application. The beauty of persistent message notifications is that the message subsystem handles all the details of locating, launching, and notifying your application; your application requires very little change.
Note: |
---|
Note: The topics discussed in the following subsections are demonstrated in Example 3 located near the end of this paper. |
Creating Persistent Message Notifications
A persistent message interceptor usually starts as a transient message interceptor. You create the MessageInterceptorinstance specifying the InterceptionActionand MessageCondition; in most cases, you will also associate an event handler with the MessageReceivedevent. To make the message interceptor persistent, you call the MessageInterceptor.EnableApplicationLaunchermethod.
You can call the EnableApplicationLaunchermethod any time after you set the MessageConditionproperty. Unlike the MessageConditionproperty, you can safely call the EnableApplicationLaunchermethod after you attach an event handler to the MessageReceivedevent; this is safe because the EnableApplicationLaunchermethod does not change the state of the MessageInterceptorinstance. Exactly when you call the EnableApplicationLaunchermethod is up to you. You can call the EnableApplicationLaunchermethod immediately after you create and configure the MessageInterceptorinstance, at the end of your program just before you call the MessageInterceptorinstance's Dispose method, and anywhere in between.
The EnableApplicationLaunchermethod accepts a string parameter that uniquely identifies the MessageInterceptor. The string can be any value that you like as long as it will not collide with any other persistent message interceptor identifiers. Common examples of persistent message interceptor identifiers include globally unique identifiers (GUIDs), URLs, strings comprised of a combination of your organization and application name, and so on. Other versions of the EnableApplicationLaunchermethod let you specify a program other than the calling program as the program that the messaging subsystem should notify; you can also specify command-line arguments that the messaging subsystem will include when launching the application.
Note: |
---|
For a more detailed discussion of creating persistent
notification identifiers, see the Persistent Notifications section
of
|
Once you call the EnableApplicationLaunchermethod, your application is registered as a persistent notification handler; however, nothing changes for your application until the application exits.
Handling Application Start Up
Once you create a persistent message interceptor, you create the MessageInterceptorinstance to handle the message notifications differently. Rather than specifying the InterceptionActionand MessageConditionagain, you instead pass the persistent notification identifier to the MessageInterceptorconstructor. Using the identifier, the constructor reads the persistent message interceptor information from the registry and sets the MessageInterceptorinstance's InterceptionActionand MessageConditionappropriately. Whether you create the MessageInterceptorinstance using the transient notification or persistent notification constructor, you must associate an event handler with the MessageReceivedevent to receive the message notifications.
If you attempt to construct a MessageInterceptorinstance with a message interceptor identifier that that has not yet been registered by a call to the EnableApplicationLaunchermethod, the MessageInterceptorconstructor will throw an exception. To confirm that the message interceptor identifier is already registered, use the MessageInterceptor.IsApplicationLauncherEnabledstatic method. The IsApplicationLauncherEnabledmethod accepts a persistent message interceptor identifier and returns true if a persistent message interceptor definition exists with the specified identifier. When the IsApplicationLauncherEnabledmethod returns true, you create the MessageInterceptorinstance using the constructor that accepts the identifier; otherwise, you create the MessageInterceptornormally and call the EnableApplicationLauncherto create the persistent message interceptor.
Disabling Persistent Notifications
Because the persistent notification information is stored in the registry, the persistent notification information is truly persistent; even a soft reset of the device will not remove it. To disable a persistent notification, you must explicitly remove it. To remove a persistent notification, you call the MessageInterceptor.DisableApplicationLaunchermethod on a MessageInterceptorinstance that is associated with the persistent notification. You associate a MessageInterceptorinstance with a persistent notification by either calling the MessageInterceptorconstructor with the persistent notification identifier as a parameter or by calling the EnableApplicationLaunchermethod.
Message Notifications and Threading
By default, the MessageInterceptorclass signals the MessageReceivedevent on the main application thread, which in turn causes your event handler to run on the main application thread. If your application processes a large number of messages or message processing causes your application user interface to appear sluggish, you may want to move the message process to a separate thread.
Note: |
---|
The topics discussed in the following subsections are demonstrated in Examples 2 and 3 located near the end of this paper. |
Handling Message Notifications on a Separate Thread
Two of the MessageInterceptorconstructors accept a Boolean parameter named useFormThread. Passing false to the useFormThreadparameter causes the MessageInterceptorclass to monitor for arriving messages on a separate thread and therefore executes your MessageReceivedevent handler on this same thread. To simplify the discussion, the remainder of this paper will refer to the thread handling the message processing as the "message-interceptor" thread.
Even when you handle the MessageReceivedevent on the separate message-interceptor thread, you should avoid performing any long-running tasks in the event handler. All MessageInterceptorinstances share a single message-interceptor thread. As a result only one MessageInterceptorevent handler can run at a time. Therefore, a long-running event handler in one MessageInterceptorinstance prevents not only that instance from processing incoming messages but all MessageInterceptorinstances from processing incoming messages until the long-running event handler exits. In this case, your event handler should pass the message processing to a thread separate from the message-interceptor thread. By using a thread separate from the message-interceptor thread to process the message, your event handler can exit quickly and make the message-interceptor thread available to receive additional message notifications.
Note: |
---|
The
MessageInterceptorclass' thread handling is very much like
the thread handling of the
SystemStateand
RegistryStateclasses. If you would like to read a detailed
discussion of the threading behavior of these classes, please see
the "Threading and Notification Handling" section of
|
The MessageInterceptorinstance's threading choice is not stored as part of a persistent notification. If you would like the MessageInterceptorinstance associated with a persistent notification to run on a background thread, you must specify the desired threading behavior when you call the MessageInterceptorconstructor.
Interacting with the User Interface
Just as is the case with any application code running on a non-UI thread, your event handler must not attempt to interact directly with the application user interface. Your event handler must instead use the Control.Invokeand Control.BeginInvokemethods to interact with the user interface; failure to do so will cause your application to throw an exception.
Disposing Message Notifications
The MessageInterceptorimplements the IDisposableinterface which, of course, indicates that you should call the MessageInterceptor.Disposemethod when you no longer need the MessageInterceptorinstance. Many classes in the .NET Compact Framework are very forgiving if you forget to call the Disposemethod; however, that is not the case for the MessageInterceptorclass. Forgetting to call the MessageInterceptor.Disposemethod can cause your application to hang indefinitely at application shutdown.
In the .NET Compact Framework, an application does not fully exit until all of the application threads terminate. In the case of the MessageInterceptorclass, the message-interceptor thread does not terminate until you call the Disposemethod; therefore, your application will hang during the exit process if you forget to call the Disposemethod. As mentioned earlier in this paper, all MessageInterceptorinstances share a single message-interceptor thread. The MessageInterceptorclass tracks the number of MessageInterceptorinstances that are using the message-interceptor thread and does not terminate the thread until you call the Disposemethod on all of them.
Note: |
---|
In some cases, a .NET Compact Framework application will
automatically terminate running threads as part of the application
shutdown process but this not the case with the
MessageInterceptorclass. If you would like to learn more
about affects of threads on an application's lifecycle, see
|
Examples
The following examples demonstrate several common usages of the MessageInterceptorclass. All examples are provided in both C# and Visual Basic .NET. You can test the behavior of the MessageInterceptorin your application using the Device Emulator and Cellular Emulator included as part of the Windows Mobile 6 SDK.
If you're not familiar with how to set up and use the Cellular
Emulator, you may find the following short video helpful:
Example #1
This example demonstrates how to create a MessageInterceptorinstance that receives a copy of all SMS messages from a person named John Smith. To check the sender by name, the sender must be in the device's Contacts list. The MessageInterceptorinstance is handling the message notifications on the main application thread.
C#
Copy Code | |
---|---|
MessageInterceptor _smsInterceptor = null; private void Form1_Load(object sender, EventArgs e) { // Default constructor indicates that message handling should occur // on the main application thread, and message should be passed // to other message interceptors and to the SMS message reader _smsInterceptor = new MessageInterceptor(); // The name is reported in the form of the Contact's File As field // Therefore must check for "Smith, John", not "John Smith" _smsInterceptor.MessageCondition = new MessageCondition(MessageProperty.Sender, MessagePropertyComparisonType.Contains, "Smith, John", false); _smsInterceptor.MessageReceived += SmsInterceptor_MessageReceived; } void SmsInterceptor_MessageReceived(object sender, MessageInterceptorEventArgs e) { // Cast to SmsMessage to access message body // Not expecting to receive any non-SMS messages but use "as" to // cast to be extra safe SmsMessage newMessage = e.Message as SmsMessage; if (newMessage != null) { statusBar1.Text = "From:" + newMessage.From.Address; Debug.WriteLine(string.Format("Sender:{0} - Body:{1}", _ newMessage.From.Address, newMessage.Body)); } } private void Form1_Closed(object sender, EventArgs e) { if (_smsInterceptor != null) { // Remove event handler to assure proper registry cleanup _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived; _smsInterceptor.Dispose(); } } |
Visual Basic .NET
Copy Code | |
---|---|
' Do not use WithEvents or cannot associate a MessageCondition Private _smsInterceptor As MessageInterceptor = Nothing Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Default constructor indicates that message handling should occur ' on the main application thread, and message should be passed ' to other message interceptors and to the SMS message reader _smsInterceptor = New MessageInterceptor() _smsInterceptor.MessageCondition = New MessageCondition(MessageProperty.Sender, _ MessagePropertyComparisonType.Contains, "Smith, John", False) ' Explicitly attach the event handler rather than use WithEvents on the decleration AddHandler _smsInterceptor.MessageReceived, AddressOf SmsInterceptor_MessageReceived End Sub Private Sub SmsInterceptor_MessageReceived(ByVal sender As Object, ByVal e As MessageInterceptorEventArgs) ' Cast to SmsMessage to access message body ' Not expecting to receive any non-SMS messages but use "as" to ' cast to be extra safe Dim newMessage As SmsMessage = TryCast(e.Message, SmsMessage) If Not newMessage Is Nothing Then StatusBar1.Text = "From:" & newMessage.From.Address Debug.WriteLine(String.Format("Sender:{0} - Body:{1}", newMessage.From.Address, newMessage.Body)) End If End Sub Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed If Not _smsInterceptor Is Nothing Then RemoveHandler _smsInterceptor.MessageReceived, AddressOf SmsInterceptor_MessageReceived _smsInterceptor.Dispose() End If End Sub |
Example #2
This example demonstrates how to create a MessageInterceptorinstance that receives a copy of all SMS messages sent from the phone number 425.555.1212. The MessageInterceptorinstance handles the message notifications on a thread separate from the main application thread and prevents any further message interceptors, including the SMS message reader, from receiving the message.
C#
Copy Code | |
---|---|
MessageInterceptor _smsInterceptor = null; private void Form1_Load(object sender, EventArgs e) { // Construct interceptor so that the message does not propagate // any further than this application which prevents the message // from appearing in the message reader. // Handle message notifications on background thread _smsInterceptor = new MessageInterceptor(InterceptionAction.NotifyAndDelete, false); // When filtering by phone number, do not include any special // characters such as ().- // Can filter by phone number for all senders - whether the sender // is in the Contact list does not affect this. _smsInterceptor.MessageCondition = new MessageCondition(MessageProperty.Sender, MessagePropertyComparisonType.Contains, "4255551212"); _smsInterceptor.MessageReceived += SmsInterceptor_MessageReceived_OnThread; } // Notification runs on the message-interceptor thread, not the main // application thread void SmsInterceptor_MessageReceived_OnThread(object sender, MessageInterceptorEventArgs e) { SmsMessage newMessage = e.Message as SmsMessage; if (newMessage != null) { // Cannot interact directly with user interface - in this case // using an anonymous delegate with the BeginInvoke method to // to transfer control to the main application thread to update // the status bar statusBar1.BeginInvoke( (MethodInvoker)delegate { statusBar1.Text = "From:" + newMessage.From.Address; }); Debug.WriteLine(string.Format("Sender:{0} - Body:{1}", newMessage.From.Address, newMessage.Body)); } } private void Form1_Closed(object sender, EventArgs e) { if (_smsInterceptor != null) { // Remove event handler to assure proper registry cleanup _smsInterceptor.MessageReceived -= SmsInterceptor_MessageReceived; _smsInterceptor.Dispose(); } } #if PocketPC || Smartphone // MethodInvoker is a delegate with no arguments and no return value // MethodInvoker is part of the full .NET Framework but not the // .NET Compact Framework so must declare explicitly delegate void MethodInvoker(); #endif |
Visual Basic .NET
Copy Code | |
---|---|
Private _smsInterceptor As MessageInterceptor = Nothing Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Construct interceptor so that the message does not propagate ' any further than this application which prevents the message ' from appearing in the message reader. ' Handle message notifications on background thread _smsInterceptor = New MessageInterceptor(InterceptionAction.NotifyAndDelete, False) ' When filtering by phone number, do not include any special ' characters such as ().- ' Can filter by phone number for all senders - whether the sender ' is in the Contact list does not affect this. _smsInterceptor.MessageCondition = New MessageCondition(MessageProperty.Sender, _ MessagePropertyComparisonType.Contains, "4255551212") AddHandler _smsInterceptor.MessageReceived, AddressOf SmsInterceptor_MessageReceived_OnThread End Sub ' Notification runs on the message-interceptor thread, not the main ' application thread Private Sub SmsInterceptor_MessageReceived_OnThread(ByVal sender As Object, ByVal e As MessageInterceptorEventArgs) Dim newMessage As SmsMessage = TryCast(e.Message, SmsMessage) If Not newMessage Is Nothing Then ' Cannot interact directly with user interface ' using a custom delegate with the BeginInvoke method ' to transfer control to the main application thread to update ' the status bar Dim updateDelegate As New UpdateStatusBarDelegate(AddressOf UpdateStatusBar) StatusBar1.BeginInvoke(updateDelegate, New Object() {"From:" & newMessage.From.Address}) Debug.WriteLine(String.Format("Sender:{0} - Body:{1}", newMessage.From.Address, newMessage.Body)) End If End Sub ' This method is run on the main application thread by the call to ' StatusBar1.Invoke. Running on the main application thread, this method ' can safely update the user interface Sub UpdateStatusBar(ByVal text As String) StatusBar1.Text = text End Sub Private Sub Form1_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed If Not _smsInterceptor Is Nothing Then RemoveHandler _smsInterceptor.MessageReceived, AddressOf SmsInterceptor_MessageReceived _smsInterceptor.Dispose() End If End Sub ' Custom delegate used when StatusBar1.BeginInvoke calls UpdateStatusBar Delegate Sub UpdateStatusBarDelegate(ByVal text As String) |
Example #3
This example demonstrates how to create a MessageInterceptorinstance that is associated with a persistent notification. The program checks to see if the persistent notification was previously created and constructs the MessageInterceptorappropriately. The MessageInterceptorreceives only those messages where the message body begins with the text "Contoso Data:". The MessageInterceptorinstance handles the message notifications on a thread separate from the main application thread and prevents any further message interceptors, including the SMS message reader, from receiving the message.
This example also includes a menu handler that disables the persistent notification.
Note: |
---|
The SmsInterceptor_MessageReceived_OnThreadand Form1_OnClosedmethods are the same as those in Example 2 and are therefore not repeated. |
C#
Copy Code | |
---|---|
MessageInterceptor _smsInterceptor = null; const string _persistentIdentifier ="Contoso.Pharmaceuticals.MessageHandlerApp"; private void Form1_Load(object sender, EventArgs e) { if ( ! MessageInterceptor.IsApplicationLauncherEnabled(_persistentIdentifier)) { // Persistent notification does not yet exist - must explicitly create _smsInterceptor = new MessageInterceptor(InterceptionAction.NotifyAndDelete, false); _smsInterceptor.MessageCondition = new MessageCondition(MessageProperty.Body, MessagePropertyComparisonType.StartsWith, "Contoso Data:", false); // Make the interceptor persistent _smsInterceptor.EnableApplicationLauncher(_persistentIdentifier); } else { // Persistent notification already defined - create this instance using the // same characteristics _smsInterceptor = new MessageInterceptor(_persistentIdentifier, false); } // Once the interceptor is created, add event handler. Whether the interceptor is constructed // explicitly or constructed from the persistent notification identifier, // the event handling behavior is the same. _smsInterceptor.MessageReceived += SmsInterceptor_MessageReceived_OnThread; } // Remove persistent notification private void menuDisablePersistentNotification_Click(object sender, EventArgs e) { // Confirm that _smsInterceptor is a valid reference, that the current // _smsInterceptor instance is associated with the correct persistent // notification identifier, and that a persistent notification exists // that has the specified identifier if (_smsInterceptor != null && _smsInterceptor.ApplicationLaunchId == _persistentIdentifier && MessageInterceptor.IsApplicationLauncherEnabled(_persistentIdentifier)) { _smsInterceptor.DisableApplicationLauncher(); } } |
Visual Basic .NET
Copy Code | |
---|---|
Private _smsInterceptor As MessageInterceptor = Nothing Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load If Not MessageInterceptor.IsApplicationLauncherEnabled(_persistentIdentifier) Then ' Persistent notification does not yet exist - must explicitly create _smsInterceptor = New MessageInterceptor(InterceptionAction.NotifyAndDelete, False) _smsInterceptor.MessageCondition = New MessageCondition(MessageProperty.Body, _ MessagePropertyComparisonType.StartsWith, "Contoso Data:", False) ' Make the interceptor persistent _smsInterceptor.EnableApplicationLauncher(_persistentIdentifier) Else ' Persistent notification already defined - create this instance using the ' same characteristics _smsInterceptor = New MessageInterceptor(_persistentIdentifier, False) End If ' Once the interceptor is created, add event handler. Whether the interceptor is constructed ' explicitly or constructed from the persistent notification identifier, the event ' handling behavior is the same. AddHandler _smsInterceptor.MessageReceived, AddressOf SmsInterceptor_MessageReceived_OnThread End Sub ' Remove persistent notification Private Sub MenuEx3Disable_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuEx3Disable.Click If Not _smsInterceptor Is Nothing Then If _smsInterceptor.ApplicationLaunchId = _persistentIdentifier And _ MessageInterceptor.IsApplicationLauncherEnabled(_persistentIdentifier) Then _smsInterceptor.DisableApplicationLauncher() End If End If End Sub |
Conclusion
Communication is a key part of most mobile applications and SMS messaging is one of the simplest ways to exchange messages between applications on different devices. Using the MessageInterceptorclass, you can easily incorporate SMS message handling into your .NET Compact Framework application. The MessageInterceptorclass enables you to easily filter unwanted messages and prevent non-user messages from appearing in the device SMS message reader; you can also configure the MessageInterceptorclass to automatically start your application when a message of interest arrives. You do, of course, need to be sure that you clean up the resources appropriately to avoid cluttering the device registry, but once you create and configure an instance of the MessageInterceptorclass, it takes care of the details of filtering and routing the messages; you simply need to process the message contents when it arrives and release the associated resources when you are done.
See Also
Other Resources
Jim Wilson is president of JW Hedgehog, Inc. (http://www.jwhh.com) a New Hampshire–based consulting firm specializing in solutions, content creation, and mentoring for the Windows Mobile platform. Jim has worked extensively with the .NET Framework and .NET Compact Framework since the original beta release of each; he has over 20 years experience in the software industry including more than 14 years experience with relational database programming including SQL Server and SQL Server Compact Edition. Jim writes frequently for MSDN® and has developed mobility curriculums for two of the industry’s leading technology training organizations, DevelopMentor and PluralSight. Jim speaks regularly at Tech Ed, the Professional Developer's Conference (PDC), VSLive, and the Mobility & Embedded DevCon. You will find Jim online at http://pluralsight.com/blogs/jimw.