Pocket PC 程序设计小技巧

Two for the Road
Pocket PC Programming Tips

John Kennedy
Microsoft

March 18, 2002

This month I'm returning to the here and now, so rather than looking at the yet-to-be-released Smart Device Extensions, it's back to good old Microsoft eMbedded Visual C++®. This time around, I've selected some of the many Pocket PC programming tips and tricks I've discovered or been told about and put them into a single column. I tell ya, it's powerful stuff! Make sure to use the column feedback option to let me know if this is more of the kind of material you prefer to see in this column.

The Correct Way to Access Storage Cards

In one of my Pocket PC applications, I was naive to believe that because the device name Storage Card worked on my Pocket PC that it would work on everyone else's Pocket PC. I hard-coded the string into code, and used it to look for a file. Now this worked fine for a while, and then three things happened:

  1. Pocket PCs started to grow very popular in Europe and suddenly I was getting e-mails from disgruntled Germans wondering why my application didn't work with their Compact Flash cards. I had no idea why it wouldn't work until I discovered that on German devices, the Storage Card isn't called Storage Card anymore.
  2. Pocket PCs started to appear on the market with more than one memory slot. It started with the Compaq iPaq and its dual PCMCIA sleeve. Then other devices appeared that had Compact Flash and those tiny SSD memory cards. Now there was Storage Card, and Storage Card2.
  3. The Jornada Pocket PC and similar devices appeared with some spare Flash ROM memory, which HP provided to the user as a small, integral storage card. Once again the name changed to a variation of Storage Card, and broke my application.

Now there's a valuable lesson here somewhere here, but I'm not very good about taking lessons, so I asked around for the best way to get the REAL name of any Storage Card memory. Here's what I've found—use the FindFirstFile API function to uncover the names of any cards present. Here's a short program that will list the names of all storage cards in a series of message boxes. Once you have this information, it's up to you how you utilize it. The important things to remember are:

  • There may not be a storage card present.
  • There may be more than one storage card present.
  • You can't rely on the card(s) having a fixed name.

So here's that sample program.

//
// List all Storage Cards present on device
//
#include "stdafx.h"
 
int WINAPI WinMain(   HINSTANCE hInstance,
                                   HINSTANCE hPrevInstance,
                                   LPTSTR     lpCmdLine,
                                   int        nCmdShow)
{
 
        #define CF_CARDS_FLAGS (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_TEMPORARY)
 
 
        WIN32_FIND_DATA fd;
        HANDLE hCF = FindFirstFile(L"//*",&fd);
 
        if (INVALID_HANDLE_VALUE == hCF) return 0;
 
        do
        {
               if ((fd.dwFileAttributes & CF_CARDS_FLAGS) == CF_CARDS_FLAGS)
               {
                      MessageBox(NULL,fd.cFileName,fd.cFileName,MB_OK);
               }
        } while (FindNextFile(hCF,&fd));
 
        FindClose(hCF);
        
        return 0;
}
 

Other Localization Tricks

You'll be pleased to note that I've found other ways to annoy readers. As in life, the things that will get you into the most trouble are unfounded assumptions. Of course, it's also true to say that trying to discover what you shouldn't be making the assumptions about in the first place is the really hard part.

One thing I assumed was that there was always going to be a directory called Program Files on a Pocket PC device. Doh! You cannot make this assumption on non-English devices because it's often not true. So, it's definitely a good thing that there is an API function with the name SHGetSpecialFolderPath for us to utilize.

Given a special code referring to folders such as Program Files, this function returns a string that controls the true path and name of the folder. It's something you should check your code for and make sure that you are not assuming folder names. There is another function called SHGetSpecialFunctionLocation that does a similar job.

The documentation is slightly misleading, as only seven of the special folder codes are supported, and they are as follows:

Folder ValueDescription
CSIDL_PROGRAMSFolder that contains the names of the programs that the Start Menu displays. Can be shortcuts or executables.
CSIDL_FAVORITESFolder that stores the Pocket Internet Explorer Favorites list.
_DESKTOPThe My Documents folder.
CSIDL_FONTSFolder containing system fonts.
CSIDL_STARTUPFolder containing programs that are executed on system startup. Note: that means after a reset, not simply pressing the On button.
CSIDL_PERSONALAnother pointer to the My Documents folder.
CSIDL_RECENTDoesn't appear to return anything.

Here's a short sample program that demonstrates the API function in action.

//
// Display 'Special Folders'
//
#include "stdafx.h"
 
int WINAPI WinMain(   HINSTANCE hInstance,
                                   HINSTANCE hPrevInstance,
                                   LPTSTR     lpCmdLine,
                                   int        nCmdShow)
{
 
        TCHAR localised_path[MAX_PATH];
 
        SHGetSpecialFolderPath(NULL, localised_path, CSIDL_PROGRAMS, 0);
        MessageBox(NULL,localised_path,L"Program files",MB_OK);
 
        SHGetSpecialFolderPath(NULL, localised_path, CSIDL_FAVORITES, 0);
        MessageBox(NULL,localised_path,L"Favorites",MB_OK);
 
        SHGetSpecialFolderPath(NULL, localised_path, CSIDL_DESKTOP, 0);
        MessageBox(NULL,localised_path,L"Desktop (My Documents)",MB_OK);
 
        SHGetSpecialFolderPath(NULL, localised_path, CSIDL_FONTS, 0);
        MessageBox(NULL,localised_path,L"Fonts",MB_OK);
 
        SHGetSpecialFolderPath(NULL, localised_path, CSIDL_STARTUP, 0);
        MessageBox(NULL,localised_path,L"Startup",MB_OK);
 
        SHGetSpecialFolderPath(NULL, localised_path, CSIDL_PERSONAL, 0);
        MessageBox(NULL,localised_path,L"Personal Folder",MB_OK);
 
        SHGetSpecialFolderPath(NULL, localised_path, CSIDL_RECENT, 0);
        MessageBox(NULL,localised_path,L"Recent",MB_OK);
 
        return 0;
}
 

