Solved

Calling a 16 bit DLL from Win32

Posted on 1998-01-13
21
512 Views
Last Modified: 2013-12-03
I need to call a 16 bit DLL from a Win32 DLL.  To my knowledge, I can't use any of Microsoft's thunk mechanisms, because they either work in the wrong direction or they don't work under Windows NT.  I suppose I could write a 16 bit application wrapper for the DLL, and have my Win32 app communicate with said wrapper, but I'd like to avoid the mess involved there.  Can anyone offer a better (cleaner) suggestion?  It would seem that I want something that works like a generic thunk, but in the opposite direction.
0
Comment
Question by:fwilkinson
  • 9
  • 4
  • 3
  • +4
21 Comments
 
LVL 11

Expert Comment

by:alexo
ID: 1410049
I'm not sure that it is possible to load a Win16 DLL in a Win32 application under NT.

That is because NT executes 16bit code in a special subsystem.

You could limit yourself to Win95/98 and use flat thunks.

0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410050
The idea is that NT should load the 16 bit DLL in a VDM, and make calls to it from the Win32 subsystem.

I cannot (and would not even if I could) limit my program to run on Windows 95 only.  I would sooner take the trouble to write a wrapper application than limit my Windows app to running on an inferior version of Windows.


0
 
LVL 11

Expert Comment

by:alexo
ID: 1410051
"The idea is that NT should load the 16 bit DLL in a VDM, and make calls to it from the Win32 subsystem." -- Don't think it's possible.  Write an app wrapper.

Speaking of "inferior version of Windows",Why do you use a Win16 DLL?

0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410052
I use a Win16 DLL because it's the only consistent way I know of to access NetWare API functions with all the currently available NetWare clients for Windows.  If Microsoft supported their software properly, perhaps this wouldn't be an issue.  (Speaking of which, the details of this are better suited to a different forum.)


0
 
LVL 11

Expert Comment

by:alexo
ID: 1410053
Hmmm... as far as I know, (1) Netware has free downloadable 32bit clients for Win95, and (2) Win95 and NT have built-in 32bit Netware clients.

I suggest you either wrap your 16bit DLL or use either a full 32bit or a full 16bit solution.

0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410054
Yes, Novell provies their clients free of charge, but I'm not going to try to force my customers (and their customers) to install said clients.  It just won't work.  Be happy you don't have to write NetWare client code that must run everywhere automatically.

:)

0
 
LVL 5

Expert Comment

by:inter
ID: 1410055
You can do it by FLAT THUNKING

Flat thunking is found only in Windows 95 operating system. It is a method by wich 16 and 32 bit codes can interact (more information can be found in www.microsoft.com\msdn-but you should register for free first )

QT_THUNK :
This is an undocumented function which is used for thunking.

In order to achieve the thunking we used 4 undocumented functions (from the
kernel) as follows :-

function LoadLibrary16(LibraryName: PChar): THandle; stdcall; external kernel32 index 35;

procedure FreeLibrary16(HInstance: THandle); stdcall; external kernel32 index 36;

function GetProcAddress16(Hinstance: THandle; ProcName: PChar): Pointer; stdcall; external kernel32 index 37;

procedure QT_Thunk; cdecl; external kernel32 name 'QT_Thunk';

you can find the example source from Delphi Super Page http://sunsite.icm.edu.pl/delphi/ with the name zthunk.zip

or if you give me your email I can send you the source.
0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410056
inter, you apparently did not read my question thoroughly.  I cannot use flat thunking, because my application must work under Windows NT.
0
 

Expert Comment

by:AlunCarp
ID: 1410057
Here is another alternative.

You say your app is going to be running on Win NT and you want access to Netware.

If this means you will be using the IPX/SPX protocol?

If so why not use Winsock, it supports IPX/SPX 'out of the box' and is installed on both Windows 95 OSR 1 & 2, and Windows NT from v3.51 and maybe earlier.

