Creating a Temperature Sensor Gadget for Windows Sidebar with C++

The following post describes a gadget for Windows Sidebar that displays the temperature reading from a temperature sensor device. Similar applications could be written to display: battery-level or available memory for a portable media device, contact lists from a mobile phone or PDA, route lists from a GPS device, and so on.

Introduction

Microcontrollers are used in a variety of applications from industrial to automotive to the home. One use that stretches across these boundaries is the microcontroller-based sensor which monitors parameters such as temperature, humidity, acceleration, distance, and light.

While the microcontroller device-universe has grown exponentially, there hasn’t been a common interface for integrating these devices with the PC. As a result, device and application developers were forced to write custom software to handle operations like data retrieval and display.

Microsoft recently introduced Microsoft® Windows® Portable Devices (WPD), a technology that addresses the challenges of integrating microcontroller-based devices with your PC. A microcontroller-based device can be as simple as a remote sensor or as complex as a mobile phone, a portable media player, or a digital camera. WPD consists of a driver model that runs in the user-mode driver framework (UMDF) and an API that simplifies the creation of applications for these devices.

This paper describes the use of the WPD API to create a Windows Console application that retrieves temperature data from a temperature sensor device. In addition, it describes a corresponding gadget for Windows Sidebar that consumes the data collected by the application.

The temperature sensor used by this application is based on the BASIC Stamp Activity Kit for Windows Portable Devices. This kit is offered by the Parallax Corporation in Rocklin, California. You can order the kit from the company’s Web site.

The console application obtains real-time temperature data from a Parallax temperature sensor device. It writes this data to a file on disk. A script in the gadget’s HTML file retrieves the data and renders it in Windows Sidebar.

The console application was written in Microsoft Visual Studio® 8 using the C++ programming language. The WPD gadget was written in HTML and Jscript®.

Downloading the Sample Application and Sidebar Gadget

To download the sample application, see this page on the Microsoft Downloads site.

To download the gadget, see this page on the Microsoft Downloads site.

Running the Sample Application

The sample application requires that the WPD temperature sensor driver (WpdTempSensorDriver.dll) is installed and that a temperature sensor device is connected over a standard RS232 port.

The WPD temperature sensor driver exposes a Temperature Sensor object. This object, in turn, exposes three programmatic elements: two properties and an event. These elements are described in the following table.

Programmatic Element

Description

Interval property

This read/write property specifies the frequency at which the device should return the current temperature. (This property is specified in milliseconds.)

Temperature property

This read-only property specifies the current temperature in degrees Kelvin.

Temperature-reading event

This event is fired each time the device retrieves the current temperature. (The Interval property specifies the frequency at which the device will fire this event.)

 

The sample console application, described in this white paper, registers to receive the Temperature-reading event notification each time it’s fired. Upon receiving the notification, the application writes the temperature data as HTML and saves it in an ASCII text file. The gadget, in turn, reads the HTML from this file and renders it in Sidebar.

Building and Installing the Temperature Sensor Device

The temperature sensor device referenced in this paper is based on a Parallax BS2 microcontroller and an AD592 Temperature Sensor transducer.

Parallax supplies a complete hardware kit that includes all of the required components. To order the kit, see this page on the Parallax site.

You can download the Basic Stamp source code for the temperature sensor device from the WHDC site.

Building and Installing the WPD Temperature Sensor Driver

In order to install the driver, download the source code and build it. For information about downloading the driver, see the following topic on the WHDC Web site.

Installing the Gadget

The download package referenced above in this article contains a file named WpdTemperatureSensor.gadget. Copy this file to your local machine, open Windows Explorer, and double-click this file. You will be asked whether you want to install the gadget. Click Install.

The gadget will be installed in the Desktop\\AppData\Local\Microsoft\Windows Sidebar\Gadgets folder.

Now you’re ready to build and run the sample application.

Building and Running the Sample Application