Turning Off the Pocket PC Programmatically

How can you program a Pocket PC to turn itself off? Easy, simply fake the keystrokes that perform this function. A more difficult question is why you would want to do this? I've only had a few situations when I needed to do this, but it did come in handy to have this bit of code when needed. Here's the code:

//
// Switch off a Pocket PC
//
#include "stdafx.h"
 
int WINAPI WinMain(   HINSTANCE hInstance,
                                   HINSTANCE hPrevInstance,
                                   LPTSTR     lpCmdLine,
                                   int        nCmdShow)
{
 
        // Send keypresses that mean power off
        keybd_event(VK_OFF,0,KEYEVENTF_SILENT,0);
        keybd_event(VK_OFF,0,(KEYEVENTF_KEYUP|KEYEVENTF_SILENT),0);
 
        return 0;
}
 

The same technique of sending fake keystrokes can be used to prevent a device from automatically powering off. Although this should only be used in special circumstances, it can be useful to set up a timer and then use code like that above to send a harmless key press. Sending the Off key press above would just get annoying, so I wouldn't recommend that!

Turning On the Pocket PC Programmatically

This is one of my favorite tricks, and of course is a perfect match for the previous example. How do you program the Pocket PC to switch itself on? Well, this is actually slightly more subtle. Do you really just want the Pocket PC to power up, all by itself? Or do you want a program to run when the user powers up the Pocket PC? And in that case, do you really want the Pocket PC to power itself up at all, or do you just want to know when the user has powered up?

Okay, before we get bogged down in temporal paradoxes, here's a table of some scenarios and how you might be able to go about writing code that does what you want.

Desired ActionSolution
Switch on Pocket PC at given time.Set the Alarm Clock to go off at a certain time.

-or-

Use CeRunAppAtTime with a special application that does nothing.

Run an application when the Pocket PC is switched on (using the power button).Use CeRunAppAtEvent with an event of NOTIFICATION_EVENT_WAKEUP.
Run an application when the Pocket PC is reset (that is, a warm reset).Place a link to your application into the /Windows/Startup directory.
Run an application at a given time, regardless of whether the Pocket PC is switched on or off.Use CeRunAppAtTime.

With this kind of control, you can get rather devious and make the poor little Pocket PC do some fun things. Making noises when you power up the device is something I covered many months ago. How about something cleverer though, like powering up and creating new tasks automatically? Or even powering up and then powering down, just to make sure you haven't accidentally switched the Pocket PC on in your bag and it's sitting there draining the battery?

Here's an example program that uses CeRunAppAtTime to start the calculator application within a minute of the program launching. You can switch off the Pocket PC if you like, and then wait with trepidation for it to come alive.

//
// Switch on a Pocket PC and do something
//
#include "stdafx.h"
#include "Notify.h"
 
int WINAPI WinMain(   HINSTANCE hInstance,
                                   HINSTANCE hPrevInstance,
                                   LPTSTR     lpCmdLine,
                                   int        nCmdShow)
{
 
        SYSTEMTIME time;
 
        // Get the current time
        GetLocalTime(&time);
 
        // Move to the next minute (not a recommended way of doing this)
        time.wMinute = time.wMinute+1;
 
        MessageBox(NULL,L"Calculator will run in less than a _
          minute.",L"Tap OK",MB_OK);
 
        // Set up the even to happen!
        CeRunAppAtTime (L"calc.exe", &time);
 
        return 0;
}
 

More Tips?

If you liked this month's column, please use the feedback option to let me know. I've plenty more programming tips. If you have any little pieces of hard-won information, please do send them in and we'll feature the best.

More Smart Device Extensions News

In my last column, I gave a brief introduction to Smart Device Extensions (SDE), the new tool for developing Pocket PC applications. SDE is a plug-in for Visual Studio® .NET, and provides access to the Common Language Runtime (CLR) and the .NET Framework through C# and Visual Basic® on our favorite little devices.

The bad news was that the Visual Studio .NET requirement meant that unlike the eMbedded Visual Toolkit, there was some expense involved in developing on this platform. The good news that I just discovered is that it may by much more of a bargain than I though. Microsoft have produced versions of Visual Studio .NET that focus on individual languages—the Visual C#® .NET Standard release, and the Visual Basic .NET Standard release. These versions cost about $100 each, and according to the people I've spoken to, they will work with the SDE plug-in. At that price, the tools are a bargain. You even get a copy of the large ATL poster that I spent an entire afternoon putting together. Viewed from a certain angle, some might even say it looks like Drew Barrymore. Well, oddly obsessed people might say that anyway.

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值