### Example (_rmem_term -- Terminate Memory Functions for Subsystem DLL)

This example shows the _DLL_InitTerm function from the IBM C and C++ Compilers sample program for building subsystem DLLs, which calls _rmem_term to terminate the library memory functions.

    /******************************************************************************/
    /* 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;
       }