The download package included with this white paper contains the project, source, and header files for the sample console application that retrieves temperature data from the sensor.

After you’ve installed the temperature sensor device, driver, and gadget files, you’ll need to extract the contents of the download package to your development machine. This includes the following files.

· stdafx.h

· stdafx.cpp

· deviceevents.cpp

· sidebar_console.cpp

· sidebar_console.vcproj

For a description of these files, see the Temperature Sensor Console Application section that follows.

If you haven’t installed the Windows SDK for Windows Vista, you’ll need to do so before building the project. For information about installing the Windows SDK, visit the Windows SDK web page.

 

Once the Windows SDK is installed, open the project file (sidebar_console.vcproj) in Visual Studio 8. Select the Build_Sidebar console option from the Build menu. Visual Studio 8 will build an executable file and place it in the \Debug subdirectory. You can test the gadget and verify that it works by selecting Start Debugging from the Debug menu.

WPD Application and Gadget Overview

The WPD application and gadget consists of two separate processes: a server and a client. The server is a console application which monitors the temperature sensor device for event notifications. Each time this application receives a notification, it writes corresponding temperature data formatted as HTML to a file on disk. The client is a script running in the gadget’s HTML file. This script retrieves the data from the file created by the console application and renders it in Sidebar.

The WPD Console Application registers to receive temperature events from the device. These events are fired at an interval specified by the device’s Interval property. (The default value for this property is 2,000 milliseconds.)

The event handler in the console application writes the temperature as a string of HTML to an ASCII text file on the local disk. This string has the following appearance.

<P>Office Temperature<P>304&deg; Kelvin

The gadget’s script executes every 3,000 milliseconds. The script reads the string of HTML created by the console application and inserts that string into the body of the gadget’s HTML.

The Temperature Sensor Console Application

The temperature sensor console application is a simple application that accomplishes the following tasks.

· Searches for the temperature sensor device and opens a connection if the device is found.

· Registers to receive event notifications from the device.

· Enters a loop and responds to any one of three inputs from the user.

· While listening for user input, and for as long as the event registration is intact, writes temperature data to the local disk.

The temperature sensor application project consists of the following files:

File

Description

stdafx.h

Contains #defines for the target platform as well as #includes for the standard system include file.

deviceevents.cpp

Implements IPortableDeviceEventCallback which is required by any WPD application that registers to receive device events.

sidebar_console.cpp

Implements the entry point for the console application and the helper functions which perform tasks like searching for the device and establishing a connection.

stdafx.cpp

Contains #include for stdafx.h

sidebar_console.vcproj

The Visual Studio 8 project file.

 

Most of work accomplished by the application is found in the module named sidebar_console.cpp; the exception is the event handling code which is found in the module deviceevents.cpp.

Opening a Connection to the Temperature Sensor Device

The WPD API provides a set of interfaces that a Windows programmer can use to accomplish tasks like enumerating connected devices, opening a device, closing a device, enumerating objects on a device, reading and writing properties on a device, sending a command to a device, and registering to receive events from a device.

One of the primary interfaces is the IPortableDevice interface which supports the methods a programmer calls to open a device, receive events, send a command, and so on.

The first task the sample application accomplishes is to open (establish a connection to) the temperature sensor device. It does this by calling the IPortableDevice::Open method. This method takes two parameters: a pointer to a string that specifies a special identifier for the device and a pointer to an array of key/value pairs that specify information about the calling application.

 

