Board index » delphi » Using THUNK to call a 32-bit DLL from a 16-bit application

Using THUNK to call a 32-bit DLL from a 16-bit application

Hello,
    I need to call functions in a 32-bit DLL I am building with Borland
C++ 5.01, but they need to be called from a 16-bit application in
Windows XP.  The DLL has to be 32-bit because it includes a 32-bit
library that I can't change.  I've heard that it is possible to call a
32-bit DLL from a 16-bit application by using something called a
"thunk". So far I found a program called thunk.exe in my \BC5\SDKTOOLS
directory and two "universal thunking" libraries called "w32sut32.lib"
and "w32sut16.lib" in my \BC5\LIB directory.

Does anyone know a good source that describes how to use this thunk
concept to call a 32-bit DLL from a 16-bit application?  Or is it just a
simple process to describe.

Thank you, (I've already learned a great deal from this newsgroup)

Brent Darley

 

Re:Using THUNK to call a 32-bit DLL from a 16-bit application


On Thu, 13 Jun 2002 17:37:01 -0500, Brent Darley <notbdar...@notcharter.net>
wrote:

Quote
>I've heard that it is possible to call a
>32-bit DLL from a 16-bit application by using something called a
>"thunk". So far I found a program called thunk.exe in my \BC5\SDKTOOLS
>directory and two "universal thunking" libraries called "w32sut32.lib"
>and "w32sut16.lib" in my \BC5\LIB directory.

Universal thunks are used with Win32s, and allow a Win32 application to
load and call a 16-bit DLL. To load and call a Win32 DLL from a Win16
application requires the use of Generic thunks.

Quote
>Does anyone know a good source that describes how to use this thunk
>concept to call a 32-bit DLL from a 16-bit application?  

MSDN is probably the best source, *if* they still maintain such legacy
information. Since Win16 was abandoned by MS years ago, it may be
more difficult to come by this info now. I have some old (1993) code from
Walter Oney which was in MSJ.

Try these links:

http://msdn.microsoft.com/library/en-us/winprog/winprog/about_generic...
http://msdn.microsoft.com/library/en-us/winprog/winprog/using_generic...
http://msdn.microsoft.com/library/en-us/winprog/winprog/testing_your_...

Also go to http://www.microsoft.com/msj/  and search for "thunks".

Quote
>is it just a simple process to describe.

Hardly. It's not for the squeamish. Since you're new to Windows programming
it might be quite a challenge to get it right.

--
Wayne A. King
(ba...@torfree.net, wayne.k...@ablelink.org,
 wak...@idirect.com, Wayne_A_K...@compuserve.com)

Re:Using THUNK to call a 32-bit DLL from a 16-bit application


Hi,

I had the same problem in the past. Here my solution.

Regards,
Gnter Wirth

<<<<<<<<<Header>>>>>>>>>>
#if !defined(__EXGT32_H)
#define __EXGT32_H

//$HB$----------------------------------------------------------------------
----
//  DATEI: EXGT32.H
//  AUTOR: G. Wirth
//$HE$----------------------------------------------------------------------
----

#if !defined(__EXMAIDLL_H)
#  include <exmaidll.h> // include some header files and defines
#endif
#pragma hdrstop

// To use in a DLL, define  EXGT32DLL
//#if defined(_EXGT32DLL)
//  #define __EXGT32__  __export _OWLFASTTHIS
//  #define _EXGT32DATA __export
//  #define _EXGT32FUNC __export
//#else
//  #define __EXGT32__  __import
//  #define _EXGT32FUNC
//  #define _EXGT32DATA
//#endif

#if !defined(__WIN32__)

// Generelle Einstellungen und Compileroptionen um Klassen zu definieren
// Wird vor Klassen/Strukturen und nach Includes eingefgt
// $BEGIN$
#include <preclass.h>

DECLARE_HANDLE32 (HPROC32);
DECLARE_HANDLE32 (HINSTANCE32);

// Klasse ExGenericThunk
// ~~~~~~ ~~~~~~~~~~~~~~
//
// Zugriff auf 32-Bit-Funktionen unter Windows 3.X
//
class __EXGT32__ ExGenericThunk {
public:

   ~ExGenericThunk ();

   bool IsOK () const { return mInst32 != 0; }

protected:

   ExGenericThunk(const char * fileName);

   ExGenericThunk(const ExGenericThunk& thunk);
   ExGenericThunk& operator=(const ExGenericThunk& thunk);

   DWORD __cdecl CallProc32    (HPROC32, DWORD fAddrCvt, DWORD nArgs, ...);
   void          FreeVdmPtr32  (void far *);
   HPROC32       GetProcAddr32 (const char * procName);
   DWORD         GetVdmPtr16   (void far *buffer, unsigned cbSize);
   void far *    GetVdmPtr32   (DWORD dwAddr32, DWORD cbSize);
   HINSTANCE32   GetInstance   () const { return mInst32; }

private:

   HINSTANCE32     mInst32;
   char*           lpszFile;

   static HINSTANCE32 (WINAPI *LoadLibraryEx32W) (LPCSTR, DWORD, DWORD);
   static BOOL        (WINAPI *FreeLibrary32W)   (HINSTANCE32);
   static HPROC32     (WINAPI *GetProcAddress32W)(HINSTANCE32, LPCSTR);
   static DWORD       (WINAPI *GetVDMPointer32W) (LPVOID, UINT);
   static DWORD       (WINAPI *CallProc32W)      (HPROC32, DWORD, DWORD);

   void Init(const char* fileName);

Quote
};

// Generelle Einstellungen und Compileroptionen um Klassen zu definieren
// Wird nach Klassen/Strukturen eingefgt
#include <posclass.h>
// $END$

#endif  // __WIN32__

#endif  // __EXGT32_H

/* EOF */

<<<<<<<<<<< Code >>>>>>>>>>>>

/*
  DATEI:        exgt32.cpp
  AUTOR:        G. Wirth
*/

#include <exmaidll.h>
#pragma hdrstop

#ifndef __WIN32__  // only for 16-bit platform

#include <stdarg.h>
#include <exgt32.h>

HINSTANCE32 (WINAPI *ExGenericThunk::LoadLibraryEx32W) (LPCSTR, DWORD,
DWORD);
BOOL        (WINAPI *ExGenericThunk::FreeLibrary32W)   (HINSTANCE32);
HPROC32     (WINAPI *ExGenericThunk::GetProcAddress32W)(HINSTANCE32,
LPCSTR);
DWORD       (WINAPI *ExGenericThunk::GetVDMPointer32W) (LPVOID, UINT);
DWORD       (WINAPI *ExGenericThunk::CallProc32W)      (HPROC32, DWORD,
DWORD);

void ExGenericThunk::Init(const char* fileName)
{
  if( fileName ) {

     //  Initialize our static members if they're not already:
     //
     if (! LoadLibraryEx32W)
     {
       HMODULE hKernel = GetModuleHandle ("KERNEL");

       (FARPROC) LoadLibraryEx32W  = GetProcAddress (hKernel,
"LoadLibraryEx32W");
       (FARPROC) FreeLibrary32W    = GetProcAddress (hKernel,
"FreeLibrary32W");
       (FARPROC) GetProcAddress32W = GetProcAddress (hKernel,
"GetProcAddress32W");
       (FARPROC) GetVDMPointer32W  = GetProcAddress (hKernel,
"GetVDMPointer32W");
       (FARPROC) CallProc32W       = GetProcAddress (hKernel,
"CallProc32W");

       //  All or nothing:
       if (! LoadLibraryEx32W || ! FreeLibrary32W || ! GetProcAddress32W ||
           ! GetVDMPointer32W || ! CallProc32W)
       {
         LoadLibraryEx32W    = 0;
         FreeLibrary32W      = 0;
         GetProcAddress32W   = 0;
         GetVDMPointer32W    = 0;
         CallProc32W         = 0;
       }
     }

     mInst32 = 0;
     lpszFile = strnewdup(fileName);

     if (LoadLibraryEx32W)
       mInst32 = LoadLibraryEx32W (fileName, 0, 0);
    }

Quote
}

ExGenericThunk::ExGenericThunk (const char * fileName) :
   mInst32(NULL), lpszFile(NULL)
{
 Init(fileName);

Quote
}

ExGenericThunk::ExGenericThunk(const ExGenericThunk& thunk) :
   mInst32(NULL), lpszFile(NULL)
{
 *this = thunk;

Quote
}

ExGenericThunk::~ExGenericThunk ()
{
  if( mInst32 ) {
    FreeLibrary32W (mInst32);
    mInst32 = 0;
  }

  delete [] lpszFile;

Quote
}

ExGenericThunk& ExGenericThunk::operator=(const ExGenericThunk& thunk)
{
 if( this != &thunk ) {
    Init(thunk.lpszFile);
   }

 return *this;

Quote
}

HPROC32 ExGenericThunk::GetProcAddr32 (const char * procName) {
  return mInst32 ? GetProcAddress32W (mInst32, procName)
                 : NULL;

Quote
}

//--------------------------------------------------------------------------
----
//  This method makes the call to the 32-bit function referenced by hProc.
//  The fAddrCvt flags are the trickiest part, while nArgs is simply the
//  number of DWORD arguments to pass.  Each bit of fAddrCvt maps to one of
//  the arguments.  The lowest bit represents the last parameter, the 2nd
//  lowest bit represents the 2nd-to-last parameter, etc..  If the bit is
//  set (ie, a 1), that parameters is treated as a 16:16 far pointer.  The
//  32-bit side will receive a 32-bit pointer to that buffer.  If the bit
//  is not set, the 32-bit side will receive the 32-bit value unchanged.
//--------------------------------------------------------------------------
----
DWORD __cdecl ExGenericThunk::CallProc32 (HPROC32 hProc, DWORD fAddrCvt,
                                                        DWORD nArgs, ...)
{
  va_list     args;
  DWORD       dwTemp;

  if (! CallProc32W || ! hProc)
    return 0;

  va_start (args, nArgs);

  //  Copy the arguments from our stack frame to the stack frame that
  //  CallProc32W expects:
  //
  for (DWORD n = nArgs; n; ) {
    dwTemp = va_arg (args, DWORD);
    -- n;

    __asm push word ptr [dwTemp+2];
    __asm push word ptr [dwTemp];
  }

  va_end (args);

  //  Call CallProc32W.  The pushed variable list precedes the parameters,
  //  as assumed by CallProc32W.  Appropriate parameters will be popped by
  //  CallProc32W based on the value of nArgs:
  //
  return CallProc32W (hProc, fAddrCvt, nArgs);

Quote
}

//--------------------------------------------------------------------------
----
//  This method returns the 32-bit address for the specified 16:16 address
//  and size.
//--------------------------------------------------------------------------
----
DWORD ExGenericThunk::GetVdmPtr16 (void far *buffer, unsigned cbSize)
{
  return GetVDMPointer32W ? GetVDMPointer32W (buffer, cbSize)
                          : 0;

Quote
}

//--------------------------------------------------------------------------
----
//  This method will allocate a 16:16 pointer that points at the specified
//  32-bit memory address range.  This pointer must be released by calling
//  FreeVdmPtr32.
//--------------------------------------------------------------------------
----
void far * ExGenericThunk::GetVdmPtr32 (DWORD dwAddr32, DWORD cbSize)
{
  UINT  uSelector = ::AllocSelector (_DS); // our DS (for access rights)

  if (uSelector) {
    // Assign its linear base address and limit
    ::SetSelectorBase  (uSelector, dwAddr32);
    ::SetSelectorLimit (uSelector, cbSize);
  }

  return MAKELP (uSelector, 0);

Quote
}

//--------------------------------------------------------------------------
----
//  This method will free the selector allocated by GetVdmPtr32.
//--------------------------------------------------------------------------
----
void ExGenericThunk::FreeVdmPtr32 (void far *ptr)
{
  if (SELECTOROF (ptr))
    ::FreeSelector (SELECTOROF (ptr));

Quote
}

#endif  // __WIN32__

/* EOF */

<<<<< How to use >>>>>>

class TFileThunk : public ExGenericThunk {
public:
   TFileThunk();
   uint32 GetShortPathName(const char* lpszLongPath, char* lpszShortPath,
uint32 cchBuffer);

private:
    HPROC32 m_hGetVer;

Quote
};

TFileThunk::TFileThunk () :
   ExGenericThunk ("KERNEL32") { // name of the DLL
 m_hGetVer = GetProcAddr32 ("GetShortPathNameA"); // name of the function

Quote
}

uint32 TFileThunk::GetShortPathName(const char* lpszLongPath, char*
lpszShortPath, uint32 cchBuffer) {
 return CallProc32(m_hGetVer, 0x06, 3, lpszLongPath, lpszShortPath,
cchBuffer);

Quote
}

uint32 GetShortPathName(const char* lpszLongPath, char* lpszShortPath,
uint32 cchBuffer) {
 return TFileThunk().GetShortPathName(lpszLongPath, lpszShortPath,
cchBuffer);
Quote
}

Other Threads