File:  [WindowsNT SDKs] / q_a / samples / mutex / mutex.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:29:19 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-jun-1992, HEAD
Microsoft Windows NT Build 297 06-28-1992

/*************************************************************************\
*  PROGRAM: Mutex.c
*
*  PURPOSE:
*
*    To demonstrate the use of a named mutex between processes.
*
*  GLOBAL VARIABLES:
*
*    HANDLE hInst;  - Instance handle.
*
*    HWND   hWnd;   - Client window handle.
*
*    CHAR Buf[80], Buf2[80];
*           Error message buffers.
*
*  FUNCTIONS:
*
*    WinMain()      - Initializes the window, and process the message loop.
*    MainWndProc()  - To handle the messages to the main window.
*    RequestProc()  - Prints a message when it gets access to the mutex.
*
*  COMMENTS:
*
*    Overview:
*      Between processes it is better to use a mutex than a semaphore
*      to control access to a mutual resourse.  A serious draw back
*      to a semaphore is that any thread can call ReleaseSemaphore
*      and change its usage count (or access).  Another drawback is that
*      if a thread or process dies before calling ReleaseSemaphore, than
*      no other process or thread will be able to access it (because the
*      use count hasn't been updated).  When a process controlling
*      a mutex dies, the mutex is freed for other processes.
*
*    To Use:
*      Start any number of instances of this application.  Each instance
*      will start a thread which will request access to the mutex.
*      when the thread has the mutex, it will print a message in the
*      application window "I HAVE CONTROL OF THE MUTEX!", and then
*      sleep for two seconds.  It will then wakeup, erase the message,
*      release the mutex; and then sleep for another two seconds before
*      asking for control again.  By starting several instances, you will
*      see that each instance will often have to wait longer than its two
*      seconds before it gets control.
*
\*************************************************************************/

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include "mutex.h"

                            // used for error messages.
#define WERR(who,where)    {sprintf(Buf,"ERROR: %s returned %u, line: %u", who, GetLastError(), __LINE__);\
                            sprintf(Buf2,"From within %s", where);\
                            MessageBox(hWnd, Buf, Buf2, MB_OK);}


CHAR Buf[80];
CHAR Buf2[80];
HANDLE hInst;
HWND   hWnd;




/*************************************************************************\
*
*  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
*
*  PURPOSE:  Calls initialization function, processes message loop.
*
*  COMMENTS: A fairly standard WinMain.
*
\*************************************************************************/

int APIENTRY WinMain (HANDLE hInstance,
                      HANDLE hPrevInstance,
                      LPSTR  lpCmdLine,
                      int    nCmdShow)


{

  MSG  msg;
  WNDCLASS wc;

  UNREFERENCED_PARAMETER( lpCmdLine );
  UNREFERENCED_PARAMETER( hPrevInstance );

  hInst = hInstance;

  wc.style = NULL;                       // Replaces CS_SIZEREDRAW.
  wc.lpfnWndProc = (WNDPROC)MainWndProc; // The client window procedure.
  wc.cbClsExtra = 0;                     // No room reserved for extra data.
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  wc.lpszMenuName = "";
  wc.lpszClassName = "MutexWClass";

  RegisterClass(&wc);

  hWnd = CreateWindow ("MutexWClass",
                       "Mutex Between Processes Sample",
                       WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       NULL,
                       NULL,
                       hInstance,
                       NULL);


  ShowWindow  (hWnd, nCmdShow);

  while (GetMessage (&msg, NULL, NULL, NULL))
       DispatchMessage (&msg);   // Dispatch message to window.

  return (msg.wParam);           // Returns value from PostQuitMessage.

}

/*************************************************************************\
*
*  FUNCTION:  MainWndProc (HWND, UINT, UINT, LONG)
*
*  PURPOSE:   To process messages.  To launch client and server threads
*             as appropriate.
*
*
*  MESSAGES:
*
*    WM_CREATE       - Creates a thread.
*
*    WM_DESTROY      - Standard, destroys the window.
*
*  CALLED BY:
*
*    WinMain();
*
*  CALLS TO:
*
*    RequestProc()   - The thread procedure.
*
\*************************************************************************/

LONG APIENTRY MainWndProc (HWND hwnd,
                           UINT message,
                           UINT wParam,
                           LONG lParam)
{
  DWORD    ThreadID;
  HANDLE   hThread;

  switch (message)
      {

        case WM_CREATE:

          hThread = CreateThread (NULL, 0,
                                  (LPTHREAD_START_ROUTINE)RequestProc,
                                  (LPVOID)NULL, NULL,
                                  (LPDWORD)&ThreadID);
          if (!hThread)
            WERR("CreateThread", "WM_CREATE");
          CloseHandle (hThread);
          return (0);


        case WM_DESTROY :
          PostQuitMessage (0);
          return (0);
       }
  return DefWindowProc (hwnd, message, wParam, lParam);
}


/*************************************************************************\
*
*  FUNCTION:  VOID RequestProc (VOID)
*
*  PURPOSE:   This thread tries to create the Mutex.  Only the first thread
*             created will succeed, all others will fail.  Then this thread
*             tries to open the mutex.  If successful, it
*             enters a loop.  The loop asks for control of the mutex.
*             Once it has control, it prints the message in the application
*             window, and sleeps for two seconds.  It then releases
*             the mutex, erases the message, and sleeps another two
*             seconds before trying to get control again.
*
*  VARIABLES USED:
*
*    - hMutex:
*             A handle to the mutex.
*
*    - rect, textRect:
*             RECT structures.  One for the client area, one for the
*             text location.
*
*    - hDC:   The DC of the window.
*
*    - X, Y:  Integers/coordinates used to locate the text
*
*    - hBrush:
*             Handle to a brush, used to erase the old text.
*
*    - size:  A SIZE struct, used to determin the size of the font
*             and message on the window.
*
*
\*************************************************************************/
VOID RequestProc(VOID)
{
  HANDLE hMutex;
  RECT   rect, textRect;
  HDC    hDC;
  LONG   X, Y;
  SIZE   size;
  DWORD  retCode;



  hMutex = CreateMutex (NULL, FALSE, "my_mutex");
   if (!hMutex)
     {
     retCode = GetLastError();
     if (retCode != ERROR_ALREADY_EXISTS)
       {
       SetLastError(retCode);
       WERR("CreateMutex", "WM_CREATE");
       PostQuitMessage(0);
       }
     }

  hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "my_mutex");
  if (!hMutex)
     {
     WERR("OpenMutex", "From RequestProc");
     return;
     }

  hDC = GetDC (hWnd);
  GetTextExtentPoint (hDC, "I HAVE CONTROL OF THE MUTEX!", 28, &size);
  ReleaseDC (hWnd, hDC);

  while(!IsWindow(hWnd));

  while(1)
    {
     WaitForSingleObject (hMutex, INFINITE);

     hDC = GetDC (hWnd);
     GetClientRect (hWnd, &rect);
     X = ((rect.right - rect.left) / 2) - (size.cx / 2);
     Y = (rect.bottom - rect.top) / 2;

     TextOut (hDC, X, Y, "I HAVE CONTROL OF THE MUTEX!", 28);

     MessageBeep (0);              // Forces a flush of the window buffers.
     Sleep(2000);

     textRect.left   = X,
     textRect.right  = X + size.cx;
     textRect.top    = Y;
     textRect.bottom = Y + size.cy;
     FillRect (hDC, &textRect, GetStockObject(WHITE_BRUSH));

     ReleaseDC(hWnd, hDC);
     ReleaseMutex (hMutex);
     Sleep(2000);
    }
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.