ID: Q104009
- Windows NT, versions 3.10, 3.50, 3.51, 4.0 - Windows 95, version 4.0
Neither Windows NT nor Windows 95 allow direct mixing of 16-bit code and 32- bit code in the same process. Both platforms support IPC mechanisms, such as DDE, RPC, OLE, named pipes, and WM_COPYDATA, which you can use for communication between 16-bit code and 32-bit code. However, there are occasions when it is necessary to call a function in a Win32-based DLL (including functions in the system DLLs) from a 16-bit application under WOW.
Under Windows NT and Windows 95, it is possible to call routines in a Win32 dynamic-link library (DLL) from a 16-bit Windows application using an interface called Generic Thunking. This is not to be confused with the Win32s Universal Thunks interface, which provides the same functionality under Windows 3.1.
Also, Generic Thunks is not to be confused with the Windows 95 Flat Thunks interface, which provides the same functionality under Windows 95. For more information on the different types of thunking interfaces on each Win32 platform, please refer to the following Microsoft Knowledge Base article:
ARTICLE-ID: Q125710
TITLE : PRB: Types of Thunking Available in Win32 Platforms
The Generic Thunking interface consists of functions that allow a 16-bit
application to load the Win32 DLL, get the address of an exported DLL
routine, call the routine (passing it up to thirty-two 32-bit arguments),
convert 16:16 (WOW) addresses to 0:32 addresses (useful if you need to
build up a 32-bit structure that contains pointers and pass a pointer to
it), call back into the 16-bit application from the Win32 DLL, and free the
Win32 DLL.
Generic Thunks are documented in the Win32 SDK documentation, under "Programming and Tools Guides/Programming Techniques."
NOTE: It is a good idea to test the Win32 DLL by calling it from a Win32- based application before attempting to call it from a 16-bit Windows-based application, because the debugging support is superior in the 32-bit environment.
The basic steps for calling a function through generic thunking are:
The problem with CallProc32W() is that you cannot create a prototype for it unless you restrict each file so that it only uses calls to functions that contain the same number of parameters. This is a limitation of the Pascal calling convention. Windows NT 3.5 and later supports CallProcEx32W(), which uses the C calling convention to support variable arguments. However, under Windows 95 there are certain caveats in using the CallProc32W() and CallProcEx32W() functions. For more information, see the documentation for these functions.
The following code fragments can be used as a basis for Generic Thunks.
Assume that the 16-bit Windows-based application is named app16, the Win32 DLL is named dll32, and the following are declared:
typedef void (FAR PASCAL *MYPROC)(LPSTR, HANDLE);
DWORD ghLib;
MYPROC hProc;
char FAR *TestString = "Hello there";
The DLL routine is defined in dll32.c as follows:
void WINAPI MyPrint( LPTSTR lpString, HANDLE hWnd )
{
...
}
Attempt to load the library in the app16 WinMain():
if( NULL == (ghLib = LoadLibraryEx32W( "dll32.dll", NULL, 0 )) ) {
MessageBox( NULL, "Cannot load DLL32", "App16", MB_OK );
return 0;
}
Attempt to get the address of MyPrint():
if( NULL == (hProc = (MYPROC)GetProcAddress32W( ghLib, "MyPrint" ))) {
MessageBox( hWnd, "Cannot call DLL function", "App16", MB_OK );
...
}
Although some of the Generic Thunking functions are called in 16-bit code,
they need to be provided with 32-bit handles, and they return 32-bit
handles. Therefore, before calling CallProcEx32W() and passing it a handle,
you must convert the window handle, hWnd, to a 32-bit window handle,
hWnd32:
hWnd32 = WOWHandle32( hWnd, WOW_TYPE_HWND );
Call MyPrint() and pass it TestString and hWnd32 as arguments:
CallProcEx32W( 2, 2, hProc, (DWORD) TestString, (DWORD) hWnd32 );
Alternatively, you can use CallProc32W() as follows:
CallProc32W( (DWORD) TestString, (DWORD) hWnd32, hProc, 2, 2 );
A mask of 2 (0x10) is given because we want to pass TestString by reference
(WOW translates the pointer) and we want to pass the handle by value.
Free the library right before exiting WinMain():
FreeLibrary32W( ghLib );
NOTE: When linking the Windows-based application, you need to put the
following statements in the .DEF file, indicating that the functions will
be imported from the WOW kernel:
IMPORTS
kernel.LoadLibraryEx32W
kernel.FreeLibrary32W
kernel.GetProcAddress32W
kernel.GetVDMPointer32W
kernel.CallProcEx32W
kernel.CallProc32W
The complete sample is available for download from the Microsoft
Software Library:
~ GThunks.exe (size: 18926 bytes)
For more information about downloading files from the Microsoft Software
Library, please see the following article in the Microsoft Knowledge Base:
ARTICLE-ID: Q119591
TITLE : How to Obtain Microsoft Support Files from Online Services
On MIPS systems, an alignment fault will occur when a Win32-based application de-references a pointer to unaligned data that was passed by a 16- bit Windows application. As a workaround, declare the parameter with the UNALIGNED keyword. For example,
void func( DWORD *var );
becomes
void func( DWORD unaligned *var);
An application can use SetErrorMode() to specify SEM_NOALIGMENTFAULTEXCEPT
flag. If this is done, the system will automatically fix up alignment
faults and make them invisible to the application.
The default value of this error mode is OFF for MIPS, and ON for ALPHA. So on MIPS platforms, an application MUST call SetErrorMode() and specify SEM_NOALIGMENTFAULTEXCEPT if it wants the system to automatically fix alignment faults. This call does not have to be made on ALPHA platforms. This flag has no effect on x86 systems. Note that the fix above is preferable.
Additional reference words: kbKernBase kbThunks kbSDKWin32 kbDSupport
Keywords : kbcode kbfile kbsample
Version : 4.00 | 3.10 3.50 3.51 4.00
Platform : NT WINDOWS
Issue type : kbhowto
Last Reviewed: June 24, 1998