'코드'에 해당되는 글 3건

  1. 2007.08.29 Virtual-Key Codes 4
  2. 2007.07.31 RegistryNotifyCallback 4
  3. 2007.07.31 The State and Notifications Broker Part I 4
개발이야기2007. 8. 29. 13:45

 

Virtual-Key Codes

Send Feedback

The following table shows the symbolic constant names, hexadecimal values, and keyboard equivalents for the virtual-key codes used by the Microsoft Windows CE operating system. The codes are listed in numeric order. You can combine any of the codes with a modifier key to create a hot key.

Virtual key codes

Symbolic constant
Hexadecimal value
Mouse or keyboard equivalent

VK_LBUTTON
01
Left mouse button

VK_RBUTTON
02
Right mouse button

VK_CANCEL
03
Control-break processing

VK_MBUTTON
04
Middle mouse button on a three-button mouse

0507
Undefined

VK_BACK
08
BACKSPACE key

VK_TAB
09
TAB key

0A0B
Undefined

VK_CLEAR
0C
CLEAR key

VK_RETURN
0D
ENTER key

0E0F
Undefined

VK_SHIFT
10
SHIFT key

VK_CONTROL
11
CTRL key

VK_MENU
12
ALT key

VK_PAUSE
13
PAUSE key

VK_CAPITAL
14
CAPS LOCK key

1519
Reserved for Kanji systems

1A
Undefined

VK_ESCAPE
1B
ESC key

1C1F
Reserved for Kanji systems

VK_SPACE
20
SPACEBAR

VK_PRIOR
21
PAGE UP key

VK_NEXT
22
PAGE DOWN key

VK_END
23
END key

VK_HOME
24
HOME key

VK_LEFT
25
LEFT ARROW key

VK_UP
26
UP ARROW key

VK_RIGHT
27
RIGHT ARROW key

VK_DOWN
28
DOWN ARROW key

VK_SELECT
29
SELECT key

2A
Specific to original equipment manufacturer

VK_EXECUTE
2B
EXECUTE key

VK_SNAPSHOT
2C
PRINT SCREEN key

VK_INSERT
2D
INS key

VK_DELETE
2E
DEL key

VK_HELP
2F
HELP key

3A40
Undefined

VK_LWIN
5B
Left Windows key on a Microsoft Natural Keyboard

VK_RWIN
5C
Right Windows key on a Microsoft Natural Keyboard

VK_APPS
5D
Applications key on a Microsoft Natural Keyboard

5E5F
Undefined

VK_NUMPAD0
60
Numeric keypad 0 key

VK_NUMPAD1
61
Numeric keypad 1 key

VK_NUMPAD2
62
Numeric keypad 2 key

VK_NUMPAD3
63
Numeric keypad 3 key

VK_NUMPAD4
64
Numeric keypad 4 key

VK_NUMPAD5
65
Numeric keypad 5 key

VK_NUMPAD6
66
Numeric keypad 6 key

VK_NUMPAD7
67
Numeric keypad 7 key

VK_NUMPAD8
68
Numeric keypad 8 key

VK_NUMPAD9
69
Numeric keypad 9 key

VK_MULTIPLY
6A
Multiply key

VK_ADD
6B
Add key

VK_SEPARATOR
6C
Separator key

VK_SUBTRACT
6D
Subtract key

VK_DECIMAL
6E
Decimal key

VK_DIVIDE
6F
Divide key

VK_F1
70
F1 key

VK_F2
71
F2 key

VK_F3
72
F3 key

VK_F4
73
F4 key

VK_F5
74
F5 key

VK_F6
75
F6 key

VK_F7
76
F7 key

VK_F8
77
F8 key

VK_F9
78
F9 key

VK_F10
79
F10 key

VK_F11
7A
F11 key

VK_F12
7B
F12 key

VK_F13
7C
F13 key

VK_F14
7D
F14 key

VK_F15
7E
F15 key

VK_F16
7F
F16 key

VK_F17
80H
F17 key

VK_F18
81H
F18 key

VK_F19
82H
F19 key

VK_F20
83H
F20 key

VK_F21
84H
F21 key

VK_F22
85H
F22 key

(PPC only) Key used to lock device.

VK_F23
86H
F23 key

VK_F24
87H
F24 key

888F
Unassigned

VK_NUMLOCK
90
NUM LOCK key

VK_SCROLL
91
SCROLL LOCK key

VK_LSHIFT
0xA0
Left SHIFT

VK_RSHIFT
0xA1
Right SHIFT

VK_LCONTROL
0xA2
Left CTRL

VK_RCONTROL
0xA3
Right CTRL

VK_LMENU
0xA4
Left ALT

VK_RMENU
0xA5
Right ALT

BA-C0
Specific to original equipment manufacturer; reserved. See following tables.

C1-DA
Unassigned

DB-E2
Specific to original equipment manufacturer; reserved. See following tables.

E3 – E4
Specific to original equipment manufacturer

E5
Unassigned

E6
Specific to original equipment manufacturer

VK_PACKET
E7
Used to pass Unicode characters as if they were keystrokes. If VK_PACKET is used with SendInput, then the Unicode character to be delivered should be placed into the lower 16 bits of the scan code. If a keyboard message is removed from the message queue and the virtual key is VK_PACKET, then the Unicode character will be the upper 16 bits of the lparam.

E8
Unassigned

E9-F5
Specific to original equipment manufacturer

VK_ATTN
F6
ATTN key

VK_CRSEL
F7
CRSEL key

VK_EXSEL
F8
EXSEL key

VK_EREOF
F9
Erase EOF key

VK_PLAY
FA
PLAY key

VK_ZOOM
FB
ZOOM key

VK_NONAME
FC
Reserved for future use

VK_PA1
FD
PA1 key

VK_OEM_CLEAR
FE
CLEAR key

VK_KEYLOCK
F22
Key used to lock device

Original equipment manufacturers should make special note of the VK key ranges reserved for specific original equipment manufacturer use: 2A, DBE4, E6, and E9F5.

In addition to the VK key assignments in the previous table, Microsoft has assigned the following specific original equipment manufacturer VK keys.

Symbolic constant
Hexadecimal value
Mouse or keyboard equivalent

VK_OEM_SCROLL
0x91
None

VK_OEM_1
0xBA
";:" for US

VK_OEM_PLUS
0xBB
"+" any country/region

VK_OEM_COMMA
0xBC
"," any country/region

VK_OEM_MINUS
0xBD
"-" any country/region

VK_OEM_PERIOD
0xBE
"." any country/region

VK_OEM_2
0xBF
"/?" for US

VK_OEM_3
0xC0
"`~" for US

VK_OEM_4
0xDB
"[{" for US

