This chapter provides all the information required to install and adjust user applications on a terminal server. It not only describes pure installation procedures, but also the prior gathering of all the relevant data that will affect the server infrastructure and the applications used.
Applications used simultaneously by multiple users need to meet certain criteria and be compatible with terminal servers. This chapter describes the relevant technical requirements.
A terminal server needs to run in a certain mode when applications are installed. This chapter explains why and describes the correct application installation procedures.
Manual installation of applications is untenable in large terminal server environments. This chapter presents the key arguments for special installation tools.
Several examples are cited to illustrate the installation of frequently used applications.
In the past, companies and individuals developed Microsoft Windows–based applications themselves. This will likely continue as long as the functionality needed is not built into the off-the-shelf product. This chapter describes what you need to bear in mind if you want to commission or code your own customized applications for terminal servers.
At the end of this chapter, you will find out how the application mix influences the sizing of your terminal server.
Thus far, this book has focused on Microsoft Windows Server 2003 multiple-user options and Terminal Services clients. We looked at all key concepts and tools for Terminal Services, user administration, and network connection of clients from the point of view of an administrator. We did not elaborate on applications until now. In the final analysis, a terminal server relies on user acceptance and effective delivery of applications.
Ideally, no problems should arise when you install and run any program on a terminal server without special configuration. Unfortunately, this is the exception rather than the rule. Many older applications or their installation routines might already behave badly on a standard Windows 2000 workstation or in Windows XP. Even more applications were designed in a way that does not allow their default settings to handle simultaneous multiple users. Consequently, such applications often make assumptions about the operating system that do not apply to a multiple-user environment.
Basically, the Microsoft programming principles for 32-bit applications should ensure proper functioning of programs that are used in multiple instances by multiple users. In the past, however, many application developers did not adhere to these principles, making subsequent improvements necessary to run within a terminal server environment. The adjustments involve registry settings as well as directory structures and file access permissions.
In a terminal server–based environment, applications run on the server platforms only. The clients do not execute any type of local application logic. They display only the user interface and accept input. Of course, applications on the server do need to support this scenario.
The design of conventional Windows-based applications had already been specified for Windows 2000 Server, and the result was a standard that set important design guidelines for applications. This standard formed the basis for certifying an application for its use with Windows 2000. A similar certification program exists for Windows Server 2003 as well. The applicable logo is Certified for Windows Server 2003. Find more information on this topic at http://www.microsoft.com/winlogo.
A conventional application is an application based on unmanaged code. Therefore, statements made in this connection do not apply to Windows-based applications that are built on the .NET Framework and based on managed code. They will be addressed separately.
A conventional application that meets the Certified for Windows requirements can be used freely in Windows 2000 and Windows Server 2003 multiple-user environments. If an application strictly follows all the guidelines, it has several predefined properties. The installation is robust and self-repairing, minimizing any conflicts between shared components (such as DLLs). This allows different applications to peacefully coexist on one platform.
Furthermore, a “clean” application is easily distributed in a networked environment and ensures easy administration within organized structures. It can also save user and computer settings in one central profile and thus allows you to manage roaming users. It supports multiple users per computer and recreates application settings if a computer needs to be physically exchanged. Global and user-specific data is strictly separated. Optimally, this type of application also supports several different clients with their own customized user interfaces (for example, logos, colors, or fonts).
Naturally, the application should be able to run in a strictly controlled network environment and allow administrators to set the security and user interface parameters according to company regulations. Finally, an application must be able to provide a clear path for converting from an earlier version of Windows to Windows Server 2003.
When evaluating applications, you need to look at several categories that are based on different fundamental technologies or require different conditions.
Conventional Windows-based applications that access the 32-bit API of the operating system. These are typical, frequently used applications such as Microsoft Office XP, CorelDRAW, or Adobe Acrobat Reader.
Applications that are based on the Microsoft ASP.NET Web Forms concept or XML Web services and behave like Web applications. Web servers such as the Microsoft Internet Information Server control their processing logic.
Applications that are based on the .NET Windows Forms concept and generally behave like conventional 32-bit Windows-based applications.
Let us now look in detail at each of these categories.
A terminal server environment allows different users to simultaneously execute several application instances. Therefore, an application’s components (.exe files or DLLs) need to be programmed in a way that several users can work with them at the same time. Consequently, the following special conditions for user data and files need to be met:
Separate memory areas Several application instances executed by different users should not access common memory areas containing user-specific data to prevent unwanted data exchange between two user sessions.
File access lockout When one user accesses a program file, file access should not be locked for other users. Otherwise, only one application instance can be executed.
File access permission Non-administrative users should probably not have access to system files or have the same permissions as administrators. Avoid setups that would, for instance, prevent users who did not install an application from starting it.
File saving location User-specific data and configuration files must be saved in separate, user-specific locations to avoid collisions and to manage access permissions.
At first glance, this does not seem complicated. However, in reality, older applications usually do not expect to be used in a multiple-user environment. They therefore make certain assumptions about their living space and behave accordingly. If this type of application is further developed, legacy design decisions often survive, even though they are not in keeping with the terminal server requirements previously discussed.
Through a corresponding API (Application Programming Interface), conventional applications are able to access specific system functions and data structures on terminal servers. This allows the development of applications that recognize they are running on terminal servers. In this way, developers can predefine certain program behaviors that apply only to terminal servers. A great example is an application that unambiguously identifies its user through a computer property, such as the IP address on a server running Windows Server 2003 without Terminal Services installed. On a terminal server, this property is not unique and might prevent simultaneous use of the application by several users. However, if the application recognizes that it is running on a terminal server and is so configured, it can switch to a mode that recognizes the user name as the unique differentiating feature. It is, of course, preferable to avoid such dependencies right from the start, when the application is being developed.
Conventional 32-bit applications that run on a terminal server present potential problems.
Dynamic link libraries Frequently, applications running on terminal servers use dynamic link libraries (DLLs). DLLs are software components, and they can be used by several applications. There are no general mechanisms to manage different DLL versions. For this reason, an application that accesses DLLs is not guaranteed to work properly. Under Windows 2000, side-by-side DLL (SxS DLL) support was introduced. It allows parallel use of several DLL versions on one system. However, SxS DLL did nothing to make DLL management easier, which is why the term DLL hell evolved with respect to the susceptibility to failure of complex Windows environments. This, of course, is not a terminal server–only problem; the multiple-user environment just highlights it more.
Registry The registry manages system and user configurations. (See Chapter 6.) Unfortunately, not all programs handle the differences between system and user settings as carefully as they should. This might be acceptable for systems that are used by a single individual. For terminal servers, this could mean a mixing of information from different users.
.Ini files From a historical point of view, .ini files were used before the registry was introduced. They were used to save and reload system and configuration data. All this happened at a central system location and therefore did not support differentiation between users. Older applications that use .ini files are therefore a special challenge when working with terminal servers.
User-specific application data An application should be able to save all user-generated data within files in a user-specific folder. The application should be configured to point to the user’s home directory as the default archive directory. This requires the application to handle certain conventions, such as file access over the network or home directories with long names. User-specific application data is essential for terminal servers because terminal server users usually save user data on file servers on the network, not locally.
Temporary data Applications often create temporary data in temporary system folders. However, if several users are working on the system simultaneously, the temporary data must be strictly separated. Otherwise, data might get mixed up and possibly result in unauthorized data access. If user-specific temporary directories are used properly, such problems will not occur.
Due to the potential problems described above, some applications’ installation routines need to be adapted for terminal servers to establish a working system environment without having to change the applications and installation programs themselves.
In the summer of 2000, Microsoft announced the development of the .NET Framework, which allows completely new types of applications for Windows platforms. The .NET Framework has been on the market since the beginning of 2002 and supports three different types of applications.
ASP.NET Web Forms This type of application runs on Web servers (that is, Internet Information Services under Windows Server 2003) and generates output in HTML format (as Web forms). To display the graphical user interface (GUI) and interact with the application, the client requires a Web browser. The application logic is encoded with a technology called ASP.NET. Web forms do not usually have a role on terminal servers, but they can have an indirect impact if they are used to implement an application access portal.
XML Web Services These applications also run on Web servers, but they interact with programs instead of with users. Web services thus represent a new generation of technology for developing modular software components that can be distributed on the network by means of a formal description and standard protocols. Web services are normally based on eXtensible Markup Language (XML) for data and document formats, Web Services Description Language (WSDL) to describe messages and services, and the Simple Object Access Protocol (SOAP) for communication among the software modules. XML Web services do not usually run on terminal servers.
.NET Windows Forms Windows Forms are the descendants of conventional 32-bit Windows programs. They normally run in one window on the Windows desktop and can therefore be installed on terminal servers. If so programmed, Windows Forms can access Web services via the default interfaces and use their functions. The .NET Framework offers class libraries that can be used to develop Windows Forms applications.
The three Framework application types have one thing in common: they do not communicate directly with the operating system. They need a runtime environment as an intermediate layer, the common language runtime (CLR), which is able to process any application code written in Microsoft Intermediate Language Code (MSIL code). This platform-independent code is also known as managed code because it is strictly controlled by the runtime environment instance. For an application developed in a .NET language per common language runtime guidelines (for example, C# or Microsoft Visual Basic .NET), a compiler translates the source code into MSIL. The result in MSIL is then bundled into executable and transportable packages called assemblies. In rough terms, MSIL is like the assembler code of a Framework application and as such can be modified directly. However, a developer usually uses one of the .NET programming languages, not MSIL.
The .NET common language runtime was developed primarily for security and to be independent of any programming language. Because the CLR controls the code in MSIL, it is easier to control security than in conventional 32-bit applications. Windows Server 2003 comes with .NET Common Language Runtime version 1.1 and can run Framework applications without any modifications.
An assembly is a self-contained unit that contains all the metadata, resources, and data it needs. A complete Framework application consists of at least one assembly, which you can install on a platform simply by copying it. No registration is required. Additional functions can be encapsulated in further assemblies. These assemblies must be located in the same folder or in a subfolder. You can also use an XML file to determine where the runtime environment should look for additional assemblies. Assemblies used by more than one application are an exception. They are saved in a special folder, the %SystemRoot% \Assembly folder, also called the Global Assembly Cache (GAC). All assemblies in the GAC need to have a name, a version number, a public key, and a signature for unambiguous identification. All these elements comprise the strong name. The combination of assemblies, predefined folders, and strong names wards off the DLL hell of conventional 32-bit applications.
What happens if you want to run a Framework application that is an assembly in Microsoft Intermediate Language Code? In the case of .NET Windows Forms, the assembly is packed into an executable file that you can launch. Special header entries in the .exe file identify it as a .NET program that the operating system recognizes. This file first needs to be converted from the correct version of the common language runtime to a platform-specific byte code, either a 32-bit x86 code or a 64- bit Itanium code, depending on the platform. A just-in-time compiler is launched automatically after the .exe file with a Framework application is started and helps with the translation. This process runs every time the application is started. After the first time, the applications generally start a lot faster because the files are still in the main memory cache.
Why not install a platform-independent version of the Framework application in the target environment? The just-in-time compiler might know certain details about its computer such as number of available processors, memory, and other resources. It uses that information to optimize the application for the target environment when it translates the Microsoft Intermediate Language Code to platform-independent byte code. If a developer starts the just-in-time compiler on his own computer system to pre- compile the code and later transfers the code to another target machine, the result might not be optimized for a terminal server.
Configuration data that might be necessary for the runtime behavior of the application is usually in XML format. If these configurations affect user-specific settings, they need to be managed individually.
User-specific application data should be saved in the user’s home directory.
.NET programs can also access the registry, although usually they do not. They are nonetheless subject to the same rules as conventional 32-bit applications. Because Framework applications rarely access .ini files, we can forego a detailed explanation on this point.
To keep the system in a consistent state, you need to disable all options for user-initiated installations of Framework applications. Only administrators should have the right to install new Framework applications.
One recommendation is to translate future Framework applications with the just-in-time compiler before a user invokes them for the first time. The Ngen.exe tool from .NET Framework SDK allows an administrator to translate the MSIL code of the assembly into platform-specific code and save it in the GAC. This needs to happen on every server where the application will be installed (for example, with a specific installation routine). However, performance improvements occur only while loading the application. Code created by the user by automatically evoking the just-in-time compiler is usually faster than code created by the Ngen.exe tool.
It is best for the application’s installation routine to make some of the modifications, whereas other settings must be taken into account during the application’s development. Overall, the basic structure of .NET Windows Forms application is clearly better than most conventional 32-bit applications and is certainly just as compatible with terminal servers. So far, there are too few .NET Windows Forms applications on the market to make a qualified statement. However, the simplified programming model and excellent development tools will quickly change this.
Finally, we will briefly review the GDI+ graphical interface and how it interacts with Framework applications. GDI+ is not part of the .NET Framework, as often assumed, but rather is part of the Windows XP operating system and Windows Server 2003. However, the graphics requests through the related class library of the .NET Framework use GDI+. All GDI+ classes are located in the Gdiplus namespace and can easily be used in Windows Forms applications because they tend to be programmed in C# or Visual Basic .NET.