1 Introduction - Choices



( Copyright by Anil Thomas, 1998

THE DESIGN AND IMPLEMENTATION

OF A DISTRIBUTED WINDOWING SYSTEM

FOR WIN32 PLATFORMS

BY

ANIL THOMAS

B.Tech., Mangalore University, 1994

THESIS

Submitted in partial fulfillment of the requirements

for the degree of Master of Science in Computer Science

in the Graduate College of the

University of Illinois at Urbana-Champaign, 1998

Urbana, Illinois

To my parents, with love.

Acknowledgements

I thank all those who supported me through this effort. I especially thank Professor Roy Campbell for his technical and financial support and for being an all around swell guy. I am grateful to Ashish Singhai for acting as an excellent sounding board. Neil Goldman of Information Sciences Institute was kind enough to share some of his expertise with me. The software was tested over the Internet with assistance from Indu Mahadevan, Washington State University. Lastly, I thank Kishore Narasimhan Mandyam, CEO of Ampersand Corporation for getting me interested in distributed windowing systems.

Table of Contents

Chapter

1 Introduction 1

1.1 Thesis Outline 1

1.2 A Note to the Reader 2

2 Background 3

2.1 Related Work 3

2.1.1 X-Windows 3

2.1.2 ICA 5

2.1.3 WTS 5

2.1.4 VNC 6

2.2 Technology Backgrounder 6

2.2.1 RPC 7

2.2.2 CORBA 7

2.2.3 ILU 8

3 Design 9

3.1 Design Goals 9

3.2 Architecture 9

4 Implementation 12

4.1 Intercepting Function Calls 12

4.2 Redirecting Function Calls 16

4.2.1 Replicated GUI Distribution 17

4.2.2 Non-replicated GUI Distribution 17

4.3 Evolution of the System 18

4.4 Issues Encountered 21

4.4.1 Intercepted Functions 21

4.4.2 Redirected Functions 21

4.4.3 Type of Parameters 22

4.4.4 Handling Resources 22

4.4.5 Processing Events 23

4.4.6 Remote Execution 25

4.4.7 Web Enabling the System 25

5 Results 27

5.1 Outcome 27

5.2 Performance Evaluation 29

6 Extensions 34

6.1 Applications 34

6.2 Optimizations 35

7 Conclusion 38

Bibliography 39

Appendix

A Definition Files for the Interceptor DLLs 42

B Interface Definition for the Redirector 46

List of Figures

2.1: The X window system. 4

3.1: System components and interaction between them. 10

4.1: Redirecting API function calls. 16

4.2: The application used to test the initial version of the system 19

4.3: Event handling and callback functions 24

4.4: The complete system configured for use on the Web 26

5.1: Applications running on the final system 28

5.2: Test setup used for performance evaluation 29

5.3: Screenshot of randobj.exe 30

5.4: Network traffic produced by randobj.exe running on Terminal Server. 31

5.5: Network traffic produced by randobj.exe running on VNC…...………………………..31

5.6: Network traffic produced by winmine.exe running on Terminal Server. 32

5.7: Network traffic produced by winmine.exe running on VNC. 32

5.8: Comparison of peak network traffic. 33

6.1: Synchronous RPC vs. Asynchronous RPC 36

Chapter 1

Introduction

Distributed windowing systems enable users to locally interact with programs running remotely. The X Window system born in 1984 at the Massachusetts Institute Technology is a prime example for such a system[1]. While X enjoys widespread support in the UNIX community, Microsoft and Apple chose not to implement distributed computing capabilities in their popular windowing systems. This left users handicapped by restricting them to using local programs only.

Several attempts have been made to remedy this shortcoming. Among them is a host of Remote Control applications that let the user control a PC from a remote location. The usefulness of such software is limited because they allow only one user at a time. Multi-user solutions include WinFrame( from Citrix Systems[2] and Windows Terminal Server( (WTS) from Microsoft[3]. These products work at a device driver level and result in substantial network traffic. This treatise focuses on the design and implementation of an alternative scheme that partitions programs at a higher level.

This novel approach involves intercepting function calls and redirecting them to a remote location where the user interface is displayed. The software was implemented for Win32 platforms. It enables users to partition Win32 applications in such a way that the user interface is de-coupled from the rest of the logic and can be executed on a different machine. The issues involved in forcibly partitioning monolithic applications at the API layer are discussed. The thesis also describes how this technology can be adapted to deploy applications on the World Wide Web.

1. Thesis Outline

The rest of this thesis is organized into chapters as follows:

2. Background

This chapter discusses similar work done elsewhere and also gives an overview of technical concepts used in the implementation.

3. Design

A high level description of the system and its architecture.

4. Implementation

A detailed description of how the system was built to meet the objectives. Enumerates and discusses the issues faced during the implementation stage.

5. Results

Observations on the end product. Performance evaluation is also documented in this chapter.

6. Extensions

This chapter discusses various applications of the system and also a few possible improvements.

7. Conclusion

A summation of the entire project.

2. A Note to the Reader

The notion of client and server in X protocol terminology is the opposite of that held conventionally. To avoid confusion, the author has limited the usage of these words and used host and terminal instead. The host is the machine that hosts applications and the terminal is where the GUI is displayed. The terminal corresponds to an X server in X terminology.

Chapter 2

Background

This chapter covers background information such as similar work done elsewhere and various technological concepts used to implement the system.

2.1 Related Work

This section gives an overview of conceptually similar projects. Distributed windowing systems such as X Windows, ICA and WTS are discussed.

2.1.1 X-Windows

X has been accepted as ‘the’ windowing system for workstations, minicomputers, mainframes and supercomputers. X began in 1984 at the Massachusetts Institute of Technology as a joint project between the Laboratory for Computer Science and Project Athena with much of the early work sponsored by DEC and IBM[4].

The X system consists of three main parts:

1. The server – the software that controls the user’s display, including the screen, keyboard and mouse.

2. The clients – the application programs, which are completely separate from the server.

3. A communications link, which connects the clients and the server.

The client is the actual application. Whenever an application wants to render data on the screen or make a change to the visual interface, it sends a request to the server. Examples of requests are to create windows on the screen, to change the size or location of windows and to draw text or graphics on these windows. The server accepts these requests and does the required processing. Another function of the server is to notify the client about user events. It does so by sending events across the communications link telling them about input from the keyboard or mouse, or indicating certain changes in the status of windows.

Figure 2.1: The X window system.

The X Window System differs from Microsoft windowing systems and Macintosh in the following aspects.

• X is a client/server windowing system. Applications running on one machine can use the display of another.

• X is not a part of the operating system.

• The user interface is not built into the base X system.

The X-windows API was designed specifically for a distributed windowing system. X-Windows applications cannot interact with the display directly. Applications have to send requests to the X-Server to display anything on the screen. This ensures that the display and its clients are effectively de-coupled. The flip side is that it makes X comparatively inefficient. Even while running locally, clients have to request the server to update the display and this involves an overhead.

The clients transmit most of the requests to the X-server asynchronously and the server does not acknowledge the requests. So after the client sends one request it doesn't have to wait for a reply but can send the next request immediately. The effect of this is good utilization of network bandwidth. Because the client can push requests to the network as fast as it can generate them, there are no occasions when the network is idle because the client is waiting for a response from the server. Similarly, the server sends events to the client asynchronously.

Another feature of X that helps to minimize network traffic is selective event handling. Clients have to specify explicitly to the server the types of events it wants to be informed of, and in which windows. The server will send only these specific events to the client. This feature avoids unnecessary network traffic and also ensures that clients do not waste time in processing events that are not of any consequence.

2.1.2 ICA

ICA (Independent Computing Architecture) is the presentation protocol used by WinFrame( from Citrix Systems[2]. WinFrame is a multi-user Windows application server based on Windows NT under license from Microsoft that supports enterprise application deployment using a thin-client architecture.

The key to this thin-client architecture is ICA. Along with a data protocol called thinwire, it specifies how the user interface of applications is captured, transported and reproduced. ICA is a physical protocol that takes care of lower level network issues such as reliability and sequencing packets. The thinwire stream is constructed by encapsulating data in ICA packets. The thinwire component operates at a device driver level. It turns each call to the display driver into a set of optimized drawing primitives. These primitives are encapsulated into an ICA packet and passed through a set of protocol drivers that provide functionality like encryption, compression and framing. This packet is then sent to the client where it passes through the same layers in the opposite order. This results in the user interface of the application being reproduced on the client side.

2.1.3 WTS

WTS (Windows Terminal Server) is an add-on that provides distributed computing capabilities to the Windows NT operating system[5]. The components of this system include the multi-user core of Windows NT, the Remote Desktop Protocol (RDP) and the thin-client software.

The multi-user core provides the ability to support multiple, simultaneous client sessions. The protocol, RDP is based on International Telecommunications Union’s (ITU) T.120 protocol, a multichannel conferencing protocol currently used in the Microsoft NetMeeting(.

RDP makes use of a special display driver, which gets loaded for remote sessions. All the information passed by the GDI layer is transferred to the remote client where it is used to produce the user interface. RDP also takes care of the user events that have to travel in the reverse direction. The current implementation of RDP runs over TCP/IP.

WTS can optionally use ICA instead of RDP.

2.1.4 VNC

VNC (Virtual Network Computing) is a remote display system developed by the Olivetti & Oracle Research Laboratories [7]. It is a remote control software that makes it possible to access the desktop of a remote machine from a variety of machine architectures.

The VNC protocol is based on the concept of a remote frame buffer or RFB. The protocol simply allows a server to update the screen buffer of a remote client. Because it works at the framebuffer level, it is potentially applicable to all kinds of windowing systems and operating systems. The display part of the protocol is based on a single graphics primitive, which manifests a rectangle of pixel data at given co-ordinates. Updates are sent to the clients only on request. Input events are sent to the server by the client whenever the user presses a key or pointer button, or whenever the pointing device is moved.

2.2 Technology Backgrounder

Our windowing system makes use of several technology paradigms. An introduction to concepts such as RPC and CORBA is given in this section. Also included is an overview of the ILU system from Xerox PARC.

2.2.1 RPC

Remote Procedure Calling provides a mechanism for a service to publish a set of operations that can be used by remote clients[8]. Clients invoke service operations by sending request messages to the servers. These messages can be sent either synchronously or asynchronously[9]. If the messages are sent synchronously the client has to wait for a reply from the server before proceeding. Asynchronous RPC allows sending messages as and when they are generated without waiting for acknowledgements.

The remote procedure call is modeled on the local procedure call making it usable with conventional programming languages in a convenient way. An RPC server can be viewed as a software module, that exports a particular interface which can be made use of remotely. Normally, a server process is implemented as a daemon that constantly waits for requests from potentially multiple clients.

The implementation of RPC requires an interface compiler, a communication handler and a binding service. The interface compiler is used to generate the software components necessary to implement remote procedure calling transparent to the client program. The interface of the server module is specified using an interface definition language. The communication handling is usually done by some form of request-reply protocol. Binding provides a way to establish an identity for the server modules.

Widely used RPC implementations include Open Network Computing (ONC) RPC from Sun Microsystems[10] and Distributed Computing Environment (DCE) from Open Software Foundation (OSF)[11].

2.2.2 CORBA

The Common Object Request Broker Architecture (CORBA) is an interoperability standard that allows applications to communicate with one another regardless of where they are located[12]. CORBA helps users gain access to data and services transparently without them having to know about which software or hardware platform they reside in or their location on the network. Any specific implementation of this standard is called an ORB (Object Request Broker). The ORB is the middleware that makes communication between client and server objects possible. Typically the protocol used by distributed applications depends on a lot of factors like implementation language, network transport and way of defining interfaces. ORBs simplify this by defining the protocol through an implementation language-independent specification, the IDL (Interface Definition Language). ORBs also allow flexibility by letting programmers choose the most appropriate operating system, execution environment and implementation language for each component of a system.

CORBA 2.0 specification from OMG (Object Management Group) defines true interoperability by specifying how different ORBs can interoperate.

2.2.3 ILU

The Inter-Language Unification system (ILU) is a multi-language object interface system from Xerox PARC[13]. ILU provides support for building distributed applications. It includes a self-contained implementation of ONC RPC. It also supports the use of OMG IDL to define object interfaces and can be thought of as a partially compliant ORB system.

The object interfaces provided by ILU hide implementation distinctions between different languages, between different address spaces, and between operating system types. ILU interfaces can be specified in either OMG IDL or ILU’s Interface Specification Language (ISL).

Chapter 3

Design

The system was designed keeping in mind a set of objectives. This chapter discusses these goals and the different modules in the system.

3.1 Design Goals

The primary requirement was that the system needed to be a non kernel-modifying solution. We did not want any modifications to the operating system because we were dealing with proprietary operating systems like Windows NT and Windows 95.

We wanted a multi-user system allowing multiple users to access the applications on the host simultaneously. The system needed to be Internet-ready allowing application delivery on the Web as transparently as possible.

There were stipulations on the expected performance in terms of network bandwidth required and latency. The system had to be practicable for use over the Internet. This required that we minimize the network traffic as much as possible. At the same time, the latency had to be kept low so that user events are reflected on the display without any uncomfortable delay.

The architecture needed to be thin-client, thereby effortlessly lending itself to network computing. Other requirements included scalability and generality. The design was expected to work for all applications on a chosen platform. Although the implementation was not required to be complete, we had to make sure that the architecture would scale to accommodate the entire range of applications. The design was also expected to lead to a common implementation for all Win32 platforms, viz. Windows NT, Windows 95 and Windows 98.

3.2 Architecture

Various components that make up the system are depicted in Figure 3.1.

Figure 3.1: System components and interaction between them.

The Starter is a daemon that runs on the host waiting for requests from clients to run applications. As soon as an application is started, the Interceptor kicks in and passes all user interface API function calls to the Redirector. The Redirector routes these calls to the terminal. The Terminal Server is the module that takes care of displaying the GUI and trapping events on the client machine. The API Function Server receives the redirected calls and executes them to produce the user interface on the screen. The Event Handler is responsible for trapping events and passing them back to the host machine. The Event Dispatcher replays these events on the application.

Chapter 4

Implementation

The implementation of the system went through several iterations. This chapter describes these stages in detail. Several issues encountered during implementation are also discussed.

4.1 Intercepting Function Calls

The Win32 user interface API was not designed to be used in a distributed fashion. Since we were interested in forcibly partitioning applications to run in a distributed environment, the first requirement was an API capturing mechanism. i.e. a scheme that would allow us to intercept Win32 API calls, access the parameters and return responses to the caller. The requirements for this system were laid out as follows,

1. Applicability: The system should not require modifications to source or object code. This is a requirement because as a generic solution it should work with off-the-shelf applications. However modification of the executable file itself is allowed.

2. Generality: It should work with Windows NT and 95. Again, our aim was to make the solution as generic as possible. Since both Windows NT and 95 use a common API, it made sense to have a common solution that works for both.

3. Completeness: It should be able to intercept all the calls made to user32 and gdi32 DLLs by a specific application whether direct or indirect. However, calls within and between functions in user32 and gdi32 can be left out. This is because it is sufficient to trap and redirect a high level API function to trigger off all the lower level API functions called by it.

4. Noninterference: The system should not affect the performance of other applications that may be running on the same machine. The system should be capable of being employed on an individual basis without interfering with either the operating system or other application programs.

An intercepting system has to insert itself into the flow of control of application programs. The system should get control whenever an API call is issued and before the target of the call is reached. The control is handed back to the caller after the intended processing is done. (In our case the original target is never reached; but the caller is fooled into believing that the response it gets back is from the original target). Numerous schemes were investigated to achieve this.

The simplest mechanism is the one commonly used by profilers such as APF32CVT. For each DLL whose functions are to be intercepted, a custom DLL is made with the same exported interface. As long as we keep the names and ordinal numbers same as the original, it is possible to make the program dynamically bind to the custom DLL. This is achieved by modifying the executable file. The net effect is the same as linking the program with a custom import library that exports the same interface as the one we want to replace. Care has to be taken to have identical function signatures and to return appropriate values so that undesirable effects are avoided during run-time.

Another approach is to modify the prologue code of each API function to transfer control to the interceptor. This can be achieved by inserting JMP or CALL instructions with appropriate operands at the start of the function. In this case, the target is modified to alter the flow of control. The image of the DLL in the memory is modified and this requires that the interceptor run in the same process context as the application.

A third approach is to modify the calls to the API functions as described in Matt Pietrek’s ‘Windows 95 System Programming Secrets’[29]. This works by finding CALLs to the API functions and modify the CALL to point to the interceptor program. The spy program will need to be implemented as a DLL and will have to be injected into the address space of the process being spied on. In Win32 applications all calls to a given API function end up traveling through the same spot in the executable file. Each CALL instruction to this spot results in a JMP to a particular location in the import function table. By patching that one location to point at the spy program, you intercept all calls made by the EXE to that function. Now, the problem boils down to finding these locations that the JMP points to. The import function table typically resides in the .idata section of each executable. The linker fills this table with dummy addresses during link time and the Win32 loader patches the table with actual addresses during loading. The spy program can intercept calls by merely overwriting this table with its own routines.

The first approach was chosen in the final implementation by virtue of its simplicity and fair conformance to the design requirements. The only requirement that is violated is that of completeness. If a program uses ‘dynamic dynamic binding’ to call an API function, it would be impossible to intercept with this mechanism. i.e. Using LoadLibrary() and GetProcAddress() to call a function would defeat the system. The system would also fail if user32 and gdi32 libraries are statically linked to the application. But the probability of a program doing either of these is practically nil. At a later stage if it becomes inadequate, it can be replaced by any of the other schemes without significantly affecting the rest of the software.

Two DLLs were developed to substitute for user32 and gdi32 DLLs. These DLLs called xser32 and xdi32 respectively export the same API as user32 and gdi32 with the same ordinal numbers. For a specific application, it is sufficient to provide only those API functions that it is statically seen to import. Therefore, it was decided not to implement the complete set of API functions. A number of Win32 applications were examined with the EXEHDR utility to determine the functions they import. Based on thus collected statistical data, a subset of commonly used functions was chosen. Another criterion was that the chosen API should be sufficient to partition at least one off-the-shelf application for demonstration purposes. Winmin.exe was chosen for this intent and it was examined to determine the functions imported. The set of API functions finally selected are given in the definition files of the DLLs (Appendix A).

Each of these functions was implemented in such a way that they can be executed on a remote machine. They can also be parameterized as a whole to force redirection to a particular machine. (Remoting is described in detail in section 4.2) . All of them (except variable argument functions) use the Pascal calling convention (__stdcall) where the callee pops the stack. This is required so that they can be called just like Win32 API. Variable argument functions such as wsprintf uses the C calling convention (__cdecl).

The other problem that we faced was how to make applications dynamically bind to these custom DLLs instead of the system DLLs. A simple-minded solution would be to call these DLLs user32.dll and gdi32.dll and put them in the directory from which the application is loaded. It would seem that the loader would see these DLLs before it hits the actual DLLs because the order of search is

1. The directory from which the application loaded.

2. The current directory.

3. The Windows system directories

4. The Windows directory.

5. The directories listed in the PATH environment variable.

But this scheme will not work because user32.dll and gdi32.dll are mapped into the memory as soon as the OS boots up. Since the code inside dynamic link libraries is shared between all applications, they are not loaded again. Of course, we could replace the actual user32.dll and gdi32.dll with our custom DLLs. But this is as good as placing a system-wide hook and goes against the design requirement of noninterference. We do not want to remote the entire desktop but only specific applications.

The solution is to modify the executable file image to make it link to the interceptor DLLs. This is easier than it sounds because the link happens to be a text string. We can just do a global search for user32.dll and gdi32.dll and replace them with xser32.dll and xdi32.dll respectively. When the application is run, the loader maps xser32.dll and xdi32.dll into its virtual address space and patches all the user interface API calls to point to these DLLs.

Another complication arises with indirect dynamic linking. If an application X dynamically links to DLL Y and DLL Y dynamically links to user32.dll or gdi32.dll, the user interface API calls will not be trapped. Fortunately, there is a simple work-around. We can make a DLL Y' by modifying DLL Y in such a way that it dynamically links to xser32.dll and gdi32.dll. Then we modify the executable X so that it links to Y' instead of Y. e.g. notepad.exe uses comdlg32.dll which in turns uses user32.dll. We can intercept the indirect calls to user32.dll by making a DLL xomdlg32.dll that links to xser32.dll and making notepad.exe link with xomdlg32.dll. Clearly, this would work for any depth of indirection.

4.2 Redirecting Function Calls

The next step in remoting the interface was to redirect the API calls. As can be seen, this fits neatly into the Remote Procedure Call paradigm. Whenever an API function call is intercepted, we need to marshal the parameters and send them to the RPC server that is running at the terminal. The parameters are unmarshalled at the terminal and the same API call is made with the same parameters (with a few exceptions discussed later). The result of this call is transmitted back to the host and returned to the caller of the function.

Figure 4.1: Redirecting API function calls.

4.2.1 Replicated GUI Distribution

After the remote call returns, we have the option of calling the original API function on the host machine. In this case, the application is not truly distributed. On the host machine, it would run like an unpartitioned application. But the GUI will show up on the terminal by virtue of duplication. The return values from the remote procedure calls constitute the state of the application on the terminal. Since part of this state could be an input to calls that follow, we require a mapping between these values. Whenever a remote call returns a value, we put it into a table. Another table is built up with the return values of API functions called locally. There is a one-to-one mapping between these two tables. Whenever a remote call is to be made, its parameters are inspected for machine dependency. If a dependency exists, it is substituted with the corresponding terminal value obtained using the mapping already constructed. The net effect of doing all this is that the same GUI shows up on both the host and the terminal. For convenient referring, this method was named replicated GUI distribution.

4.2.2 Non-replicated GUI Distribution

The other option is not to call the function locally. The application will be truly distributed in the sense that the user interface executes on the terminal and all the rest on the host. The GUI will not show up on the host. The mapping between return values of local and remote calls is obviated. Basically, the application program is fooled into believing that the user interface is executing locally. The resultant behavior is more or less that of X-Windows.

The first method is suitable for collaborative operations such as application sharing. An application can be shared in such a way that it executes on only one machine but the GUI is displayed on more than one location. Changes to the display due to some event occurring are reflected across all screens. Processing user events is simpler because events occurring on a Terminal can be played back on the host simply by sending this events to the particular window. In the non-replicated approach, no such window exists on the host and hence playing back of events has to be done by calling the appropriate window callback procedure directly. This leads to a trade-off in the type of complexity as far as the implementation is concerned. Which method to choose is largely determined by the intended application domain. The non-replicated method is more suitable for application delivery across the World Wide Web. Replication would be an unnecessary overhead in this case and also it would interfere with the display on the host, which is certainly an undesirable side effect.

4.3 Evolution of the System

The software that we built went through three stages of evolution. Our first attempt was to build an RPC mechanism from scratch. This was achieved with the help of socket calls to communicate over the network and simple marshal-unmarshal mechanisms. Replicated GUI distribution was implemented on top of this. Microsoft Foundation Classes were used for the development. Only a small set of API functions was implemented in this version. It was tested using a small application that uses only the API functions in the set. Figure 4.2 shows a screen shot of this application.

Figure 4.2: The application used to test the initial version of the system.

The application responds to user actions by drawing lines or text at random co-ordinates. The system was tested by running the RPC server on one machine and running the partitioned application on another. As and when the application was running, all the relevant API function calls were sent to the RPC server, which executed these calls, thereby reproducing the interface. Windows messages were trapped by a callback procedure and sent back to the host machine via socket calls over TCP. On the host machine another program received these messages and sent them to the actual application. A detailed discussion of how user events are handled appears on section 4.4.5. The interesting point here is that is was as good as sharing the application between two users allowing both of them to work on the application simultaneously. The user events occurring at the host were directly handled by the application and the user events occurring at the terminal were routed to the host. Whenever the program responded to a user event by calling API functions, the display was updated on both the machines producing identical displays. However, we left it as it is and moved on to the next stage because our aim was to suppress the GUI at the host. Also, many API functions use complex data structures for parameter passing and this called for a more extensive RPC mechanism.

In the next stage, we graduated to Non-replicated GUI distribution and also decided to leverage it with an existing RPC library. Microsoft RPC was chosen to implement this version. Again only a small set of API functions was implemented. The RPC interface was written using Microsoft IDL. The details are deferred till the next section because most of the concepts are common to the final implementation. It worked fairly well as a proof of concept; but the non-availability of source code acted as a deterrent. We wanted to be able to customize the RPC libraries to improve performance. At this point, we decided to use an ORB for the remote call mechanism. Using CORBA had other advantages such as replacing the ORB with a different one with minimal changes to the rest of the system.

We first experimented with OmniBroker, a CORBA-2 compliant, free ORB, available with full source code[30]. The interface was rewritten in OMG IDL and the system was implemented using C++. It worked as expected; but implementing the system in C++ involved new challenges. The parameters had to be converted into objects for transfer through the ORB. At the other end they had to be converted back into their original form that is understood by the API functions. This involved some overhead, especially for functions with complex parameters. What we wanted was a lightweight scheme, which also allowed implementation in C. We wanted to avoid as many overheads as possible because performance was critical in such a system. Fortunately, the Inter-language Unification system (ILU) from Xerox Corporation had all the qualities that we were looking for. An overview of the ILU system is given in section 2.2.3.

4.4 Issues Encountered

Most of the software had to be rewritten to make it use ILU for the remoting mechanism. The parts that could be reused were the interceptor and the IDL file. The issues to be resolved in the final implementation were,

• Deciding which functions to intercept.

• Deciding which functions to redirect.

• Deciding the type of parameters (in, out or inout).

• Handling functions with resource identifiers as parameters.

• Handling functions with callback functions as parameters and distributing events.

• Starting up applications remotely.

• Web enabling the system.

1. Intercepted Functions

The interceptor was extended to take care of many more API functions that are commonly used by Windows programs. Since our objective was to make it work for at least one off-the-shelf application, it was decided to implement all the user interface API functions used by a commonly used program that comes with the operating system. The game Minesweeper was chosen for this purpose. The interceptor DLLs xser32 and xdi32 were extended to trap all the calls made by winmine.exe to user32 and gdi32 respectively.

4.4.2 Redirected Functions

Some functions in user32 and gdi32 do not have any visual effect and therefore need not be redirected. If a function is not redirected, it is called locally and the results returned to the caller. There is no harm in redirecting all the function calls as far as the correctness of the program is concerned. However, for optimum performance, unnecessary network communication should be avoided. The rule of thumb used was to redirect all the functions that have either direct or indirect visual consequence. Direct visual consequence is when a function call results in some visible change to the screen. Indirect visual consequence means the output (the return value and/or parameters passed by reference) of a function constitutes part of the input to another function that has either direct or indirect visual consequence.

e.g. The function LoadBitmap() has indirect visual consequence because its output can be used as an input to SelectObject() whose output in turn can be used by BitBlt() resulting in visual modifications to the display.

But there are exceptions such as LoadString() which need not be redirected even though they have indirect visual consequence. The string loaded by LoadString() is passed by value to the functions that use it through the RPC mechanism and therefore does not have to be loaded again at the terminal.

Another way to look at it would be to think of the application as having two contexts. One is the state of the host machine and another that of the terminal. Let the context at the terminal be called the visual state. Any function that can potentially change this visual state has to be redirected. If not, it will result in unnecessarily duplicating part of the state at the host.

3. Type of Parameters

It turns out that there are no hard and fast rules to determine whether a parameter is in or inout. Each function was examined to determine whether any of the parameters are used to return the results. Care was taken not to tag a parameter as out unnecessarily because that would result in extra data transfer across the wire.

4.4.4 Handling Resources

Some of the API functions take resource (bitmaps, icons, menus, dialog box templates, cursors etc) identifiers as parameters. Typically, these resources are inside the executable file. Since the executable file does not exist on the terminal, we have to extract these resources and send them across. We used resource extraction functions provided by Win32 API to do this. The resources can also be extracted by following the executable format and searching for particular sections. At the terminal, these resources are received and saved into a dummy executable before the application starts running. Whenever a function that requires a resource is called, the module parameter is substituted with the loaded image of this dummy executable. This approach results in a small delay before the application can be run. Another approach would be to extract the resources and transfer them only when they are needed. In this case, the application can be started right away but the performance while usage will suffer. Improvements are discussed in the optimization section.

4.4.5 Processing Events

Handling user events is directly connected to the way callback functions are dealt with. Whenever an event occurs its handler is to be called. In our case this becomes complicated because the event occurs on one machine and the handler resides on another machine. This problem is solved as described below.

Whenever the application program registers a callback function, the function that does the registering is remoted to the Terminal. The callback function is entered into a table along with the window handle. At the Terminal, the callback function is substituted with a generic event handler. Whenever this particular event occurs, the generic event handler is called. The generic handler sends this event across the network back to the Host. This event is received by the interceptor and dispatched to the appropriate event handler. Dispatching is done by looking up the table of callback functions, using the window handle as the key.

Figure 4.3: Event handling and callback functions.

An event is represented by four values; the window handle (hWnd), message type (Msg) and two message parameters (wParam and lParam). The Dispatcher uses hWnd to decide which function to call. The mapping between the window handles and callback functions is actually more complicated than what is depicted in the diagram. A single window can have more than one callback procedure to handle different type of events. In that case the Dispatcher has to check the message type to disambiguate the callback function. The timer callback function registered by SetTimer() is an example of this occurrence. After the event is dispatched, the callback function responds by doing some processing. If this processing involves more USER or GDI calls, they are redirected to the Terminal as before. The Dispatcher and Redirector execute as separate threads so that waiting for events does not interfere with redirecting function calls.

4.4.6 Remote Execution

The setup also requires a component that is used to remotely start up applications on the host. This module called the Starter was implemented to receive requests from the Terminal Server. Again, the RPC paradigm was used to send these requests across the network. Upon receival of a request, the starter uses the CreateProcess() API function to execute the application. The Starter is a daemon, which is presumed to be always running on the host waiting for requests from Terminal Servers.

4.4.7 Web Enabling the System

Web enabling the system involves making application delivery possible on the Web. The users must be able to access and execute programs published on Web pages and interact with them. All the necessary components to achieve this are already in the system. All that needs to be done is configure the Terminal Server as a helper application to any browser. To publish applications, make a file corresponding to each program containing its name. When a browser retrieves this file, it will be passed on to the helper application. The helper application contacts a name server to find out which machine is hosting the application and requests the Host to run it. The interface shows up on the terminal as described before.

.

Figure 4.4: The complete system configured for use on the Web.

The simple binding service provided by the ILU system was used as the name server. By default, ILU uses files to publish interfaces. Certain include files had to be modified and the kernel recompiled to incorporate the change. The location of the name server is hard-coded into the ILU kernel. But this can be overridden by defining an environment variable as described in the ILU manual.

Chapter 5

Results

5.1 Outcome

A set of applications was chosen to illustrate the operation of the system. The choice was limited by the number of API functions that were implemented to be remotable. The use of these programs for benchmarking is questionable. Only two of them are off-the-shelf applications and the rest were written by us for illustrative purposes. However, these programs act as a good indicator as to how the system will behave with proper benchmarking programs. A screenshot of these applications running in a distributed fashion is given in Figure 5.1.

The screenshot shows the entire desktop of SRGPC4 where a Terminal Server is running. The four applications shown were remotely started on another PC, SRGPC6. The applications from top to bottom are,

Polybez.exe: GDI example program that draws Bezier curves on a window.

Randobj.exe: GDI example program that continuously draws random objects with random colors on a window.

Reversi.exe: A software implementation of the game Reversi.

Winmine.exe: Minesweeper game that is shipped with all MS-Windows operating systems.

Figure 5.1: Applications running on the final system.

As can be seen from the screenshot, the user interfaces appear as if the programs are running locally. The user can interact with the user interfaces and they display acceptable responsiveness. The sample programs were also tested using VNC (a remote control system from Olivetti Research Laboratory) for comparison purposes. All the applications displayed superior responsiveness and faster painting running on our system. The improvement was especially apparent with polybez and randobj, which continuously call a number of GDI functions (20 calls per second).

5.2 Performance Evaluation

Figure 5.2 shows the test setup used.

| | |

| |Dual-processor Pentium 200MHz |

| |128MB RAM |

| |Microsoft Windows NT Server |

| |Version 4.0 (Build 1381: Service Pack 3) |

| | |

| | |

|SRGPC4 | |

| | |

| |10 Mbps Ethernet |

|NETWORK | |

| | |

| |Dual-processor Pentium 200MHz |

| |128MB RAM |

| |Microsoft Windows NT Server |

| |Version 4.0 (Build 1381: Service Pack 3) |

| | |

| | |

|SRGPC6 | |

Figure 5.2: Test setup used for performance evaluation.

The network traffic was monitored using the Network Monitor Agent available with Windows NT Server. The number of bytes transferred per second was plotted against time. The charts produced by randobj.exe are shown in Figure 5.4 and Figure 5.5. The Y-axis is the network traffic in kilobytes and each division in the X-axis represents a second. The charts were produced with updates every second.

Figure 5.4 shows the network traffic with randobj.exe running on SRGPC6 and the Terminal Server on SRGPC4. Figure 5.5 shows the traffic with randobj.exe running on SRGPC6 and VNCViewer on SRGPC4. As can be seen, VNC transfers less number of bytes on an average. This is contrary to our expectations because VNC transfers the contents of the video memory across the wire and this is clearly at a lower level than remoting API functions. But a closer inspection of the results reveals the reasons behind this unanticipated behavior. It turns out that VNC produces less network traffic because it does not faithfully update the screen at the client side.

The program randobj.exe uses a timer to trigger off GDI calls. The time-out value of this timer is set as 50 milliseconds which means the program makes 20 GDI calls per second. But the graph for VNC shows a peak approximately every two seconds. This means it is updating the screen once in two seconds instead of 20 times in one second. This significantly hampers the performance of the system and can be observed visually. The Terminal Server produces a smooth visual effect, which is practically indistinguishable from the program running locally. VNC results in jerky refreshing as can be deduced from the graphs.

Moreover, VNC uses RRE (rise-and-run-length encoding) to compress the data thereby reducing the amount of data transferred over the network.

Figure 5.3: Screenshot of randobj.exe.

Figure 5.4: Network traffic produced by randobj.exe running on Terminal Server.

Figure 5.5 Network traffic produced by randobj.exe running on VNC.

Figure 5.6: Network traffic produced by winmine.exe running on Terminal Server.

Figure 5.7: Network traffic produced by winmine.exe running on VNC.

Figures 5.6 and 5.7 compare the network traffic for a typical run of Minesweeper. VNC results in less network traffic even in this case. Additionally, it also displayed superior responsiveness. This is probably due to the huge number of synchronous RPC calls caused by Minesweeper when running on our system. However the performance was comparable. The Terminal Server version also exhibited better cursor tracking.

Another interesting observation is that the peak network traffic is typically greater for VNC. This is especially true for polybez.exe and randobj.exe. The table in Figure 5.8 shows a comparison of peak traffic.

| Application | Peak Network Traffic (bytes/s) |

| | Terminal Server | VNC |

| Randobj.exe | 44K | 105K |

| Polybez.exe | 58K | 104K |

| Reversi.exe | 62K | 96K |

| Winmine.exe | 96K | 98K |

Figure 5.8: Comparison of peak network traffic.

It was also observed that VNC causes the network traffic to peak more often than Terminal Server does.

Chapter 6

Extensions

6.1 Applications

1. Centralizing application deployment: Applications can be deployed on a central server and accessed from multiple desktops. This simplifies deployment and slashes maintenance costs. Software upgrading, troubleshooting and management becomes easier because they can be done from a single access point to the entire network. Another advantage is, powerful servers can be used to host applications and less powerful ones can be used as desktop clients resulting in efficient utilization of available resources.

2. Publishing applications on the Web: As explained in section 4.4.7, this technology can be used to deliver applications from a Web page. Anybody on the Internet with access to Terminal Server software will be able to use these applications. This can be especially useful for evaluation software. The user is saved from the hassles of downloading and installing the software for evaluation purposes.

3. An alternative to Java applets: This can be achieved simply by having the Terminal Server as a plug-in to any Web browser. But to make it work on non-Win32 platform a subset of the Win32 API will have to be emulated.

4. Remote control: A PC can be controlled remotely from any location on the Internet using this technology. This enables users to access their software and data from a remote location.

5. Network computing: A thin-client device is sufficient to run programs off a central server. This device needs only the minimum capabilities necessary to communicate over the network and execute a set of functions. This could even be a Java machine implemented to run a predetermined subset of Win32 API.

6. Generic viewer: Publishing documents on the Web requires a viewer application at the client side. Typically, the formats not understood by the browser are handled by either a helper application or a plug-in. It would be possible to have this viewer on the server instead. Whenever a particular document is requested, this viewer application is launched and its interface transported to the client side where it is displayed using the Terminal Server software. Thus it acts as a generic viewer for all kinds of file formats (subject to certain constraints). The document itself need not be downloaded.

6.2 Optimizations

What has been implemented is a very basic system that is just sufficient to satisfy the objectives laid out in the beginning. There are a number of optimizations possible to make it perform better. The optimizations discussed result in reduced network traffic, reduced latency or both.

An obvious way to reduce network traffic is to compress the data before sending it over the network. The parameters to function calls can be examined to determine their size and see if it is worthwhile to spend some CPU time in compressing them. There is trade-off between minimizing the network traffic and the delay involved in compressing the parameters. A reasonable compromise can be arrived at after taking the available bandwidth and the processor speed into consideration.

Parameters can be cached at the Terminal so that if another call is made with the same parameter, it doesn't have to be transferred at all. This requires that the Redirector be aware of what values are cached by the Terminal Server. It makes sense to do this for large parameters like bitmaps and large arrays. A variation of this is to cache entire RPC calls so that if the same call is made with the same parameters, just an identifier can be sent to the Terminal Server.

Implementing on-demand resource retrieval can reduce the start-up time. The current implementation downloads all the static resources (bitmaps, menus, dialog box templates etc.) before the application is actually run. Instead, we can retrieve them as and when they are needed. Even though it enables the application to start up immediately, it will slow down the execution of API functions that use static resources. Another option is to download all the resources using a background thread and block any function call that needs a resource that has not been downloaded yet.

Techniques can be borrowed from the X-protocol, to get the maximum performance out of the system. One possibility is to make asynchronous RPC calls whenever possible. If the return value of a function is just a success indicator or void, it can be made into a one-way call. Since the function is assumed to succeed, it raises questions such as what happens if it does not. But dealing with this additional complexity is definitely worth it because it enables the Redirector to push functions onto the network as soon as they are generated. This is also applicable to RPC in the reverse direction that is used to pass events.

Figure 6.1: Synchronous RPC vs. Asynchronous RPC.

Even functions that return consequential values can be issued asynchronously. Note that this is not a one-way call because the return value might be wanted further down the program. All the functions that use this return value need to be blocked till it arrives. The improvement in performance will depend on how many calls can be issued without having to wait for a response.

The number of events sent to the Host can be significantly reduced by pruning out events that are not handled by the application. For example, an event is generated whenever the mouse is moved and can lead to substantial traffic on the network. But if this event is not handled by the application, there is no point in sending this event across. Other ways to reduce the number of events include using local timers instead of remote ones. This can lead to substantial bandwidth saving because the timer messages (which can occur as frequently as 1000 per one second) will be generated and handled locally.

Chapter 7

Conclusion

Popular windowing systems from Microsoft have been found lacking in distributed computing capabilities. The demand for an X-windows-like system has been on the rise for the past few years. This need was partially met by remote control programs and more recently Microsoft’s Terminal Server Edition of Windows NT 4.0. Our project focused on how an improved distributed windowing system can be built on top of Win32 operating systems by employing an alternative scheme.

An experimental system was designed and implemented following a set of goals. The system required implementing a mechanism to intercept user interface API function calls and redirecting them to a different machine. Other components of this distributed windowing system include an event interceptor and dispatcher that are used to process remote user events and a server module that starts up applications remotely. The system was built in such a way as to make deployment of applications on the World Wide Web possible. It also allows multiple clients to access published applications simultaneously. The ILU system from Xerox PARC was used to implement the RPC layer on top of which the system was built.

The implementation was tested using various benchmarking programs and the performance evaluated. A comparison study showed that it performed better than existing solutions in several cases. The implementation is not generic and there are restrictions to the kind of programs that can be partitioned to run in a distributed environment. Nevertheless, it satisfies all the objectives that were laid out in the beginning of the project and proves the concept of partitioning applications at the API level.

Bibliography

[1] A. Nye. X Protocol Reference Manual. O'Reilly & Associates, Inc., 1989.

[2] Citrix Systems. ICA Technical Paper. URL - ,

1996.

[3] Microsoft Corporation. Microsoft Windows NT Server 4.0, Terminal Server Edition: An

Architectural Overview. White paper, Jun 1998.

[4] N. Mansfield. The Joy of X. Addison-Wesley Publishing Company, 1993.

[5] Microsoft Corporation. Microsoft Windows NT Server 4.0, Terminal Server Edition:

Bringing Windows to Desktops That Can't Run Windows Today. White paper, Jun 1998.

[6] Microsoft Corporation. Comparing Microsoft Windows NT Server 4.0, Terminal Server

Edition and UNIX Application Deployment Solutions. White paper, Jun 1998.

[7] The Olivetti & Oracle Research Laboratory. Virtual Network Computing. URL -

, 1998.

[8] A.D.Birrell and B.Y.Nelson. Implementing Remote Procedure Calls. ACM Transactions on

Computer Systems, 2(1):39-59, Feb 1984.

[9] G. Coulouris, J. Dollimore and T. Kindberg. Distributed Systems: Concepts and Design.

Addison-Wesley Publishing Company, 1995.

[10 ] SunSoft. Solaris ONC: Design and Implementation of Transport-Independent RPC. Solaris

2.0 White Papers, 1991.

[11] Open Software Foundation. OSF DCE 1.0 Application Development Guide. Technical

report, Dec 1991.

[12] J. Siegel. CORBA Fundamentals and Programming. John Wiley & Sons, 1996.

[13] Xerox Corporation. Inter-Language Unification - ILU. URL -

, 1998.

[14] Sun Microsystems Inc. Network Programming Guide, Revision A Mar 1990.

[15] S.J. Mullender. Distributed Systems. Addison-Wesley Publishing Company, 1993.

[16] A.D. Birrel, R. Levin, R.M. Needham and M.D. Schroeder. Grapevine: an Exercise in

Distributed Computing. Communications of the ACM, 25(4):260-73, 1982.

[17] B.W. Lampson. Designing a Global Name Service. Proceedings of the 5th ACM Symposium

on Principles of Distributed Computing, 1-10, Aug 1986.

[18] Microsoft Corporation. RPC Programmer's Guide and Reference, 1993.

[19] R. Srinivasan. RPC: Remote Procedure Call Protocol Specification, Version 2. IETF RFC

1831, Aug 1995.

[20] A. Nye. XLib Reference Manual. O'Reilly & Associates, Inc., 1989.

[21] A.S.TanenBaum and S.J. Mullender. An Overview of the Amoeba Distributed Operating

System. ACM Operating System Review, 51-56, Jul 1981.

[22] V.F. Russo. LINK: A Kernel Based Distributed UNIX. M.S. Thesis, University of Illinois at

Urbana-Champaign, Jan 1987.

[23] Object Management Group. CORBA 2.2/IIOP Specification, 1998.

[24] D. Schmidt. Overview of CORBA. URL -

overview.html, 1998.

[25] S. Vinoski, CORBA:Integrating Diverse Applications Within Distributed Heterogeneous

Environments. IEEE Communications Magazine, Feb 1997.

[26 ] H. Custer. Inside Windows NT. Microsoft Press, Sep 1995.

[27] G. Eddon and H. Eddon. Inside Distributed COM. Microsoft Press, Mar 1998.

[28] C. Petzold. Programming Windows 95. Microsoft Press, Microsoft Press, Mar 1996.

[29] M. Pietrek. Windows 95 System Programming Secrets. IDG Books Worldwide, Inc., 1995.

[30] Object Oriented Concepts, Inc. ORBacus Homepage. URL - , 1998.

[31] B. Zaratian. Microsoft Visual C++ Owner's Manual. Microsoft Press, Apr 1997.

[32] Wine Development HQ. URL - , 1998.

[33] Sun Microsystems. Wabi Software. URL -

Integration-products, 1998.

Appendix A

Definition Files for the Interceptor DLLs

The .def files for the interceptor DLLs, xser32.dll and xdi32.dll are reproduced in this appendix.

;xser32.def : Declares the module parameters for xser32.dll

LIBRARY "xser32"

DESCRIPTION 'Win32 Dynamic Link Library'

EXPORTS

; Function Name Ordinal Number

; ------------------ -------------------

AppendMenuW @6

BeginPaint @10

CheckMenuItem @49

ClientToScreen @55

CreateWindowExA @85

CreateWindowExW @87

DefFrameProcA @125

DefMDIChildProcA @127

DefWindowProcA @128

DefWindowProcW @130

DialogBoxParamA @143

DispatchMessageA @144

DispatchMessageW @146

DrawTextA @171

EnableMenuItem @177

EndDialog @181

EndPaint @183

FillRect @205

GetAsyncKeyState @216

GetClassLongA @224

GetClientRect @229

GetDC @239

GetDesktopWindow @241

GetDialogBaseUnits @242

GetDlgItem @244

GetDlgItemInt @245

GetDlgItemTextA @246

GetKeyState @258

GetMenu @266

GetMessageA @278

GetMessageW @282

GetSysColor @298

GetSystemMenu @300

GetSystemMetrics @301

GetWindowLongA @315

GetWindowLongW @316

GetWindowRect @318

InflateRect @332

InvalidateRect @339

IsIconic @357

IsZoomed @364

KillTimer @366

LoadAcceleratorsA @367

LoadBitmapA @369

LoadCursorA @370

LoadCursorW @374

LoadIconA @375

LoadIconW @376

LoadMenuA @383

LoadStringA @388

LoadStringW @389

MessageBoxA @406

MessageBoxW @411

MoveWindow @414

OffsetRect @422

PeekMessageA @432

PostMessageA @434

PostMessageW @435

PostQuitMessage @436

PtInRect @444

RegisterClassA @446

RegisterClassW @450

ReleaseCapture @461

ReleaseDC @462

SendMessageA @475

SetCapture @484

SetCursor @493

SetCursorPos @495

SetDlgItemInt @498

SetDlgItemTextA @499

SetFocus @502

SetMenu @508

SetRect @521

SetTimer @535

SetWindowLongA @540

SetWindowLongW @541

SetWindowPos @543

SetWindowRgn @544

SetWindowTextA @546

SetWindowTextW @547

ShowCursor @554

ShowWindow @557

TranslateAcceleratorA @579

TranslateMDISysAccel @581

TranslateMessage @582

UnregisterClassA @590

UpdateWindow @593

WinHelpA @607

wsprintfA @613

wsprintfW @616

; gdi32.def : Declares the module parameters for xdi.dll.

LIBRARY "xdi32"

DESCRIPTION 'Win32 Dynamic Link Library'

EXPORTS

; Function Name Ordinal Number

; ------------------ -------------------

BitBlt @11

Chord @15

CombineRgn @20

CreateCompatibleBitmap @31

CreateCompatibleDC @32

CreateDCA @33

CreateDiscardableBitmap @39

CreateEllipticRgn @40

CreateFontIndirectW @46

CreatePalette @54

CreatePen @56

CreateRectRgn @60

CreateSolidBrush @65

DeleteDC @68

DeleteObject @71

Ellipse @76

ExtTextOutW @100

FillRgn @102

GetDeviceCaps @200

GetNearestColor @233

GetStockObject @251

GetTextExtentExPointW @261

GetTextExtentPointA @264

GetTextExtentPointW @265

GetTextMetricsA @268

GetWorldTransform @276

LineTo @281

ModifyWorldTransform @283

MoveToEx @284

PatBlt @291

Pie @293

PolyBezier @299

Polygon @307

Polyline @308

RealizePalette @312

Rectangle @315

RoundRect @323

SelectObject @331

SelectPalette @332

SetBkColor @337

SetBkMode @338

SetDIBitsToDevice @345

SetMapMode @354

SetPixel @360

SetROP2 @364

SetTextAlign @369

SetTextColor @371

SetViewportExtEx @373

SetViewportOrgEx @374

SetWindowExtEx @377

SetWorldTransform @379

TextOutA @388

Appendix B

Interface Definition for the Redirector

The definition of the object interfaces is given here in ILU Interface Specification Language (ISL).

INTERFACE UserGdi;

TYPE CHAR = SHORT CHARACTER TYPEID "IDL:Hd/CHAR:1.0";

TYPE "LONG" = INTEGER TYPEID "IDL:Hd/LONG:1.0";

TYPE "SHORT" = SHORT INTEGER TYPEID "IDL:Hd/SHORT:1.0";

TYPE BOOL = INTEGER TYPEID "IDL:Hd/BOOL:1.0";

TYPE "BYTE" = BYTE TYPEID "IDL:Hd/BYTE:1.0";

TYPE FLOAT = SHORT REAL TYPEID "IDL:Hd/FLOAT:1.0";

TYPE WCHAR = SHORT CARDINAL TYPEID "IDL:Hd/WCHAR:1.0";

TYPE UINT = CARDINAL TYPEID "IDL:Hd/UINT:1.0";

TYPE WORD = SHORT CARDINAL TYPEID "IDL:Hd/WORD:1.0";

TYPE ATOM = SHORT CARDINAL TYPEID "IDL:Hd/ATOM:1.0";

TYPE DWORD = CARDINAL TYPEID "IDL:Hd/DWORD:1.0";

TYPE VOID = SHORT CARDINAL TYPEID "IDL:Hd/VOID:1.0";

TYPE LPINT = ARRAY OF 1 INTEGER;

TYPE PUINT = ARRAY OF 1 CARDINAL;

TYPE PBOOL = ARRAY OF 1 BOOL;

TYPE LPVOID = VOID TYPEID "IDL:Hd/LPVOID:1.0";

TYPE LPWSTR = ilu.CString TYPEID "IDL:Hd/LPWSTR:1.0";

TYPE PWSTR = ilu.CString TYPEID "IDL:Hd/PWSTR:1.0";

TYPE LPTSTR = ilu.CString TYPEID "IDL:Hd/LPTSTR:1.0";

TYPE LPCWSTR = ilu.CString TYPEID "IDL:Hd/LPCWSTR:1.0";

TYPE LPCTSTR = ilu.CString TYPEID "IDL:Hd/LPCTSTR:1.0";

TYPE LRESULT = "LONG" TYPEID "IDL:Hd/LRESULT:1.0";

TYPE WPARAM = UINT TYPEID "IDL:Hd/WPARAM:1.0";

TYPE LPARAM = "LONG" TYPEID "IDL:Hd/LPARAM:1.0";

TYPE COLORREF = UINT TYPEID "IDL:Hd/COLORREF:1.0";

TYPE HANDLE = CARDINAL TYPEID "IDL:Hd/HANDLE:1.0";

TYPE HWND = HANDLE TYPEID "IDL:Hd/HWND:1.0";

TYPE HICON = HANDLE TYPEID "IDL:Hd/HICON:1.0";

TYPE HCURSOR = HANDLE TYPEID "IDL:Hd/HCURSOR:1.0";

TYPE HBRUSH = HANDLE TYPEID "IDL:Hd/HBRUSH:1.0";

TYPE HPEN = HANDLE TYPEID "IDL:Hd/HPEN:1.0";

TYPE HMENU = HANDLE TYPEID "IDL:Hd/HMENU:1.0";

TYPE HINSTANCE = HANDLE TYPEID "IDL:Hd/HINSTANCE:1.0";

TYPE HDC = HANDLE TYPEID "IDL:Hd/HDC:1.0";

TYPE HBITMAP = HANDLE TYPEID "IDL:Hd/HBITMAP:1.0";

TYPE HGDIOBJ = HANDLE TYPEID "IDL:Hd/HGDIOBJ:1.0";

TYPE HRGN = HANDLE TYPEID "IDL:Hd/HRGN:1.0";

TYPE HACCEL = HANDLE TYPEID "IDL:Hd/HACCEL:1.0";

TYPE HFONT = HANDLE TYPEID "IDL:Hd/HFONT:1.0";

TYPE HPALETTE = HANDLE TYPEID "IDL:Hd/HPALETTE:1.0";

TYPE WNDPROC = CARDINAL TYPEID "IDL:Hd/WNDPROC:1.0";

TYPE DLGPROC = CARDINAL TYPEID "IDL:Hd/DLGPROC:1.0";

TYPE TIMERPROC = CARDINAL TYPEID "IDL:Hd/TIMERPROC:1.0";

TYPE FARPROC = CARDINAL TYPEID "IDL:Hd/FARPROC:1.0";

TYPE VOIDS = SEQUENCE OF VOID;

TYPE BYTE-SEQUENCE = SEQUENCE OF BYTE;

TYPE tagWNDCLASS = RECORD

style : UINT,

lpfnWndProc : WNDPROC,

cbClsExtra : INTEGER,

cbWndExtra : INTEGER,

hi : HANDLE,

hIcn : HICON,

hCursr : HCURSOR,

hbrBackGround : HBRUSH,

lpszMenuName : LPCTSTR,

lpszClassName : LPCTSTR

END TYPEID "IDL:Hd/tagWNDCLASS:1.0";

TYPE WNDCLASS = tagWNDCLASS TYPEID "IDL:Hd/WNDCLASS:1.0";

TYPE tagCLIENTCREATESTRUCT = RECORD

hWindowMenu : HANDLE,

idFirstChild : UINT

END TYPEID "IDL:Hd/tagCLIENTCREATESTRUCT:1.0";

TYPE CLIENTCREATESTRUCT = tagCLIENTCREATESTRUCT TYPEID "IDL:Hd/CLIENTCREATESTRUCT:1.0";

TYPE LPCLIENTCREATESTRUCT = ARRAY OF 1 tagCLIENTCREATESTRUCT;

TYPE tagPOINT = RECORD

x : "LONG",

y : "LONG"

END TYPEID "IDL:Hd/tagPOINT:1.0";

TYPE POINT = tagPOINT TYPEID "IDL:Hd/POINT:1.0";

TYPE PPOINT = ARRAY OF 1 POINT;

TYPE NPPOINT = ARRAY OF 1 POINT;

TYPE LPPOINT = ARRAY OF 1 POINT;

TYPE POINTS = ARRAY OF 4 POINT;

TYPE tagSIZE = RECORD

cx : "LONG",

cy : "LONG"

END TYPEID "IDL:Hd/tagSIZE:1.0";

TYPE SIZE = tagSIZE TYPEID "IDL:Hd/SIZE:1.0";

TYPE PSIZE = ARRAY OF 1 SIZE;

TYPE LPSIZE = ARRAY OF 1 SIZE;

TYPE tagMSG = RECORD

hw : HWND,

message : UINT,

wp : WPARAM,

lp : LPARAM,

time : DWORD,

pt : POINT

END TYPEID "IDL:Hd/tagMSG:1.0";

TYPE MSG = tagMSG TYPEID "IDL:Hd/MSG:1.0";

TYPE PMSG = ARRAY OF 1 MSG;

TYPE NPMSG = ARRAY OF 1 MSG;

TYPE LPMSG = ARRAY OF 1 MSG;

TYPE tagRECT = RECORD

left : "LONG",

right : "LONG",

top : "LONG",

bottom : "LONG"

END TYPEID "IDL:Hd/tagRECT:1.0";

TYPE RECT = tagRECT TYPEID "IDL:Hd/RECT:1.0";

TYPE tagDEVMODE = RECORD

dmSpecVersion : WORD,

dmDriverVersion : WORD

END TYPEID "IDL:Hd/tagDEVMODE:1.0";

TYPE DEVMODE = tagDEVMODE TYPEID "IDL:Hd/DEVMODE:1.0";

TYPE BYTE-ARRAY-32 = ARRAY OF 32 BYTE;

TYPE tagPAINTSTRUCT = RECORD

hd : HDC,

fErase : BOOL,

rcpaint : RECT,

fRestore : BOOL,

fIncUpdate : BOOL,

rgbReserved : BYTE-ARRAY-32

END TYPEID "IDL:Hd/tagPAINTSTRUCT:1.0";

TYPE PAINTSTRUCT = tagPAINTSTRUCT TYPEID "IDL:Hd/PAINTSTRUCT:1.0";

TYPE LPDEVMODE = ARRAY OF 1 DEVMODE;

TYPE LPWNDCLASS = ARRAY OF 1 WNDCLASS;

TYPE LPRECT = ARRAY OF 1 RECT;

TYPE LPPAINTSTRUCT = ARRAY OF 1 PAINTSTRUCT;

TYPE CHAR-ARRAY-LF-FACESIZE = ARRAY OF 32 CHAR;

TYPE tagLOGFONTA = RECORD

lfHeight : "LONG",

lfWidth : "LONG",

lfEscapement : "LONG",

lfOrientation : "LONG",

lfWeight : "LONG",

lfItalic : "BYTE",

lfUnderline : "BYTE",

lfStrikeOut : "BYTE",

lfCharSet : "BYTE",

lfOutPrecision : "BYTE",

lfClipPrecision : "BYTE",

lfQuality : "BYTE",

lfPitchAndFamily : "BYTE",

lfFaceName : CHAR-ARRAY-LF-FACESIZE

END TYPEID "IDL:Hd/tagLOGFONTA:1.0";

TYPE LOGFONTA = tagLOGFONTA TYPEID "IDL:Hd/LOGFONTA:1.0";

TYPE PLOGFONTA = ARRAY OF 1 LOGFONTA;

TYPE NPLOGFONTA = ARRAY OF 1 LOGFONTA;

TYPE LPLOGFONTA = ARRAY OF 1 LOGFONTA;

TYPE AnonType-1- = ARRAY OF 32 WCHAR;

TYPE tagLOGFONTW = RECORD

lfHeight : "LONG",

lfWidth : "LONG",

lfEscapement : "LONG",

lfOrientation : "LONG",

lfWeight : "LONG",

lfItalic : "BYTE",

lfUnderline : "BYTE",

lfStrikeOut : "BYTE",

lfCharSet : "BYTE",

lfOutPrecision : "BYTE",

lfClipPrecision : "BYTE",

lfQuality : "BYTE",

lfPitchAndFamily : "BYTE",

lfFaceName : AnonType-1-

END TYPEID "IDL:Hd/tagLOGFONTW:1.0";

TYPE LOGFONTW = tagLOGFONTW TYPEID "IDL:Hd/LOGFONTW:1.0";

TYPE PLOGFONTW = ARRAY OF 1 LOGFONTW;

TYPE NPLOGFONTW = ARRAY OF 1 LOGFONTW;

TYPE LPLOGFONTW = ARRAY OF 1 LOGFONTW;

TYPE LOGFONT = LOGFONTA TYPEID "IDL:Hd/LOGFONT:1.0";

TYPE PLOGFONT = PLOGFONTA TYPEID "IDL:Hd/PLOGFONT:1.0";

TYPE NPLOGFONT = NPLOGFONTA TYPEID "IDL:Hd/NPLOGFONT:1.0";

TYPE LPLOGFONT = LPLOGFONTA TYPEID "IDL:Hd/LPLOGFONT:1.0";

TYPE tagBITMAPINFOHEADER = RECORD

biSize : DWORD,

biWidth : "LONG",

biHeight : "LONG",

biPlanes : WORD,

biBitCount : WORD,

biCompression : DWORD,

biSizeImage : DWORD,

biXPelsPerMeter : "LONG",

biYPelsPerMeter : "LONG",

biClrUsed : DWORD,

biClrImportant : DWORD

END TYPEID "IDL:Hd/tagBITMAPINFOHEADER:1.0";

TYPE BITMAPINFOHEADER = tagBITMAPINFOHEADER TYPEID "IDL:Hd/BITMAPINFOHEADER:1.0";

TYPE LPBITMAPINFOHEADER = ARRAY OF 1 BITMAPINFOHEADER;

TYPE PBITMAPINFOHEADER = ARRAY OF 1 BITMAPINFOHEADER;

TYPE tagRGBQUAD = RECORD

rgbBlue : "BYTE",

rgbGreen : "BYTE",

rgbRed : "BYTE",

rgbReserved : "BYTE"

END TYPEID "IDL:Hd/tagRGBQUAD:1.0";

TYPE RGBQUAD = tagRGBQUAD TYPEID "IDL:Hd/RGBQUAD:1.0";

TYPE LPRGBQUAD = ARRAY OF 1 RGBQUAD;

TYPE PRGBQUAD = ARRAY OF 1 RGBQUAD;

TYPE RGBQUAD-SEQUENCE = SEQUENCE OF RGBQUAD;

TYPE tagBITMAPINFO = RECORD

bmiHeader : BITMAPINFOHEADER,

bmiColors : RGBQUAD-SEQUENCE

END TYPEID "IDL:Hd/tagBITMAPINFO:1.0";

TYPE BITMAPINFO = tagBITMAPINFO TYPEID "IDL:Hd/BITMAPINFO:1.0";

TYPE LPBITMAPINFO = ARRAY OF 1 BITMAPINFO;

TYPE PBITMAPINFO = ARRAY OF 1 BITMAPINFO;

TYPE tagPALETTEENTRY = RECORD

peRed : "BYTE",

peGreen : "BYTE",

peBlue : "BYTE",

peFlags : "BYTE"

END TYPEID "IDL:Hd/tagPALETTEENTRY:1.0";

TYPE PALETTEENTRY = tagPALETTEENTRY TYPEID "IDL:Hd/PALETTEENTRY:1.0";

TYPE PPALETTEENTRY = ARRAY OF 1 tagPALETTEENTRY;

TYPE LPPALETTEENTRY = ARRAY OF 1 tagPALETTEENTRY;

TYPE tagLOGPALETTE = RECORD

palVersion : WORD,

palNumEntries : WORD,

palPalEntry : PPALETTEENTRY

END TYPEID "IDL:Hd/tagLOGPALETTE:1.0";

TYPE LOGPALETTE = tagLOGPALETTE TYPEID "IDL:Hd/LOGPALETTE:1.0";

TYPE PLOGPALETTE = ARRAY OF 1 tagLOGPALETTE;

TYPE NPLOGPALETTE = ARRAY OF 1 tagLOGPALETTE;

TYPE LPLOGPALETTE = ARRAY OF 1 tagLOGPALETTE;

TYPE tagTEXTMETRICA = RECORD

tmHeight : "LONG",

tmAscent : "LONG",

tmDescent : "LONG",

tmInternalLeading : "LONG",

tmExternalLeading : "LONG",

tmAveCharWidth : "LONG",

tmMaxCharWidth : "LONG",

tmWeight : "LONG",

tmOverhang : "LONG",

tmDigitizedAspectX : "LONG",

tmDigitizedAspectY : "LONG",

tmFirstChar : "BYTE",

tmLastChar : "BYTE",

tmDefaultChar : "BYTE",

tmBreakChar : "BYTE",

tmItalic : "BYTE",

tmUnderlined : "BYTE",

tmStruckOut : "BYTE",

tmPitchAndFamily : "BYTE",

tmCharSet : "BYTE"

END TYPEID "IDL:Hd/tagTEXTMETRICA:1.0";

TYPE TEXTMETRICA = tagTEXTMETRICA TYPEID "IDL:Hd/TEXTMETRICA:1.0";

TYPE PTEXTMETRICA = ARRAY OF 1 tagTEXTMETRICA;

TYPE NPTEXTMETRICA = ARRAY OF 1 tagTEXTMETRICA;

TYPE LPTEXTMETRICA = ARRAY OF 1 tagTEXTMETRICA;

TYPE LPTEXTMETRIC = LPTEXTMETRICA TYPEID "IDL:Hd/LPTEXTMETRIC:1.0";

TYPE tagXFORM = RECORD

eM11 : FLOAT,

eM12 : FLOAT,

eM21 : FLOAT,

eM22 : FLOAT,

eDx : FLOAT,

eDy : FLOAT

END TYPEID "IDL:Hd/tagXFORM:1.0";

TYPE XFORM = tagXFORM TYPEID "IDL:Hd/XFORM:1.0";

TYPE PXFORM = ARRAY OF 1 tagXFORM;

TYPE LPXFORM = ARRAY OF 1 tagXFORM;

TYPE RemWin = OBJECT OPTIONAL COLLECTIBLE

SUPERTYPES ilu.CORBA-Object END TYPEID "IDL:Hd/RemWin:1.0"

METHODS

AppendMenuW (hm : HMENU, uFlags : UINT, uIDNewItem : UINT, lpNewItem : LPCTSTR) : BOOL,

BeginPaint (hw : HWND, INOUT lpPaint : LPPAINTSTRUCT) : HDC,

CheckMenuItem (hm : HMENU, uIDCheckItem : UINT, uCheck : UINT) : DWORD,

ClientToScreen (hw : HWND, INOUT lpp : LPPOINT) : BOOL,

CreateWindowExA (dwExStyle : DWORD, lpClassName : LPCTSTR, lpWindowName : LPCTSTR, dwStyle : DWORD, x : INTEGER, y : INTEGER, nWidth : INTEGER, nHeight : INTEGER, hWndParent : HWND, hm : HMENU, hi : HINSTANCE, lpParam : LPVOID) : HWND,

CreateWindowExW (dwExStyle : DWORD, lpClassName : LPCTSTR, lpWindowName : LPCTSTR, dwStyle : DWORD, x : INTEGER, y : INTEGER, nWidth : INTEGER, nHeight : INTEGER, hWndParent : HWND, hm : HMENU, hi : HINSTANCE, lpParam : LPVOID) : HWND,

DefFrameProcA (hw : HWND, hWndMDIClient : HWND, uMsg : UINT, wp : WPARAM, lp : LPARAM) : LRESULT,

DefMDIChildProcA (hw : HWND, uMsg : UINT, wp : WPARAM, lp : LPARAM) : LRESULT,

DefWindowProcA (hw : HWND, Msg : UINT, wp : WPARAM, lp : LPARAM) : LRESULT,

DefWindowProcW (hw : HWND, Msg : UINT, wp : WPARAM, lp : LPARAM) : LRESULT,

DialogBoxParamA (hi : HINSTANCE, lpTemplateName : LPCTSTR, hWndParent : HWND, lpDialogFunc : DLGPROC, dwInitParam : LPARAM) : INTEGER,

DispatchMessageA (lpm : LPMSG) : "LONG",

DispatchMessageW (lpm : LPMSG) : "LONG",

DrawTextA (hd : HDC, lpString : LPCTSTR, nCount : INTEGER, lpr : LPRECT, uFormat : UINT) : INTEGER,

EnableMenuItem (hm : HMENU, uIDEnableItem : UINT, uEnable : UINT) : BOOL,

EndDialog (hDlg : HWND, nResult : INTEGER) : BOOL,

EndPaint (hw : HWND, lppaint : LPPAINTSTRUCT) : BOOL,

FillRect (hd : HDC, lprc : LPRECT, hbr : HBRUSH) : INTEGER,

GetAsyncKeyState (vKey : INTEGER) : "SHORT",

GetClassLongA (hw : HWND, nIndex : INTEGER) : DWORD,

GetClientRect (hw : HWND, INOUT lpr : LPRECT) : BOOL,

GetDC (hw : HWND) : HDC,

GetDesktopWindow () : HWND,

GetDialogBaseUnits () : "LONG",

GetDlgItem (hDlg : HWND, nIDDlgItem : INTEGER) : HWND,

GetDlgItemInt (hDlg : HWND, nIDDlgItem : INTEGER, INOUT lpTranslated : PBOOL, bSigned : BOOL) : UINT,

GetDlgItemTextA (hDlg : HWND, nIDDlgItem : INTEGER, INOUT lpString : LPTSTR, nMaxCount : INTEGER) : UINT,

GetKeyState (nVirtKey : INTEGER) : "SHORT",

GetMenu (hw : HWND) : HMENU,

GetMessageA (INOUT lpm : LPMSG, hw : HWND, wMsgFilterMin : UINT, wMsgFilterMax : UINT) : BOOL,

GetMessageW (INOUT lpm : LPMSG, hw : HWND, wMsgFilterMin : UINT, wMsgFilterMax : UINT) : BOOL,

GetSysColor (nIndex : INTEGER) : DWORD,

GetSystemMenu (hw : HWND, bRevert : BOOL) : HMENU,

GetSystemMetrics (nIndex : INTEGER) : INTEGER,

GetWindowLongA (hw : HWND, nIndex : INTEGER) : "LONG",

GetWindowLongW (hw : HWND, nIndex : INTEGER) : "LONG",

GetWindowRect (hw : HWND, INOUT lpr : LPRECT) : BOOL,

InflateRect (lprc : LPRECT, dx : INTEGER, dy : INTEGER) : BOOL,

InvalidateRect (hw : HWND, lpr : LPRECT, bErase : BOOL) : BOOL,

IsIconic (hw : HWND) : BOOL,

IsZoomed (hw : HWND) : BOOL,

KillTimer (hw : HWND, uIDEvent : UINT) : BOOL,

LoadAcceleratorsA (hi : HINSTANCE, lpTableName : LPCTSTR) : HACCEL,

LoadBitmapA1 (hi : HINSTANCE, lpBitmapName : LPCTSTR) : HBITMAP,

LoadBitmapA2 (hi : HINSTANCE, lpBitmapName : WORD) : HBITMAP,

LoadCursorA1 (hi : HINSTANCE, lpCursorName : LPCTSTR) : HCURSOR,

LoadCursorA2 (hi : HINSTANCE, lpCursorName : WORD) : HCURSOR,

LoadCursorW1 (hi : HINSTANCE, lpCursorName : LPCTSTR) : HCURSOR,

LoadCursorW2 (hi : HINSTANCE, lpCursorName : WORD) : HCURSOR,

LoadIconA1 (hi : HINSTANCE, lpIconName : LPCTSTR) : HICON,

LoadIconA2 (hi : HINSTANCE, lpIconName : WORD) : HICON,

LoadMenuA1 (hi : HINSTANCE, lpMenuName : LPCTSTR) : HMENU,

LoadMenuA2 (hi : HINSTANCE, lpMenuName : WORD) : HMENU,

LoadStringA (hi : HINSTANCE, uID : UINT, INOUT lpBuffer : LPTSTR, nBufferMax : INTEGER) : INTEGER,

LoadStringW (hi : HINSTANCE, uID : UINT, INOUT lpBuffer : LPTSTR, nBufferMax : INTEGER) : INTEGER,

MessageBoxA (hw : HWND, lpText : LPCTSTR, lpCaption : LPCTSTR, uType : UINT) : INTEGER,

MessageBoxW (hw : HWND, lpText : LPCTSTR, lpCaption : LPCTSTR, uType : UINT) : INTEGER,

MoveWindow (hw : HWND, X : INTEGER, Y : INTEGER, nWidth : INTEGER, nHeight : INTEGER, bRepaint : BOOL) : BOOL,

OffsetRect (lprc : LPRECT, x : INTEGER, y : INTEGER) : BOOL,

PeekMessageA (INOUT lpm : LPMSG, hw : HWND, wMsgFilterMin : UINT, wMsgFilterMax : UINT, wRemoveMsg : UINT) : BOOL,

PostMessageA (hw : HWND, Msg : UINT, wp : WPARAM, lp : LPARAM) : BOOL,

PostMessageW (hw : HWND, Msg : UINT, wp : WPARAM, lp : LPARAM) : BOOL,

PostQuitMessage (nExitCode : INTEGER),

PtInRect (lprc : LPRECT, pt : POINT) : BOOL,

RegisterClassA (lpw : LPWNDCLASS) : ATOM,

RegisterClassW (lpw : LPWNDCLASS) : ATOM,

ReleaseCapture () : BOOL,

ReleaseDC (hw : HWND, hd : HDC) : INTEGER,

SendMessageA (hw : HWND, Msg : UINT, wp : WPARAM, lp : LPARAM) : LRESULT,

SetCapture (hw : HWND) : HWND,

SetCursor (hcur : HCURSOR) : HCURSOR,

SetCursorPos (X : INTEGER, Y : INTEGER) : BOOL,

SetDlgItemInt (hDlg : HWND, nIDDlgItem : INTEGER, uValue : UINT, bSigned : BOOL) : BOOL,

SetDlgItemTextA (hDlg : HWND, nIDDlgItem : INTEGER, lpString : LPCTSTR) : BOOL,

SetFocus (hW : HWND) : HWND,

SetMenu (hw : HWND, hm : HMENU) : BOOL,

SetRect (lprc : LPRECT, xLeft : INTEGER, yTop : INTEGER, xRight : INTEGER, yBottom : INTEGER) : BOOL,

SetTimer (hw : HWND, nIDEvent : UINT, uElapse : UINT, lpTimerFunc : TIMERPROC) : UINT,

SetWindowLongW (hw : HWND, nIndex : INTEGER, lNewLong : "LONG") : "LONG",

SetWindowLongA (hw : HWND, nIndex : INTEGER, lNewLong : "LONG") : "LONG",

SetWindowPos (hw : HWND, hwndInsertAfter : HWND, x : INTEGER, y : INTEGER, cx : INTEGER, cy : INTEGER, fuFlags : UINT) : BOOL,

SetWindowRgn (hw : HWND, hr : HRGN, bRedraw : BOOL) : INTEGER,

SetWindowTextA (hw : HWND, lpsz : LPCTSTR) : BOOL,

SetWindowTextW (hw : HWND, lpsz : LPCTSTR) : BOOL,

ShowCursor (bShow : BOOL) : INTEGER,

ShowWindow (hw : HWND, nCmdShow : INTEGER) : BOOL,

TranslateAcceleratorA (hw : HWND, hAccTable : HACCEL, lpm : LPMSG) : INTEGER,

TranslateMDISysAccel (hw : HWND, lpm : LPMSG) : BOOL,

TranslateMessageA (lpm : LPMSG) : BOOL,

TranslateMessage (lpm : LPMSG) : BOOL,

UnregisterClassA (lpClassName : LPCTSTR, hi : HINSTANCE) : BOOL,

UpdateWindow (hw : HWND) : BOOL,

wsprintfA (lpOut : LPTSTR, lpFmt : LPCTSTR) : INTEGER,

wsprintfW (lpOut : LPTSTR, lpFmt : LPCTSTR) : INTEGER,

WinHelpA (hWndMain : HWND, lpszHelp : LPCTSTR, uCommand : UINT, dwData : DWORD) : BOOL,

BitBlt (hdcDest : HDC, nXDest : INTEGER, nYDest : INTEGER, nWidth : INTEGER, nHeight : INTEGER, hdcSrc : HDC, nXSrc : INTEGER, nYSrc : INTEGER, dwRop : DWORD) : BOOL,

Chord (hd : HDC, nLeftRect : INTEGER, nTopRect : INTEGER, nRightRect : INTEGER, nBottomRect : INTEGER, nXRadial1 : INTEGER, nYRadial1 : INTEGER, nXRadial2 : INTEGER, nYRadial2 : INTEGER) : BOOL,

CombineRgn (hrgnDest : HRGN, hrgnSrc1 : HRGN, hrgnSrc2 : HRGN, fnCombineMode : INTEGER) : INTEGER,

CreateCompatibleBitmap (hd : HDC, nWidth : INTEGER, nHeight : INTEGER) : HBITMAP,

CreateCompatibleDC (hd : HDC) : HDC,

CreateDCA (lpszDriver : LPCTSTR, lpszDevice : LPCTSTR, lpszOutput : LPCTSTR, lpInitData : DEVMODE) : HDC,

CreateDiscardableBitmap (hd : HDC, nWidth : INTEGER, nHeight : INTEGER) : HBITMAP,

CreateEllipticRgn (nLeftRect : INTEGER, nTopRect : INTEGER, nRightRect : INTEGER, nBottomRect : INTEGER) : HRGN,

CreateFontIndirectW (lplf : LPLOGFONT) : HFONT,

CreatePalette (lplgpl : LPLOGPALETTE) : HPALETTE,

CreatePen (fnPenStyle : INTEGER, nWidth : INTEGER, crColor : COLORREF) : HPEN,

CreateRectRgn (nLeftRect : INTEGER, nTopRect : INTEGER, nRightRect : INTEGER, nBottomRect : INTEGER) : HRGN,

CreateSolidBrush (crColor : COLORREF) : HBRUSH,

DeleteDC (hd : HDC) : BOOL,

DeleteObject (hObject : HGDIOBJ) : BOOL,

Ellipse (hd : HDC, nLeftRect : INTEGER, nTopRect : INTEGER, nRightRect : INTEGER, nBottomRect : INTEGER) : BOOL,

ExtTextOutW (hd : HDC, X : INTEGER, Y : INTEGER, fuOptions : UINT, lprc : LPRECT, lpString : LPCTSTR, cbCount : UINT, lpDx : LPINT) : BOOL,

FillRgn (hd : HDC, hr : HRGN, hbr : HBRUSH) : BOOL,

GetDeviceCaps (hd : HDC, nIndex : INTEGER) : INTEGER,

GetNearestColor (hd : HDC, crColor : COLORREF) : COLORREF,

GetStockObject (fnObject : INTEGER) : HGDIOBJ,

GetTextExtentExPointW (hd : HDC, lpszStr : LPCTSTR, cchString : INTEGER, nMaxExtent : INTEGER, lpnFit : LPINT, alpDx : LPINT, INOUT lps : LPSIZE) : BOOL,

GetTextExtentPointA (hd : HDC, lpString : LPCTSTR, cbString : INTEGER, INOUT lps : LPSIZE) : BOOL,

GetTextExtentPointW (hd : HDC, lpString : LPCTSTR, cbString : INTEGER, INOUT lps : LPSIZE) : BOOL,

GetTextMetricsA (hdc : HDC, INOUT lptm : LPTEXTMETRIC) : BOOL,

GetWorldTransform (hdc : HDC, INOUT lpXform : LPXFORM) : BOOL,

LineTo (hd : HDC, nXEnd : INTEGER, nYEnd : INTEGER) : BOOL,

ModifyWorldTransform (hdc : HDC, lpXform : LPXFORM, iMode : DWORD) : BOOL,

MoveToEx (hd : HDC, X : INTEGER, Y : INTEGER, INOUT lpp : LPPOINT) : BOOL,

PatBlt (hd : HDC, nXLeft : INTEGER, nYLeft : INTEGER, nWidth : INTEGER, nHeight : INTEGER, dwRop : DWORD) : BOOL,

Pie (hd : HDC, nLeftRect : INTEGER, nTopRect : INTEGER, nRightRect : INTEGER, nBottomRect : INTEGER, nXRadial1 : INTEGER, nYRadial1 : INTEGER, nXRadial2 : INTEGER, nYRadial2 : INTEGER) : BOOL,

PolyBezier (hd : HDC, lppt : POINTS, cPoints : DWORD) : BOOL,

Polygon (hd : HDC, lpp : LPPOINT, nCount : INTEGER) : BOOL,

Polyline (hdc : HDC, lppt : LPPOINT, cPoints : INTEGER) : BOOL,

RealizePalette (hd : HDC) : UINT,

Rectangle (hd : HDC, nLeftRect : INTEGER, nTopRect : INTEGER, nRightRect : INTEGER, nBottomRect : INTEGER) : BOOL,

RoundRect (hd : HDC, nLeftRect : INTEGER, nTopRect : INTEGER, nRightRect : INTEGER, nBottomRect : INTEGER, nWidth : INTEGER, nHeight : INTEGER) : BOOL,

SelectObject (hd : HDC, hg : HGDIOBJ) : HGDIOBJ,

SelectPalette (hd : HDC, hpal : HPALETTE, bForceBackground : BOOL) : HPALETTE,

SetBkColor (hd : HDC, crColor : COLORREF) : COLORREF,

SetBkMode (hd : HDC, iBkMode : INTEGER) : INTEGER,

SetDIBitsToDevice (hd : HDC, XDest : INTEGER, YDest : INTEGER, dwWidth : DWORD, dwHeight : DWORD, XSrc : INTEGER, YSrc : INTEGER, uStartScan : UINT, cScanLines : UINT, lpvBits : BYTE-SEQUENCE, lpbmi : LPBITMAPINFO, fuColorUse : UINT) : INTEGER,

SetMapMode (hd : HDC, fnMapMode : INTEGER) : INTEGER,

SetPixel (hd : HDC, X : INTEGER, Y : INTEGER, crColor : COLORREF) : COLORREF,

SetROP2 (hd : HDC, fnDrawMode : INTEGER) : INTEGER,

SetTextAlign (hd : HDC, fMode : UINT) : UINT,

SetTextColor (hd : HDC, crColor : COLORREF) : COLORREF,

SetViewportOrgEx (hd : HDC, X : INTEGER, Y : INTEGER, INOUT lpp : LPPOINT) : BOOL,

SetViewportExtEx (hd : HDC, nXExtent : INTEGER, nYExtent : INTEGER, INOUT lps : LPSIZE) : BOOL,

SetWindowExtEx (hd : HDC, nXExtent : INTEGER, nYExtent : INTEGER, INOUT lps : LPSIZE) : BOOL,

SetWorldTransform (hdc : HDC, lpXform : LPXFORM) : BOOL,

TextOutA (hdc : HDC, nXStart : INTEGER, nYStart : INTEGER, lpString : LPCTSTR, cbString : INTEGER) : BOOL,

ShellAboutA (hWnd : HWND, szApp : LPCTSTR, szOtherStuff : LPCTSTR, hIcon : HICON) : INTEGER

END;

TYPE Factory = OBJECT OPTIONAL

SUPERTYPES ilu.CORBA-Object END TYPEID "IDL:Hd/Factory:1.0"

METHODS

CreateRemWin () : RemWin

END;

-----------------------

Redirector

APIFunc (args)

RemoteAPIFuncStub (args)

API Function Server

RemoteAPIFuncImpl (args)

APIFunc (args)

Terminal Server

Event Dispatcher

Application



Generic Handler

HWND CALLBACK

… …

CALLBACK1

CALLBACK2

CALLBACK3

Event (hWnd, Msg, wParam, lParam)

Sends the event to the Dispatcher via RPC

Calls the appropriate function after looking up the callback function table

API Function Server

Event Handler

Terminal Server

Terminal

Redirects USER and GDI calls

Sends events back

Requests for application to be run

Redirector

Event Dispatcher

Interceptor

USER and GDI calls

Dispatches events

Application

Starts up the application

Starter

Host

Web Browser

Terminal Server

Web Server

Starter

Name Server

Interceptor

Application

Retrieves document containing embedded application

Publishes and reads interfaces

Publishes interface

Requests application

Reads interface

[pic]

[pic]

F1 F2

F1

F1 travels to server

Server replies

Sever processes F1

F2

X Server

Application

Events

Requests

Screen

Keyboard

Mouse

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download