VK_OEM_5
0xDC
"\|" for US

VK_OEM_6
0xDD
"]}" for US

VK_OEM_7
0xDE
"'"" for US

VK_OEM_8
0xDF
None

VK_OEM_AX
0xE1
AX key on Japanese AX keyboard

VK_OEM_102
0xE2
"<>" or "\|" on RT 102-key keyboard

For East Asian Input Method Editors (IMEs) the following additional virtual keyboard definitions must be observed.

Symbolic constant
Hexadecimal value
Description

VK_DBE_ALPHANUMERIC
0x0f0
Changes the mode to alphanumeric.

VK_DBE_KATAKANA
0x0f1
Changes the mode to Katakana.

VK_DBE_HIRAGANA
0x0f2
Changes the mode to Hiragana.

VK_DBE_SBCSCHAR
0x0f3
Changes the mode to single-byte characters.

VK_DBE_DBCSCHAR
0x0f4
Changes the mode to double-byte characters.

VK_DBE_ROMAN
0x0f5
Changes the mode to Roman characters.

VK_DBE_NOROMAN
0x0f6
Changes the mode to non-Roman characters.

VK_DBE_ENTERWORDREGISTERMODE
0x0f7
Activates the word registration dialog box.

VK_DBE_ENTERIMECONFIGMODE
0x0f8
Activates a dialog box for setting up an IME environment.

VK_DBE_FLUSHSTRING
0x0f9
Deletes the undetermined string without determining it.

VK_DBE_CODEINPUT
0x0fa
Changes the mode to code input.

VK_DBE_NOCODEINPUT
0x0fb
Changes the mode to no-code input.

Original equipment manufacturers should not use the unassigned portions of the VK mapping tables. Microsoft will assign these values in the future. If manufacturers require additional VK mappings, they should reuse some of the current manufacturer-specific and vendor-specific assignments.

See Also

Using Virtual-Key Codes | Manufacturer-specific Virtual-Key Codes

Virtual-Key Codes

Posted by krsuncom
개발이야기2007. 7. 31. 16:46

원본 : 요기

RegistryNotifyCallback

Windows Mobile

Windows Embedded CE

6/12/2007

This function registers a transient notification request. It is used to request that the caller be notified by a specified callback when a specified value has been changed.

SyntaxSyntax

Copy Code

HRESULT WINAPI RegistryNotifyCallback(
  HKEY hKey,
  LPCTSTR pszSubKey,
  LPCTSTR pszValueName,
  REGISTRYNOTIFYCALLBACK pfnRegistryNotifyCallback,
  DWORD dwUserData,
  NOTIFICATIONCONDITION * pCondition,
  HREGNOTIFY * phNotify
);

ParametersParameters

hKey

[in] Handle to a currently open key, or a predefined root value.

pszSubKey

[in] The key under which the value is stored. If this value is NULL, pszValueName is assumed to be under hKey.

pszValueName

[in] The name of the value on which change notifications are requested. If this value is NULL, it indicates the default value.

dwUserData

[in] User data that will be passed back to the user with the notification.

pfnRegistryNotifyCallback

[in] A pointer to a function that will be called back when a notification arrives. For a prototype for this function, see REGISTRYNOTIFYCALLBACK.

pCondition

[in] Condition that determines when to send the notification. When the comparison between pCondition and the new registry value is TRUE, then a notification is sent. If this value is NULL, any change results in a notification.

phNotify

[out] Receives the handle to the notification request. This handle should be closed using RegistryCloseNotification when notifications on this key are no longer needed. Resetting the device also stops the notification.

Return ValueReturn Value

Value
Description

S_OK

Request for change notification is registered.

E_INVALIDARG

Invalid hKey, phNotify, or pfnRegistryNotifyCallback.

An error value returned.

Error value wrapped as a FACILITY_WIN32 HRESULT.

RemarksRemarks

The client will be notified of changes via the callback, which is executed on private thread separate from the thread that called RegistryNotifyCallback.

If the value does not exist at the time of the call to RegistryNotifyCallback, the client will be notified when the value is added.

To stop notification and to close the notification handle, the caller must call RegistryCloseNotification. However, this type of notification is transient. Resetting the device stops the notification.

This function can be used to monitor any registry key in the system. The header file snapi.h contains definitions for the registry keys, paths, values, and bitmasks for all the base notifications that are provided by the system.

If the notification to the callback function fails, the notification will be removed.

If the key specified by hKey and pszSubKey doesn't exist, then hKey is monitored until pszSubKey is created, after which pszSubKey is monitored and changes to the key will trigger notifications as requested. To minimize possible performance degradation stemming from a large nuimber of subkeys being monitored, it is a best practice to pass (as hKey) the handle to a key that's as close as possible to pszSubKey rather than passing a root key. For example, if the client is a game and it is monitoring the key structure HKEY_CURRENT_USER\...\MyCoolGame\Player1 and the game could later create HKEY_CURRENT_USER\...\MyCoolGame\Player2, two possible ways to approach notification of changes to the Player2 key include:

Potential performance degradation
Fewer potential problems

hKey = handle to HKEY_CURRENT_USER andpszSubKey=the full path to Player2

hKey = handle to HKEY_CURRENT_USER\...\MyCoolGame\ andpszSubKey=Player2

Code ExampleCode Example

The following code example demonstrates how to use RegistryNotifyCallback.

Note:

To make the following code example easier to read, security checking and error handling are not included. This code example should not be used in a release configuration unless it has been modified to include them.

Copy Code

void AdjustPowerConsumption(HREGNOTIFY hNotify, DWORD dwUserData, const PBYTE pData, const UINT cbData);
// Register to be notified of changes to the eighth bit
// in SN_POWERBATTERYSTATE_VALUE. The eighth bit is set to one when 
// the battery is critically low (and set to zero and when it is not).
HRESULT RegistryNotifyCallbackExample()
{
    NOTIFICATIONCONDITION nc;
    HRESULT hr         = S_OK;
    HREGNOTIFY hNotify = NULL;
    // Initialize the notification structure.
    // The mask for the eighth bit.
    nc.dwMask = 0x8;
    // Receive a notification whenever that bit toggles.
    nc.ctComparisonType = REG_CT_ANYCHANGE;
    // dw is ignored for REG_CT_ANYCHANGE.
    nc.TargetValue.dw = 0;
    
    hr = RegistryNotifyCallback(SN_POWERBATTERYSTATE_ROOT, 
                                SN_POWERBATTERYSTATE_PATH, 
                                SN_POWERBATTERYSTATE_VALUE, 
                                AdjustPowerConsumption, 
                                0, 
                                &nc, 
                                &hNotify);
    // Close the notification using RegistryCloseNotification when done.
    // Note that it is alright to call RegistryCloseNotification from the callback function.
    // hr = RegistryCloseNotification(hNotify);
    return hr;
}
// This is the callback function.
void AdjustPowerConsumption(HREGNOTIFY hNotify, DWORD dwUserData, const PBYTE pData, const UINT cbData)
{
    DWORD dwCritical;
    HRESULT hr = S_OK;
    // pData contains the new value for SN_POWERBATTERYSTATE_VALUE.
    dwCritical = (*(DWORD*) pData);
    // Extract the eighth bit.
    dwCritical = dwCritical & 0x8; 
critically low.
    {
 your statements for preserving energy, here.
    }
    // The battery level was critically low, but it is not now.
    else
    {
        // Add your statements for returning to the normal battery state, here.
    }
}