I am currently working on a Network Project which needs to support IPX/SPX as it will eventually have to run as an NLM on a Netware server, at the moment we have a complete 32Bit version which will run on WinNT 3.51,4.0 and 5.0, Win95 OSR 1 & 2 and Win98.

This was all done using Winsock 1.1 and it all works without problems.

Check out www.stardust.com for info on Winsock development and also MSDN.
0
 

Expert Comment

by:AlunCarp
ID: 1410058
An afterthought.

Flat thunking under NT is not possible. We also had a similar problem which could only be fixed with a wrapper app.

We have a hidden window for the app which we send messages to. This means we only need one copy running and not one for each app that needs to call it.
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 1

Author Comment

by:fwilkinson
ID: 1410059
Unfortunately, my requirements aren't as simple as IPX/SPX.  I have to use NetWare-specific functions, which are only available through NCP.


0
 
LVL 11

Expert Comment

by:alexo
ID: 1410060
Sigh...  Forget about 16bit DLLs.
Go to http://developer.novell.com/cgi-bin/devnet/download, subscribe to the developers network (free), download the Novell SDK and write a full 32bit product.  OK?

0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410061
"Sigh" yourself, alexko.  You apparently failed to read my comments in this thread.

I am already a member of Novell's developer program, and I already have their client SDK.  However, the libraries contained therein only work on systems that have Novell's NetWare client installed.  I cannot force the users of my program to install Novell's client.  Until Novell's SDK works with Microsoft's client as well as their own, it is not a viable solution for me.


0
 

Expert Comment

by:AlunCarp
ID: 1410062
I am sorry to say that we have also had similar misfortune at the hands of Microsoft and Novell not quite getting it together on this.

Fortunately we only need access to the protocol so problem with network clients aren't such an issue. One problem we have faced is getting a list of users from the Novell server, this so far has totally eluded us and it looks like 16bit code is the only way.

If your 16bit code works reliably on all platforms it is needed for I would recommend the wrapper .EXE for the time being using a hidden window to get messages from your caller apps, which then passes them on to the .DLL.

However you may then come into another problem with retrieving data from the 16bit application because of Win32 applications running in their own address space and copying memory from one to the other.

Under Win32 you can use Read/WriteProcessMemory to copy data from one process to another. I dont know if this is possible when one process is a Win16 app running on a Win32 OS.

Not really sure if it qualifies as an answer, but its worth a try. If I have any other ideas I'll post them here.

Just out of interest what Netware specifics are you after and what are you trying to do with them?
0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410063
Yes, the wrapper app is still my most likely solution.  For the sake of discussion, copying data between Win32 and Win16 apps is (according to the information I have) actually not so difficult.  Both platforms support the WM_COPYDATA message, though it's not defined in the Win16 windows.h file.  That's what I'll probably use.


0
 
LVL 2

Expert Comment

by:AlFa
ID: 1410064
perhaps is what you need :
Microsoft Knowledge Base
HOWTO: Call 16-bit Code from 32-bit Code on Windows 95
Last reviewed: June 10, 1997
Article ID: Q155763  

The information in this article applies to:

  - Microsoft Win32 Software Development Kit (SDK) for:
    - Microsoft Windows 95


SUMMARY
As a developer, you may need to access the functionality provided by a 16- bit dynamic-link library (DLL) from your Win32 application. This is true particularly when you do not have the source code for the DLL so that you can port it to Win32. This article discusses the mechanism by which 32-bit DLLs can call 16-bit DLLs. The mechanism is called a thunk and the method implemented under Windows 95 is called a flat thunk.

The following describes the three major steps involved in creating a flat thunk:


Create the thunk script.

Build the 32-bit DLL.

Build the 16-bit DLL.

MORE INFORMATION
A flat thunk consists of a 32-bit and a 16-bit DLL that work together. A Win32 application calls the 32-bit DLL, and the 32-bit DLL calls an exported function in the 16-bit DLL. When the function in the 16-bit DLL returns, it returns back to the 32-bit DLL, which in turn returns back to the Win32 application. The 32-bit and 16-bit DLLs work by calling the Windows 95 32-bit and 16-bit kernels to handle all of the low-level details necessary to make the transition from 32-bit to 16-bit code and back.

