|
|
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);
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.