Code ExampleCode Example

The following code example demonstrates how to register transient notification requests for phone StatStore values.

Note:

To make the following code example easier to read, security checking and error handling are not included. This code example should not be used in a release configuration unless it has been modified to include them.

Copy Code

#include <regext.h>
#include "snapi.h"
const TCHAR c_szPhoneRegistryRootkey[]      = TEXT("System\\State");
const TCHAR c_szPhoneRegistrySubkey[]       = TEXT("Phone");
const TCHAR c_szPhoneSignalStrength[]       = TEXT("Signal Strength");
const TCHAR c_szPhoneIncomingCallerNumber[] = TEXT("Incoming Caller Number");
const TCHAR c_szPhoneStatus[]               = TEXT("Status");
#define MAX_NOTIF 3
enum NotifType
{
      SignalStrength = 0,
      IncomingCallerNumber,
      PhoneRoaming
};
HREGNOTIFY g_hRegNotify[ MAX_NOTIF ] ;
// The call-back function for Registry Notifications.
void RegistryNotifyCallbackFunc(HREGNOTIFY hNotify, DWORD dwUserData, const PBYTE pData, const UINT cbData)
{
    TCHAR szOutput[MAX_PATH];
    // Identify the Notification received, based upon the User Data passed in, while registering for the notification.
    switch( dwUserData )
    {
        case SignalStrength:
            StringCchPrintf(szOutput, MAX_PATH, _T("The Signal Strength is %d"), (DWORD) *pData);
            break;
        case IncomingCallerNumber:
            StringCchPrintf(szOutput, MAX_PATH, _T("The Incoming Caller Number is %s"), (TCHAR*)pData);
            break;
        case PhoneRoaming:
            {
                  DWORD dw = 0;
                  // Copy the data sent to us into a local buffer.
                  memcpy(&dw, pData, cbData);
                  // Find out if the roaming status has been set by logically ANDing the data with the value 512 (the bitmask for roaming).
                  StringCchPrintf(szOutput, MAX_PATH, _T("The Roam Status of the Phone is %s"), ( dw & SN_PHONEROAMING_BITMASK ) == SN_PHONEROAMING_BITMASK  ? _T("TRUE") : _T("FALSE")  );
            }
            break;
        default :
            break;
    }
    OutputDebugString( szOutput );
    return;
}
void RegisterForPhoneNotifications()
{
    HKEY hKey;
    // Let us open the registry to get a handle to the Phone Registry key.
    if (S_OK == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szPhoneRegistryRootkey, 0,  KEY_QUERY_VALUE, &hKey))
    {
    // Since we are registering for multiple notifications, let's pass some unique User Data for each notification ( 5th param ), 
    // which will help us identify the notification in the Call Back.
     // Let us register for Signal strength notifications.
     HRESULT hr = RegistryNotifyCallback(hKey, 
                                         c_szPhoneRegistrySubkey,
                                         c_szPhoneSignalStrength,
                                         RegistryNotifyCallbackFunc,
                                         SignalStrength,
                                         NULL,
                                         &g_hRegNotify[ SignalStrength ] );
        
    // Let us register for Incoming Caller Number notifications.
            hr = RegistryNotifyCallback(hKey, 
                                        c_szPhoneRegistrySubkey,
                                        c_szPhoneIncomingCallerNumber,
                                        RegistryNotifyCallbackFunc,
                                        IncomingCallerNumber,
                                        NULL,
                                        &g_hRegNotify [ IncomingCallerNumber ] );
    //  Let us register for Roaming status change notifications.
            hr = RegistryNotifyCallback(hKey, 
                                        c_szPhoneRegistrySubkey,
                                        c_szPhoneStatus,
                                        RegistryNotifyCallbackFunc,
                                        PhoneRoaming,
                                        NULL,
                                        &g_hRegNotify [ PhoneRoaming ] );
        RegCloseKey(hKey);
      
    }
}
void  CloseAllNotifications ()
{
     for (int i = 0; i < MAX_NOTIF; i++)
    {
            RegistryCloseNotification(g_hRegNotify[i]);
    }
}

RequirementsRequirements

Header
regext.h

Library
aygshell.lib

Windows Embedded CE
Windows Embedded CE 6.0 and later

Windows Mobile
Pocket PC for Windows Mobile Version 5.0 and laterSmartphone for Windows Mobile Version 5.0 and later

See AlsoSee Also

Reference
REGISTRYNOTIFYCALLBACK Structure
RegistryBatchNotification
State and Notifications Broker Functions
State and Notifications Broker Reference
Concepts
Using the State and Notifications Broker in Native Code
Other Resources
State and Notifications Broker

 

RegistryNotifyCallback

Posted by krsuncom
개발이야기2007. 7. 31. 16:03

원본 : 요기

The State and Notifications Broker Part I

Jim Wilson
JW Hedgehog, Inc.

February 2006

Applies to:
   Microsoft .NET Compact Framework version 2.0
   Microsoft Visual Studio 2005
   Windows Mobile 5.0

Summary: In this month's column, Jim introduces the State and Notifications Broker and its role in enabling applications to work more closely with the Windows Mobile platform. The discussion covers the underlying architecture of the State and Notifications Broker, the use of the State and Notifications Broker API to retrieve more than 100 different state values, and how an application can cooperate with the State and Notifications Broker to receive notifications about changes to important state values, such as a change in network availability. This column covers both native and managed code usage of the State and Notifications Broker API.

This month's column is part one of a two-part examination of the State and Notifications Broker and is the first in a series of many deep-dive discussions about the new features Windows Mobile 5.0, the .NET Compact Framework 2.0 and Visual Studio 2005 provide. (20 printed pages)

Contents

Introduction
Getting Started with the State and Notifications Broker
Retrieving Windows Mobile State Information
Receiving Notifications
Conclusion

Introduction

