Appendix A: Best Practices

Important   The guidelines outlined in this appendix are not required to comply with the Application Specification for Windows 2000, but are strongly encouraged to provide a better user experience.

A-1  Installation of your application must not require a reboot on a freshly installed Windows 2000 system

Installation of your application should not require a reboot when you install it onto a freshly installed Windows 2000 system with no applications running unless you are deploying any of the following as part of your install.

Generally, a reboot on Windows 2000 should not be necessary, even if applications are running. In the past a typical reason apps would reboot was because they were replacing a file that was in use at the time. However, on Windows 2000, these situations are greatly eliminated when this Specification is adhered to because:

A-2  Use SHGetFolderPath to determine special folder paths

Whenever you access any of the special folders in the following list, your application should use the Win32 APIs to dynamically obtain the proper language-specific folder names. The preferred way to do this is using the SHGetFolderPath API with the appropriate CSIDL constant. This function behaves consistently across Windows 95, Windows 98, Windows NT 4.0, and Windows 2000.

This API is redistributable via the SHFOLDER.DLL. SHFOLDER.DLL is installed by the Windows Installer redistributable. Software vendors are encouraged to redistribute this component as much as possible to enable this support on Windows operating systems prior to Windows 2000. Windows 2000 includes this DLL as a protected system file and, as such, this DLL cannot be replaced on Windows 2000 or greater.

To help ensure your application can run on Windows 9x, Windows NT 4 as well as Windows 2000, always link to the SHGetFolderPath implementation in SHFOLDER.DLL. Windows 2000 natively implements SHGetFolderPath in SHELL32.DLL, but other versions of Windows do not include SHGetFolderPath in SHELL32.DLL.

Standard Folder CSIDL Constant Name
Alternate Startup ([user], DBCS) CSIDL_ALTSTARTUP
Alternate Startup folder (All Users profile, DBCS) CSIDL_COMMON_ALTSTARTUP
Application Data ([user] profile) CSIDL_APPDATA
Application Data (All Users Profile) CSIDL_COMMON_APPDATA
Control Panel virtual folder CSIDL_CONTROLS
Cookies folder CSIDL_COOKIES
Desktop (namespace root) CSIDL_DESKTOP
Desktop folder ([user] profile) CSIDL_DESKTOPDIRECTORY
Desktop folder (All Users profile) CSIDL_COMMON_DESKTOPDIRECTORY
Favorites folder ([user] profile) CSIDL_FAVORITES
Favorites folder (All Users profile) CSIDL_COMMON_FAVORITES
Fonts virtual folder CSIDL_FONTS
History folder CSIDL_HISTORY
Internet Cache folder CSIDL_INTERNET_CACHE
Internet virtual folder CSIDL_INTERNET
Local (non-roaming) data repository for apps CSIDL_LOCAL_APPDATA
My Computer virtual folder CSIDL_DRIVES
My Pictures folder CSIDL_MYPICTURES
Network Neighborhood directory CSIDL_NETHOOD
Network Neighborhood root CSIDL_NETWORK
Personal folder ([user] profile) CSIDL_PERSONAL
Printers virtual folder CSIDL_PRINTERS
PrintHood folder ([user] profile) CSIDL_PRINTHOOD
Program Files folder CSIDL_PROGRAM_FILES
Program Files folder for x86 apps on Alpha systems CSIDL_PROGRAM_FILESX86
Programs folder (under Start menu in [user] profile) CSIDL_PROGRAMS
Programs folder (under Start menu in All Users profile) CSIDL_COMMON_PROGRAMS
Recent folder ([user] profile) CSIDL_RECENT
Recycle Bin folder CSIDL_BITBUCKET
SendTo folder ([user] profile) CSIDL_SENDTO
Start menu ([user] profile) CSIDL_STARTMENU
Start menu (All Users profile) CSIDL_COMMON_STARTMENU
Startup folder ([user] profile) CSIDL_STARTUP
Startup folder (All Users profile) CSIDL_COMMON_STARTUP
System folder CSIDL_SYSTEM
System folder for x86 applications on Alpha systems CSIDL_SYSTEMx86
Templates folder ([user] profile) CSIDL_TEMPLATES
User's profile folder CSIDL_PROFILE
Windows directory or SYSROOT CSIDL_WINDOWS

