Windows-based Terminal Server

[This is preliminary documentation and subject to change.]

Microsoft® Windows®-based Terminal Server, version 4.0, is a product that enables the Microsoft® Windows NT® Server version 4.0 operating system to act as a terminal server for multiple, simultaneous client sessions. A Windows NT user can connect to a Terminal Server by logging on to a Windows-based Terminal or a Windows-based Terminal emulator.

A Windows-based Terminal is a thin-client hardware device that runs an embedded Windows-based operating system. A Windows-based Terminal emulator is client software that enables a Windows, Macintosh, or UNIX client to connect to a Terminal Server to display Windows-based applications. This combination of Terminal Server clients provides access to 16-bit and 32-bit Windows applications from virtually any desktop.


About Windows-based Terminal Server

Microsoft® Windows®-based Terminal Server is similar to a terminal-based, centralized host, or mainframe, environment in which multiple terminals connect to a host computer. Each terminal provides a conduit for input and output between a user and the host computer. A user can log on at a terminal, and then run applications on the host computer, accessing files, databases, network resources, and so on. Each terminal session is independent, with the host operating system managing conflicts between multiple users contending for shared resources.

The primary difference between Windows-based Terminal Server and the traditional mainframe environment is that the dumb terminals in a mainframe environment only provide character-based input and output. A Windows-based Terminal provides a complete graphical user interface including a Windows desktop and support for a variety of input devices, such as a keyboard and mouse.

In the Terminal Server environment, an application runs entirely on the Terminal Server. The Terminal Server client performs no local processing of application software. The Terminal Server transmits the graphical user interface to the client. The client transmits the user's input back to the server.


Clients Share Terminal Server Resources

In a Windows®-based Terminal Server environment, multiple users can log on simultaneously to a Terminal Server. Consequently, the users are sharing the hardware and software resources of the Terminal Server, which can create the following areas of contention:

  • CPU time. Each user has his or her own desktop environment and can run whatever applications are available to that desktop. However, all applications run by all users are contending for the central CPU resources available on the Terminal Server. If one user runs a poorly written, CPU-intensive application, other users might experience a visible loss of performance.
  • Disk access. Users contend for access to applications and related application files. In addition, users contend for disk accesses by the server operating system, such as loading DLLs or swapping memory between the paging file and physical memory.
  • Random Access Memory (RAM). Users contend for RAM on the Terminal Server because the client computers do not have local RAM.
  • Network access. Network access is essential in the Terminal Server environment because all desktop activity—graphical output and mouse/keyboard input—flows over the network links between the client desktop and the server. In addition, the users' applications running on the Terminal Server contend for access to other network resources.
  • Server-side hardware components. Hardware components such as CD-ROMs, floppy disk drives, serial ports, and parallel ports are typically server-based, not client-based. Sharing these traditionally non-shared components creates new considerations for users and for applications that access these hardware components. For more information, see Peripheral Hardware.
  • Access to global Windows NT objects and resources. In the Terminal Server environment, users do not run individual copies of Windows NT—some of the core components are cloned, but the remaining components are shared among the users. Thus, users are competing for access to the registry, the paging file, system services, and other global objects and resources.

Many of the preceding points of contention can be mitigated by sizing the Terminal Server with sufficient CPU, memory, and disk resources to handle the client demand. For example, a multiple processor configuration can maximize CPU availability. Memory availability can be maximized by installing extra physical memory. Finally, disk access performance can be maximized by configuring multiple SCSI channels and distributing your operating system and application loads across different physical drives. Properly configuring a Terminal Server is a critical element of perceived application performance.

Although hardware sizing is an important part of creating a scalable Terminal Server environment, the software considerations are equally important. In fact, fine-tuning an application often can do a lot to reduce resource competition and improve perceived application performance. For more information, see Terminal Server Programming Guidelines.


Terminal Server Programming Guidelines

Most existing 16-bit or 32-bit Windows-based applications run "as is" on a Microsoft® Windows®-based Terminal Server. However, some applications perform well in a Terminal Server environment; others do not perform as well. This section provides guidelines for developing applications that perform well in a Terminal Server environment.

