Examples (_DLL_InitTerm -- Initialize and Terminate DLL Environment)

Example 1
This example shows the _DLL_InitTerm function from the IBM C and C++ Compilers sample program for building DLLs.

#ifndef WIN32_LEAN_AND_MEAN
   #define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/* _CRT_init is the C run-time environment initialization function.         */
/* It will return 0 to indicate success and -1 to indicate failure.         */

extern int _IMPORT _CRT_init(void);

/* _CRT_term is the C run-time environment termination function.            */

extern void _IMPORT _CRT_term(void);

size_t _Export nSize;
int *_Export pArray;

/* _DLL_InitTerm is the function that gets called by the operating system   */
/* loader when it loads and frees this DLL for each process that accesses   */
/* this DLL.  However, it only gets called the first time the DLL is loaded */
/* and the last time it is freed for a particular process.  The system      */
/* linkage convention MUST be used because the operating system loader is   */
/* calling this function.                                                   */

unsigned long __stdcall _DLL_InitTerm(unsigned long hModule, unsigned long
                                    ulFlag, long * dummy)
{
   size_t i;
   int  rc;
   char namebuf[MAX_PATH];

   /* If ulFlag is DLL_PROCESS_ATTACH then the DLL is being loaded so initialization should*/
   /* be performed.  If ulFlag is DLL_PROCESS_DETACH then the DLL is being freed so       */
   /* termination should be performed.                                      */

   switch (ulFlag) {
      case DLL_PROCESS_ATTACH :

         /*******************************************************************/
         /* The C run-time environment initialization function must be      */
         /* called before any calls to C run-time functions that are not    */
         /* inlined.                                                        */
         /*******************************************************************/

         if (_CRT_init() == -1)
            return 0UL;
         if ((rc = GetModuleFileName((void *)hModule, namebuf, sizeof namebuf)) == 0)
            printf("GetModuleFileName returned %lu\n", GetLastError());
         else
            printf("The name of this DLL is %s\n", namebuf);
         srand(17);
         nSize = (rand()%128)+32;
         printf("The array size for this process is %u\n", nSize);
         if ((pArray = malloc(nSize *sizeof(int))) == NULL) {
            printf("Could not allocate space for unsorted array.\n");
            return 0UL;
         }
         for (i = 0; i < nSize; ++i)
            pArray[i] = rand();
         break;

      case DLL_PROCESS_DETACH :
         printf("The array will now be freed.\n");
         free(pArray);
         _CRT_term();
         break;

      default  :
         printf("ulFlag = %lu\n", ulFlag);
         return 0UL;
   }

   /* A non-zero value must be returned to indicate success.                */

   return 1UL;
}

Example 2
The following example shows the _DLL_InitTerm function from the IBM C and C++ Compilers sample for building subsystem DLLs.

/******************************************************************************/
/* This example provides 5 external entrypoints of which 2 are exported for   */
/* use by client processes.  The entrypoints are:                             */
/*                                                                            */
/* _DLL_InitTerm - Initialization/Termination function for the DLL that is    */
/*                 invoked by the loader.  When the /Ge- compile option is    */
/*                 used the linker is told that this is the function to       */
/*                 execute when the DLL is first loaded and last freed for    */
/*                 each process.                                              */
/*                                                                            */
/* DLLREGISTER  - Called by _DLL_InitTerm for each process that loads the     */
/*                DLL.                                                        */
/*                                                                            */
/* DLLINCREMENT - Accepts a count from its client and adds this value to      */
/*                the process and system totals.                              */
/*                                                                            */
/* DLLSTATS     - Dumps process and system totals on behalf of its client.    */
/*                                                                            */
/* DLLDEREGISTER- Called by _DLL_InitTerm for each process that frees the     */
/*                DLL.                                                        */
/*                                                                            */
/******************************************************************************/

#ifndef WIN32_LEAN_AND_MEAN
   #define WIN32_LEAN_AND_MEAN 1