hr = CoCreateInstance(CLSID_PortableDevice,

                         NULL,

                         CLSCTX_INPROC_SERVER,

                         IID_IPortableDevice,

                         (VOID**) &pIPortableDevice);

   if (SUCCEEDED(hr))

   {

       if (pIPortableDevice != NULL)

       {

            hr = (pIPortableDevice)->Open(DeviceID, pClientInformation);

           if (FAILED(hr))

           {

               // Release the IPortableDevice interface

              // because we cannot proceed with an

               // unopen device.

               pIPortableDevice = NULL;

            }

           else

           {

               printf("Device successfully opened.\n\r\n\r");

           }

        }

In order to retrieve the device identifier DeviceID, which is passed as the first parameter to IPortableDevice::Open, the application first needs to determine whether the temperature sensor device is connected to the PC and, if it is, retrieve the identifier.

The FindDevice helper function in the Sidebar_Console.cpp module accomplishes this work. The FindDevice function has two arguments: the first is a “friendly” name for the target device; the second is the special Plug and Play identifier that the WPD API returns as a match for this friendly name.

The FindDevice helper function accomplishes the following tasks.

1.  Retrieves a count of devices connected to the PC.

2. Retrieves an array of friendly names for each device.

3. Compares the friendly name passed in its first argument to the friendly names for each of the connected devices.If a match is found, it retrieves the Plug and Play identifier for the target device.

Retrieving a Count of Connected Devices

The first task of the FindDevice function is the retrieval of a count of connected devices. This is done in two stages: first, by creating an IPortableDeviceManager object, and second, by calling the IPortableDeviceManager::GetDevices method. (In order to retrieve a count of connected devices, the first argument to GetDevices is set to NULL.)

 

// CoCreate the IPortableDeviceManager interface to enumerate

// portable devices and to get information about them.

hr = CoCreateInstance(CLSID_PortableDeviceManager,

              NULL,

              CLSCTX_INPROC_SERVER,

              IID_IPortableDeviceManager,

              (VOID**) &pPortableDeviceManager);

if (FAILED(hr))

{

     printf("! Failed to CoCreateInstance CLSID_PortableDeviceManager\n\r\n\r");

     return hr;

}

 

// First, pass NULL as the LPWSTR array pointer to get the total

// number of devices found on the system.

if (SUCCEEDED(hr))

{

    hr = pPortableDeviceManager->GetDevices(NULL, &cPnPDeviceIDs);

    if (FAILED(hr))

    {

        printf("! Failed to get number of devices on the system\n\r\n\r");

        return hr;

    }

}

Retrieving a Plug and Play name for the Temperature Sensor

WPD supports two types of device names: friendly names and Plug and Play names. The friendly names are the names applications display to the user. The friendly name for the temperature sensor device is: "Parallax BS2 Temperature Sensor". The Plug and Play names are used internally by WPD to identify devices. The Plug and Play name for the temperature sensor device is:

\\?\root#wpd#0000#{6ac27878-a6fa-4155-ba85-f98f491d4f33}

This string uniquely identifies the device instance and the device interface, and it is defined as part of the Windows Driver Model (WDM). For more information, refer to this MSDN topic.

 

After retrieving a count of connected devices and storing it in the cPnPDeviceIDs variable, FindDevice iterates through the available devices until it finds a device whose friendly name matches the string “Parallax BS2 Temperature Sensor”. If this match is made, FindDevice returns the corresponding Plug and Play name in the DeviceID argument.

 

        if (cPnPDeviceIDs > 0)

        {

            pPnpDeviceIDs = new LPWSTR[cPnPDeviceIDs];

            if (pPnpDeviceIDs != NULL)

            {

                DWORD dwIndex = 0;

 

                hr = pPortableDeviceManager->GetDevices(pPnpDeviceIDs, &cPnPDeviceIDs);

                if (SUCCEEDED(hr))

                {

                    // For each device found, retrieve the friendly

                    // name and compare it to the submitted name.

                    for (dwIndex = 0; dwIndex < cPnPDeviceIDs; dwIndex++)

                    {

                        CAtlStringW FriendlyName;

                        hr = RetrieveFriendlyName(pPortableDeviceManager, pPnpDeviceIDs[dwIndex], FriendlyName);

                 if ((hr == S_OK) && (DeviceName.CompareNoCase(FriendlyName) == 0))

                        {

                             DeviceID = pPnpDeviceIDs[dwIndex];

                             bFoundDevice = TRUE;

                             break;

      }

                    }

                }

                else

                {

                    printf("! Failed to get the device list from the system\n\r\n\r");

                }

 

                if (SUCCEEDED(hr) && (!bFoundDevice))

                {

                    printf("! Failed to find a matching device\n\r\n\r");

                    hr = E_FAIL;

                }

 

 

                // Free all returned PnPDeviceID strings by using

                // CoTaskMemFree.

        // NOTE: CoTaskMemFree can handle NULL pointers, so

                // no NULL check is needed.

                for (dwIndex = 0; dwIndex < cPnPDeviceIDs; dwIndex++)

                {

                    CoTaskMemFree(pPnpDeviceIDs[dwIndex]);

                    pPnpDeviceIDs[dwIndex] = NULL;

                }

 

                // Delete the array of LPWSTR pointers.

                delete [] pPnpDeviceIDs;

                pPnpDeviceIDs = NULL;

        }

        else

        {

            printf("! Failed to allocate memory for LPWSTR array\n\r\n\r");

            hr = E_OUTOFMEMORY;

        }

       }

 

    return hr;

}

 