Many of the guidelines in the following sections are good programming practices that will benefit applications running in either a Terminal Server or a traditional Windows NT environment. However, some of the sections recommend optimizations, such as limiting graphic effects, that you would want only when your application is running under Terminal Server. For sample code that illustrates how to detect the Terminal Server environment, see Detecting the Terminal Server Environment.

Note Following these guidelines does not limit or compromise an application's ability to function in the traditional Windows NT environment—applications optimized for Terminal Server work well in both environments.


Application Setup in a Terminal Server Environment

The automated setup procedure for many existing applications assumes that the application is being installed for a single user. In a multi-user Windows®-based Terminal Server environment, this assumption can create the following problems:

  • If the setup procedure updates the registry and desktop environment for just one user, additional users must reinstall the entire package or an administrator must manually copy information from the registry and desktop of one user to the other users.
  • With some setup procedures, you can customize the application at installation time by excluding features or components. If the initial installer excludes part of the application, additional users must reinstall the application to get the excluded features.

To avoid these problems, setup procedures should use the following guidelines when installing an application on a Terminal Server.

  • Install applications into the default user environment common to all users.
  • Support user-specific customization through the use of user profiles. To do this, create a template file for the System Policy Editor so an administrator can easily configure the registry to indicate the features available to each user. Then, at run time, the application can enable or disable features depending on the settings in the current user's registry hives. For more information, see System Policies.


Storing User-Specific Information

In a Windows®-based Terminal Server environment, applications should store user-specific information in user-specific locations, separately from global information that applies to all users. This rule applies to information stored in the registry, as well as information stored in files. In general, do not assume that one computer is equivalent to one user.

Store user-specific registry information under the HKEY_CURRENT_USER registry key. Terminal Server loads the current user's personal registry hive into HKEY_CURRENT_USER when the user logs on. Of course, the Terminal Server manages the registry to ensure that each of the logged on clients detects the correct user hive under HKEY_CURRENT_USER.

In contrast, all users share the HKEY_LOCAL_MACHINE hive. Use HKEY_LOCAL_MACHINE to store computer-specific information, not user-specific information.

Store user preference files or other user-specific files in the user's home directory or in a user-specified directory. This consideration applies to temporary files used to store interim information (such as cached data) or to pass data on to another application. User-specific temporary files must also be stored on a per-user basis.

You can use the SHGetSpecialFolderLocation function with the CSIDL_PERSONAL flag to get the location of the user's personal files directory. You can also use the GetWindowsDirectory function to retrieve the path of the Windows directory. In a Terminal Server environment, the Windows directory is guaranteed to be private for each user. Do not store user-specific files under the system directory (for example, WINNT) or program directory (for example, Program Files).


IP Addresses and Computer Names

Multiple users can be logged on simultaneously to a Windows®-based Terminal Server. Consequently, it is not safe to assume that the computer name or the IP address assigned to the computer are associated with a single user. This differs from a traditional Windows NT system, in which only one user is logged on at a time.

Applications that use the computer name or IP address for licensing or as a means of identifying an iteration of the application on the network will not work properly in the Terminal Server environment because the server's computer name or IP address can be associated with many users.

In the Terminal Server environment, each client terminal or terminal emulator has a separate IP address and computer name, but these addresses and names are visible only to the Terminal Server. Applications can detect only the IP address of the Terminal Server. Similarly, the GetComputerName function returns only the computer name of the Terminal Server.


Client/Server Applications

Client/server applications in a Windows®-based Terminal Server environment must be able to handle multiple clients connecting from the same computer. If your application is composed of a server component (such as a Windows NT service) and client components that connect to the server component, make sure that the server component can differentiate between multiple clients residing on the same system. To accomplish this, clients should establish communication with the server component through a well-defined global interface (for example, RPC or named pipes). The server and client should negotiate a different communication channel for each user session.

This same client/server consideration applies to client applications running in the Terminal Server environment that must establish connections to server components over the network. In this case, the client/server connection should use protocols that easily support this type of operation, such as TCP/IP where a different socket connection can be used for each client application. Applications should not assume that a single system connection is equivalent to a single user session.