#endif
#include <windows.h>
#include <stdio.h>
#include "sample05.h"

extern int _IMPORT _rmem_init(void);
extern void _IMPORT _rmem_term(void);

static unsigned long DLLREGISTER( void );
static unsigned long DLLDEREGISTER( void );

#define SHARED_SEMAPHORE_NAME "DLL.LCK"

/* The following data will be per-process data.  It will not be shared among  */
/* different processes.                                                       */

static HANDLE hmtxSharedSem;         /* Shared semaphore                      */
static unsigned long ulProcessTotal; /* Total of increments for a process     */
static DWORD pid;                    /* Process identifier                    */

/* This is the global data segment that is shared by every process.           */

#pragma data_seg( GLOBAL_SEG )

static unsigned long ulProcessCount;        /* total number of processes      */
static unsigned long ulGrandTotal;          /* Grand total of increments      */

/* _DLL_InitTerm() - called by the loader for DLL initialization/termination  */
/* This function must return a non-zero value if successful and a zero value  */
/* if unsuccessful.                                                           */

unsigned long __stdcall _DLL_InitTerm( HINSTANCE hModule,
                                     DWORD ulFlag, LPVOID dummy)
   {
   ULONG rc;

   /* If ulFlag is DLL_PROCESS_ATTACH then initialization is required:        */
   /*    If the shared memory pointer is NULL then the DLL is being loaded    */
   /*    for the first time so acquire the named shared storage for the       */
   /*    process control structures.  A linked list of process control        */
   /*    structures will be maintained.  Each time a new process loads this   */
   /*    DLL, a new process control structure is created and it is inserted   */
   /*    at the end of the list by calling DLLREGISTER.                       */
   /*                                                                         */
   /* If ulFlag is DLL_PROCESS_DETTACH then termination is required:          */
   /*    Call DLLDEREGISTER which will remove the process control structure   */
   /*    and free the shared memory block from its virtual address space.     */

   switch( ulFlag )
      {
      case DLL_PROCESS_ATTACH:
         _rmem_init();
         if ( !ulProcessCount )
            {
            /* Create the shared mutex semaphore.                             */

            if (( hmtxSharedSem = CreateMutex(NULL,
                                              FALSE,
                                              SHARED_SEMAPHORE_NAME)) == NULL)
               {
               printf( "CreateMutex  rc = %lu\n", GetLastError() );
               return FALSE;
               }
            }

         /* Register the current process.                                     */

         if ( DLLREGISTER( ) )
            return FALSE;

         break;

      case DLL_PROCESS_DETACH:
         /* De-register the current process.                                  */

         if ( DLLDEREGISTER( ) )
            return 0;

         _rmem_term();
         break;

      default:
         return 0;
      }

   /* Indicate success.  Non-zero means success!!!                            */

   return TRUE;
   }

/* DLLREGISTER - Registers the current process so that it can use this        */
/*               subsystem.  Called by _DLL_InitTerm when the DLL is first    */
/*               loaded for the current process.                              */

static unsigned long DLLREGISTER( void )
   {
   unsigned long rc;

   /* Get the process id       */

    pid = GetCurrentProcessId();

   /* Open the shared mutex semaphore for this process.                       */

   if ( ( hmtxSharedSem = OpenMutex(SYNCHRONIZE,
                                    TRUE,
                                    SHARED_SEMAPHORE_NAME ) ) == NULL)
      {
      printf( "OpenMutex rc = %lu\n", rc = GetLastError() );
      return rc;
      }

   /* Acquire the shared mutex semaphore.                                     */

   if ( WaitForSingleObject( hmtxSharedSem,
                                   INFINITE )  == 0xFFFFFFFF )
      {
      printf( "WaitFor SingleObject rc = %lu\n", rc = GetLastError() );
      CloseHandle( hmtxSharedSem );
      return rc;
      }

   /* Increment the count of processes registered.                            */

   ++ulProcessCount;

   /* Initialize the per-process data.                                        */

   ulProcessTotal = 0;

   /* Tell the user that the current process has been registered.             */

   printf( "\nProcess %lu has been registered.\n\n", pid );

   /* Release the shared mutex semaphore.                                     */

   if ( ReleaseMutex( hmtxSharedSem ) == FALSE )
      {
      printf( "ReleaseMutex rc = %lu\n", rc = GetLastError() );
      return rc;
      }

   return 0;
   }