A-3  Test your application under Terminal Services

Many enterprise customers use Terminal Services to provide Windows 2000 applications to an array of desktop and mobile clients. Applications running under terminal services run only on the server. The terminal server client performs no local processing of applications. This means that in a terminal services environment, multiple instances of the same application may be running on the same machine at the same time, serving different users.

Considerations for developers

How to Pre-Test

  1. Set up a Windows 2000 Server computer as a Terminal Server Host and configure it to allow both administrator and non-administrator access.

  2. Install the application on this machine logged on as an Administrator.
  3. On a separate client machine, log on to the Terminal Server Host with normal (non-Power, non-Admin) User privileges.

  4. Ensure that all shortcuts, files and folders are available to the user.

  5. Launch each program in the application.

  6. Run a full set of functionality tests on your application.

  7. Create customized interface, file option and new default settings for the user.

  8. Log on as a different user and make sure that the setting changes you made for the first user are not the new defaults for the new user.

  9. Run a full set of functionality tests on your application simultaneously from two client computers as two different users.

  10. Run a full set of functionality tests on your application simultaneously from two client computers with one (non-Power, non-Admin) User and one Administrator.

Diagnosing Common Problems

References

A-4  Clients query Active Directory for Services

Any client that is locating a Windows 2000 service should query Active Directory to obtain binding information for the services that are of interest.

In Windows 2000, services publish their existence via objects in Active Directory. The objects contain binding information that applications use to connect to instances of the service. To access a service, an application does not need to know about specific computers; the objects in Active Directory include this information. An application queries Active Directory for an object representing a service (called a connection point object) and uses the binding information from the object to connect to the service.

In a distributed system, the computers are engines; the interesting entities are the services that are available. From the user's perspective, the identity of the computer that provides a particular service is not important. What is important is accessing the service itself.

To take advantage of the service-centric view afforded by the Active Directory Service, client applications must:

For examples and more detailed information, see the section titled "Searching Active Directory" in the "Active Directory Programmer's Guide" at: http://msdn.microsoft.com/developer/windows2000/adsi/actdirguide.asp.

A-5  Globalization

Globalization is the practice of designing and implementing software that is not locale dependent, i.e., can accommodate any locale. In software design, a locale is defined as a set of user preferences associated with a user's language. A locale in Windows 2000 includes formats for date, time, currency and numbers; rules and tables for sorting and comparison; and tables of character classifications.

Other user preferences that a globalized application should accommodate include user-interface language, default font selection, language rules for use in spell checking and grammar, and input methods such as keyboard layouts and input method editors. See: http://www.microsoft.com/globaldev for more details.

Guidelines for developing a globalized application include the following:

A-6  Localizability

In contrast to globalization, localization is the process of modifying an application so that its user interface is in the language of the user. Well designed software can be localized to any of the languages supported by Windows 2000 without changes to the source code, i.e., without recompilation. In addition to the guidelines for globalization mentioned above, those for localizability include the following:

  1. Isolate all user interface elements from the program source code. Put them in resource files, message files, or a private database.

  2. Use the same resource identifiers throughout the life of the project. Changing identifiers makes it difficult to update localized resources from one build to another.

  3. Make multiple copies of the same string if it is used in multiple contexts. The same string may have different translations in different contexts.

  4. Do not place strings that should not be localized in resources. Leave them as string constants in the source code.

  5. Allocate text buffers dynamically, since text size may expand when translated. If you must use static buffers, make them extra large to accommodate localized strings (e.g., double the English string length).

  6. Keep in mind that dialog boxes may expand due to localization. Thus, a large dialog box that occupies the entire screen in low-resolution mode may have to be resized to an unusable size when localized.

  7. Avoid text in bitmaps and icons, as these are difficult to localize.

  8. Do not create a text message dynamically at runtime, either by concatenating multiple strings or by removing characters from static text. Word order varies by language, so dynamic composition of text in this manner requires code changes to localize to some languages.

  9. Similarly, avoid composing text using multiple insertion parameters in a format string (e.g., in sprintf or wsprintf), because the order of insertion of the arguments changes when translated to some languages.

  10. If localizing to a Middle Eastern language such as Arabic or Hebrew, use the right-to-left layout APIs to layout your application right to left.

  11. Test localized applications on all language variants of Windows 2000. If your application uses Unicode, as recommended, it should run with no modifications. If it uses a Windows codepage you will need to set the system locale to the appropriate value for your localized application, and reboot, before testing.