As I mentioned in my previous column, A View of Windows Mobile 5.0 from 10,000 Feet, we are going to spend the next several months taking a detailed look at the new features that Windows Mobile 5.0, Visual Studio 2005, and the .NET Compact Framework version 2.0 offer developers. This first article in the series provides a detailed look at the Windows Mobile 5.0 State and Notifications Broker API.

I have to say that choosing the first feature to investigate was actually easier than I thought. I'm not saying that Windows Mobile 5.0, Visual Studio 2005, and the .NET Compact Framework 2.0 don't offer a lot of great new features—they certainly do. But the State and Notifications Broker API is one of those APIs that literally opens up a whole world of opportunities. Common situations that have historically been difficult to deal with programmatically become quite easy to manage—such as detecting changes in network connectivity, locating the Pocket Outlook contact that corresponds to the incoming caller, or determining that the device battery has become critically low. Similarly, situations where you have an application that needs to publish changes in the application's state or share data with other applications become significantly easier with the State and Notifications Broker API.

The State and Notifications Broker API offers too many features to cover in a single edition of this column, so I'm going to divide this discussion about the State and Notifications Broker API into two parts. In part I, we'll look at using the State and Notifications Broker API to more closely integrate your applications with the device and built-in Windows Mobile applications. In part II, we'll discuss using the State and Notifications Broker API in some more advanced situations, and we'll also look at how to expose state information from your own applications.

Getting Started with the State and Notifications Broker

As the name implies, the State and Notifications Broker provides two services. First, it acts as a central repository for state information without regard for the source of that information. Second, it provides a standard architecture for monitoring those state values for changes and distributing change notifications to the list of interested parties. Fundamentally the State and Notifications Broker is a data store that provides a standardized publish-subscribe model for distributing data change notifications. Don't let this simple definition fool you. The State and Notifications Broker is a very powerful tool.

With the State and Notifications Broker, Windows Mobile 5.0 changes a smart device from a device that simply runs a bunch of independent applications to a holistic platform where applications can easily share information and respond to changes in the device's state and to the state of other applications. The State and Notifications Broker provides the user with a high degree of continuity between individual applications and creates a device that, in a sense, runs a single meta-application made up of the best features of the individual applications that run on the device.

Remember that the State and Notifications Broker and the corresponding API, the State and Notifications Broker API, are part of the Windows Mobile 5.0 platform and, therefore, require you to install Visual Studio 2005 and the Windows Mobile 5.0 SDK for Pocket PC or Smartphone on your desktop computer.

Note   See the Windows Mobile 5.0 Developer Tools section in last month's column for the complete list of downloads and installations that are required to develop Windows Mobile 5.0 applications.
Locating the State and Notifications Broker API SDK Files

The exact location of the Windows Mobile 5.0 SDK on your desktop computer depends on which Windows Mobile 5.0 SDK you've installed. If you install the Windows Mobile 5.0 SDK for Smartphone and accept the default installation path, the SDK files are installed in \Program Files\Windows CE Tools\wce500\Windows Mobile 5.0 Smartphone SDK\. If you install the Windows Mobile 5.0 SDK for Pocket PC, you need to substitute Pocket PC for Smartphone in the previous path. With the Windows Mobile 5.0 SDK installed on their desktop computers, both managed-code and native-code developers have everything they need to use the State and Notifications Broker API.

The classes that are contained in the Microsoft.WindowsMobile.Status assembly expose the State and Notifications Broker API to managed-code developers. With the Windows Mobile 5.0 SDK installed, you can add a reference to the assembly by simply selecting it from the Add Reference dialog box in Visual Studio 2005, as shown in Figure 1.

Note   The Microsoft.WindowsMobile.Status assembly relies on types that are defined in the Microsoft.WindowsMobile assembly; therefore, anytime you add a reference to Microsoft.WindowMobile.Status to a project, you must also add a reference to Microsoft.WindowsMobile. Failing to do so will result in build errors.

Click here for larger image

Figure 1. Adding a reference to the Microsoft.WindowsMobile.Status assembly. Click the thumbnail for a larger image.

If you want to spelunk through the contents of the assembly by using a tool like ildasm or Reflector (for more information, see the Lutz Roeder's Programming.NET Web site), you need to open the assembly file directly, which you can find in the Designtimereferences subfolder of the Windows Mobile 5.0 SDK installation folder. All classes that are contained in the Microsoft.WindowsMobile.Status assembly are part of the "Microsoft.WindowsMobile.Status" namespace.

Native-code developers access the State and Notifications Broker API functions and structures by including the regext.h header file. This header file and other Windows Mobile 5.0 header files are located in the \Include\Armv4i subfolder of the Windows Mobile 5.0 SDK installation folder. The State and Notifications Broker API functions are all implemented in the aygshell.lib library. Visual Studio 2005 generated projects that target the Windows Mobile 5.0 platform automatically link to this library, so in most cases, you won't have to add the aygsell.lib file to the project libraries—because it will already be there.

Retrieving Windows Mobile State Information

As I mentioned previously in this article, one role of the State and Notifications Broker API is to provide unified access to state information. This information provides one-stop shopping for all of your system state needs. The Windows Mobile 5.0 platform ships with over 100 state values that the State and Notifications Broker tracks. These values relate to both the state of the device itself and the state of standard Windows Mobile 5.0–based applications such as Pocket Outlook.

Examples of system-wide state values include the following:

  • ActiveSync status
  • Whether a camera is present
  • Number of Bluetooth connections
  • List of current network connections
  • Whether a headset is connected
  • Whether a keyboard is connected
  • Display orientation
  • Battery strength
  • Outlook Mobile contact that corresponds to the current caller on the phone

Examples of per-user state values include the following:

  • Names of the currently active and previously active applications
  • Next calendar appointment
  • Media player information including current track title, artist, and album
  • Name of the Outlook Mobile e-mail account and number of unread e-mail messages
  • Name of short message service (SMS) account and number of unread SMS messages
  • Number of missed phone calls
  • Number of active tasks and number of overdue tasks

As you can see, the list of state information that the State and Notifications Broker tracks is quite comprehensive. In addition to more than 100 standard state values, original equipment manufacturers (OEMs) are free to add more values.

If you've been working with Windows Mobile–based devices for a while, you might notice that several of the listed state values are available from other APIs. For example, you can determine the current display orientation by calling the GetSystemMetrics function or by checking the Screen.PrimaryScreen.Bounds property if you are using managed code. Similarly, you can retrieve the current battery strength by calling the GetSystemPowerStatusEx method. And of course, information regarding the Calendar and Tasks is available through the Pocket Outlook API.

With these existing APIs, you may wonder why the State and Notifications Broker API has been added. As you'll see, there are a number of reasons, but one of the most notable is that the State and Notifications Broker API provides a single source for retrieving all state information. It is no longer necessary to hunt down a separate function or API for each individual state value. Also, prior to the introduction of the State and Notifications Broker API, determining a specific state value often required several function calls—and sometimes additional logic. With the State and Notifications Broker API, each state value is available through a single function call (in the case of native code) and as a single property value (in managed code).

The underlying implementation of the State and Notifications Broker uses the registry as the data store. All system-wide state values are stored under the HKEY_LOCAL_MACHINE\System\State registry key, and per-user state information is stored under the HKEY_CURRENT_USER\System\State registry key.

Under each of these registry keys, there are multiple child keys. Each child key has one or more values. These values hold the actual state information. Figure 2 shows the contents of the HKEY_LOCAL_MACHINE\System\State registry key on the Windows Mobile 5.0 Smartphone emulator.

Click here for larger image

Figure 2. State registry keys on the Windows Mobile 5.0 Smartphone emulator. Click the thumbnail for a larger image.

Accessing State Values from Native Code

With the information for the State and Notifications Broker being stored in the registry, you can easily access the information by using standard registry functions like RegOpenKeyEx and RegQueryValueEx. The following code example shows how to retrieve the name of the phone's service operator with native code by using these functions.

Copy Code

HKEY hPhone;
TCHAR tszOperatorName[1024];
DWORD dwType;
DWORD dwSize = sizeof(tszOperatorName);

RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\State\\Phone"),
             0, 0, &hPhone);
