|
|
Posted on 2004-07-14 10:15 黑暗中的舞者 阅读(1985) 评论(0) 编辑 收藏
1. 如何控制系统的重启或者关机 可以调用函数ExitWindowsEx, 在Win CE上,这属于Undocument API,虽然没有公开,但是可以使用。 /* #define EWX_LOGOFF 0 #define EWX_SHUTDOWN 1 #define EWX_REBOOT 2 重启 #define EWX_FORCE 4 #define EWX_POWEROFF 8 关机 */ extern "C" BOOL ExitWindowsEx(UINT uFlags, DWORD dwReason); ExitWindowsEx(EWX_REBOOT, 0); //重启 ExitWindowsEx(EWX_POWEROFF, 0); //关机
2. 列出系统中安装的所有数据库
VOID EnumDataBaseName() { FILE *pf; CEGUID guid; HANDLE dbEnum; TCHAR szBuf[256]; CEOID oidDb; CEOIDINFO oidDbInfo; UINT VolumeIndex; UINT DataBaseIndex;
CREATE_INVALIDGUID(&guid); pf = fopen("\\temp\\volname.txt", "w");
if(pf) { VolumeIndex = 0;
fprintf(pf, "Init GUID is %08lX-%08lX-%08lX-%08lX\n\n", guid.Data1, guid.Data2, guid.Data3, guid.Data4);
while(CeEnumDBVolumes(&guid, szBuf, 256)) { fprintf(pf, "Volume %3u : ", ++VolumeIndex); fwprintf(pf, szBuf); fprintf(pf, "\nGUID is %08lX-%08lX-%08lX-%8lX\n\n", guid.Data1, guid.Data2, guid.Data3, guid.Data4);
DataBaseIndex = 0; dbEnum = CeFindFirstDatabaseEx(&guid, 0); if(dbEnum) { while(oidDb = CeFindNextDatabaseEx(dbEnum, &guid)) { ++DataBaseIndex;
if (CeOidGetInfoEx(&guid, oidDb, &oidDbInfo)) { fprintf(pf, "\tDatabase %3u : ", DataBaseIndex); fwprintf(pf, oidDbInfo.infDatabase.szDbaseName); fprintf(pf, "\n"); } } CloseHandle(dbEnum); } else { fprintf(pf, "Invalid handle\n"); }
fprintf(pf, "\n"); } fclose(pf); } else { MessageBox(NULL, L"Open file error", L"EnumDataBaseName", MB_OK); } }
在我的SPV手机中,输出如下:
Init GUID is FFFFFFFF-FFFFFFFF-FFFFFFFF-FFFFFFFF
Volume 1 : SystemHeap GUID is 00000000-00000000-00000000-00000000
Volume 2 : \Storage\mxip_notify.vol GUID is 343CC4C1-154CA6EF-6520DAD2-0F943778
Database 1 : DB_notify_queue Database 2 : DB_notify_events
Volume 3 : \Storage\mxip_lang.vol GUID is F618DD27-0D3F2492-1BCB24B0-DF873166
Database 1 : \MetabaseOptions Database 2 : \MetabaseLabels Database 3 : \FileNameLang
Volume 4 : \Storage\mxip_initdb.vol GUID is 135488F0-B87ADC98-1B51C8C6-826801C0
Database 1 : MailActiveSync Database 2 : cidcache.db Database 3 : SyncStateMoves Database 4 : clog.db Database 5 : speed.db Database 6 : \Categories Database Database 7 : Contacts Database Database 8 : \SimEntries Database 9 : Tasks Database Database 10 : Appointments Database Database 11 : \DesktopPositions
Volume 5 : \Storage\cemail.vol GUID is 8CAF0001-652D0098-08E35CCD-576D6963
Database 1 : fldr3100001b Database 2 : fldr31000023 Database 3 : fldr31000025 Database 4 : pmailAttachs Database 5 : fldr31000021 Database 6 : fldr32000020 Database 7 : fldr31000017 Database 8 : fldr31000024 Database 9 : fldr31000022 Database 10 : pmailNamedProps Database 11 : pmailMsgClasses Database 12 : pmailServices Database 13 : pmailOldTables Database 14 : pmailMsgs Database 15 : pmailFolders
Volume 6 : \Storage\mxip_system.vol GUID is 513CC4C1-0E4CA6E1-C420DC7F-C897A562
Database 1 : \ConfigMetabase
3. 如何在SP2003上显示或者隐藏等待图标
// Set the cursor as the wait cursor. SetCursor (LoadCursor (NULL, IDC_WAIT));
// Hide the cursor. SetCursor (0);
4. 如何在最顶层的Navigate Bar上显示自己订制的ICON 实现这个功能需要调用Shell_NotifyIcon函数, 首先,可以在WM_CREATE消息中加入下列语句: g_hIcon = CreateStatusIcon(hwnd); if(g_hIcon) { NOTIFYICONDATA nid; nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hwnd; nid.uID = 100; nid.hIcon = g_hIcon; nid.uFlags = NIF_ICON; if(!Shell_NotifyIcon(NIM_ADD, &nid)) { MessageBox(NULL, L"Error", 0, 0); } } else { MessageBox(NULL, L"Error2", 0, 0); }
其中CreateStatusIcon函数就是调用CreateIconIndirect用来手工创建16x16图标 好像没有其他简单方法用来创建图标
HICON CreateStatusIcon(HWND hWnd) { // AND XOR Display // ------------------------------------------- // 0 0 Black // 0 1 White // 1 0 Screen // 1 1 Screen-Reverse // #define STATUSICONWIDTH 16 #define STATUSICONHEIGHT 16 HDC hdc; HBITMAP hbmMask, hbmFront; HDC hdcMask, hdcFront; HBITMAP hbmMaskOld, hbmFrontOld; ICONINFO ii; HICON hIcon; RECT rect; hdc = GetDC(hWnd);
// When filling the specified rectangle, FillRect does not include // the rectangle's right and bottom sides. GDI fills a rectangle up to, // but not including, the right column and bottom row, regardless of // the current mapping mode. SetRect(&rect, 0, 0, STATUSICONWIDTH, STATUSICONHEIGHT);
hdcMask = CreateCompatibleDC(hdc); hbmMask = CreateCompatibleBitmap(hdc, STATUSICONWIDTH, STATUSICONHEIGHT); hbmMaskOld = (HBITMAP)SelectObject(hdcMask, hbmMask); FillRect(hdcMask, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH)); Ellipse(hdcMask, 0, 0, STATUSICONWIDTH-1, STATUSICONHEIGHT-1); SelectObject(hdcMask, (HPEN)GetStockObject(BLACK_PEN)); SelectObject(hdcMask, (HBRUSH)GetStockObject(BLACK_BRUSH)); Ellipse(hdcMask, 5, 5, 10, 10);
hdcFront = CreateCompatibleDC(hdc); hbmFront = CreateCompatibleBitmap(hdc, STATUSICONWIDTH, STATUSICONHEIGHT); hbmFrontOld = (HBITMAP)SelectObject(hdcFront, hbmFront); FillRect(hdcFront, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
SelectObject(hdcFront, (HPEN)GetStockObject(WHITE_PEN)); SelectObject(hdcFront, (HBRUSH)GetStockObject(BLACK_BRUSH)); Ellipse(hdcFront, 0, 0, STATUSICONWIDTH-1, STATUSICONHEIGHT-1); SelectObject(hdcFront, (HBRUSH)GetStockObject(WHITE_BRUSH)); Ellipse(hdcFront, 5, 5, 10, 10);
SelectObject(hdcMask, hbmMaskOld); SelectObject(hdcFront, hbmFrontOld); DeleteDC(hdcMask); DeleteDC(hdcFront); ii.fIcon = TRUE; ii.hbmColor = hbmFront; ii.hbmMask = hbmMask; ii.xHotspot = 0; ii.yHotspot = 0;
hIcon = CreateIconIndirect(&ii);
DeleteObject(hbmMask); DeleteObject(hbmFront); ReleaseDC(hWnd, hdc);
return hIcon; #undef STATUSICONWIDTH #undef STATUSICONHEIGHT } 现在,Navigate Bar上加上了我定制的图表,一个白色的圆圈,很简单,当然,可以做成彩色,但是好像没有人这么做。
别忘了,在退出程序时要删掉这个ICON case WM_DESTROY: if(g_hIcon) { NOTIFYICONDATA nid; nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hwnd; nid.uID = 100; nid.hIcon = g_hIcon; nid.uFlags = NIF_ICON; if(!Shell_NotifyIcon(NIM_DELETE, &nid)) { MessageBox(NULL, L"Error3", 0, 0); } DestroyIcon(g_hIcon); }
5. 给大家推荐一个非常棒的国内网站, http://www.91mobile.com/bbs/index.asp 上面有很多SP2003 & Pocket PC 2003的使用技巧和心得,最棒的是有很多应用软件可以免费下载,这个网站上的高手很多。 就是在这个网站上,我知道了怎么在我的英文SPV上支持中文显示,更妙的是,我现在也能用中文写短消息了,不会被我的那帮哥们嘲笑我XX.
6.在UI实现渐进颜色处理(或者说加入灯光效应)
大家可能都知道现在的Windows支持渐进标题栏,就像加入了灯光处理一样,每块地方的颜色都不一样,那么如何实现了,说白了,无非采用差分处理,在起始颜色和终点颜色中插入一系列中间过渡颜色,让人眼产生错觉。当然这个算法实现起来比较简单,但是微软已经提供了GradientFill函数,不用自己去实现了,这个函数原型是: GradientFill( HDC hdc, PTRIVERTEX pVertex, ULONG nVertex, // 注意pVertex可以是一个数组,大小用nVertex表示 PVOID pMesh, ULONG nCount, // 同上pMesh可以是一个数组,大小用nCount表示 ULONG ulMode // GRADIENT_FILL_RECT_H or GRADIENT_FILL_RECT_V );
其中用到两个结构,大家一看就明白, typedef struct _TRIVERTEX { LONG x; LONG y; COLOR16 Red; // RGB分量值 COLOR16 Green; COLOR16 Blue; COLOR16 Alpha; // 我没有用过这个分量,假若你感兴趣,试试 }TRIVERTEX,*PTRIVERTEX,*LPTRIVERTEX;
typedef struct _GRADIENT_RECT { ULONG UpperLeft; // 这里的值是pVertex数组的下标。 ULONG LowerRight; }GRADIENT_RECT, *PGRADIENT_RECT;
多说无意,举个例子大家都明白了: VOID DrawRainbow(HWND hWnd) { HDC hdc; RECT rect; TRIVERTEX vert[2] ; GRADIENT_RECT gRect; hdc = GetDC(hWnd); GetClientRect(hWnd, &rect);
vert [0] .x = rect.left; vert [0] .y = rect.top; vert [0] .Red = 0x0000; vert [0] .Green = 0xFF00; vert [0] .Blue = 0x0000; vert [0] .Alpha = 0x0000; vert [1] .x = rect.right; vert [1] .y = rect.bottom; vert [1] .Red = 0x0000; vert [1] .Green = 0x0000; vert [1] .Blue = 0xFF00; vert [1] .Alpha = 0x0000; gRect.UpperLeft = 0; gRect.LowerRight = 1; GradientFill(hdc,vert,2,&gRect,1,GRADIENT_FILL_RECT_H);
ReleaseDC(hWnd, hdc); }
这里实现了一个水平从蓝色变到绿色的区域,其中TRIVERTEX数组大小为2,在结构GRADIENT_RECT中左上角就是TRIVERTEX数组第一个元素,右下角就是TRIVERTEX数组第二个元素。比较简单吧。就像看到灯光效果一样。
来,我们看一个比较复杂了,大家自己去理解吧,这个例子懂了后,这个API你就会了: VOID DrawRainbow2(HWND hWnd) { HDC hdc; RECT rect; TRIVERTEX vert[7] ; GRADIENT_RECT gRect[4]; hdc = GetDC(hWnd); GetClientRect(hWnd, &rect);
vert [0] .x = rect.left; vert [0] .y = rect.top; vert [0] .Red = 0x3100; vert [0] .Green = 0x9A00; vert [0] .Blue = 0xEF00; vert [0] .Alpha = 0x0000; vert [1] .x = rect.right; vert [1] .y = 20;//rect.bottom/3; vert [1] .Red = 0x0000; vert [1] .Green = 0x4500; vert [1] .Blue = 0x9C00; vert [1] .Alpha = 0x0000; vert [2] .x = rect.left; vert [2] .y = rect.bottom/3; vert [2] .Red = 0x0000; vert [2] .Green = 0x0000; vert [2] .Blue = 0x0000; vert [2] .Alpha = 0x0000; vert [3] .x = rect.right; vert [3] .y = rect.bottom*2/3; vert [3] .Red = 0x0000; vert [3] .Green = 0xFF00; vert [3] .Blue = 0x0000; vert [3] .Alpha = 0x0000; gRect[0].UpperLeft = 0; gRect[0].LowerRight = 1; gRect[1].UpperLeft = 2; gRect[1].LowerRight = 3; vert [4] .x = rect.left; vert [4] .y = rect.bottom*2/3; vert [4] .Red = 0x0000; vert [4] .Green = 0x0000; vert [4] .Blue = 0x0000; vert [4] .Alpha = 0x0000; vert [5] .x = rect.right/2; vert [5] .y = rect.bottom*5/6; vert [5] .Red = 0x0000; vert [5] .Green = 0x0000; vert [5] .Blue = 0xFF00; vert [5] .Alpha = 0x0000; vert [6] .x = rect.right; vert [6] .y = rect.bottom; vert [6] .Red = 0x0000; vert [6] .Green = 0xFF00; vert [6] .Blue = 0x0000; vert [6] .Alpha = 0x0000; gRect[2].UpperLeft = 4; gRect[2].LowerRight = 5; gRect[3].UpperLeft = 5; gRect[3].LowerRight = 6; GradientFill(hdc,vert,7,&gRect,4,GRADIENT_FILL_RECT_H);
ReleaseDC(hWnd, hdc); }
7.在SP2003注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Rai\下面隐藏了一些有趣的主键,如 :MSINBOX :MSCONTACTS :MSCALENDAR :MSTASKS :MSSettings :MSHome :MSStart :MSTNOTES 等等。 当用户在Start Menu中选择Contacts,系统会查找注册表: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Rai\:MSCONTACTS下的子键”0”,它是一个String Value,包含对应窗口的类名,对于Contacts,它的类名,也就是子键”0”的值就是” Contacts”,系统根据这个类去查找系统冲的窗口,如果匹配,激活它,如果不存在,继续查找子键”1”的值,它是一个String Value,包含启动这个程序的快捷方式,对于Contacts,子键”1”的值是“appman.exe -s Apps :MSCONTACTS tpcutil.dll AMContacts“,我们暂且不考虑这个值具体表达的意思,想想如果把子键”1”改为我们定义的程序,那么在Start Menu中选择Contacts,就会启动我们定义的程序。也就是,如果想扩展系统程序Contacts的功能,只需修改这个键值指向我们定义的程序,一切OK了。事实确实如此。 事实上,不光Start Menu中的程序Inbox, Contacts, Calendar, Tasks, Settings等程序的处理原理同Contacts类似,连Start Menu程序本身也是这样处理的,商业软件Surreal Start就是修改了HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Rai\:MSStart\1的键值,替换了系统的Start程序。 更有趣的是,对于系统一些按键,如录音键的处理方式也是如此。当用户按了录音键,操作系统查找注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Rai\:MSTNOTES\1键值, 这个键值缺省时指向录音程序。这是一个全局事件,不管当前停留在什么窗口,按下录音键都会调用该子健对应的程序。假若你有一个程序想随时随地激活,使用这个键值是最佳选择。 当然,灵活运用这些键值可以使你的程序和系统程序无缝结合到一起,甚至可以为系统作一些扩展功能。
|