| Windows Fundamentals | Client | Server | 
| Provide 32-bit-only components |  |  | 
| Do not add to Win.ini, System.ini, Autoexec.bat or Config.sys |  |  | 
| Support long file names and UNC paths |  |  | 
| Support printers with long names and UNC paths |  |  | 
| Define icons and context menus for your own file types |  |  | 
| Perform Windows version checking correctly |  |  | 
| Support autoplay of compact discs |  |  | 
| Install/Uninstall | Client | Server | 
| Install using a Windows installer package that passes validation testing |  |  | 
| Migrate correctly upon upgrade to Windows 2000 Professional |  |  | 
| Identify shared components |  |  | 
| Install to Program Files by default |  |  | 
| Support Add/Remove Programs properly |  |  | 
| Ensure that the Windows installer package supports advertising |  |  | 
| Ensure correct uninstall support |  |  | 
| Component Sharing | Client | Server | 
| On Windows 2000 do not replace files that are protected by system file protection |  |  | 
| Component producers: build side-by-side components |  |  | 
| Application developers: consume and install side-by-side components |  |  | 
| Install any non side-by-side shared files to the correct location |  |  | 
| User and Computer Settings Management | Client | Server | 
| Adhere to all system policies |  |  | 
| Register shell extensions as such |  |  | 
| Default to My Documents for storage of user-created data |  |  | 
| Store application and user data in separate folders (preferred) or registry keys |  |  | 
| Degrade gracefully on Access Denied |  |  | 
| Extend the computer management with an MMC snap-in |  |  | 
| User Interface Fundamentals | Client | Server | 
| Support standard system size, color, font, and input settings |  |  | 
| Ensure compatibility with the High Contrast option |  |  | 
| Provide documented keyboard access to all features |  |  | 
| Expose the location of the keyboard focus |  |  | 
| Do not rely on sound alone |  |  | 
| Publish program information properly in the Start Menu |  |  | 
| Active Directory | Client | Server | 
| Services publish themselves in the Active Directory |  |  | 
| Clients must rely on Active Directory for network services |  |  | 
| Applications must support both DNS and NetBIOS names in their API and UI |  |  | 
| Services must adhere to the schema extensibility rules |  |  | 
| OnNow/ACPI Support | Client | Server | 
| Respond to sleep requests from the operating system |  |  | 
| Respond to sleep notifications properly |  |  | 
| Handle noncritical wake notifications without losing data |  |  | 
| Handle critical sleep and wake notifications properly |  |  | 
| Use SetThreadExecution to indicate a busy application |  |  | 
| Reconcile multiuser edits on network files |  |  | 
Figure 5 Migration DLL Exports
| Function | Description | 
| QueryVersion | Determines if migration is necessary. The function should verify that the application is still installed. | 
| Initialize9x | Confirms migration from Windows 9x to Windows 2000. | 
| MigrateUser9x | Gathers information about the users, and saves private data to be used later. | 
| MigrateSystem9x | Gathers systemwide information concerning the target application, and saves private data to be used later. | 
| InitializeNT | Called during the Windows NT GUI portion of the setup; indicates that now it's time to prepare the application to run on Windows 2000. | 
| MigrateUserNT | Migrates the user accounts to Windows 2000. Uses information saved during MigrateUser9x. | 
| MigrateSystemNT | Migrates the systemwide information stored during MigrateSystem9x. | 
Figure 8 The Windows 2000 GPE
|  | 
Figure 9 Saving Application Data to Disk
| Category | Folder Root Location | Description | 
| Roaming User | CSIDL_APPDATA\User\ Application Data | Contains user-specific application preferences. This folder will roam and is accessible through different computers on the network. | 
| Nonroaming User | CSIDL_LOCAL_APPDATA\Local Settings\Application Data | Contains user-specific machine-dependent settings. It's still part of the user profile but is used only on that machine. | 
| Nonuser (nonroaming) | CSIDL_COMMON_APPDATA\All Users\Application Data | Contains application data that is not user-specific such as log, temporary, and configuration files. | 
| Note: CSIDL_Xxx is the system folder ID described in the SHGetFolderPath documentation. | ||
Figure 11 Handiest Windows 2000 APIs and Technologies
| API | Description | Windows 98 | 
| GetLongPathName | Converts a short 8.3 name to its corresponding long format, if any. | Yes | 
| SHGetFolderPath | Unified function to get the path of both file system and virtual folders. | Yes, through a separate redistributable DLL. | 
| AnimateWindow | Opens and closes windows, applying some special transition effects. | Yes | 
| AllowSetForegroundWindow | Allows SetForegroundWindow to work as it does under Windows 95 and Windows NT 4.0. | No | 
| MoveFileWithProgress | Provides a callback routine to monitor activity while moving files from path to path. | No | 
| CreateProcessWithLogonW | Lets you run a program as though you were the specified user. | No | 
| VerifyVersionInfo | Verifies whether the current operating system has the characteristics (version, build, SP) you're requiring. | Yes | 
| ReplaceFile | A long-awaited function to replace a file with another one. | No | 
| OpenThread | Opens a thread. It's the thread counterpart of OpenProcess. | No | 
| SetThreadExecutionState | Through this function an application can prevent the system from entering the low power state. | Yes | 
| Technology | Description | Windows 98 | 
| ToolHelp | The Windows 2000 edition of the Windows 9x API to snoop processes and threads. | Yes | 
| Shell LightWeight | Utility library with handy functions to manage path names, strings, and registry operations. | Yes | 
| Jobs | Collection of kernel functions to deal with groups of processes seen as a single entity. | No | 
| MsImg32 | Includes frequently used graphic functions to do transparent blitting, blending, and draw gradients. | Yes | 
| Recycle Bin | Functions to manage the object stored in the Recycle Bin. | Yes | 
| Encryption | Includes functions to encrypt and decrypt NTFS files. | No | 
| NTFS storage system | Handles the new features of NTFS: hard links, streams, quotas, and reparse points. | No | 
| TAPI 3.0 | COM-based collection of functions to arrange telephony applications. | No | 
| Task Scheduling | COM-based interface to programmatically def batch tasks to execute regularly. | Yes | 
| Multi-monitor | Set of new, improved functions to exploit multi-monitor machines. | Yes | 
Figure 16 OFNEx.cpp
 // OFNEx.cpp : Defines the extensions for the Open File Dialog
 //
 
 #include "ofnex.h"
 
 // Handle of the keyboard hook
 static HHOOK g_hHook=NULL;
 static WNDPROC g_fnDlg=NULL;
 
 // New wndproc for the Shell DefView window
 LRESULT CALLBACK DVHandler(HWND, UINT, WPARAM, LPARAM);
 
 // Context Menu Item IDs
 #define CMD_SHORTCUT    30736    // Create Shortcut
 #define CMD_DELETE    30737      // Delete
 #define CMD_RENAME    30738      // Rename
 #define CMD_PROPERTIES    30739  // Properties
 
 /*---------------------------------------------------------------*/
 // Procedure....: AdjustListViewStyle()
 // Description..: Change some styles in the file listview
 // Input........: HWND
 // Output.......: void
 /*---------------------------------------------------------------*/
 void APIENTRY AdjustListViewStyle(HWND hDlg)
 {
     // Get the Listview handle
     HWND hwndLV = GetListViewHandle(hDlg);
 
     // Remove the label edit style
     DWORD dwStyle = GetWindowStyle(hwndLV);
     SetWindowLong(hwndLV, GWL_STYLE, dwStyle & ~LVS_EDITLABELS);
 
     // Set some extended styles
     ListView_SetExtendedListViewStyle(hwndLV, 
         LVS_EX_FULLROWSELECT|LVS_EX_TRACKSELECT|LVS_EX_GRIDLINES);
     return;
 }
 
 /*---------------------------------------------------------------*/
 // Procedure....: GrayRenameDeleteMenuItems()
 // Description..: Turn some file object attributes off 
 // Input........: HWND 
 // Output.......: void
 /*---------------------------------------------------------------*/
 void APIENTRY GrayRenameDeleteMenuItems(HWND hDlg)
 {
     // Get the Shell DefView handle (the listview's parent)
     HWND hwnd = GetParent(hDlg);
     HWND hwndDV = FindWindowEx(hwnd, NULL, 
         _T("SHELLDLL_DefView"), NULL);
     
     // Subclass the window to hook on context menu handle
     g_fnDlg = SubclassWindow(hwndDV, 
         reinterpret_cast<WNDPROC>(DVHandler));
 }
 
 /*---------------------------------------------------------------*/
 // Procedure....: SetNoDeleteMode()
 // Description..: Set/Reset the keyboard hook for file deletion
 // Input........: BOOL
 // Output.......: void
 /*---------------------------------------------------------------*/
 void APIENTRY SetNoDeleteMode(BOOL fSet)
 {
     if (fSet)
         g_hHook = SetWindowsHookEx(WH_KEYBOARD, 
             reinterpret_cast<HOOKPROC>(KeybProc), 
             NULL, GetCurrentThreadId());
     else 
         UnhookWindowsHookEx(g_hHook);
 }
 
 /*---------------------------------------------------------------*/
 // Procedure....: KeybProc()
 // Description..: Handle keyboard activity
 // Input........: int, WPARAM, LPARAM
 // Output.......: UINT
 /*---------------------------------------------------------------*/
 UINT CALLBACK KeybProc(int nCode, WPARAM wParam, LPARAM lParam)
 {
     if (nCode <0)
         return CallNextHookEx(g_hHook, nCode, wParam, lParam);
 
     // Do not call CallNextHookEx to prevent the system to delete
     if (wParam==VK_DELETE)
         return 1;
 
     return CallNextHookEx(g_hHook, nCode, wParam, lParam);
 }
 
 /*---------------------------------------------------------------*/
 // Procedure....: DVHandler()
 // Description..: New listview window procedure
 // Input........: HWND, UINT, WPARAM, LPARAM
 // Output.......: LRESULT
 /*---------------------------------------------------------------*/
 LRESULT CALLBACK DVHandler(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
 {
     switch(uiMsg)
     {
         case WM_INITMENUPOPUP:    
             {
                 HMENU hmenu = reinterpret_cast<HMENU>(wParam);
                 int iNumItems = GetMenuItemCount(hmenu);
                 int iItemID;
 
                 // Rename is last but 2. 0-based index needed.  
                 iItemID = GetMenuItemID(hmenu, (iNumItems-2)-1);
                 if (iItemID == CMD_RENAME) {
                     EnableMenuItem(hmenu, iItemID,
                         MF_BYCOMMAND|MF_GRAYED);
                 }
                 
                 // Delete is last but 3. 0-based index needed.
                 iItemID = GetMenuItemID(hmenu,(iNumItems-3)-1);
                 if (iItemID == CMD_DELETE) {
                     EnableMenuItem(hmenu, iItemID,
                         MF_BYCOMMAND|MF_GRAYED);
                 }
             }
             break;
     }
 
     return CallWindowProc(g_fnDlg, hwnd, uiMsg, wParam, lParam);
 }
 
 /*---------------------------------------------------------------*/
 // Procedure....: GetListViewHandle()
 // Description..: Returns the handle of the listview
 // Input........: HWND
 // Output.......: HWND
 /*---------------------------------------------------------------*/
 HWND GetListViewHandle(HWND hDlg)
 {
     HWND hwnd = GetParent(hDlg);
     HWND hwndDV = FindWindowEx(hwnd, NULL, 
         _T("SHELLDLL_DefView"), NULL);
     HWND hwndLV = FindWindowEx(hwndDV, NULL, 
         _T("SysListView32"), NULL);
     
     return hwndLV;
 }
 
 /*  End of file: OFNex.cpp  */