RegQueryValueEx(hPhone, _T("Current Operator Name"), 0, &dwType,
               (BYTE*)tszOperatorName, &dwSize);

This code uses the RegOpenKeyEx function to open the HKEY_LOCAL_MACHINE\System\State\Phone registry key and then retrieves the operator name from the key's Current Operator Name value using the RegQueryValueEx function.

If you've done some work with the registry, you know that this pattern of opening a key and then accessing a value is common. With the introduction of the State and Notifications Broker, this pattern of access will likely become even more common. As a result, to simplify accessing registry values, the State and Notifications Broker API introduces two new functions: RegistryGetString and RegistryGetDWORD. Each function encapsulates both opening a key and accessing a value. The two functions behave exactly the same; they are just specialized for retrieving either string or DWORD values. The following example retrieves the phone service operator this time by using the RegistryGetString function.

Copy Code

TCHAR tszOperatorName[1024];
RegistryGetString(HKEY_LOCAL_MACHINE, _T("System\\State\\Phone"), 
    "Current Operator Name", tszOperatorName, sizeof(tszOperatorName));

As you can see, this code example is much simpler than the previous code example because it requires only a single function call and avoids the need to declare the extra variables that the RegOpenKeyEx and RegQueryValueEx functions require.

One of the biggest challenges in working with the State and Notifications Broker API in native code is keeping track of all of the registry key and value names. With more than 100 standard state values in the State and Notifications Broker, there are also more than 100 registry key and value name combinations. You also need to keep track of whether the registry key that corresponds to the state value of interest is located under the HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER registry key. Thankfully, you can find the list of standard state values that the State and Notifications Broker API tracks and the corresponding registry information in the State and Notifications Broker Base Properties help topic within the mobile5sdk.chm help file, which is located in the Help subfolder of the Windows Mobile 5.0 SDK installation folder.

Note   The easiest way to locate the help topic is to open the mobile5sdk.chm file and search for the string "State and Notifications Broker Base Properties". At the time I wrote this article, there is a version of the State and Notifications Broker Base Properties help topic located in the MSDN Library, but it didn't include the registry key and value names.

The documentation is a great help, but with the registry key names and value names being strings, there's no way to know about any error that might exist in the registry key or value name strings at compile time. Instead, the program will fail at run time. To avoid this failure, the State and Notifications Broker API provides a header file, snapi.h, that provides a complete list of #define values for the standard State and Notifications Broker API state values. The #define values include the root key, the key name, and value name for each state value. The following code example is the portion of the snapi.h header file that corresponds to the phone service operator state value.

Copy Code

///////////////////////////////////////////////////////////////////////
// PhoneOperatorName
// Gets the name of the mobile operator (i.e., the mobile phone 
// company, or carrier).
#define SN_PHONEOPERATORNAME_ROOT HKEY_LOCAL_MACHINE
#define SN_PHONEOPERATORNAME_PATH TEXT("System\\State\\Phone")
#define SN_PHONEOPERATORNAME_VALUE TEXT("Current Operator Name")

The following code example shows accessing the phone service operator, this time by using the provided #define values instead of the literal strings.

Copy Code

TCHAR tszOperatorName[1024];
RegistryGetString(SN_PHONEOPERATORNAME_ROOT, SN_PHONEOPERATORNAME_PATH, 
    SN_PHONEOPERATORNAME_VALUE, tszOperatorName, 
    sizeof(tszOperatorName));

Using the #define values rather than literal strings makes the code easier to read and, in the event that there are any errors in the #define value names, the compiler reports them.

Working with DWORD Values and Bitmasks in Native Code

When accessing DWORD state values you use the RegistryGetDWORD function rather than the RegistryGetString function of course, but there's also a little more to it. Let's take a look at the #defines values for two state values in the snapi.h header file: Phone Multi-Line and Phone Radio Present.

Copy Code

///////////////////////////////////////////////////////////////////////
// PhoneMultiLine
// Gets a value indicating whether the phone supports multiple lines.
#define SN_PHONEMULTILINE_ROOT HKEY_LOCAL_MACHINE
#define SN_PHONEMULTILINE_PATH TEXT("System\\State\\Phone")
#define SN_PHONEMULTILINE_VALUE TEXT("Multiline Capabilities")

///////////////////////////////////////////////////////////////////////
// PhoneRadioPresent
// Gets a value indicating whether the mobile device has a phone.
#define SN_PHONERADIOPRESENT_ROOT HKEY_LOCAL_MACHINE
#define SN_PHONERADIOPRESENT_PATH TEXT("System\\State\\Phone")
#define SN_PHONERADIOPRESENT_VALUE TEXT("Status")
#define SN_PHONERADIOPRESENT_BITMASK 32

In the case of Phone Multi-Line, a single function call accesses the DWORD value very much like accessing a string state value, as shown in the following code example.

Copy Code

DWORD dwPhoneMultiLine;
RegistryGetDWORD(SN_PHONEMULTILINE_ROOT, SN_PHONEMULTILINE_PATH, 
    SN_PHONEMULTILINE_VALUE, &dwPhoneMultiLine);

