Running Nonnative Applications in Windows 2000 Professional

OS/2 16-bit character-based applications run directly on Windows 2000 without modification. Windows 2000 recognizes an OS/2-based application from information in the header of the executable file. It then calls the OS/2 subsystem to load the application.

File Systems Supported

The OS/2 subsystem supports long file names and extended attributes, but not the High Performance File System (HPFS). The subsystem does not use or expose recoverability and C2 security functions.

Starting an Application

You can start a character-based or VIO application from the system command prompt, from My Computer , from Windows Explorer, or from within a Win32-based or OS/2-based application. You can create a single batch file that can start any combination of MS-DOS, Windows, or OS/2 programs.

If you never run an OS/2-based application, the subsystem uses no Windows 2000 resources. The Os2srv process is loaded when you run an application for the first time and remains loaded after you quit the application.

Thunking

The thunking mechanism in the OS/2 subsystem allows the 16-bit OS/2 and Presentation Manager applications to load and call any Win32 DLL. Thunking code translates 16-bit calls to 32-bit, so they can be received by the 32-bit processor, and translates the responses back into 16-bit code so the application can process them.

You might want to use the thunking mechanism to:

  • Call from your OS/2-based application to some functionality that is available under Windows 2000 only as Win32 code.

  • Split an application available under Windows 2000 only as Win32 code into applications based on OS/2 and Win32, then communicate between them using named pipes. This method, however, is more complicated and can slow performance.

  • Port your OS/2-based application from the OS/2 subsystem to Win32 in stages, starting with only part of the application.

To use the thunking feature in the OS/2 subsystem

  1. Write a small header file (.h file, as shown in Figure B.5) to act as a thunking layer. The file defines the Win32 APIs that the application calls. This file contains six 16-bit APIs:
    Dos32LoadModule
    Dos32GetProcAddr
    Dos32Dispatch
    Dos32FreeModule
    FarPtr2FlatPtr
    FlatPtr2FarPtr

  2. Write a .def file for your 16-bit application, containing calls to the six 16-bit APIs, as follows:

IMPORTS

DOSCALLS.DOS32LOADMODULE

DOSCALLS.DOS32GETPROCADDR

DOSCALLS.DOS32DISPATCH

DOSCALLS.DOS32FREEMODULE

DOSCALLS.FARPTR2FLATPTR

DOSCALLS.FLATPTR2FARPTR

extern USHORT pascal far

Dos32GetProcAddr(ULONG DllHandle, PSZ pszProcName, PULONG pWin32Thunk);

extern USHORT pascal far

Dos32Dispatch(ULONG Win32Thunk, PVOID pArguments, PULONG pRetCode);

extern USHORT pascal far

Dos32FreeModule(ULONG DllHandle);

extern USHORT pascal far

FarPtr2FlatPtr(ULONG FarPtr, PULONG pFlatPtr);

extern USHORT pascal far

FlatPtr2FarPtr(ULONG FlatPtr, PULONG pFarPtr);

Figure B.5 Thunking Layer (.h file) to be Linked with 16-Bit OS/2-based Application

The thunking layer actually calls the Win32 APIs, using parameters passed in the 16-bit APIs. This relay is necessary because the OS/2 subsystem has only one generic pointer parameter, EXTERN, and the Win32 APIs need more or different parameters. The thunking layer uses the EXTERN parameter to point to an application-defined data structure containing the parameters for the calls to the Win32 APIs.

The .def file imports the six APIs into the Doscalls.dll file on the OS/2 subsystem. They remain there while the application runs.

Parameters Passed by the 16-Bit APIs

The OS/2-based application code uses the six 16-bit APIs to pass parameters. The application defines the parameters, shown in bold here, as it makes the call. The variable pascal stands for a Pascal-style call; far , for a callout of the local process space; p , for a pointer; and psz , for a pointer to a null-terminated string. The six APIs, defined in the same manner as on native OS/2, are described as follows:

Dos32LoadModule

This API loads a Win32 thunking .dll file, an intermediate between the application and the Win32 APIs to be called. Its format is:

USHORT pascal far Dos32LoadModule

(PSZ DllName ,

PULONG p DllHandle );