Prompts for user input are another potential source of problems for client/server applications in a Terminal Server environment. If the server component is a Windows NT service, the server component should not display a user interface to request input from the client. Any user interface displayed by a Windows NT service displays on the Terminal Server desktop, not on the client desktop. If a service prompts for input, the client application will appear to stop responding until the input is provided at the server console. Instead, the service should request input from the client application, and the client should display the user interface and send the resulting input back to the server.


Graphic Effects

A Windows®-based Terminal Server relies on the network to transmit all input and output to its client terminals. Consequently, applications that make excessive use of graphic effects can affect performance for all Terminal Server clients by bogging down the network. In addition, the slower transmission speed over a network might cause the appearance of these special effects to be less pleasing than it would be in a local video environment.

In particular, applications should disable or minimize the use of the following features when running in a Terminal Server environment:

  • Splash screens—graphical product or company information displayed while an application is starting. Transmitting a splash screen to a Terminal Server client consumes extra network bandwidth and forces the user to wait before accessing the application.
  • Animations, which consume both CPU time and network bandwidth.
  • Direct input or output to the video display. If you need to read bits from the screen, maintain a separate, off-screen copy of the video buffer. Similarly, if you need to do elaborate screen output—for example, overlaying several images to arrive at a final composite screen—do that work in an off-screen buffer, and then send the results to the actual video buffer.


Peripheral Hardware

To a Windows®-based Terminal Server client, the Terminal Server is the local computer. Consequently, devices such as disk drives and printers attached to the Terminal Server appear as local devices to a Terminal Server client. In contrast, drives and printers attached to a client terminal appear to be remote devices. To access a device attached to a client terminal, you must use the UNC name of the client share or printer, just as you would any other remote share or printer.

The initial release of Windows-based Terminal Server does not support applications that send output directly to serial, parallel, and sound ports attached to the client terminal. In other words, the serial, parallel, and sound ports attached to the client terminal are not treated as local ports. However, you can use the built-in redirectors to do the appropriate "net share" and "net use" commands to share these devices.


Background Tasks

Background tasks—tasks performed when an application's message loop is idle—provide a mechanism for handling low-priority tasks in a single-user environment. In the Windows®-based Terminal Server environment, however, one user's background task competes for CPU cycles with another user's foreground tasks. When multiple users are running both foreground and background tasks, the CPU demands are much higher than when all users are running only foreground tasks. To maximize CPU availability for all users, either disable background tasks when running in a Terminal Server environment or create efficient background tasks that are not resource-intensive.


Thread Usage

Threads provide a convenient way of allowing an application to maximize its usage of CPU resources in a system, especially in a multiple processor configuration. In the Windows®-based Terminal Server environment, however, multiple users can be running multi-threaded applications, and all of the threads for all of the users compete for the central CPU resources of that system. With this in mind, you should tune and balance application thread usage for the multi-user, multiprocessor Terminal Server environment.


Other Guidelines for Terminal Server Developers

When you are developing applications to run in a Windows®-based Terminal Server environment, follow these guidelines:

  • Lock files and databases while making changes to prevent other users from make simultaneous changes to the same data.
  • Check your application for memory leaks and resolve any problems. Of course this is good advice for any application, but in a Terminal Server environment an application can be run multiple times by multiple users, thus rapidly magnifying the effect of a memory leak.
  • Use the MFC library whenever possible. The MFC library has a long list of tried-and-true classes for performing a wide variety of tasks. Most of these classes work well in the Terminal Server environment—usually much better than re-engineered solutions. A good example is the class that provides context-sensitive help text—help text that appears on-screen when the mouse pointer hovers over a button or menu item. If an application uses the MFC implementation to provide this feature, it will work reasonably well on the desktop system. But if the application implements this feature using dialog boxes or an alternate approach, the final result might not function well in the Terminal Server environment.


Legacy Applications in a Terminal Server Environment

The Windows NT Server operating environment has specific requirements for hosting MS-DOS®-based and 16-bit Windows-based applications. These requirements also apply to the Windows® -based Terminal Server environment. Any MS-DOS-based or 16-bit Windows-based application that does not run under Windows NT Server will not run under Terminal Server either. Terminal Server is, however, more sensitive to ill-behaved legacy applications than the traditional Windows NT Server because a single ill-behaved application can affect all of the users on the Terminal Server system.

