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

📄 dynlink.gml

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 GML
📖 第 1 页 / 共 3 页
字号:
There are two ways to achieve this.
.np
The first method is to create a linker directive file which contains
an "IMPORT" directive for all entry points in the dynamic link
library.
The "IMPORT" directive provides the name of the entry point and the
name of the dynamic link library.
When creating an application that references a function in the dynamic
link library, this linker directive file would be included as part of
the linking process that created the application.
.np
The second method is to use import libraries.
.ix 'import library'
An import library is a standard library that is created from a dynamic
link library by using the &libname..
It contains object modules that describe the entry points in a dynamic
link library.
The resulting import library can then be specified in a "LIBRARY"
directive in the same way one would specify a standard library.
.np
Using an import library is the preferred method of providing
references to functions in dynamic link libraries.
When a dynamic link library is modified, typically the import library
corresponding to the modified dynamic link library is updated to
reflect the changes.
Hence, any directive file that specifies the import library in a
"LIBRARY" directive need not be modified.
However, if you are using "IMPORT" directives, you may have to modify
the "IMPORT" directives to reflect the changes in the dynamic link
library.
.np
Let us create an import library for our sample dynamic link library we
created in the previous section.
We do this by issuing the following command.
.millust begin
&prompt.&libcmd dllsamp +dllsamp.dll
.millust end
.np
A standard library called
.fi dllsamp.lib
will be created.
.np
Suppose the following sample program, contained in the file
.fi dlltest.&langsuff,
calls the functions from our sample dynamic link library.
.if '&lang' eq 'FORTRAN 77' .do begin
.code begin
* DLLTEST.FOR

      call dll_entry_1()
      call dll_entry_2()
      end
.code end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.code begin
#include <stdio.h>
.if '&targetos' eq 'Windows NT' .do begin
#include <process.h>
.do end

.if '&targetos' eq 'Windows NT' .do begin
#if defined(__cplusplus)
#define IMPORTED extern "C" __declspec( dllimport )
#else
#define IMPORTED __declspec( dllimport )
#endif

IMPORTED void dll_entry_1( void );
IMPORTED void dll_entry_2( void );
.do end
.if '&targetos' eq 'OS/2 2.x' .do begin
#if defined(__cplusplus)
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif

EXTERNC void dll_entry_1( void );
EXTERNC void dll_entry_2( void );
.do end

.code break
.if '&targetos' eq 'Windows NT' .do begin
#define STACK_SIZE      8192

static void thread( void *arglist )
{
    printf( "Hi from thread\n" );
    _endthread();
}