/* DLLINCREMENT - Increments the process and global totals on behalf of the   */
/*                calling program.                                            */

int _Export DLLINCREMENT( int incount )
   {
   unsigned long rc;               /* return code from DOS APIs               */

   /* Acquire the shared mutex semaphore.                                     */

   if ( WaitForSingleObject( hmtxSharedSem,
                                INFINITE )  == 0xFFFFFFFF )
      {
      printf( "WaitForSingleObject rc = %lu\n", rc = GetLastError());
      return rc;
      }

   /* Increment the counts the process and grand totals.                      */

   ulProcessTotal += incount;
   ulGrandTotal += incount;

   /* Tell the user that the increment was successful.                        */

   printf( "\nThe increment for process %lu was successful.\n\n", pid );

   /* Release the shared mutex semaphore.                                     */

   if ( ReleaseMutex( hmtxSharedSem )  == FALSE )
      {
      printf( "ReleaseMutex rc = %lu\n", rc = GetLastError() );
      return rc;
      }

   return 0;
   }

/* DLLSTATS  - Prints process and grand totals.                               */

int _Export DLLSTATS( void )
   {
   unsigned long rc;

   /* Acquire the shared mutex semaphore.                                     */

   if ( WaitForSingleObject( hmtxSharedSem,
                                   INFINITE )  == 0xFFFFFFFF )
      {
      printf( "WaitForSingleObject rc = %lu\n", rc = GetLastError());
      return rc;
      }

   /* Print out per-process and global information.                           */

   printf( "\nCurrent process identifier     = %lu\n", pid );
   printf( "Current process total          = %lu\n", ulProcessTotal );
   printf( "Number of processes registered = %lu\n", ulProcessCount );
   printf( "Grand Total                    = %lu\n\n", ulGrandTotal );

   /* Release the shared mutex semaphore.                                     */

   if ( ReleaseMutex( hmtxSharedSem ) == FALSE )
      {
      printf( "ReleaseMutex rc = %lu\n", rc = GetLastError() );
      return rc;
      }

   return 0;
   }

/* DLLDEREGISTER - Deregisters the current process from this subsystem.       */
/*                 Called by _DLL_InitTerm when the DLL is freed for the      */
/*                 last time by the current process.                          */

static unsigned long DLLDEREGISTER( void )
   {
   unsigned long rc;

   /* Acquire the shared mutex semaphore.                                     */

   if ( ( rc = WaitForSingleObject( hmtxSharedSem,
                                   INFINITE ) ) == 0xFFFFFFFF )
      {
      printf( "WaitForSingleObject rc = %lu\n", GetLastError());
      return rc;
      }

   /* Decrement the count of processes registered.                            */

   --ulProcessCount;

   /* Tell the user that the current process has been deregistered.           */

   printf( "\nProcess %lu has been deregistered.\n\n", pid );

   /* Release the shared mutex semaphore.                                     */

   if ( ReleaseMutex( hmtxSharedSem ) == FALSE )
      {
      printf( "ReleaseMutex rc = %lu\n", rc= GetLastError() );
      return rc;
      }

   /* Close the shared mutex semaphore for this process.                      */

   if ( CloseHandle( hmtxSharedSem )  == FALSE )
      {
      printf( "CloseHandle   rc = %lu\n", rc = GetLastError() );
      return rc;
      }

   return 0;
   }