Designing a new flat thunk involves creating a thunk script (.thk file). This script is compiled with the Thunk compiler into an assembly- language file, which is then assembled twice; one time with each of two flags of -DIS_32 and -DIS_16. This allows you to create both the 32-bit and 16-bit object modules. These object modules are linked in the 32-bit and 16-bit DLLs, respectively. The following diagram summarizes the files involved in building the DLLs:


                         +------------+
                         | 32to16.thk |
                         +------------+
                               |
                         +------------+
                         | 32to16.asm |
                         +------------+
                           /         \
                  -DIS_32 /           \ -DIS_16
                        /              \
                  +-----------+  +-----------+
                  | 32THK.obj |  | 16THK.obj |
                  +-----------+  +-----------+
                        /                 \
        +-------+    +-------+             +-------+
        | APP32 | -> | DLL32 | -- THUNK -- | DLL16 |
        +-------+    +-------+             +-------+


Tools Needed to Build Flat Thunks
Microsoft Visual C++ version 1.5x (16-bit) compiler for the 16-bit side of creating the thunk. The 16-bit side of the thunk is a 16-bit DLL.
Microsoft Visual C++ version 2.x or higher (32-bit) compiler for creating the 32-bit side of the thunk. The 32-bit side of the thunk is a 32-bit DLL.
Thunk compiler (Thunk.exe) from the Microsoft Win32 SDK for compiling thunk scripts.
Microsoft Macro Assembler (MASM) version 6.1 or higher for assembling the assembly-language output of the thunk compiler.
16-bit Rc.exe file from the BINW16 directory of the Microsoft Win32 SDK for marking the 16-bit thunk DLL as version 4.0.

Creating the Thunk Script
You need to create a script that can be used by the Thunk compiler to create a thunk. A thunk script is a text file that contains type definitions, the function prototypes of the functions you wish to call via thunks and a specification of the direction of the parameters for each function. For example, some functions require both input and output parameters while others may only require input parameters. Thunk scripts use special syntax to describe whether parameters are input, output, or both input and output.

A thunk script for 32->16 thunks begins with the following statement:


   enablemapdirect3216 = true;

The Thunk compiler expects that the 32-bit side of the thunk is declared as __stdcall, and that the 16-bit side is __far __pascal. (The WINAPI declaration takes care of this on both sides.) The __cdecl and __fastcall calling conventions are not supported by the Thunk compiler. Note, however, that the Thunk compiler does not actually accept the __far, __pascal, or __stdcall keywords; they are assumed.
The following example shows a thunk script for a function that has no parameters:


   enablemapdirect3216 = true;

   void MyThunk16()
   {
   }

The equivalent declaration would be:

   C   language:  void WINAPI MyThunk16(void);
   C++ language:  extern "C" void WINAPI MyThunk16();

The following example script describes a function that takes two parameters and returns a value. The second parameter is an output parameter that contains a pointer that is passed back to the 32-bit DLL.

   enablemapdirect3216 = true;

   typedef int   BOOL;
   typedef char *LPSTR;

   BOOL MyThunk16(LPSTR lpstrInput, LPSTR lpstrOutput)
   {
      lpstrInput  = input;    // optional; input is default
      lpstrOutput = output;
   }

The statement "lpstrOutput = output" tells the Thunk compiler that the 16-bit function returns an address that needs to be converted from a selector:offset pointer into a 32-bit linear address.
The following thunk script uses more complex parameter types such as structures. This example also shows how to specify input and output parameters.


   enablemapdirect1632 = true;

   typedef unsigned int UINT;
   typedef char *LPSTR;

   typedef struct _POINT {
      UINT x;
      UINT y;
   }POINT, *LPPOINT;

   typedef struct _CIRCLE {
      POINT center;
      UINT  radius;
   }CIRCLE, *LPCIRCLE;

   void MyThunk32( LPCIRCLE lpCircleInOut)
   {
      lpCircleInOut = inout;
   }

