Generic Thunks: Calling a Win32 DLL from a Win16 ApplicationLast reviewed: December 17, 1996Article ID: Q104009 |
The information in this article applies to:
SUMMARYNeither 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 interface on each Win32 platform, please refer to the following Microsoft Knowledge Base article:
ARTICLE-ID: Q125710 TITLE : Types of Thunking Available in Win32 PlatformsThe 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.
MORE INFORMATIONThe 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.
Sample CodeThe 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.CallProc32WThe complete sample can be obtained by downloading GTHUNKS.EXE, a self- extracting file, on these services:
ARTICLE-ID: Q119591 TITLE : How to Obtain Microsoft Support Files from Online Services FaultsOn 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: 3.10 3.50 3.51 4.00 softlib GTHUNKS.EXE
© 1998 Microsoft Corporation. All rights reserved. Terms of Use. |