Parameters     DllName is the name of a Win32 API that the application calls. DllHandle is the name given to the .dll file that is opened to include this Win32 API. For example, if the application calls WinSocket mysock , the file name is Mysock.dll.

Returns    If NO_ERROR is returned, the value of DllHandle is used in other Win32 thunking APIs as described later in this section. DllHandle is invalid for use with regular OS/2 APIs. If ERROR_MOD_NOT_FOUND is returned, DllHandle is undefined.

Dos32GetProcAddr

This API points a cookie (flat pointer) to a routine in the .dll file previously opened by Dos32LoadModule . Its format is:

USHORT pascal far Dos32GetProcAddr

(ULONG DllHandle ,

PSZ psz ProcName ,

PULONG p Win32Thunk );

Parameters     DllHandle has the value given by **Dos32LoadModule . ProcName is the name given to the exported 16-bit API that corresponds to the called Win32 API. The name is created by prefixing My. For example, if WinSocket example API is called, the exported API is MyWinSocket example API . Win32Thunk is the name of a 32-bit thunking API created to call ProcName.

Returns    If NO_ERROR is returned, Win32Thunk is used later in Dos32Dispatch . If ERROR_PROC_NOT_FOUND or ERROR_INVALID_HANDLE is returned, Win32Thunk is undefined.

Dos32Dispatch

This API calls the 32-bit thunking API Win32Thunk , previously loaded by Dos32GetProcAddr . Its format is:

USHORT pascal far Dos32Dispatch

(ULONG Win32Thunk ,

PVOID p Arguments ,

PULONG p RetCode );

Parameters     Win32Thunk calls the ProcName API, which in turn calls the DllName API. Arguments is the value of the 16:16 pointer, which is translated to a flat pointer and passed to the Win32Thunk call. RetCode is the error code returned by Win32Thunk . The structure pointed to by pArguments , and the values of pRetCode , are application specific and are not interpreted or modified by the OS/2 subsystem.

The Win32 thunking API is defined in DllHandle as follows:

ULONG ProcName

(PVOID p FlatArg );

FlatArg is the value of the flat argument as returned from ProcName ; the application defines it, and the OS/2 subsystem copies it to pRetCode .

Returns    If NO_ERROR is returned, pFlatArg is a valid pointer and no exception occurred in the call to it.

Dos32FreeModule

This API unloads the intermediate Win32 thunking .dll file represented by DllHandle . Its format is:

USHORT pascal far Dos32FreeModule(ULONG DllHandle );

Parameter     DllHandle is the value of the Win32 .dll file loaded by Dos32LoadModule.

Returns    If NO_ERROR is returned, DllHandle indeed corresponds to the Win32 .dll file loaded by Dos32LoadModule (after the call, DllHandle is no longer valid). Otherwise, ERROR_INVALID_HANDLE is returned.

FarPtr2FlatPtr

This API translates the segmented 16-bit pointer to a flat 32-bit pointer. Its format is:

USHORT pascal far FarPtr2FlatPtr

(ULONG FarPtr ,

PULONG p FlatPtr );

Parameters     FarPtr is the value of the 16:16 segmented pointer. FlatPtr is the flat pointer to which FarPtr is translated.

Returns    If NO_ERROR is returned, FarPtr is valid and FlatPtr is a valid 32-bit flat pointer to be used by Win32 code. ERROR_INVALID_PARAMETER is returned if FarPtr is not valid, or if FlatPtr is undefined.

FlatPtr2FarPtr

This API translates the 32-bit flat pointer FlatPtr to a segmented 16:16 pointer, which it stores in pFarPtr . Its format is:

USHORT pascal far FlatPtr2FarPtr

(ULONG FlatPtr ,

PULONG p FarPtr );

Parameters     FlatPtr is the value of the flat pointer. FarPtr is the segmented pointer to which FlatPtr is translated.

Returns    If NO_ERROR is returned, FlatPtr maps to a valid 16:16 pointer in the context of the 16-bit application, and FarPtr is a valid 16:16 segmented pointer to be used by the 16-bit OS/2 code. If the 16:16 pointer is not a valid address in the context of the 16-bit application, ERROR_INVALID _PARAMETER is returned and FarPtr is undefined.