The statement "lpCircleInOut = inout" tells the script compiler that this pointer is going to be used for input and output. This causes the Thunk compiler to convert lpCircleInOut from a 32-bit linear address to a selector:offset pointer when the function is called and then back to a 32-bit linear address when the function returns. The conversion is handled by the thunk created by the Thunk compiler.


Using the Thunk Compiler
The Thunk compiler usage is as follows:


   thunk.exe /options <inputfile> -o <outputfile>

The following command line shows how to compile a 32->16 thunk script. This line takes a thunk script named 32to16.thk and produces an assembly-language file named 32to16.asm.

   thunk -t thk 32to16.thk -o 32to16.asm

The "-t thk" option tells the Thunk compiler to prefix the thunk functions in the assembly-language file with "thk_." This prefix is used when linking multiple thunk scripts into a pair of DLLs, and is useful for creating a pair of DLLs that contain both 32->16 and 16->32 thunks. Each thunk script should have a unique prefix.


Building the 32-bit DLL

In the DllMain function of your 32-bit DLL, you must make a call to a function created by the Thunk compiler named thk_ThunkConnect32 for every reason (dwReason) DllMain is called, as shown here ("thk" is the prefix from the Thunk compiler -t switch):


      // prototype for function in .obj file from the thunk script
      BOOL WINAPI thk_ThunkConnect32(LPSTR     lpDll16,
                                     LPSTR     lpDll32,
                                     HINSTANCE hDllInst,
                                     DWORD     dwReason);

      BOOL WINAPI DllMain(HINSTANCE hDLLInst,
                          DWORD     dwReason,
                          LPVOID    lpvReserved)
      {
         if (!thk_ThunkConnect32("DLL16.DLL", "DLL32.DLL",
                                 hDLLInst, dwReason))
         {
            return FALSE;
         }
         switch (dwReason)
         {
            case DLL_PROCESS_ATTACH:
               break;

            case DLL_PROCESS_DETACH:
               break;

            case DLL_THREAD_ATTACH:
               break;

            case DLL_THREAD_DETACH:
               break;
         }
         return TRUE;
      }


Include the following lines in the EXPORTS section of the module definition (.def ) file for the 32-bit DLL. For example:


      thk_ThunkData32

Export the functions that the Win32 application calls. You can either use the 32-bit DLL's module definition (.def) file or the __declspec(dllexport) keyword. Be sure the functions are declared and defined as __stdcall (or WINAPI). If the 32-bit DLL is written in C++, be sure to declare the functions as extern "C" as well.

Compile the thunk script as follows (if not already compiled):


      thunk -t thk 32to16.thk -o 32to16.asm

Assemble the assembly-language file produced by the Thunk compiler as a 32-bit object module. For example:


      ml /DIS_32 /c /W3 /nologo /coff /Fo thk32.obj 32to16.asm

Link this object module as part of the 32-bit DLL.

Link the Thunk32.lib library as part of the 32-bit DLL. This is the 32-bit import library provided in the Win32 SDK that contains references to the 32-bit thunking APIs that the code created by the Thunk compiler uses.

Building the 16-bit DLL

The 16-bit DLL must export a function named "DllEntryPoint." This function must make a call to a function created by the Thunk compiler named thk__ThunkConnect16 ("thk" is the prefix from the Thunk compiler -t switch) every time DllEntryPoint is called:


      // prototype for function in .obj file from the thunk script
      BOOL WINAPI __export thk_ThunkConnect16(LPSTR lpDll16,
                                              LPSTR lpDll32,
                                              WORD  hInst,
                                              DWORD dwReason);

      BOOL WINAPI __export DllEntryPoint(DWORD dwReason,
                                         WORD  hInst,
                                         WORD  wDS,
                                         WORD  wHeapSize,
                                         DWORD dwReserved1,
                                         WORD  wReserved 2)
      {
         if (!thk_ThunkConnect16("DLL16.DLL",
                                 "DLL32.DLL",
                                 hInst,
                                 dwReason))
         {
            return FALSE;
         }
         return TRUE;
      }