By looking at the Phone Multi-Line #define values, you can see that the state value is stored in the MultiLine Capabilities value of HKEY_LOCAL_MACHINE\System\State\Phone. A quick look at Figure 3 shows that the state value is 1. As a result, the call to the RegististryGetDWORD function in the previous code example returns 1, indicating that the phone on the current device—in this case is the Windows Mobile 5.0 Smartphone emulator—supports multiple lines.

Click here for larger image

Figure 3. The Phone state values viewed with regedit.exe. Click the thumbnail for a larger image.

Note   In the case of the Windows Mobile 5.0 Smartphone emulator, the radio is a fake radio with service provided by Fake Network. From a programming standpoint, this emulator provides all of the characteristics of having a phone radio, so attempts to make a phone call or to check the status of the radio appear to succeed when, in reality, no phone actually exists. This fake radio is very useful for developing and initial testing of phone-related applications without incurring the cost of placing a mobile phone call or acquiring a device.

For the Phone Radio Present state value, the #define values show that it is stored in the registry value Status under the same key as Phone Multi-Line. If you look at Figure 3 again, it shows that the value stored in the registry for Status is 9437344. This value may look strange and certainly doesn't seem to apply to whether or not the device has a radio.

Unlike the registry value MultiLine Capabilities, which stores a single state value, Status actually stores multiple state values, and each state value is represented as a separate bit. To access the specific state value of interest, you must apply a bitmask. In the case of the Phone Radio Present state value, that bitmask is contained in the #define value SN_PHONERADIOPRESENT_BITMASK. The following code example shows using the bitmask to determine if the current device has a phone radio.

Copy Code

DWORD dwValue;
RegistryGetDWORD(SN_PHONERADIOPRESENT_ROOT, SN_PHONERADIOPRESENT_PATH, 
                 SN_PHONERADIOPRESENT_VALUE, &dwValue);
  BOOL bPhoneRadioPresent = dwValue & SN_PHONERADIOPRESENT_BITMASK;

As you can see, the initial value is still retrieved from the registry by using the RegistryGetDWORD function, but the additional step of applying the bitwise AND operator to the returned value is required to see if the bit corresponding to the state value Phone Radio Present is set.

Not all DWORD state values that require a bitmask are Boolean values. In some cases, a single DWORD is used to store two smaller ranged state values—as in the case of the Main registry value under HKEY_LOCAL_MACHINE\System\Status\Battery. This one registry value represents both the battery strength level and the battery state. These two state values also demonstrate another important issue: these values are enumerations. As enumerations, they each represent a finite set of values. The thing that I find frustrating is that the current implementation of the State and Notifications Broker API doesn't provide any corresponding C/C++ enum declarations or #define values. So you can either place the literal values in your code—leaving anyone who must later support that code to figure out what they mean—or you can provide your own #define declarations. The mobile5sdk.chm help file topic, State and Notifications Broker Base Properties, that I mentioned previously in this article contains the list of possible values for these two state values. The following code example contains #define values that you can use with the battery state and battery strength level state values.

Copy Code

#define BATTERYLEVEL_VERYLOW    0
#define BATTERYLEVEL_LOW       21
#define BATTERYLEVEL_MEDIUM    41
#define BATTERYLEVEL_HIGH      61
#define BATTERYLEVEL_VERYHIGH  81

#define BATTERYSTATE_NORMAL     0
#define BATTERYSTATE_NOTPRESENT 1
#define BATTERYSTATE_CHARGING   2
#define BATTERYSTATE_LOW        4
#define BATTERYSTATE_CRITICAL   8

Using these #define values, the following code example demonstrates accessing the battery state and battery strength level state values.

Copy Code

DWORD dwBatteryMain;
RegistryGetDWORD(SN_POWERBATTERYSTRENGTH_ROOT, 
                 SN_POWERBATTERYSTRENGTH_PATH, 
                 SN_POWERBATTERYSTRENGTH_VALUE, 
                 &dwBatteryMain);

int batteryLevel = (dwBatteryMain & SN_POWERBATTERYSTRENGTH_BITMASK) >> 16;
int batteryState = dwBatteryMain & SN_POWERBATTERYSTATE_BITMASK;

TCHAR tszBatteryLevel[256];
// Build a string description of the battery strength level
switch(batteryLevel)
{
    case BATTERYLEVEL_VERYLOW :
        _tcscpy(tszBatteryLevel, _T("Battery Level: Very Low"));
        break;
    case BATTERYLEVEL_LOW :
        _tcscpy(tszBatteryLevel, _T("Battery Level: Low"));
        break;
    case BATTERYLEVEL_MEDIUM :
        _tcscpy(tszBatteryLevel, _T("Battery Level: Medium"));
    case BATTERYLEVEL_HIGH :
        _tcscpy(tszBatteryLevel, _T("Battery Level: High"));
    case BATTERYLEVEL_VERYHIGH :
        _tcscpy(tszBatteryLevel, _T("Battery Level: Very High"));
        break;
}

TCHAR tszBatteryState[256];
// Build a string description of the battery state
_tcscpy(tszBatteryState, _T("Battery State: "));
if (batteryState & BATTERYSTATE_NORMAL)
    _tcscat(tszBatteryState, _T("Normal "));
if (batteryState & BATTERYSTATE_NOTPRESENT)
    _tcscat(tszBatteryState, _T("Not Present "));
if (batteryState & BATTERYSTATE_CHARGING)
    _tcscat(tszBatteryState, _T("Charging "));
if (batteryState & BATTERYSTATE_LOW)
    _tcscat(tszBatteryState, _T("Low "));
if (batteryState & BATTERYSTATE_CRITICAL)
    _tcscat(tszBatteryState, _T("Critical "));

This code example demonstrates several simple—but important—points. The first point is the opportunity to optimize the retrieval of state values when they share a single registry value. After the RegistryGetDWORD function is called to retrieve the registry value Main for the HKEY_LOCAL_MACHINE\System\State\Battery registry key, applying the respective bitmasks determines both the battery state and battery strength level state values. Reusing the registry value is obviously more efficient than making a second call to the RegistryGetDWORD function by using the SN_POWERBATTERYSTATE_XX #define values, which would return the same registry value that the call using the SN_POWERBATTERYSTRENGTH_XX #define values returned. This optimization is especially helpful in cases where the registry value represents a large number of state values. For example, the Status registry value for the HKEY_LOCAL_MACHINE\System\State\Phone registry key I discussed previously in this article actually holds 25 different state values—meaning that a single call to the RegistryGetDWORD function can retrieve one DWORD value that contains the 25 individual values. Each individual value is determined by simply using the bitwise AND operator to apply the appropriate #define value for each.

