State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask

You Can Take it With You

Syndication

News

  • Don't miss the next Windows Mobile Webcast... Unit Testing for Mobile Devices: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032382824&EventCategory=4&culture=en-US&CountryCode=US.

As you've probably gathered, I've been spending a lot of time working with the State and Notifications Broker lately. When you have the opportunity to spend this much time with a technology, one is bound to come across some of the unpolished edges.

One such unpolished edge relates to some significant inconsistencies in the way the SystemState class reports bitmask-based state values; a bitmask-based state value is a state value that requires the use of a bitmask to derive the state value from the registry value. These bitmask-based values are useful both in saving space in the registry and, as you saw in last week's post, optimizing value comparisons.

Converting a registry value to a bitmask-based state value is usually a 2-step process.

  • Apply the bitmask to the registry value - usually using a bitwise-and
  • Convert the result of the bitwise-and to the appropriate data type (often an enumeration value)


As you may recall, there are 3 ways to access a state value with the SystemState class.

  1. The most common way is to use one of the SystemState static properties
  2. You can also access the value from the ChangeEventArgs.NewValue property in the SystemState.Changed event handler
  3. When you create an instance of the SystemState class with the SystemProperty enumeration, you can access the state value using the SystemState class' CurrentValue instance property


The issue with the SystemState class is that the 3 ways to retrieve the state value do not apply the 2 conversion steps consistently.

  1. The SystemState static properties report the value correctly – no problem on these
  2. The ChangeEventArgs.NewValue property is not quite correct – It applies the bitmask but no type conversion.
  3. The SystemState class's CurrentValue instance property is the most concerning – it does not apply the bitmask (and therefore no type conversion). It returns the entire contents of the registry value.


As an example, checkout the following code.

SystemState _batteryStrength;
public FormMain()
{
InitializeComponent();
_batteryStrength = new SystemState(SystemProperty.PowerBatteryStrength);
_batteryStrength.Changed += new ChangeEventHandler(PowerBatteryStrength_Changed);
}
void PowerBatteryStrength_Changed(object sender, ChangeEventArgs args)
{
Debug.WriteLine("SystemState.PowerBatteryStrength = " + SystemState.PowerBatteryStrength);
Debug.WriteLine("PowerBatteryStrength args.NewValue = " + args.NewValue);
Debug.WriteLine("_batteryStrength.CurrentValue = " + _batteryStrength.CurrentValue);
}

In the code you can see that the _batteryStrength instance of the SystemState class is created using the SystemProperty.PowerBatteryStrength enum value and therefore represents the same state value that the SystemState.PowerBatteryStrength static property represents. As I mentioned above, although they represent the same state value, they report the state value differently.

Take a look at the figure below which shows the output from the 3 DebugWriteLine method calls in the PowerBatteryStrength_Changed event handler.

As you can see, the SystemState.PowerBatteryStrength static property reports the state value as the appropriate enum value. The NewValue property has the correct numeric value (41 is the integer representation of the BatteryLevel.Medium enum value).

It's the CurrentValue instance property that is most concerning; the value is not actually the PowerBatteryStrength state value but rather the entire contents of the registry value that contains the PowerBatteryStrength state value. For the CurrentValue instance property to be useful, you would need to explicitly apply the bitmask in your code.

The good news is, in practice the differences in the reported state values isn't as bad as it might look. For example, the ChangeEventArgs class' NewValue property is of type Object; therefore, you need to cast it to a PowerBatteryStrength enum type anyway. This means that for most values, you would write the same line of code to convert the state value from type Object to the appropriate enum value.

The following is the same line of code you write to retrieve the NewValue property as type BatteryLevel whether it contains the integer 41 or BatteryLevel.Medium.

BatteryLevel level = (BatteryLevel)e.NewValue;

As for the SystemState class' CurrentValue instance property, the CurrentValue instance property just isn't very useful in most cases where the SystemState instance is associated with a bitmask-based value. In the current SystemState class implementation, the CurrentValue property doesn't include any special optimization (such as caching the value' registry key handle); therefore, the CurrentValue instance property is no more efficient then using the corresponding SystemState class' static property. With this being the case, you can just use the SystemState class' static properties in most cases.


Posted Apr 27 2007, 04:55 PM by jim-wilson

Comments

Pablo wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-15-2007 6:26 AM
Hi Jim,

I've been reading your colaborations with MSDN about State and Notifications Broker, and I've posted several questions about a problem:

You explain very well how to be notified by the State and Notifications Broker when an event is fired.

But how can I be notified when the SN_TIME_VALUE key equals a Time specified by me?