The application passes the returned Plug and Play name as the first argument to IPortableDevice::Open when it opens the device.

Note that the FindDevice function calls the RetrieveFriendlyName helper function to retrieve a friendly name for each Plug and Play name returned by IPortableDeviceManager::GetDevices. The RetrieveFriendlyName function calls the IPortableDeviceManager::GetFriendlyName method twice to retrieve the friendly name string. The first time, it calls this method to retrieve a count of characters in the friendly name string; the second time, it calls this method to retrieve the actual string.

 

    // First, pass NULL as the LPWSTR return string parameter to get

    // the total number of characters to allocate for the string

    // value.

    hr = pPortableDeviceManager->GetDeviceFriendlyName(pPnPDeviceID, NULL, &cchFriendlyName);

    if (FAILED(hr))

    {

        printf("! Failed to get number of characters for device friendly name.\n\r\n\r");

        return hr;

    }

 

    // Second, allocate the number of characters needed and retrieve

    // the string value.

    if ((hr == S_OK) && (cchFriendlyName > 0))

    {

    wszFriendlyName = new WCHAR[cchFriendlyName];

        if (wszFriendlyName != NULL)

        {

            hr = pPortableDeviceManager->GetDeviceFriendlyName(pPnPDeviceID, wszFriendlyName, &cchFriendlyName);

            if (SUCCEEDED(hr))

            {

  FriendlyName = wszFriendlyName;

            }

            else

            {

                printf("! Failed to get device friendly name\n\r\n\r");

            }

 

            // Delete the allocated friendly name string.

            delete [] wszFriendlyName;

            wszFriendlyName = NULL;

        }

 

Receiving Device Events

The WPD API and driver model were designed so devices can issue events and applications can register to receive notifications when these events occur. Applications that receive events must implement the IPortableDeviceEventCallback interface. This interface supports a single OnEvent method. The driver calls this method each time an event is fired. However, in order for a driver to call this method, an application first needs to register with the driver. An application registers with the driver by calling the IPortableDevice::Advise method. The third argument for this method, pCallback, is a pointer to the IPortableDeviceEventCallback interface that the application implemented.

The temperature sensor device issues a single temperature-reading event that the sample application registers to receive. Each time the driver calls the OnEvent method, the sample application writes the received temperature to a local file on disk. The gadget’s script then reads from this file to update the gadget with the most recent office temperature.

Implementing IPortableDeviceEventCallback

The sample application implements the IPortableDeviceEventCallback interface in the DeviceEvents.cpp module. Most of the code in this module was taken from the WpdApiSample application that ships with the Windows SDK. The following changes were made to the original file.

· The TEMPERATURE_SENSOR_READING property key was defined and declared.

· The OnEvent method was modified to process the TEMPERATURE_SENSOR_READING property and write the new temperature value to disk.

The IPortableDeviceEventCallback interface is implemented in the CPortableDeviceEventsCallback class in DeviceEvents.cpp. This class supports the following methods.

Method

Description

CPortableDeviceEventsCallback

Object constructor

~CPortableDeviceEventsCallback

Object destructor

QueryInterface

Returns a pointer to the IPortableDeviceEventCallback interface.

AddRef

Increments the object’s reference count.

Release

Decrements the object’s reference count.

OnEvent

Event handler. WPD will call this method if the application is registered to receive event notifications.

 

In addition to implementing IPortableDeviceEventCallback, the DeviceEvents.cpp module also contains two functions that the application calls in order to register and unregister for event notifications. These functions are described in the following table.

Function

Description

RegisterForEventNotifications

Registers the application to receive event notifications. (This method is called when the application first starts.It’s also called if the user requests registration by entering the number 2 at the command prompt.)

UnregisterForEventNotifications

Unregisters the application from receiving event notifications. (This method is called if the user requests cancellation of registration by entering the number 1 at the command prompt.)

 

Implementing the IPortableDeviceEventCallback::OnEvent Method

Once an application registers to receive event notifications, the WPD device driver will call the IPortableDeviceEventCallback::OnEvent method whenever the device fires an event. Each time the driver calls this method, it passes data associated with the given event in an IPortableDeviceValues interface. The pEventParameters argument is a pointer to this interface.

The temperature sensor device fires one event per temperature reading update, and the accompanying data is a single, signed integer value which specifies the current temperature in degrees Kelvin. The sample application retrieves this value by calling the IPortableDeviceValues::GetSignedIntegerValue method and passing the property key for the TEMPERATURE_SENSOR_READING property as the first argument. (This property key was declared and defined at the top of DeviceEvents.cpp.)

 

HRESULT __stdcall OnEvent(

    IPortableDeviceValues* pEventParameters)

{

    HRESULT hr = S_OK;

    LONG i=0;

    HANDLE hFile;

    DWORD dwBytesWritten;

    char strHtmlPrefix[]="<P>Office Temperature<P>";

    char strHtmlSuffix[]="&deg; Kelvin";

    char strHtml[40];

 

    if (pEventParameters != NULL)

    {

        pEventParameters->GetSignedIntegerValue(TEMPERATURE_SENSOR_READING, &i);

        sprintf_s(strHtml, "%s%d%s\0", strHtmlPrefix, i, strHtmlSuffix);

 

        hFile = CreateFileW(_T("c:\\temp\\tempdata.txt"),

            GENERIC_WRITE,

            0,

            NULL,

            CREATE_ALWAYS,

            FILE_ATTRIBUTE_NORMAL,

            NULL);

 

        if (WriteFile(hFile, strHtml, sizeof(strHtml), &dwBytesWritten, NULL))

        {

            printf("Current temperature: %d Kelvin\n\r", i);

            printf("Temperature written to target file.\n\r\n\r");

        }

        else

        {

            printf("Temperature not written to target file.\n\r");

            printf("WriteFile failed with error %d.\n\r\n\r", GetLastError());

        }

        CloseHandle(hFile); // We need to close the handle.

    }

     return hr;

}

 

Upon retrieving the current temperature, the OnEvent method writes a string of HTML to a temporary file on disk (c:\temp\tempdata.txt). The gadget reads this string of HTML from the temporary file and incorporates it into the gadget’s own HTML. In addition, the OnEvent method writes the current temperature to the console window.

Implementing the RegisterForEventNotifications Function

The sample application supports a single function, RegisterForEventNotfications, which it calls at startup and if the user explicitly requests registration. This function performs the following tasks.

4. Examines the event registration cookie (g_strEventRegistrationCookie) to determine whether the application is already registered.

5. If not, creates an instance of the CPortableDeviceEventsCallback object.

6. Calls the IPortableDevice::Advise method to complete the registration.

7. If registration is successful, assigns the event cookie returned by the Advise method to the g_strEventRegistrationCookie variable.

 

void RegisterForEventNotifications(IPortableDevice* pDevice)

{

    HRESULT hr = S_OK;

    LPWSTR wszEventCookie = NULL;

    CPortableDeviceEventsCallback* pCallback = NULL;

 

    if (pDevice == NULL)

    {

        return;

    }

 

    // Check to see if we already have an event registration cookie.

    // If so, then avoid registering again.

    // NOTE: An application can register for events as many times as.

    // wanted. This sample only keeps a single registration

    // cookie around for simplicity.

    if (g_strEventRegistrationCookie.GetLength() > 0)

    {

        printf("This application has already registered to receive device events.\n\r\n\r");

        return;

    }

 

    // Create an instance of the callback object. This will be

    // called when events are received.

    if (hr == S_OK)

    {

        pCallback = new CPortableDeviceEventsCallback();

        if (pCallback == NULL)

        {

            hr = E_OUTOFMEMORY;

            printf("Failed to allocate memory for IPortableDeviceEventsCallback object, hr = 0x%lx\n\r\n\r",hr);

        }

    }

 

    // Call Advise to register the callback and receive events.

    if (hr == S_OK)

    {

        hr = pDevice->Advise(0, pCallback, NULL, &wszEventCookie);

        if (FAILED(hr))

        {

            printf("! Failed to register for device events, hr = 0x%lx\n\r\n\r",hr);

        }

    }

 

    // Save the event registration cookie if event registration was

    // successful.

    if (hr == S_OK)

    {

        g_strEventRegistrationCookie = wszEventCookie;

    }

 

    // Free the event registration cookie if one was returned.

    if (wszEventCookie != NULL)

    {

        CoTaskMemFree(wszEventCookie);

        wszEventCookie = NULL;

    }

 

    if (hr == S_OK)

    {

        printf("This application has registered for device event notifications.\r\n\r\n");

    }

 

    // If a failure occurs, remember to delete the allocated callback

    // object if one exists.

    if (pCallback != NULL)

    {

        pCallback->Release();

    }

}

Implementing the UnregisterForEventNotifications Function

The sample application supports a single function, UnregisterForEventNotfications, which it calls if the user explicitly cancels registration. This function performs the following tasks.

8. Calls the IPortableDevice::Unadvise method and passes the registration cookie (which is also the event cookie returned by the IPortableDevice::Advise method).

9. Sets the internal event registration-cookie variable g_strEventRegistrationCookie to an empty string.

void UnregisterForEventNotifications(IPortableDevice* pDevice)

{

    HRESULT hr = S_OK;

 

    if (pDevice == NULL)

    {

        return;

    }

 

    hr = pDevice->Unadvise(g_strEventRegistrationCookie);

    if (FAILED(hr))

    {

        printf("! Failed to unregister for device events using registration cookie '%ws', hr = 0x%lx\n\r\n\r",g_strEventRegistrationCookie.GetString(), hr);

    }

 

    if (hr == S_OK)

    {

        printf("This application used the registration cookie '%ws' to unregister from receiving device event notifications\n\r\n\r", g_strEventRegistrationCookie.GetString());

    }

 

    g_strEventRegistrationCookie = L"";

}

 

Handling User Input

The sample application displays a simple menu in the console window when it begins execution. This menu has three options corresponding to three integer values.

Option/Value

Description

1

Unregister for device notifications. (The application calls the UnregisterForEventNotifications function.)

2

Register for device notifications. (The application calls the RegisterForEventNotifications function.)

99

Exit. (The application exits.)

 

The code that supports the menu and its options is found in the ProcessInput function in the Sidebar_Console.cpp module.

 

void ProcessInput(CComPtr<IPortableDevice> pIPortableDevice)

    {

        HRESULT hr = S_OK;

        UINT uiSelection = 0;

        CHAR szSelection[81] = {0};

 

        printf("\n\n");

        printf("===============================================\r\n");

        printf("1. Unregister for device notifications.\r\n");

        printf("2. Register for device notifications.\r\n");

        printf("99. Exit.\r\n");

        printf("===============================================\r\n");

        printf("\n\n");

 

        while (uiSelection != 99)

        {

            ZeroMemory(szSelection, sizeof(szSelection));

   

            hr = StringCbGetsA(szSelection,sizeof(szSelection));

 

            if (SUCCEEDED(hr))

            {

                uiSelection = (UINT) atoi(szSelection);

                switch (uiSelection)

                {

                    case 1:

                        // Unregister to receive device events

                        UnregisterForEventNotifications(pIPortableDevice);

                    break;

                    case 2:

                        // Register to receive device events

  RegisterForEventNotifications(pIPortableDevice);

                    default:

                    break;

                }

            }

            else

            {

                printf("! Failed to read menu selection string input, hr = 0x%lx\n\r\n\r",hr);

            }

        }

    }

 

The Temperature Sensor Gadget

The temperature sensor gadget displays the current office temperature in degrees Kelvin in Windows Sidebar.

If you’ve never created a gadget for Windows Sidebar before, refer to the Gadget Development Overview.

 

The Temperature Sensor Gadget Files

The temperature sensor gadget consists of three files: an HTML file, an XML file, and a JPEG file. These files are described in the following table.

File Name

Description

UpdateTemperatureReading.htm

An HTML file that contains the script which retrieves the updated temperature data from the local disk every 3,000 milliseconds.

gadget.xml

The gadget manifest. This file specifies properties such as the name of the gadget, the name of its HTML file, a string of descriptive text, and so on.

background.jpg

A 163 x 58 pixel image that produces the gadget’s two-tone blue background color.

 

Retrieving the Current Temperature

The gadget’s HTML file, UpdateTemperatureReading.htm, contains a script which opens the file created by the console application (c:\temp\tempdata.txt) and copies the contents of this file into a span element identified as “temperature_data” within the body of the gadget’s HTML.

This script creates a FileSystemObject which it uses to open and read the text file. It uses the OpenTextFile method to open the file and the ReadAll method to retrieve its contents.

The script uses the setTimeout method on the window object to recursively execute the update function every 3,000 milliseconds. (This function contains the code that retrieves the contents of c:\temp\tempdata.txt.)

 

<html>

 

<head>

 

<script>

var fileSystemObject = null;

 

function loaded()

{

       fileSystemObject = new ActiveXObject("Scripting.FileSystemObject");

       update();

}

 

function update()

{

      var textStream = fileSystemObject.OpenTextFile("c:\\temp\\tempdata.txt");

      try

          {

             temperature_data.innerHTML = textStream.ReadAll();

           }

         finally

           {

             textStream.Close();

             window.setTimeout(update, 3000);

      }

}

 

</script>

 

<style>

      body

        {

               margin: 0;

               width: 125px;

               height: 62px;

               font: 'normal 8pt Arial';

               line-height: 12pt;

               text-align:center;

      }

 

</style>

 

</head>

 

<body onload="loaded()">

<g:background src="background.png">

<span id="temperature_data"></span>

</g:background>

</body>

</html>

 

The HTML file also contains a description of the gadget’s window between the <style> and </style> tags that follow the script. Note that the width and height attributes match the width and height of the background image (background.png). In addition to specifying the size of the gadget’s window, the attributes found here specify the font used to render text, the line height (which creates padding between the two lines of text), and the text alignment.

The g:background element specifies the source file (background.png) for the gadget’s background image.

The span element “temperature_data” identifies the location of the HTML which is copied from c:\temp\tempdata.txt by the Update function.

 

More Information

· For general information about developing gadgets for Windows Sidebar, see the Gadget Development Overview.

· To learn more about the BASIC Stamp Activity Kit for Windows Portable Devices, refer to the Parallax site.

 

This posting is provided "AS IS" with no warranties, and confers no
rights.