The second point demonstrated in the code example is the importance of knowing the value of the bitmask used to access the state value. In the case of battery strength level, the bitmask SN_POWERBATTERYSTRENGTH_BITMASK is 0xFFFF0000, indicating that the value is stored in the upper two bytes of the registry value. To make the result of the bitwise AND operator meaningful, you must shift the value 16 bits (two bytes) to the right. For example, if the result of the bitwise AND is 0x150000 (1,376,256 decimal), shifting the value 16 bits produces 0x15 (21 decimal). Checking the battery strength level #define values tells us that a battery strength level of 21 decimal means that the battery strength level is low.

The third point from the code example has to do with the knowing whether the state enumeration values are simple values or if these values also require the use of a bitmask. In the case of the battery strength level, the state value is a simple value, meaning that of the five #defines values, the battery strength level matches exactly one. With this being the case, the easiest way in the code example to check the current value is to simply use a switch statement. In the case of the battery state, you must use a bitmask to determine the state value itself because multiple battery states may be true at the same time; for example the battery may be charging, but it may still be low. As a result, the code example explicitly checks for each battery state by using a bitwise AND operator.

Accessing State Values from Managed Code (or Managed Code is Bliss)

As is usually the case, using C or C++ gives a developer the most direct access to the behaviors and capabilities of the platform. As is also usually the case, the cost of this direct access is that the C/C++ developer is responsible to handle the details involved in interacting with the platform. On the other hand, managed code puts a greater focus on developer productivity by choosing to encapsulate details within class libraries. I don't know that I've ever seen a case where the difference between these two philosophies is more evident than in the State and Notifications Broker API.

For managed-code developers, static properties in the SystemState class provide access to the standard State and Notifications Broker state values. Whether you are accessing the State and Notifications Broker API from native or managed code, the underlying implementation is identical and the same registry structure and values are being used. The one important difference is that all of the details of interacting with the registry including specific registry locations and the required bitmasks are completely encapsulated in the SystemState class. Managed-code developers simply access the SystemState static property that corresponds to the state value of their interests. The following code example demonstrates accessing the Phone Service Operator Name, Phone Multi-Line Capabilities, and Phone Radio Present state values.

Copy Code

using Microsoft.WindowsMobile.Status;
// …string operatorName = SystemState.PhoneOperatorName;
bool phoneMultiLine = SystemState.PhoneMultiLine;
bool phoneRadioPresent = SystemState.PhoneRadioPresent;

As you can see by the code example, the SystemState properties completely encapsulate the registry and bitmask details. Each property simply accesses the corresponding state value.

In addition to encapsulating the details of accessing the state values, the managed State and Notifications Broker API also makes interpreting the returned state values easier by providing .NET Compact Framework enumerated types for those properties that have enumerated return values, as demonstrated by the following code example.

Copy Code

BatteryLevel batteryLevel = SystemState.PowerBatteryStrength;
BatteryState batteryState = SystemState.PowerBatteryState;

string batteryLevelText;
switch (batteryLevel)
{
    case BatteryLevel.VeryLow:
        batteryLevelText = "Battery Level: Very Low";
        break;
    case BatteryLevel.Low:
        batteryLevelText = "Battery Level: Low";
        break;
    case BatteryLevel.Medium:
        batteryLevelText = "Battery Level: Medium";
        break;
    case BatteryLevel.High:
        batteryLevelText = "Battery Level: High";
        break;
    case BatteryLevel.VeryHigh:
        batteryLevelText = "Battery Level: Very High";
        break;
}

string batteryStateText = "Battery State: ";
if ((batteryState & BatteryState.Normal) == BatteryState.Normal)
    batteryStateText += "Normal";
if ((batteryState & BatteryState.NotPresent) == BatteryState.NotPresent)
    batteryStateText += "Not Present";
if ((batteryState & BatteryState.Charging) == BatteryState.Charging)
    batteryStateText += "Charging";
if ((batteryState & BatteryState.Low) == BatteryState.Low)
    batteryStateText += "Low";
if ((batteryState & BatteryState.Critical) == BatteryState.ChargCriticaling)
    batteryStateText += "Critical";

As you can see, the type of the SystemState.PowerBatteryStrength property is BatteryLevel, and the type of the SystemState.PowerBatteryState property is BatteryState making it very clear what to expect from each property. Notice that the way the enumeration values are tested in managed code is consistent with the same tests in native code; the BatteryLevel values are tested against specific values, whereas the BatteryState values are tested with a bitwise AND operator.

By encapsulating the details of the registry representation, the managed implementation of the State and Notifications Broker API makes accessing the standard state values extremely easy. This doesn't mean that managed-code developers never need to understand the registry structure. When we look at some of the more advanced uses of the State and Notifications Broker API next month, you will find that solidly understanding the State and Notifications Broker registry structure is just as important for managed-code developers as native-code developers.

Receiving Notifications

Acting as a central repository, the State and Notifications Broker certainly makes retrieving system and application information much easier than it was before the State and Notifications Broker API. Centralized state information is a great start, but for our applications to effectively cooperate with the device and the other applications running on those devices, we need to be able to do more than simply retrieve state values; we also need to be notified of changes to the state values. It's these notifications that transform the Windows Mobile platform from a bunch of independent applications into a holistic and cooperative platform of applications that work together as a single meta-application.

Note   The notifications feature of the State and Notifications Broker is extremely rich and flexible; however, I've just about used up all of the space I have for this month's column, so we'll focus on notification basics for now. In next month's column, we'll dig deep into the different notification features and capabilities.
Receiving Notifications in Native Code

change notifications, your application must perform three distinct steps:

  • Register to be notified about changes in one of the state values.
  • Handle the notification event.
  • Retrieve the new state value.

We'll look at how receiving notifications works by using one of the most important notifications to a mobile device application—the number of network connections. If the value is greater than zero, the device has a network connection and, therefore, can perform network-based communications.

The RegistryNotifyWindow function is the simplest way in native code to register for change notifications. The function accepts the registry key and value name of the monitored state value in addition to a window message identifier (ID) and a window handle. As the monitored state value changes, the State and Notifications Broker sends the specified message ID to the window identified by the handle.

The window message ID can be any valid message ID, but it is usually an ID value that is created by calling the RegisterWindowMessage function or by defining a constant based on the WM_USER #define value. For simplicity, we'll define a constant as shown in the following code example.

Copy Code

const DWORD WM_CONNECTIONSNETWORKCOUNT = WM_USER + 1;
Note   If you are new to creating custom window messages or haven't created one in a while, you can find more information about the importance of the WM_USER #define value from the MSDN documentation.

With the message defined, we are now ready to call the RegistryNotifyWindow function. You can call the RegistryNotifyWindow function at almost any point in the application you like—as long as the window represented by the window handle has been created. In this case, we want the notification sent to the main application window, so we can register in either the create (WM_CREATE) message handler or the InitInstance function.