Many thanks, and keep on teaching us!
Jim Wilson wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-15-2007 7:03 AM
I apologize if you've asked questions previously that I didn't answer - The months leading up to MEDC get pretty busy. In any case, it was definitely an oversight on my part for which I apologize.

Being notified when the SN_TIME_VALUE reaches a certain time should be as easy as using the NOTIFICATIONCONDITION structure in C or setting the SystemState ComparisonType & ComparisonValue members in .NET (see http://msdn2.microsoft.com/en-us/library/bb286907.aspx#ConditionalNotifications) but I'm concerned that Time is creating a bit of an extra challenge.

The time value is stored in the registry as a byte array containing the contents of a FILETIME structure expressed in UTC. So the question is, how do we pass in a FILETIME structure to the S&NB notification engine for comparison. To be honest, I'm not sure. :-)

I'm going to try a couple things and will follow up here shortly. Thanks for the great question and thank you for your compliments.

I'll be back as soon a I can. :-)

-Jim
Jim Wilson wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-15-2007 8:10 AM
So after poking around a bit, it looks like this is a pretty significant limitation on the part of the S&NB. Basically, it does not appear that there is a way to create a conditional notification based on the SN_TIME_VALUE. The problem (as you've probably ascertained) is that the notification system is based on either string or DWORD values but the Time is stored in the registry as a byte array.

I've tried the obvious workaround of passing a pointer to a FILETIME structure as the conditional value but with no luck. I'll follow up with some people in-the-know at Microsoft to see if there's something I'm overlooking or if this is really a limitation of the S&NB.

In the mean time a workaround you might consider is P/Invoking out to CeSetUserNotificationEx (http://msdn2.microsoft.com/en-us/library/ms908105.aspx) which allows you to either start an application or signal a Win32 event at a specified time. The DllImport declaration is somewhat involved for CeSetUserNotificationEx. I have the DllImport decleration around somewhere but have to find it. I'll post it as soon as I find it.

Wish I had better news - stay tuned for more...

-Jim
Jim Wilson wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-15-2007 8:24 AM
Pablo;

It just occurs to me that based on the nature of your questions, you appear to be using C rather then .NET CF which let's me off the hook for finding that P/Invoke declaration. :-)

I will post it later but it's a little lest pressing now. :-)

-Jim
Jim Wilson wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-17-2007 11:30 AM
Pablo;

I was able to speak to the author of the SN&B today. He indeed confirms that one cannot create a condition on the SN_TIME_VALUE or any other values that are not stored as a DWORD or string.

I've been digging around looking at the storage format of the various SN&B values and it seems that pretty much everything fits into the DWORD/string storage format except time. So, to me, the logical solution is to provide support for date-time values in addition to DWORD/string.

10% of the SN&B values in WM5 are date-time values so it does seem like it should be supported. If we had DWORD/string/date-time then we could filter on just about every value.
I've made the suggestion that they include date-time support for the next version but we'll have to see what happens.

The author agreed that for now the solution is to use one of the other APIs such as CeSetUserNotificationEx or CeRunAppAtTime. CeRunAppAtTime is good if you want to actually launch an app. CeSetUserNotificationEx adds the capability to signal a Win32 Event at a specific time. By using a Win32 Event, you can have a background thread just to a WaitForSingleObject on the event and have the background thread notify your application when the event occurs. (hey maybe I should make this an actual post) :-)

-Jim
manal wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-20-2007 3:11 PM
what is the equivalent to this code in VB?
_batteryStrength.Changed += new ChangeEventHandler(PowerBatteryStrength_Changed);

thanks
Jim Wilson wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-21-2007 6:28 AM
Manal;

There are two ways to hookup that event in VB.NET...

To dynamically add a handler at run time like C# does you simply provide a class level declaration for _batteryStrength and a method to handle the event - you then hook the two together using the AddHandler keyword...

Private _batteryStrength2 As SystemState
Private Sub _batteryStrength_Changed2(ByVal sender As Object, ByVal args As ChangeEventArgs)
MsgBox("Strength = " + args.NewValue.ToString(), MsgBoxStyle.DefaultButton1, "AddHandler")
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
_batteryStrength2 = New SystemState(SystemProperty.PowerBatteryStrength)
AddHandler _batteryStrength2.Changed, AddressOf _batteryStrength_Changed2
End Sub

One thing to remember though, C# only supports dynamic event associations. VB.NET supports both dynamic and static event associations. The above example uses dynamic association. In most cases VB.NET developers create a static association which is done by declaring the class-level variable using the WithEvents keyword and then identifying the method to handle the event using the Handles keyword.

Private WithEvents _batteryStrength As SystemState = New SystemState(SystemProperty.PowerBatteryStrength)
Private Sub _batteryStrength_Changed(ByVal sender As Object, ByVal args As ChangeEventArgs) Handles _batteryStrength.Changed
MsgBox("Strength = " + args.NewValue.ToString(), MsgBoxStyle.DefaultButton1, "WithEvents")
End Sub

Once you declare a class-level variable with the WithEvents keyword, Visual Studio can generate the static association for you. Simply declare the _batteryStrength variable with the WithEvents keyword as shown above. From the source code view, you can then select _batteryStrength in the Declerations drop-down (drop-down located at the top left of the code view window) and then select the event, in this case Changed, in the Method drop-down (drop-down located at the top right of the code view window)

I hope that helps. Please feel free to ask additional questions.

As time allows, I'll create VB versions of the code examples from my State & Notifications Broker series and post them here.

-Jim
manal wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-21-2007 9:25 AM
Really thanks for the great answer.
You’ll do us a fever by creating the VB version of your series, which is very clear and helpful. :-)
Sir, I am trying to use a persistent notification. Since the whole subject is new to me I need some help in this code, if you would help, please.
After reading your series and receiving your answer I wrote the following code in a console application:

If SystemState.IsApplicationLauncherEnabled("Ppharmacy") Then
edate = New SystemState("Ppharmacy")
AddHandler edate.Changed, AddressOf edate_Changed
Else
edate = New SystemState(SystemProperty.Date)
edate.EnableApplicationLauncher("Ppharmacy")
AddHandler edate.Changed, AddressOf edate_Changed
End If

I’m working on the date property.

The code above will lunch the application when the date changes (as I understood), but I want it to check the database then displays the expired drugs:
Connection.Open()
sql = "select MedicineName from Medicine where Medicine.ExpireDate < '" & SystemState.Date & "' ;"
da = New Data.SqlServerCe.SqlCeDataAdapter(sql, Connection)
dt = New Data.DataTable
da.Fill(dt)
If dt.Rows.Count <> 0 Then
''rise the notification
End If
How can I do it? shall I put this code in the handler edate_changed?

Did I do it right by adding the console application to the original project? Or I have to save it separately?

How can I Construct the notification string to contain the expired medicines?
A lot of thanks.
manal
Jim Wilson wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-22-2007 6:36 AM
Manal;

Before I answer, I want to be sure that I properly understand the scenario that you are working in and what you're trying to achieve. The following is what I believe you're describing...

You have created a console (no UI) application that once each day checks for the list of Medications that have expired. If that application identifies that 1 or more medications have expired then the console app will raise a user-defined State & Notification Broker notification that other applications are monitoring.

Is that correct? If I'm incorrect, please let me know where I went wrong. :-)

-Jim
manal wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-23-2007 5:12 AM
Dear Mr. Jim,
First I am sooo sorry about my second sentence. I meant that “you’ll do us great favor”, but English is not my native language so I have problems in writing. Please forgive me.
Second:
I wrote pocket PC application using windows mobile 5.0 pocket PC platform. If this application was not running and the date changed, a check should be performed for the database and only if there is/are expired drugs a notification should pop-up.(exactly as you said).
So I was advised to create a console application (no UI) to track SystemState.date and perform the check, so that I am notified when the date changes and the condition was met.

I added this code to the handler:

Connection.Open()
sql = "select MedicineName from Medicine where Medicine.ExpireDate < '" & SystemState.Date & "' ;"
da = New Data.SqlServerCe.SqlCeDataAdapter(sql, Connection)
dt = New Data.DataTable
da.Fill(dt)
If dt.Rows.Count <> 0 Then
MsgBox("There are/is Expired Medicine(s)", MsgBoxStyle.DefaultButton1, "AddHandler")
End If


But neither the message in the handler nor this check is performed; the application is lunched when the date changes, no matter if there was or not expired drugs.

Note: I wrote the S&N Broker code in the first form of the application, because the console application does nothing!
Jim Wilson wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-24-2007 3:42 PM
Manal;

Thank you for your apology but no apology is necessary. I totally understood what you meant. The only language I speak is english and I can't imagine how hard it must be to formulate complex questions and statements in a foreign language.

I wanted to let you know that I've been very busy these past two days and just have not had an opportunity to look your code. I'm hoping to have an opportunity to look at it tomorrow (Friday).

My sincere apologies for the delay - I'm just a little back-logged right now.

-Jim
manal wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 05-25-2007 3:45 AM
Mr. Jim,
Please take your time. I am not on a hurry.
Thanks
manal
manal wrote re: State and Notifications Broker - SystemState Class Inconsistencies in State Values that Involve a Bitmask
on 06-06-2007 7:56 AM
Hi Mr. Jim,
If I am not bothering you, I want to know the answer for my question if you know it.
Thanks
manal

Add a Comment

(required)  
(optional)
(required)  
Remember Me?