Include the following lines in the IMPORTS section of the module definition (.def) file for the 16-bit DLL. For example:

      C16ThkSL01      = KERNEL.631
      ThunkConnect16  = KERNEL.651


Include the following lines in the EXPORTS section of the module definition (.def) file for the 16-bit DLL. THK_THUNKDATA16 is defined in the object file that is assembled from the output of the Thunk compiler. Both of these symbols must have the RESIDENTNAME keyword, but can have any ordinal number.


      THK_THUNKDATA16 @1  RESIDENTNAME
      DllEntryPoint   @2  RESIDENTNAME


Add the thunk functions to the EXPORTS statement of the 16-bit DLL's module definition (.def) file. Be sure they are declared and defined as __far __pascal __export (or WINAPI __export). If the DLL is written in C++, be sure to declare them as extern "C" as well. The 32-bit side of the thunk calls these functions.

Compile the thunk script as follows (if not already compiled):


      thunk -t thk 32to16.thk -o 32to16.asm

Assemble the assembly-language file produced by the Thunk compiler as a 16-bit object module. For example:


      ml /DIS_16 /c /W3 /nologo /Fo thk16.obj 32to16.asm

Link this object module as part of the 16-bit DLL.

Mark the 16-bit DLL as version 4.0. To do this, use the resource compiler (Rc.exe). The following line shows the syntax:


      rc -40 <DLL file>
This -40 option is available in the Resource Compiler that is provided with the Win32 SDK.

NOTE: Be sure to use the Rc.exe file in the BINW16 directory so that the DLL is marked with version 4.0. The Rc.exe file that ships with 16-bit versions of Microsoft Visual C++ does not mark the DLL as version 4.0.

 

0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410065
As I have said, flat thunking is not a viable option for me.
The code must work under Windows NT.
0
 
LVL 2

Expert Comment

by:AlFa
ID: 1410066
An alternative—if you can stick with standard OLE interfaces (including IDispatch)—is to write 16-bit OLE object wrappers for your DLLs. These wrappers can be called from either 16-bit or 32-bit code and from any language that can access OLE objects.
create a 16-bit OLE server to wrap the functions contained in a 16-bit DLL.
0
 
LVL 1

Author Comment

by:fwilkinson
ID: 1410067
That's no simpler than a wrapper app with WM_COPYDATA.
0
 
LVL 2

Accepted Solution

by:
mnguyen021997 earned 100 total points
ID: 1410068
actually there is no direct support from NT to a 16 bit dll (trust me i've researched it long and hard). actually writing a ole automation server (wrapper) for you dll isn't that bad if you have MFC and classwizard do it for you.  you can classwizard all the functions on the 16 bit side, have it update the odl file (see article Q141155 in ms kb), reimport it into a class on the 32 bit side.  the nice thing is that the functions are synchronous and data can be passed in bidirectionally via the call).  wm_copydata will work only in one direction (that is, if you need data returned, you will have to wm_copydata back) which makes it asynchronous for bidirectional support.
0
 

Expert Comment

by:Shirlmc
ID: 11351924
I have a CD program called Softkey Kitchen Gourmet. It came with a Windows 95 computer. I cannot use it on my Windows XP. I get messages like "ODBC Administrator" "SQLINSTALLDriver no longer supports INF file" and "missing 16 bit ms-dos subsystem".
  I have spent 5 years typing more than 500 recipes into this programming and scanning pictures that I have attached. I can no longer access any of this information. It makes no sense to upgrade and then find you cannot run older programs.
  Is there any way for me to run this program???
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

This article describes a technique for converting RTF (Rich Text Format) data to HTML and provides C++ source that does it all in just a few lines of code. Although RTF is coming to be considered a "legacy" format, it is still in common use... po…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

758 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now