⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pgwdll32.gml

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 GML
📖 第 1 页 / 共 3 页
字号:
.if '&lang' eq 'FORTRAN 77' .do begin
:set symbol="winmain"    value="FWinMain".
:set symbol="f16"        value="wfc".
:set symbol="srcdir"     value="&pathnamup.\SAMPLES\FORTRAN\WIN\DLL".
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
:set symbol="winmain"    value="WinMain".
:set symbol="c16"        value="wcc".
:set symbol="c32"        value="wcc386".
:set symbol="srcdir"     value="&pathnamup.\SAMPLES\DLL".
.do end
.*
.chap *refid=wdll32 Windows 32-Bit Dynamic Link Libraries
.*
.if &e'&dohelp eq 0 .do begin
.section Introduction to 32-Bit DLLs
.do end
.*
.np
.ix 'dynamic link library'
.ix '32-bit DLL'
.ix 'DLL' '32-bit'
&product allows the creation of 32-bit Dynamic Link Libraries (DLL).
In fact, 32-bit DLLs are simpler to write than 16-bit DLLs.
A 16-bit DLL runs on the caller's stack, and thus DS != SS.
This creates difficulties in the small and medium memory models
because near pointers to local variables are different from near
pointers to global variables.
The 32-bit DLL runs on its own stack, in the usual flat memory space,
which eliminates these concerns.
.np
There is a special version of the supervisor,
.fi W386DLL.EXT
that performs a similar job to
.fi WIN386.EXT.
However, the 32-bit DLL supervisor is a 16-bit Windows DLL, rather
than a 16-bit Windows application.
.ix '&winmain.'
On the first use of the 32-bit DLL, the DLL supervisor loads the
32-bit DLL and invokes the 32-bit initialization routine (the DLL's
.id &winmain.
routine).
The initialization routine declares all entry points (via
.id DefineDLLEntry
.ct )
and performs any other necessary initialization.
An index number in the range 1 to 128 is used to identify all external
32-bit DLL routines.
.id DefineDLLEntry
is used to assign an index number to each routine, as well as to
identify the arguments.
.np
The DLL supervisor contains a general entry point for Windows
applications to call into called
.id Win386LibEntry.
It also contains 128 specific entry points called
.id DLL1
to
.id DLL128
which correspond to the entry points established via
.id DefineDLLEntry
(the first argument to
.id DefineDLLEntry
is an index number in the range 1 to 128).
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
These entry points are
.id FAR PASCAL
functions.
.do end
All applications call into the 32-bit DLL via these entry points.
They build the necessary stack frame and switch to the 32-bit DLL's
data space.
.np
If you call via
.id Win386LibEntry
then you pass the DLL entry point number or index (1 to 128) as the
last argument.
.id Win386LibEntry
uses this index number to call the appropriate 32-bit DLL routine.
From a pseudo-code point of view, the 16-bit supervisor might look
like the following:
.millust begin
DLL1::  set index=1
        invoke 32bitDLLindirect

DLL2::  set index=2
        invoke 32bitDLLindirect
            .
            .
            .
DLL128:: set index=128
         invoke 32bitDLLindirect

Win386LibEntry::
        set index from index_argument
        invoke 32bitDLLindirect

32bitDLLindirect:
        set up stack frame
        switch to 32-bit data space
        call indirect registration_list[ index ]
            .
            .
            .
.millust end
.np
When you are creating a 32-bit DLL, keep in mind that the entry points
you define may be invoked by a 16-bit application as well as a 32-bit
application.
It is for this reason that all far pointers passed to a 32-bit DLL are
16-bit far pointers.
Hence, whenever a pointer is passed as an argument to a 32-bit DLL
entry point and you wish to access the data it points to, you must
convert the pointer appropriately.
.if '&lang' eq 'FORTRAN 77' .do begin
To do this, you must map a dynamically allocatable array to the memory
pointed to by the 16-bit far pointer.
.do end
.*
.section A Sample 32-bit DLL
.*
.np
.ix 'DLL' '32-bit Windows example'
Let us begin our discussion of DLLs by showing the code for a simple
DLL.
The source code for these examples is provided in the
.fi &srcdir.
directory.
We describe how to compile and link the examples in the section
entitled :HDREF refid='dlcreat'..
.if '&lang' eq 'FORTRAN 77' .do begin
.code begin
*$include winapi.fi

* WINDLLV.FOR

* Setup:            set finclude=\WATCOM\src\fortran\win
* Compile and Link: wfl386 windllv -explicit -d2 -bd -l=win386
* Bind:             wbind windllv -d -n

