Preliminary Thunk Debugging Checklist

After you have verified that each side works correctly, the next step is to put the two sides together to test the thunk itself. However, before you compile the thunk using the thunk compiler, use the following checklist to verify that you created the thunks correctly:

  1. In your thunk script, make sure each function has the correct number and types of parameters. Also make sure that the thunk compiler supports the parameter types. If it does not, you will have to pass the data using a supported type.
  2. If you pass any structures as parameters, make sure you use the same structure packing in your Win32-based DLL, 16-bit DLL, and thunk script. You set structure packing in your C/C++ compiler's command line, and in the thunk compiler command line. Note that the thunk compiler's packing switch is lowercase for the 16-bit side, and uppercase for the 32-bit side.
  3. Make sure the functions you are thunking to are exported correctly, and use the PASCAL calling convention if they are 16-bit functions. Use WINAPI if they are 32-bit functions. The thunk compiler does not support the _cdecl and __fastcall calling conventions.
  4. Make sure your Win32-based DLL calls XXX_ThunkConnect32 each time its DllMain function is called. Likewise, make sure the 16-bit DLL has an exported DllMain function, separate from its LibMain function, that calls XXX_ThunkConnect16 and returns TRUE if ThunkConnect16 succeeds.
  5. Make sure that the value specified in the thunk compiler's -t option is the same for both thunk DLLs. The value must also correspond to the prefix of the ThunkConnect calls in your 16-bit and Win32-based DLLs.
  6. Verify that the 16-bit DLL has DLLEntryPoint and XXX_ThunkData16 exported with the RESIDENTNAME keyword in its module definition (.DEF) file. Without the RESIDENTNAME keyword, the XXX_ThunkConnect32 or XXX_ThunkConnect16 call fails and the DLLs are not loaded.
  7. Verify in your 16-bit DLL's makefile that the resource compiler is marking the DLL as version 4.0. If the DLL is marked with a version number earlier than 4.0, it will not load and the thunk will fail.
  8. If your 32-bit to 16-bit thunk function returns a pointer, make sure the base type is the same size on both the 16-bit and 32-bit sides of the thunk. If the size of the base type is different, the thunk compiler issues an error message stating, "Cannot return pointers to non-identical types." One way to work around this problem is to return a pointer to a different, but compatible, data type. For example, a thunk cannot return a pointer to an integer because an integer is 2 bytes on the 16-bit side, but 4 bytes on the 32-bit side. In the thunk script and the source code, change the return type from a pointer to an integer to a pointer to a long.

    If you write a 16-bit to 32-bit thunk that returns a pointer, the thunk compiler issues an error message stating, "Pointer types may not be returned." The thunk compiler does not allow 16-bit to 32-bit thunks to return pointer types because after the thunk returns from the 32-bit function, the pointer does not point to data in the correct Win32-based process address space. This is because all Win32-based processes use the same range of addresses and are preemptively context-switched.

  9. If the linker reports an "unresolved external" error, first check to make sure the symbol is a function name that is spelled consistently throughout all source code, module definition files, and the thunk script. Next, make sure all occurrences of its prototype are consistent. On the 32-bit side, declare the thunk function with WINAPI; on the 16-bit side, declare the function with the PASCAL type. With C++ projects, be sure to declare and define both sides of the thunk function with the extern "C" linkage specifier, in addition to the WINAPI or PASCAL type.