The following code example shows calling the RegistryNotifyWindow function from the InitInstance function.

Copy Code

// Global Notification Handle
HREGNOTIFY g_hNotify = NULL;

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    // ...
    // ...

    g_hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
        NULL, NULL, hInstance, NULL);
    ShowWindow(g_hWnd, nCmdShow);
    UpdateWindow(g_hWnd);

    // Register for changes in the number of network connections
    HRESULT hr = RegistryNotifyWindow(SN_CONNECTIONSNETWORKCOUNT_ROOT,
        SN_CONNECTIONSNETWORKCOUNT_PATH, SN_CONNECTIONSNETWORKCOUNT_VALUE, 
        g_hWnd, WM_CONNECTIONSNETWORKCOUNT, 0, NULL, &g_hNotify);

    return TRUE;
}

Notice that the last parameter to the RegistryNotifyWindow function is a returned handle to the notification. The handle is used to close the notification when it is no longer needed. For easy access later, the application stores the handle in a global variable.

To handle the notification, we simply modify the switch statement that is contained in the window's WndProc function, so the switch statement includes a case condition for the notification's registered message ID. Depending on the data type of the value being monitored, the new data value may or may not be included in the message. For values that are stored in the registry as the REG_DWORD data type (which include all numeric and enumeration values), the new value is passed in the message WPARAM parameter. For string values, the application must call the RegistryGetString function to retrieve the new value. In the case of this example, the Connections Network Count state value is numeric and, therefore, the new value is contained in the WPARAM parameter of the message.

The following code example shows the relevant portions of the WndProc function to handle the notification.

Copy Code

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int nNetworkConnections;
    int wmId, wmEvent;
    
    switch (message) 
    {
        // Number of network connections changed
        case WM_CONNECTIONSNETWORKCOUNT:
            nNetworkConnections = (int) wParam;
            if (nNetworkConnections == 0)
                StopDataTransfer();
            else
                StartOrContinueDataTransfer();
            break;
        case WM_COMMAND:
            // ..
        case WM_PAINT:
            // ..
        case WM_CREATE:
            // ..
        case WM_DESTROY:
            // ..
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}

That's all there is to it—the application now responds to changes in available network connectivity. Just as the code example demonstrates, an application can monitor changes in any of the state values by simply registering to receive the notification, handling the notification, and retrieving the current value that, in many cases, is passed as part of the message.

One last thing to remember is that monitoring notifications consumes device resources, so you'll want to call the RegistryCloseNotification function when you no longer need the notification or when the application closes. The only argument to the RegistryCloseNotification function is the handle returned by calling the RegistryNotifyWindow function.

In many cases, you will want the notification for the life of the application, so the most logical place to close the notification handle is when the application closes, as shown in the following code example.

Copy Code

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int nNetworkConnections;
    int wmId, wmEvent;
    
    switch (message) 
    {
        case WM_CONNECTIONSNETWORKCOUNT:
            // ..
        case WM_COMMAND:
            wmId    = LOWORD(wParam); 
            wmEvent = HIWORD(wParam); 
            switch (wmId)
            {
                case IDM_EXIT:
                    // Close notification handle
                    if (g_hNotify)
                        RegistryCloseNotification(g_hNotify);

                    DestroyWindow(hWnd);
                    break;
                default:
                    return DefWindowProc(hWnd, message, wParam, lParam);
            }
        case WM_PAINT:
            // ..
        case WM_CREATE:
            // ..
        case WM_DESTROY:
            // ..
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}
Receiving Notifications in Managed Code

As in the case of retrieving values from the State and Notifications Broker, the .NET Compact Framework encapsulates many of the details that are involved in state value change notifications within the SystemState class. In addition to providing the many static properties that are used to access the state values, the SystemState class also provides a Changed instance-based event. To receive a state value change notifications, your application must perform the following two steps:

  • Create an instance of the SystemState class and pass the appropriate SystemProperty enumeration that identifies the value of your interest.
  • Attach a delegate to the new SystemState instance's Changed event.

After these steps are complete, the delegate will be called with each change in the state value.

The following code example shows the C# code to register for notification of changes in the Connections Network Count value.

Copy Code

public partial class FormMain : Form
{
    private void FormMain_Load(object sender, EventArgs e)
    {
         _connectionsNetworkCount = 
               new SystemState(SystemProperty.ConnectionsNetworkCount);
        _connectionsNetworkCount.Changed+=connectionsNetworkCount_Changed;
    }
    // ...
    // ...
}
    SystemState _connectionsNetworkCount;

The _connectionsNetworkCount instance invokes its Changed event on any change in the Connections Network Count state value, which then calls the connectionsNetworkCount_Changed method.

Implementing the connectionsNetworkCount_Changed method is very simple, as shown in the following code example.

Copy Code

void _connectionsNetworkCount_Changed(object sender, 
        ChangeEventArgs args)
{
    int connectionsCount = (int)args.NewValue;
    if (connectionsCount == 0;
        StopDataTransfer();
    else
        StartOrContinueDataTransfer();
}

The new state value is contained in the NewValue property of the ChangeEventArgs parameter. Unlike native code where the new value is only passed in the case of REG_DWORD typed values, managed code always passes the new value to the delegate. The ChangeEventArgs.NewValue property is of course declared as type object and must, therefore, be cast to the appropriate type as shown in the previous code example.

The only remaining consideration is releasing the resources that are associated with monitoring the state value. Like other classes in the .NET Compact Framework that hold unmanaged resources, the SystemState class implements the IDisposable interface and, therefore, has a Dispose method to release those resources.

The following code example releases the SystemState resources as part of the form's Closing event.

Copy Code

private void FormMain_Closing(object sender, CancelEventArgs e)
{
    if (_connectionsNetworkCount != null)
    {
        _connectionsNetworkCount.Dispose();
        _connectionsNetworkCount = null;
    }
}

Conclusion

You now know all you need to take advantage of the State and Notifications Broker as the central source for all device information—whether that information is related to the device itself or to the standard Windows Mobile 5.0 applications. By using the State and Notifications Broker API, you can easily retrieve the current contents of one of the state values and, if you want, you can have the system notify you of changes in that value.

The addition of the State and Notifications Broker opens up a whole new world of device application development. Device applications should not be an independent island unto themselves. With the State and Notifications Broker, you can now build your applications to interact much more closely with the system and the other applications on the system to provide the user with a much more holistic experience.

That does it for this month, but there are still many great State and Notifications Broker features we haven't gotten to yet. Please join me again next month as we cover some of the more advanced State and Notifications Broker features and show how you can integrate your own application's values into the system.

The State and Notifications Broker Part I

Posted by krsuncom