Predicting which legacy applications will work well in the Terminal Server environment and which will not is difficult. In most cases, the only real way to determine a specific application's feasibility is to test the application in the Terminal Server environment. However, there are some application behaviors and origins that typically create problems in a Terminal Server environment:

  • MS-DOS-based applications that cycle on device input. MS-DOS-based applications that tightly loop for keyboard input, mouse activity, or other device input operations are often too CPU-bound to run effectively in the Terminal Server environment.
  • FoxPro® for MS-DOS-based applications. These applications often do not run well in the Terminal Server environment because they tend to be CPU interrupt-intensive and drain processor resources away from other user sessions.
  • MS-DOS-based print applications. Many MS-DOS-based applications use print techniques that are not compatible with the Terminal Server environment. However, 16-bit Windows-based applications that use the standard Windows printing functions work correctly.
  • MS-DOS and 16-bit Windows-based applications that internally mount NetWare drives. Programmatic NetWare drive mapping operations do not work under Terminal Server. In contrast, drive mapping using UNC names works correctly.
  • 16-bit Windows applications that directly access .ini files. Older Windows applications that directly access .ini files instead of using the standard functions might not work if multiple users simultaneously access an .ini file. Terminal Server handles the standard functions properly for a multi-user environment.


Detecting the Terminal Server Environment

An application can detect if it is being installed in or is running in a Windows®-based Terminal Server environment. The application can then optimize its behavior for its environment.

When Terminal Server is installed, it adds the string "Terminal Server" to the list of installed product suites in the registry. The following example function, ValidateProductSuite, shows how to check the registry for this string. You can use the following code with the sample function, ValidateProductSuite, to determine whether Terminal Server is installed.

BOOL fIsTerminalServer;
fIsTerminalServer = ValidateProductSuite( TEXT("Terminal Server") );

The following code implements the ValidateProductSuite example function, which checks the registry to determine whether a specified product suite is installed.

#include <tchar.h>
BOOL
ValidateProductSuite(
    LPTSTR lpszSuiteName
    )
{
    BOOL fValidated = FALSE;
    LONG lResult;
    HKEY hKey = NULL;
    DWORD dwType = 0;
    DWORD dwSize = 0;
    LPTSTR lpszProductSuites = NULL;
    LPTSTR lpszSuite;

// Open the ProductOptions key.

    lResult = RegOpenKey(
        HKEY_LOCAL_MACHINE,
        TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
        &hKey
        );
    if (lResult != ERROR_SUCCESS) {
        goto exit;
    }

// Determine required size of ProductSuites buffer.

    lResult = RegQueryValueEx(
        hKey,
        TEXT("ProductSuite"),
        NULL,
        &dwType,
        NULL,
        &dwSize
        );
    if (lResult != ERROR_SUCCESS) {
        goto exit;
    }

    if (!dwSize) {
        goto exit;
    }

// Allocate buffer.

    lpszProductSuites = (LPTSTR) LocalAlloc( LPTR, dwSize );
    if (!lpszProductSuites) {
        goto exit;
    }

// Retrieve array of product suite strings.

    lResult = RegQueryValueEx(
        hKey,
        TEXT("ProductSuite"),
        NULL,
        &dwType,
        (LPBYTE) lpszProductSuites,
        &dwSize
        );
    if (lResult != ERROR_SUCCESS) {
        goto exit;
    }

    if (dwType != REG_MULTI_SZ) {
        goto exit;
    }

// Search for suite name in array of strings.

    lpszSuite = lpszProductSuites;
    while (*lpszSuite) {
        if (_tcscmp( lpszSuite, lpszSuiteName ) == 0) {
            fValidated = TRUE;
            break;
        }
        lpszSuite += (_tcslen( lpszSuite ) + 1);
    }

exit:
    if (lpszProductSuites) {
        LocalFree( lpszProductSuites );
    }

    if (hKey) {
        RegCloseKey( hKey );
    }

    return fValidated;
}


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

Remedy: Insert the MSDN Library CD into the CD-ROM drive.