A-7  Additional Accessibility Considerations

Accessibility means accommodating the widest possible range of user needs and preferences, especially those that might prevent use by individuals with temporary or permanent impairments, seniors, and those working in unusual circumstances. You accomplish this goal by providing a flexible user interface and maintaining compatibility with external software utilities that provide additional functionality.

In particular, applications should do the following:

A-8  Use 64-bit compatible data types

It is possible for developers to use a single source-code base for their Win32- and Win64™-based applications. Microsoft has added this support by introducing new data types in the Platform SDK for Windows 2000.

There are three classes of new data types: fixed-precision data types, pointer-precision types, and specific-precision pointers. These types were added to the Windows environment (specifically, to Basetsd.h) to allow developers to prepare for 64-bit Windows well before its introduction. These new types were derived from the basic C-language integer and long types, so they work in existing code. Therefore, use these data types in your code now, test your code as a Win32-based application, and recompile as a Win64-based application when 64-bit Windows is available.

Fixed-precision

Fixed-precision data types are the same length in both Win32 and Win64 programming. To help you remember this, their precision is part of the name of the data type. The following are the fixed-precision data types.

Type Definition
DWORD32 32-bit unsigned integer
DWORD64 64-bit unsigned integer
INT32 32-bit signed integer
INT64 64-bit signed integer
LONG32 32-bit signed integer
LONG64 64-bit signed integer
UINT32 Unsigned INT32
UINT64 Unsigned INT64
ULONG32 Unsigned LONG32
ULONG64 Unsigned LONG64

Pointer Precision

As the pointer precision changes (that is, as it becomes 32 bits with Win32 code and 64 bits with Win64 code), these data types reflect the precision accordingly. Therefore, it is safe to cast a pointer to one of these types when performing pointer arithmetic; if the pointer precision is 64 bits, the type is 64 bits. The count types also reflect the maximum size to which a pointer can refer. The following are the pointer-precision and count types.

Type Definition
DWORD_PTR Unsigned long type for pointer precision
HALF_PTR Half the size of a pointer. Use within a structure that contains a pointer and two small fields
INT_PTR Signed integral type for pointer precision
LONG_PTR Signed long type for pointer precision
SIZE_T The maximum number of bytes to which a pointer can refer; use for a count that must span the full range of a pointer
SSIZE_T Signed SIZE_T
UHALF_PTR Unsigned HALF_PTR
UINT_PTR Unsigned INT_PTR
ULONG_PTR Unsigned LONG_PTR

Specific Pointer-Precision Types

There are also new pointer types that explicitly size the pointer. Be cautious when using pointers in 64-bit code: If you declare the pointer using a 32-bit type, the system creates the pointer by truncating a 64-bit pointer. (All pointers are 64 bits on a 64-bit platform.)

Type Definition
POINTER_32 A 32-bit pointer. On a 32-bit system, this is a native pointer.

On a 64-bit system, this is a truncated 64-bit pointer.

POINTER_64 A 64-bit pointer. On a 64-bit system, this is a native pointer.

On a 32-bit system, this is a sign-extended 32-bit pointer.

Note that it is not safe to assume the state of the high pointer bit.


For more details, please see the Microsoft Platform SDK or visit: http://msdn.microsoft.com/library/backgrnd/html/midl64b.htm.