.code break
*$pragma aux (dll_function) Add3

      integer function Add3( w1, w2, w3 )
      integer*4 w1, w2, w3

      include 'windows.fi'

      character*128 str

      write( str, '(16hDLL 1 arguments:, 3i10, a)' ) w1, w2, w3,
     &                                               char(0)
      call MessageBox( NULL, str, 'DLL Function 1'c, MB_OK )
      Add3 = w1 + w2 + w3

      end

.code break
*$pragma aux (dll_function) Add2

      integer function Add2( w1, w2 )
      integer*4 w1, w2

      include 'windows.fi'

      character*128 str

      write( str, '(16hDLL 2 arguments:, 2i10, a)' ) w1, w2, char(0)
      call MessageBox( NULL, str, 'DLL Function 2'c, MB_OK )
      Add2 = w1 + w2

      end

.code break
      integer*2 function FWinMain( hInstance,
     &                             hPrevInstance,
     &                             lpszCmdLine,
     &                             nCmdShow )
      integer*2 hInstance
      integer*2 hPrevInstance
      integer*4 lpszCmdLine
      integer*2 nCmdShow

      include 'windows.fi'

      external Add3, Add2
      integer rc

.code break
      call BreakPoint
      rc = DefineDLLEntry( 1, Add3, DLL_DWORD, DLL_DWORD, DLL_DWORD,
     &                        DLL_ENDLIST )
      if( rc .ne. 0 )then
          FWinMain = 0
          return
      end if
.code break
      rc = DefineDLLEntry( 2, Add2, DLL_DWORD, DLL_DWORD,
     &                        DLL_ENDLIST )
      if( rc .ne. 0 )then
          FWinMain = 0
          return
      end if
      call MessageBox( NULL, '32-bit DLL started'c,
     &                 'WINDLLV'c, MB_OK )
      FWinMain = 1

      end
.code end
.np
There are two entry points defined,
.id Add3
(index number 1) and
.id Add2
(index number 2).
.id Add3
has three INTEGER*4 arguments and
.id Add2
has two INTEGER*4 arguments.
The argument lists are described by calling
.id DefineDLLEntry.
All arguments are passed by value.
As previously mentioned, all pointers passed to 32-bit DLLs are 16-bit
far pointers.
Since, by default, FORTRAN 77 passes arguments by reference (a pointer
to the data is passed instead of the actual data),
a level of complexity is introduced since some pointer conversions
must take place when accessing the data pointed to by a 16-bit far
pointer in a 32-bit environment.
We will deal with this problem in a following example.
First, let us deal with passing arguments by value to 32-bit DLLs from
16 and 32-bit Windows applications.
.np
Note that each entry name must be given the
.id dll_function
attribute using an auxiliary pragma.
This alias name is defined in the file
.fi WINAPI.FI.
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
The code for this DLL can be compiled with the 16-bit compiler to
produce a 16-bit DLL and it can can be compiled with the 32-bit
compiler to produce a 32-bit DLL.
The example illustrates the fundamental differences between the two
types of DLLs.
The 32-bit DLL has a
.id WinMain
routine and the 16-bit DLL has a
.id LibMain
routine.
.exam begin
/*
 *  DLL.C
 */
#include <stdio.h>
#include <windows.h>

#if defined(__386__)/* if we are doing a 32-bit DLL */
  #define DLL_ID "DLL32"
#else               /* else we are doing a 16-bit DLL */
  #define DLL_ID "DLL16"
