Building Great Building Great Applications For The Applications For The Pocket PCPocket PC
Luis EsparragozaLuis EsparragozaSoftware Test LeadSoftware Test LeadPocket-PCPocket-PCMicrosoft CorporationMicrosoft Corporation
8-3018-301
Wyvern v. RapierWyvern v. Rapier
Key is SimplifyKey is Simplify
Remove complexityRemove complexity Setup Device and SynchronizationSetup Device and Synchronization Flat controls & Page-based dialogsFlat controls & Page-based dialogs Single tapSingle tap Redesign of control panelsRedesign of control panels Remove redundant menus, introduce tap Remove redundant menus, introduce tap
& hold& hold
Optimize SimplificationsOptimize Simplifications
Optimize for form factor needs and Optimize for form factor needs and appliance-like behaviorappliance-like behavior New shell arrangement (nav bar on top, New shell arrangement (nav bar on top,
menus on bottom)menus on bottom) Minimize difficulty of inputMinimize difficulty of input Auto save & automatic memory Auto save & automatic memory
managementmanagement
Performance GainsPerformance Gains
Functional as well as perceivedFunctional as well as perceived
WyvernWyvern RapierRapier
Start MenuStart Menu 800ms800ms 100ms100ms
CalendarCalendar 2300ms2300ms 1200ms1200ms
Open apptOpen appt 2700ms2700ms 800ms800ms
Switch to Switch to ContactsContacts
1500ms1500ms 800ms800ms
FindFind 200ms200ms
Synch Synch (250 appt, (250 appt, 200 contacts, 50 tasks, 200 contacts, 50 tasks, 20 messages)20 messages)
130 sec130 sec20 sec20 sec
App Platform DiagramApp Platform Diagram
WinCE 3.0 (Cedar): Win32, OLE, Winsock, etc
VBMFCADOATLCEF
Your App Goes Here
GameX
WinInet/URLMon
pIE
HTMLJScript
XMLXSL
RapierShell APIs
POOM
Runtime APIsRuntime APIs
VBVB MFCMFC ATLATL ADOADO CEF – (Common Executable Format)CEF – (Common Executable Format)
See the Tools and Data Access sessions
Internet Explorer for Pocket Internet Explorer for Pocket PCPC
WinInetWinInet URLMonURLMon JScriptJScript XML/XSLXML/XSL ActiveXActiveX Oh yeah… HTML, too.Oh yeah… HTML, too.
See the Web-based Applications for the Pocket PC session
GameXGameX
First Steps towards DirectXFirst Steps towards DirectX Performance!Performance! Better access to device frame buffersBetter access to device frame buffers Describes HW buttons and facilitates Describes HW buttons and facilitates
remappingremapping Device independent!Device independent!
See the GameX session
Pocket Outlook Object Pocket Outlook Object ModelModel
No more ABAPINo more ABAPI POOM = stripped down desktop POOM = stripped down desktop
Outlook Object ModelOutlook Object Model
Rapier UI APIsRapier UI APIs
Maintain Windows affinity w/o being Maintain Windows affinity w/o being shrunken down Windowsshrunken down Windows
A few Rapier specific APIsA few Rapier specific APIs Limited new APIsLimited new APIs As “automatic” as we couldAs “automatic” as we could Largely UI design shiftLargely UI design shift
See the Rapier UI session
ToolsTools
EmulationEmulation Device directDevice direct Embedded Visual StudioEmbedded Visual Studio Rapier MFC WizardsRapier MFC Wizards Menu editorMenu editor
See the Tools session
UI Design Principles UI Design Principles
The form factor is critical, optimize for itThe form factor is critical, optimize for it Design for the 80% / 20% case rather than Design for the 80% / 20% case rather than
the 100% casethe 100% case More content, less app More content, less app Reduce redundancy, and reduce effortReduce redundancy, and reduce effort Windows affinity, not wholesale copy Windows affinity, not wholesale copy Consistency with what users expect, not Consistency with what users expect, not
for its own sake for its own sake Ease up on the eyesEase up on the eyes Simple NOT simplisticSimple NOT simplistic
New ShellNav bar on top (start button + title
bar), command bar on bottom, system tray on home screen only
New User ModelSingle tap, autosave everywhere,
close cards/documents (no cancel)
Flat look & feel Pages instead of cascading menus,
flat buttons, fewer controls Feature consolidationRemoved redundant menus/buttons,
Redesigned control panel
Client Area
New
Start Menu
App Name
SIP
Command Bar
App Menu
Redesigned UIRedesigned UI
Navigation BarNavigation Bar
Foofy Design StuffFoofy Design Stuff Start at 0,0, prime real estateStart at 0,0, prime real estate Title should only be app name, should not Title should only be app name, should not
changechange Instantly conveys a sense of placeInstantly conveys a sense of place OK button, closes dialogs & docsOK button, closes dialogs & docs No cancel, just undoNo cancel, just undo
Read is often different from editRead is often different from edit Tray objects only appear on TodayTray objects only appear on Today
Navigation Bar Navigation Bar (dev part 1 of 3)(dev part 1 of 3)
Respecting spaceRespecting space CreateWindows at CW_USEDEFAULT, CreateWindows at CW_USEDEFAULT,
CW_USEDEFAULT origin, NOT at (0,0)CW_USEDEFAULT origin, NOT at (0,0) And/Or use SHSipInfo:And/Or use SHSipInfo: si.cbSize = sizeof(si);si.cbSize = sizeof(si);
if( SHSipInfo(SPI_GETSIPINFO, 0, &si, 0) )if( SHSipInfo(SPI_GETSIPINFO, 0, &si, 0) ) {{ if (dwStyle & WS_POPUP)if (dwStyle & WS_POPUP) {{ x = si.rcVisibleDesktop.left;x = si.rcVisibleDesktop.left; y = si.rcVisibleDesktop.top;y = si.rcVisibleDesktop.top; }}
//Consider the menu at the bottom, please.//Consider the menu at the bottom, please. iDelta = (si.fdwFlags & SIPF_ON) ? 0 : MENU_HEIGHT;iDelta = (si.fdwFlags & SIPF_ON) ? 0 : MENU_HEIGHT; cx = si.rcVisibleDesktop.right - si.rcVisibleDesktop.left;cx = si.rcVisibleDesktop.right - si.rcVisibleDesktop.left; cy = si.rcVisibleDesktop.bottom - si.rcVisibleDesktop.top - iDelta;cy = si.rcVisibleDesktop.bottom - si.rcVisibleDesktop.top - iDelta; hwnd = CreateWindow(lpClassName, lpWindowName, dwStyle, hwnd = CreateWindow(lpClassName, lpWindowName, dwStyle, x, y, cx, cy, hWndParent, hMenu, hInstance, lpParam);x, y, cx, cy, hWndParent, hMenu, hInstance, lpParam); }}
Navigation Bar Navigation Bar (dev part 2 of 3)(dev part 2 of 3)
Shared ResourcesShared Resources Title – Comes from your top level Title – Comes from your top level
window’s GetWindowText();window’s GetWindowText(); OK buttonOK button
Remove WS_CAPTION and Remove WS_CAPTION and WS_SYSMENU bits, add WS_SYSMENU bits, add WS_EX_CAPTIONOKBTNWS_EX_CAPTIONOKBTN
For Dialogs, use SHInitDialog:For Dialogs, use SHInitDialog: SHINITDLGINFO shidi;SHINITDLGINFO shidi;
shidi.hDlg = hwnd;shidi.hDlg = hwnd; shidi.dwMask = SHIDIM_FLAGS;shidi.dwMask = SHIDIM_FLAGS; shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN | shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN |
SHIDIF_DONEBUTTON;SHIDIF_DONEBUTTON; SHInitDialog(&shidi);SHInitDialog(&shidi);
Navigation Bar Navigation Bar (dev part 3 of 3)(dev part 3 of 3)
Hiding the NavBar:Hiding the NavBar: SHFullScreenSHFullScreenBOOL SHFullScreen(HWND BOOL SHFullScreen(HWND hwndRequesterhwndRequester, DWORD , DWORD dwStatedwState););
SHFS_SHOWTASKBARSHFS_SHOWTASKBAR
SHFS_HIDETASKBARSHFS_HIDETASKBAR
SHFS_SHOWSIPBUTTONSHFS_SHOWSIPBUTTON
SHFS_HIDESIPBUTTONSHFS_HIDESIPBUTTON
SHFS_SHOWSTARTICONSHFS_SHOWSTARTICON
SHFS_HIDESTARTICONSHFS_HIDESTARTICON
Must be foreground windowMust be foreground window Do this on WM_ACTIVATEDo this on WM_ACTIVATE
New Menu BarNew Menu Bar
Design StuffDesign Stuff Moved to bottom so hand does not Moved to bottom so hand does not
obstruct operationsobstruct operations Menus & toolbar buttons mixed on ONE Menus & toolbar buttons mixed on ONE
bar, no overlapping rebarbar, no overlapping rebar Tooltips Tooltips
if the icon isn’t 100% self-evident, just use a if the icon isn’t 100% self-evident, just use a menu or textmenu or text
Buttons and menus are NOT redundantButtons and menus are NOT redundant
New Menu Bar New Menu Bar (dev 1 of 4)(dev 1 of 4)
Nerd StuffNerd Stuff Rebars: still available, but not Rebars: still available, but not
recommendedrecommended How you create Rapier menus:How you create Rapier menus:
Code side:Code side: SHMENUBARINFO cbi = {0};SHMENUBARINFO cbi = {0}; // Set up in parameters// Set up in parameters cbi.cbSize = sizeof(SHMENUBARINFO);cbi.cbSize = sizeof(SHMENUBARINFO); cbi.hwndParent = hwndParent;cbi.hwndParent = hwndParent; cbi.nToolBarId = cbi.nToolBarId = IDR_MENUIDR_MENU;; // Resource id of menu// Resource id of menu cbi.dwFlags = 0;cbi.dwFlags = 0; cbi.hInstRes = hInstance; cbi.hInstRes = hInstance; // location of buttons and images// location of buttons and images
cbi.nBmpId = IDB_TOOLBAR; // if you have imagescbi.nBmpId = IDB_TOOLBAR; // if you have images cbi.cBmpImages = 3; cbi.cBmpImages = 3; // number of images// number of images
SHCreateMenuBar(&cbi);SHCreateMenuBar(&cbi);
New Menu Bar New Menu Bar (dev 2 of 4)(dev 2 of 4)
Resource side:Resource side:IDR_MENU RCDATAIDR_MENU RCDATABEGINBEGIN IDMENU_CARD, IDMENU_CARD, // hmenu resource id// hmenu resource id 5,5, // number of menu items below// number of menu items below
// Image , COMMAND_ID , Initial state , Initial style,// Image , COMMAND_ID , Initial state , Initial style, string resource for menu text, string resource for tooltip, menu offsetstring resource for menu text, string resource for tooltip, menu offset
I_IMAGENONE, IDM_SHAREDNEW, TBSTATE_ENABLED, I_IMAGENONE, IDM_SHAREDNEW, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, IDS_SHNEW, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE, IDS_SHNEW, IDS_TOOLTIP_NEWCONTACT, NOMENU,IDS_TOOLTIP_NEWCONTACT, NOMENU,
I_IMAGENONE, IDM_CARD_EDIT, TBSTATE_ENABLED, I_IMAGENONE, IDM_CARD_EDIT, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_SHEDIT, 0, 0,TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_SHEDIT, 0, 0,
I_IMAGENONE, IDM_CARD_TOOLS, TBSTATE_ENABLED, I_IMAGENONE, IDM_CARD_TOOLS, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_SHTOOLS, 0, 1,TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_SHTOOLS, 0, 1,
4, IDM_VOICE_BAR, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 4, IDM_VOICE_BAR, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, IDS_TOOLTIP_VOICE_BAR, NOMENU,IDS_TOOLTIP_VOICE_BAR, NOMENU,
5, IDM_PEN, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 5, IDM_PEN, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, IDS_TOOLTIP_PEN, NOMENU,IDS_TOOLTIP_PEN, NOMENU,
ENDEND
New Menu Bar New Menu Bar (dev 3 of 4)(dev 3 of 4)
Notes:Notes: Menu string resource id < 100 is reserved. Menu string resource id < 100 is reserved.
(IDS_SH*) (IDS_SH*) IDM_SHAREDNEW is reserved and a IDM_SHAREDNEW is reserved and a
special tokenspecial token Tooltip should only be added for icons (or Tooltip should only be added for icons (or
intl). Set to 0 otherwise.intl). Set to 0 otherwise. Last parameter is the menu offset for the Last parameter is the menu offset for the
menu set specified in IDMENU_CARDmenu set specified in IDMENU_CARD
New Menu Bar New Menu Bar (dev 4 of 4)(dev 4 of 4)
More Notes:More Notes: Non-menu activations come through as Non-menu activations come through as
WM_COMMAND+your_idWM_COMMAND+your_id Menu commands come through with Menu commands come through with
WM_COMMAND on select and WM_COMMAND on select and WM_INITMENUPOPUP on activation with lParam WM_INITMENUPOPUP on activation with lParam set to MENU_ID, NOT INDEX!set to MENU_ID, NOT INDEX!
case WM_INITMENUPOPUP:case WM_INITMENUPOPUP:switch (LOWORD(lParam))switch (LOWORD(lParam)){{
case IDM_MAIN_EDIT:case IDM_MAIN_EDIT:SetupEditMenu((HMENU)wParam);SetupEditMenu((HMENU)wParam);break;break;
case IDM_MAIN_BAZZLE:case IDM_MAIN_BAZZLE:SetupBazzleMenu((HMENU)wParam);SetupBazzleMenu((HMENU)wParam);break;break;
}} break;break;
New “New” ButtonNew “New” Button
Design StuffDesign Stuff Quick input is criticalQuick input is critical Shared with all appsShared with all apps On Today page and user option to turn on On Today page and user option to turn on
everywhereeverywhere Don’t spam itDon’t spam it You can spam it in your own appYou can spam it in your own app
New “New” Button New “New” Button (dev 1 of 2)(dev 1 of 2)
Global NewGlobal New INewMenuItemServerINewMenuItemServerDECLARE_INTERFACE_(INewMenuItemServer, IUnknown)DECLARE_INTERFACE_(INewMenuItemServer, IUnknown)
{{
// *** IUnknown methods ***// *** IUnknown methods ***
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
STDMETHOD_(ULONG,AddRef) (THIS) PURE;STDMETHOD_(ULONG,AddRef) (THIS) PURE;
STDMETHOD_(ULONG,Release) (THIS) PURE;STDMETHOD_(ULONG,Release) (THIS) PURE;
STDMETHOD(CreateNewItem) (THIS_ HWND hwndParent) PURE;STDMETHOD(CreateNewItem) (THIS_ HWND hwndParent) PURE;
};};
Registration locationRegistration location[HKLM\Software\Microsoft\Shell\Extensions\NewMenu\{guid}][HKLM\Software\Microsoft\Shell\Extensions\NewMenu\{guid}]
@=LOC_NAME_OF_MENU ;; named displayed on menu.@=LOC_NAME_OF_MENU ;; named displayed on menu.
New “New” Button New “New” Button (dev 2 of 2)(dev 2 of 2)
App Local “New” (templates)App Local “New” (templates) WM_NOTIFY, WM_NOTIFY,
NMN_GETAPPREGKEY sent on new NMN_GETAPPREGKEY sent on new menu popupmenu popuptypedef struct tagNMNEWMENU typedef struct tagNMNEWMENU {{ NMHDR hdr;NMHDR hdr; TCHAR szReg[80]; // out parameter of app local reg keyTCHAR szReg[80]; // out parameter of app local reg key HMENU hMenu; // in param of the hmenu to popupHMENU hMenu; // in param of the hmenu to popup CLSID clsid; // unused for this notifyCLSID clsid; // unused for this notify
} NMNEWMENU, *PNMNEWMENU} NMNEWMENU, *PNMNEWMENU;;
App menus items > App menus items > IDM_NEWMENUMAXIDM_NEWMENUMAX
On invoke of Global, app first On invoke of Global, app first notified WM_NOTIFY, notified WM_NOTIFY, NMN_INVOKECOMMANDNMN_INVOKECOMMAND
Other BarsOther Bars
Design StuffDesign Stuff View bar, e.g. contacts & tasksView bar, e.g. contacts & tasks Folder bar, e.g. file explorer & notesFolder bar, e.g. file explorer & notes Address bar, e.g. pIEAddress bar, e.g. pIE Status bar, e.g. InboxStatus bar, e.g. Inbox
Nerd StuffNerd Stuff None… just win32 here!None… just win32 here!
Single ClickSingle Click
Design StuffDesign Stuff Single. Everywhere. Period.Single. Everywhere. Period. 5mm stylus. 9.1mm finger.5mm stylus. 9.1mm finger.
Nerd StuffNerd Stuff NOT OS disabled – Convention onlyNOT OS disabled – Convention only ListViewListView
LVS_EX_ONECLICKACTIVATELVS_EX_ONECLICKACTIVATE WM_NOTIFY+LVN_ITEMACTIVATEWM_NOTIFY+LVN_ITEMACTIVATE
Multiple selection via Action and/or dragMultiple selection via Action and/or drag VK_F23 == VK_ACTIONVK_F23 == VK_ACTION
Handling user double-clicksHandling user double-clicks
Tap & Hold MenusTap & Hold Menus Design StuffDesign Stuff
Just like context menus on Just like context menus on desktopdesktop
Tap & Hold MenusTap & Hold Menus Nerd Nerd StuffStuffSHRecognizeGesture:SHRecognizeGesture: case WM_LBUTTONDOWN: case WM_LBUTTONDOWN: SHRGINFO shrgi; SHRGINFO shrgi; shrgi.cbSize = sizeof(SHRGINFO); shrgi.cbSize = sizeof(SHRGINFO); shrgi.hwndClient = hwnd; shrgi.hwndClient = hwnd; shrgi.ptDown.x = (int)(short)LOWORD(lParam); shrgi.ptDown.x = (int)(short)LOWORD(lParam); shrgi.ptDown.y = (int)(short)HIWORD(lParam); shrgi.ptDown.y = (int)(short)HIWORD(lParam); shrgi.dwFlags = SHRG_RETURNCMD; shrgi.dwFlags = SHRG_RETURNCMD; if (GN_CONTEXTMENU == SHRecognizeGesture(&shrgi)) { if (GN_CONTEXTMENU == SHRecognizeGesture(&shrgi)) {
… your code…… your code… } }
break; break;Built into ListView, catch WM_NOTIFY+GN_CONTEXTMENUBuilt into ListView, catch WM_NOTIFY+GN_CONTEXTMENU
The Flat LookThe Flat Look
Design StuffDesign Stuff Works better on small screens w/range of Works better on small screens w/range of
resolutions incl. greyscaleresolutions incl. greyscale 3D is so…953D is so…95
Nerd StuffNerd Stuff Mostly standard Win32. Avoid Mostly standard Win32. Avoid
WS_DLGFRAME and WS_DLGFRAME and WS_EX_WINDOWEDGE WS_EX_WINDOWEDGE
CCM_SETVERSION + CCM_SETVERSION + COMCTL32_VERSIONCOMCTL32_VERSION
Others inherited for free (except Others inherited for free (except PropSheets)PropSheets)
Using Color & SoundsUsing Color & Sounds
ColorColor Use as a contrast elementUse as a contrast element
When all is red, nothing stands outWhen all is red, nothing stands out Use judiciously Use judiciously
More colors = more complexityMore colors = more complexity Use to match the real world, but USE IT!Use to match the real world, but USE IT!
Solitaire with color is more funSolitaire with color is more fun SoundsSounds
Design for the scale of the deviceDesign for the scale of the deviceTrain whistle in wyvern was… exaggeratedTrain whistle in wyvern was… exaggerated
Use it to enforce or enhance user input or Use it to enforce or enhance user input or feedbackfeedback
Page Dialogs & Property Page Dialogs & Property SheetsSheets
Design StuffDesign Stuff Dialogs are full pages, NOT floating Dialogs are full pages, NOT floating
windows unless seeing the info behind is windows unless seeing the info behind is criticalcritical
Tabs are at the Bottom, gives priority to Tabs are at the Bottom, gives priority to content v. controlscontent v. controls
Fit tabs on one line Fit tabs on one line Hotlinks at the bottom to jump to related Hotlinks at the bottom to jump to related
area…should not be treated as a remedy area…should not be treated as a remedy for poor organization of functionalityfor poor organization of functionality
Page Dialogs & Property Page Dialogs & Property Sheets Sheets (dev 1 of 2)(dev 1 of 2)
Fullscreen (Page) dialogsFullscreen (Page) dialogs SHInitDialogSHInitDialog SHINITDLGINFO shidi;SHINITDLGINFO shidi;
shidi.hDlg = Hwnd();shidi.hDlg = Hwnd();
shidi.dwMask = SHIDIM_FLAGS;shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN | shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_DONEBUTTON;SHIDIF_DONEBUTTON;
SHInitDialog(&shidi);SHInitDialog(&shidi);
Page Dialogs & Property Page Dialogs & Property Sheets Sheets (dev 2 of 2)(dev 2 of 2)
PropertySheet APIsPropertySheet APIs
int CALLBACK PropSheetCallback(HWND hwndDlg, UINT uMsg, LPARAM lParam)int CALLBACK PropSheetCallback(HWND hwndDlg, UINT uMsg, LPARAM lParam)
{{
switch (uMsg)switch (uMsg)
{{
case PSCB_GETVERSION: case PSCB_GETVERSION: // to get the new UI// to get the new UI
return COMCTL32_VERSION;return COMCTL32_VERSION;
case PSCB_INITIALIZED: case PSCB_INITIALIZED: // a menu (so that the background doesn’t bleed through// a menu (so that the background doesn’t bleed through
SHMENUBARINFO cbi = {0};SHMENUBARINFO cbi = {0};
cbi.cbSize = sizeof(SHMENUBARINFO);cbi.cbSize = sizeof(SHMENUBARINFO);
cbi.hwndParent = hwndDlg;cbi.hwndParent = hwndDlg;
cbi.dwFlags = SHCMBF_EMPTYBAR;cbi.dwFlags = SHCMBF_EMPTYBAR;
SHCreateMenuBar(&cbi);SHCreateMenuBar(&cbi);
break;break;
case PSCB_GETLINKTEXT: case PSCB_GETLINKTEXT: // create link here // create link here
lstrcpy((TCHAR *)lParam, TEXT(“To start a modem connection, go to the lstrcpy((TCHAR *)lParam, TEXT(“To start a modem connection, go to the <file:commandline{Connections}> folder. “));<file:commandline{Connections}> folder. “));
break;break;
}}
return 0;return 0;
}}
Control PanelsControl Panels
Design Stuff Design Stuff Don’t abuseDon’t abuse Your options, belong in your appYour options, belong in your app If you must, support the appropriate If you must, support the appropriate
classificationsclassifications Personal: user personalization (sw)Personal: user personalization (sw) System: device customization (hw)System: device customization (hw) Communications: connectivityCommunications: connectivity
Control Panels Control Panels (dev)(dev)
Standard Win32 goo.Standard Win32 goo. Grouping:Grouping:
Reg entryReg entry[HKEY_LOCAL_MACHINE\ControlPanel\{cpl_id}][HKEY_LOCAL_MACHINE\ControlPanel\{cpl_id}]
"Group"=dword:0"Group"=dword:0
CPL_ID:CPL_ID:LONG CPLApplet(hwnd, uMsg, lParam1, lParam2)LONG CPLApplet(hwnd, uMsg, lParam1, lParam2)
{{
……
case CPL_IDNAME:case CPL_IDNAME:
lstrcpy((LPTSTR)lParam2, TEXT(“your_cpl_id”));lstrcpy((LPTSTR)lParam2, TEXT(“your_cpl_id”));
return 0;return 0;
}}
User AssistanceUser Assistance
Pray you don’t need it…Pray you don’t need it… Integrate with Help menu, not a button Integrate with Help menu, not a button
in app; track context and show in app; track context and show appropriate helpappropriate help
Integrate your help file into the main Integrate your help file into the main TOCTOC
InputInput
Design StuffDesign Stuff Design with the SIP Design with the SIP Put it up for people and take it downPut it up for people and take it down Try not to make it danceTry not to make it dance Input is hard, make it easy…Input is hard, make it easy… You can hide, but test it hardYou can hide, but test it hard Remember it is pluggable, recommended Remember it is pluggable, recommended
80 pixels high, but not necessarily80 pixels high, but not necessarily
Input Input (dev 1 of 2)(dev 1 of 2)
SIP friendliness (the rules)SIP friendliness (the rules) SHSipPreference(HWND hwnd, SHSipPreference(HWND hwnd,
SIPSTATE eState)SIPSTATE eState) SIP_UP on WM_SETFOCUSSIP_UP on WM_SETFOCUS SIP_DOWN on WM_KILLFOCUSSIP_DOWN on WM_KILLFOCUS Do nothing if you’re not an input controlDo nothing if you’re not an input control
WC_SIPPREF magic controlWC_SIPPREF magic controlCONTROL "",-1,WC_SIPPREF, NOT WS_VISIBLE,-10,-10,5,5CONTROL "",-1,WC_SIPPREF, NOT WS_VISIBLE,-10,-10,5,5
Input DialogsInput Dialogs SHInputDialog(hwnd, uMsg, wParam)SHInputDialog(hwnd, uMsg, wParam)
Input Input (dev 2 of 2)(dev 2 of 2)
Main WndProc - save & restore sip Main WndProc - save & restore sip state per windowstate per window
case WM_INITDIALOG/WM_CREATE:case WM_INITDIALOG/WM_CREATE:this->sai.cbSize = sizeof(SHACTIVATEINFO);this->sai.cbSize = sizeof(SHACTIVATEINFO);break;break;
case WM_ACTIVATE:case WM_ACTIVATE:SHHandleWMActivate(hWnd, wParam, lParam, &this->sai, 0);SHHandleWMActivate(hWnd, wParam, lParam, &this->sai, 0);
break;break; case WM_SETTINGCHANGE:case WM_SETTINGCHANGE:
SHHandleWMSettingChange(hDlg, wParam, lParam, &this->sai));SHHandleWMSettingChange(hDlg, wParam, lParam, &this->sai));break;break;
case WM_SIZE:case WM_SIZE:… … sizing goo here.sizing goo here.break;break;
Today pageToday page
Design StuffDesign Stuff Great flexibility and room for Great flexibility and room for
customization herecustomization here Quick info is important…and so is my Quick info is important…and so is my
horoscope ;-)horoscope ;-)
Today page Today page (dev 1 of 2)(dev 1 of 2)
Registering your custom plugin:Registering your custom plugin:[HKEY_LOCAL_MACHINE\Software\Microsoft\Today\Items\[HKEY_LOCAL_MACHINE\Software\Microsoft\Today\Items\
YOURCUSTOMITEMNAME]YOURCUSTOMITEMNAME]
"Type"=dword:4 ; 4 == tlitCustom"Type"=dword:4 ; 4 == tlitCustom
"Enabled"=dword:1"Enabled"=dword:1
"Options"=dword:0 ; 1 if options page available in"Options"=dword:0 ; 1 if options page available in
; control panel; control panel
"DLL"="\Windows\YOURDLL.DLL" ; path to the DLL"DLL"="\Windows\YOURDLL.DLL" ; path to the DLL
DLL Entry points:DLL Entry points:HWND APIENTRY InitializeCustomItem(TODAYLISTITEM *ptli,HWND APIENTRY InitializeCustomItem(TODAYLISTITEM *ptli,
HWND hwndParent);HWND hwndParent);
BOOL APIENTRY CustomItemOptionsDlgProc(HWND hDlg, UINT message,BOOL APIENTRY CustomItemOptionsDlgProc(HWND hDlg, UINT message,
UINT wParam, LONG lParam);UINT wParam, LONG lParam);
Today page Today page (dev 2 of 2)(dev 2 of 2)
WndProcWndProcWM_TODAYCUSTOM_CLEARCACHEWM_TODAYCUSTOM_CLEARCACHE/* Releases item-specific cached data. This message is sent, for/* Releases item-specific cached data. This message is sent, for example, when the user closes the Today settings page. */example, when the user closes the Today settings page. */ /* WPARAM = (WPARAM)(TODAYLISTITEM *)ptli; *//* WPARAM = (WPARAM)(TODAYLISTITEM *)ptli; */ /* LPARAM not used *//* LPARAM not used */ WM_TODAYCUSTOM_QUERYREFRESHCACHEWM_TODAYCUSTOM_QUERYREFRESHCACHE/* Queries the item to find out whether the item-specific cached/* Queries the item to find out whether the item-specific cached data needs to be refreshed. When updating, the item must alsodata needs to be refreshed. When updating, the item must also calculate the height and set ptli->cyp. Returns TRUE if the datacalculate the height and set ptli->cyp. Returns TRUE if the data was refreshed, FALSE if no changes were made. No drawing should bewas refreshed, FALSE if no changes were made. No drawing should be done when handling this message. */done when handling this message. */ /* WPARAM = (WPARAM)(TODAYLISTITEM *)ptli; *//* WPARAM = (WPARAM)(TODAYLISTITEM *)ptli; */ /* LPARAM not used *//* LPARAM not used */ /* return value = TRUE if refreshed, FALSE if no changes *//* return value = TRUE if refreshed, FALSE if no changes */ WM_PAINTWM_PAINTWM_LBUTTONUPWM_LBUTTONUP
duh…duh…
Optimizing for SpeedOptimizing for Speed
Design stuffDesign stuff Benchmark performance is a key metric Benchmark performance is a key metric
for appliance devicesfor appliance devices Perceived performance is still Perceived performance is still
performanceperformance
Optimizing for Speed Optimizing for Speed (dev)(dev)
Transparent text is actually fasterTransparent text is actually faster API overhead (FillRect)API overhead (FillRect) SIP messages are sent to foreground SIP messages are sent to foreground
windows onlywindows only LoadString(NULL);LoadString(NULL); Don’t forget obvious stuff:Don’t forget obvious stuff:
Control window overheadControl window overhead Delay init when appropriate (esp. DllMain)Delay init when appropriate (esp. DllMain)
Much you get for free:Much you get for free: Short circuit WndProcs (when possible)Short circuit WndProcs (when possible) Client side window dataClient side window data CS_VREDRAW, CS_SAVEBITSCS_VREDRAW, CS_SAVEBITS
Optimizing for Battery LifeOptimizing for Battery Life
Nerd StuffNerd Stuff Realtime OS Realtime OS
Means a battery win if we’re smartMeans a battery win if we’re smart Lose if we’re notLose if we’re not
Memory ManagementMemory Management
Follow the shutdown guidelines for Follow the shutdown guidelines for WM_HIBERNATE and WM_CLOSEWM_HIBERNATE and WM_CLOSE
Rapier more actively (preemptively) Rapier more actively (preemptively) shuts apps downshuts apps down
Auto memory division managementAuto memory division management
AutoRun AutoRun (dev)(dev)
CF or MMC install CF or MMC install (full install or just run)(full install or just run) Autorun.exe copied to windows directoryAutorun.exe copied to windows directory Called on insert and removeCalled on insert and remove
Autorun.exe installAutorun.exe install Autorun.exe uninstallAutorun.exe uninstall
Launch and add link to Programs folderLaunch and add link to Programs folder SHGetAutoRunPath(LPTSTR psz)SHGetAutoRunPath(LPTSTR psz)
General: \dwProcessorType\autorun.exe (GetSystemInfo)General: \dwProcessorType\autorun.exe (GetSystemInfo)
MIPS: \4000\autorun.exe MIPS: \4000\autorun.exe
SH3: \10003\autorun.exeSH3: \10003\autorun.exe
CEF: \0\autorun.exeCEF: \0\autorun.exe
Top 10 Kick Ass ThoughtsTop 10 Kick Ass Thoughts1.1. Copy usCopy us2.2. Less CAN be more…NO UI is Good UILess CAN be more…NO UI is Good UI3.3. Know your key scenarios & design only for Know your key scenarios & design only for
thosethose4.4. Read is different from editRead is different from edit5.5. Minimize the difficulty of inputMinimize the difficulty of input6.6. 5mm stylus and 9.1mm finger5mm stylus and 9.1mm finger7.7. Single tap, single tap, single tapSingle tap, single tap, single tap8.8. Be good to the SIP… WC_SIPPREF is your Be good to the SIP… WC_SIPPREF is your
friendfriend9.9. Shut down cleanly, we’re managing memory, Shut down cleanly, we’re managing memory,
one bad app makes us all look badone bad app makes us all look bad10.10. Support AutoRun & CF storageSupport AutoRun & CF storage
Q & A
Top Related