.code break
.do end
int main( void )
{
.if '&targetos' eq 'Windows NT' .do begin
    unsigned long   tid;

    dll_entry_1();
    tid = _beginthread( thread, STACK_SIZE, NULL );
.do end
.el .do begin

    dll_entry_1();
.do end
    dll_entry_2();
    return( 0 );
}
.code end
.do end
.np
We can compile and link our sample application by issuing the
following command.
.millust begin
&prompt.&wclcmd32 &tgtopts.&sw.l=&tgtosname dlltest dllsamp.lib
.millust end
.np
If we had created a linker directive file of "IMPORT" directives
instead of an import library for the dynamic link library, the linker
directive file, say
.fi dllimps.lnk,
would be as follows.
.if '&lang' eq 'FORTRAN 77' .do begin
.millust begin
import DLL_ENTRY_1 dllsamp
import DLL_ENTRY_2 dllsamp
.millust end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.millust begin
import dll_entry_1_ dllsamp
import dll_entry_2_ dllsamp
.millust end
.np
Note that the names specified in the "IMPORT" directive are appended
with an underscore.
This is the default naming convention used when compiling using the
register-based calling convention.
No underscore is required when compiling using the stack-based calling
convention.
.do end
.np
To compile and link our sample application, we would issue the
following command.
.millust begin
&prompt.&wclcmd32 &tgtopts.&sw.l=&tgtosname dlltest &sw."@dllimps"
.millust end
.*
.section The Dynamic Link Library Data Area
.*
.np
The &product 32-bit run-time library does not support the general case
operation of DLLs in an execution environment where there is only one
instance of the DATA segment (DGROUP) for that DLL.
.np
There are two cases that can lead to a DLL executing with only one
instance of the DGROUP.
.autonote
.note
DLLs linked for 32-bit OS/2 without the MANYAUTODATA option.
.note
DLLs linked for the Win32 API and executing under Win32s.
.endnote
.np
In these cases the run-time library startup code detects that there is
only one instance of the DGROUP when a second process attempts to
attach to the DLL.
At that point, it issues a diagnostic for the user and then notifies
the operating system that the second process cannot attach to the DLL.
.np
Developers who require DLLs to operate when there is only one instance
of the DGROUP can suppress the function which issues the diagnostic
and notifies the operating system that the second process cannot
attach to the DLL.
.np
Doing so requires good behaviour on the part of processes attaching to
the DLL.
This good behaviour consists primarily of ensuring that the first
process to attach to the DLL is also the last process to detach from
the DLL thereby ensuring that the DATA segment is not released back
to the free memory pool.
.np
To suppress the function which issues the diagnostic and notifies the
operating system that the second process cannot attach to the DLL, the
developer must provide a replacement entry point with the following
prototype:
.millust begin
int __disallow_single_dgroup( int );
.millust end
.np
This function should return zero to indicate that the detected single
copy of the DATA segment is allowed.
.*
.if '&targetos' eq 'OS/2 2.x' or '&lang' eq 'FORTRAN 77' .do begin
.section Dynamic Link Library Initialization/Termination
.*
.np
.ix 'dynamic link library initialization' '&targetos.'
.ix 'DLL initialization' '&targetos.'
.ix 'initialization' '&targetos dynamic link library'
.ix 'dynamic link library termination' '&targetos.'
.ix 'DLL termination' '&targetos.'
.ix 'termination' '&targetos dynamic link library'
Each dynamic link library (DLL) has an initialization and termination
routine associated with it.
The initialization routine can either be called the first time any
process accesses the DLL ("INITGLOBAL" is specified at link time) or
each time a process accesses the DLL ("INITINSTANCE" is specified at
link time).
Similarly, the termination routine can either be called when all
processes have completed their access of the DLL ("TERMGLOBAL" is
specified at link time) or each time a process completes its access of
the DLL ("TERMINSTANCE" is specified at link time).
.np
For a DLL that uses the &lang run-time libraries, initialization and
termination of the &lang run-time environment is performed
automatically.
It is also possible for a DLL to do its own special initialization and
termination process.
.*
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.np
The &lang run-time environment provides two methods for calling
user-written DLL initialization and termination code.
.autonote
.note
If you provide your own version of
.id LibMain
then it will be called for initialization and termination.
The use of
.id LibMain
is described earlier in this chapter.
.note
If you do not provide your own version of
.id LibMain
then a default version is linked in from the library.
This version will call
.ix '&dll_init'
.id &dll_init
for DLL initialization and
.ix '&dll_term'
.id &dll_term
for DLL termination.
Default stub versions of these two routines are included in the
run-time library.
If you wish to perform additional initialization/termination that is
specific to your dynamic link library, you may write your own
versions of these routines.
.endnote
.do end
.*
.el .do begin
.np
The &lang run-time environment provides a method for calling
user-written DLL initialization and termination code.
The
.ix '&dll_init'
.id &dll_init
routine is called for DLL process initialization.
.if '&targetos' eq 'Windows NT' .do begin
The
.ix '&thrd_init'
.id &thrd_init
routine is called for DLL thread initialization.
The
.ix '&thrd_term'
.id &thrd_term
routine is called for DLL thread termination.
.do end
The
.ix '&dll_term'
.id &dll_term
routine is called for DLL process termination.
Default stub versions of these routines are included in the
run-time library.
If you wish to perform additional initialization/termination
processing that is specific to your dynamic link library, you may
write your own versions of these routines.
.do end
.*
.if '&targetos' eq 'OS/2 2.x' .do begin
.np
Once the &lang run-time environment is initialized, the routine
.id &dll_init
is called.
After the &lang run-time environment is terminated, the routine
.id &dll_term
is called.
This last point is important since it means that you cannot do any
run-time calls in the termination routine.
.do end
.*
.el .do begin
.np
When a process first attaches to the DLL, the &lang run-time
environment is initialized and then the routine
.id &dll_init
is called.
When a thread is started, the routine
.id &thrd_init
is called.
When a thread is terminated, the routine
.id &thrd_term
is called.
When the main process relinquishes the DLL,
the routine
.id &dll_term
is called and then the &lang run-time environment is terminated,
.do end
.*
.np
The initialization and termination routines return an integer.
A value of 0 indicates failure; a value of 1 indicates success.
The following example illustrates sample initialization/termination
routines.
.if '&lang' eq 'FORTRAN 77' .do begin
.code begin
* DLLINIT.FOR

      integer function __fdll_initialize_()
.if '&targetos' eq 'Windows NT' .do begin
      integer __fthrd_initialize_, __fthrd_terminate_
.do end
      integer __fdll_terminate_, dll_entry

      integer WORKING_SIZE
      parameter ( WORKING_SIZE = 16*1024 )
      integer ierr, WorkingStorage
      dimension WorkingStorage(:)

.code break
      allocate( WorkingStorage(WORKING_SIZE), stat=ierr )
      if( ierr .eq. 0 )then
          __fdll_initialize_ = 1
      else
          __fdll_initialize_ = 0
      endif
      return

.if '&targetos' eq 'Windows NT' .do begin
.code break
      entry __fthrd_initialize_()
      __fthrd_initialize_ = 1
      return

.code break
      entry __fthrd_terminate_()
      __fthrd_terminate_ = 1
      return

.do end
.code break
      entry __fdll_terminate_()
* Note: no run-time calls allowed under OS/2 Warp
      deallocate( WorkingStorage )
      __fdll_terminate_ = 1
      return

.code break
      entry dll_entry()
      ! use WorkingStorage
      return

      end
.code end
.do end
.if '&lang' eq 'C' or '&lang' eq 'C/C++' .do begin
.code begin
#include <stdlib.h>

#define WORKING_SIZE (64 * 1024)

char *WorkingStorage;

#if defined(__cplusplus)
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif

void __dll_finalize( void );

EXTERNC int __dll_initialize( void )
{
    WorkingStorage = malloc( WORKING_SIZE );
    if( WorkingStorage == NULL ) return( 0 );
    atexit( __dll_finalize );
    return( 1 );
}

void __dll_finalize( void )
{
    free( WorkingStorage );
}

EXTERNC int __dll_terminate( void )
{
    return( 1 );
}

EXTERNC void dll_entry( void )
{
    /* use array WorkingStorage */
}
.code end
.do end
.np
In the above example, the process initialization routine allocates
storage that the dynamic link library needs, the routine
.id dll_entry
uses the storage, and the process termination routine frees the
storage allocated in the initialization routine.
.do end
.*
:set symbol="prompt"     value=&oprompt.

⌨️ 快捷键说明

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