#endif
.exam break
long FAR PASCAL __export FooMe1(WORD w1, DWORD w2, WORD w3)
{
  char buff[128];

  sprintf( buff, "FooMe1: w1=%hx, w2=%lx, w3=%hx",
           w1, w2, w3 );
  MessageBox( NULL, buff, DLL_ID, MB_OK );
  return( w1 + w2 );
}
.exam break
long FAR PASCAL __export FooMe2( DWORD w1, WORD w2 )
{
  char buff[128];

  sprintf( buff, "FooMe2: w1=%lx, w2=%hx", w1, w2 );
  MessageBox( NULL, buff, DLL_ID, MB_OK );
  return( w1 + 1 );
}
.exam break
#if defined(__386__)/* if we are doing a 32-bit DLL */
long PASCAL WinMain( HANDLE hInstance,
                     HANDLE hPrevInstance,
                     LPSTR  lpszCmdLine,
                     int    nCmdShow )
{
  if( DefineDLLEntry( 1, (void *) FooMe1, DLL_WORD,
              DLL_DWORD, DLL_WORD, DLL_ENDLIST )) {
      return( 0 );
  }
  if( DefineDLLEntry( 2, (void *) FooMe2, DLL_DWORD,
              DLL_WORD, DLL_ENDLIST ) ) {
      return( 0 );
  }
  MessageBox( NULL, "32-bit DLL Started", DLL_ID, MB_OK );
  return( 1 );
}
#else               /* else we are doing a 16-bit DLL */
BOOL FAR PASCAL LibMain( HANDLE hInstance,
                         WORD wDataSegment,
                         WORD wHeapSize,
                         LPSTR lpszCmdLine )
{
  #if 0
  /*
    We can't use MessageBox here since static binding is
    used and a message queue has not been created by the
    time DLL16 is loaded.
  */
  MessageBox( NULL, "16-bit DLL Started", DLL_ID, MB_OK );
  #endif
  return( TRUE );
}
#endif
.exam end
.np
To create a 16-bit DLL from this code, the following steps must be
performed.
.exam begin
C>&c16. dll /mc /bt=windows /zu /fo=dll16
C>&lnkcmd. system windows_dll file dll16
C>wlib -n dll16 +dll16.dll
.exam end
.np
To create a 32-bit DLL from this code, the following steps must be
performed.
.exam begin
C>&c32. dll /bt=windows /fo=dll32
C>wlink system win386 file dll32
C>wbind -n -d dll32
.exam end
.np
There are two entry points defined,
.id FooMe1
(index number 1)
and
.id FooMe2
(index number 2).
.id FooMe1
accepts three arguments: a WORD, a DWORD, and a WORD.
.id FooMe2
accepts two arguments: a DWORD and a WORD.
.do end
.np
.id &winmain.
returns zero to notify Windows that the DLL initialization failed,
and returns a one if initialization succeeds.
.np
.id &winmain.
accepts the same arguments as the
.id &winmain.
procedure of a regular Windows program, however, only two arguments
are used.
.id hInstance
is the DLL handle and
.id lpszCmdLine
is the command line passed to the DLL.
.*
.section Calling Functions in a 32-bit DLL from a 16-bit Application
.*
.np
.ix 'DLL' '16-bit calls into 32-bit DLLs'
The following is a 16-bit Windows program that demonstrates how to
call the two routines defined in our DLL example.
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.exam begin
/*
 *  EXE16.C
 */
#include <stdio.h>
#include <windows.h>

#define Add3 1
#define Add2 2
.exam break
typedef long (FAR PASCAL *FPROC)();
typedef long (FAR PASCAL *FARPROC1)(WORD, DWORD, WORD, int);
typedef long (FAR PASCAL *FARPROC2)(DWORD, WORD, int);

long FAR PASCAL FooMe1( WORD, DWORD, WORD );
long FAR PASCAL FooMe2( DWORD, WORD );
.exam break
int PASCAL WinMain( HANDLE hInstance,
                    HANDLE hPrevInstance,
                    LPSTR  lpszCmdLine,
                    int    nCmdShow )
{
  FPROC fp;
  HANDLE hlib;
  long cb;
  char buff[128];
.exam break
  MessageBox( NULL, "16-bit EXE Started", "EXE16", MB_OK );
.exam break
  /* Do the 16-bit demo using static binding */
  cb = FooMe1( 0x666, 0x77777111, 0x6969 );
  sprintf( buff, "RC1 = %lx", cb );
  MessageBox( NULL, buff, "EXE16", MB_OK );
.exam break
  cb = FooMe2( 0x12345678, 0x8888 );
  sprintf( buff, "RC2 = %lx", cb );
  MessageBox( NULL, buff, "EXE16", MB_OK );
.exam break
  /* Do the 32-bit demo */
  hlib = LoadLibrary( "dll32.dll" );
  fp = (FPROC) GetProcAddress( hlib, "Win386LibEntry" );
.exam break
  cb = (*(FARPROC1)fp)( 0x666, 0x77777111, 0x6969, Add3 );
  sprintf( buff, "RC1 = %lx", cb );
  MessageBox( NULL, buff, "EXE16", MB_OK );
.exam break
  cb = (*(FARPROC2)fp)( 0x12345678, 0x8888, Add2 );
  sprintf( buff, "RC2 = %lx", cb );
  MessageBox( NULL, buff, "EXE16", MB_OK );
.exam break
  return( 0 );
}
.exam end
.np
Note that the last argument of a call to the 32-bit DLL routine is
the index number of the 32-bit DLL routine to use.
To create the 16-bit sample Windows executable from this code, the
following steps must be performed.
.exam begin
C>&c16. exe16 /bt=windows
C>&lnkcmd. system windows file exe16 library dll16
.exam end
.do end
.if '&lang' eq 'FORTRAN 77' .do begin
.code begin
*$include winapi.fi

* GEN16V.FOR

* Setup:            set finclude=\WATCOM\src\fortran\win
* Compile and Link: wfl gen16v -explicit -d2 -windows -l=windows
*                              -"op desc '16-bit DLL Test'"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -