|
|
1.1 root 1: /*************************************************************************\
2: * PROGRAM: Mutex.c
3: *
4: * PURPOSE:
5: *
6: * To demonstrate the use of a named mutex between processes.
7: *
8: * GLOBAL VARIABLES:
9: *
10: * HANDLE hInst; - Instance handle.
11: *
12: * HWND hWnd; - Client window handle.
13: *
14: * CHAR Buf[80], Buf2[80];
15: * Error message buffers.
16: *
17: * FUNCTIONS:
18: *
19: * WinMain() - Initializes the window, and process the message loop.
20: * MainWndProc() - To handle the messages to the main window.
21: * RequestProc() - Prints a message when it gets access to the mutex.
22: *
23: * COMMENTS:
24: *
25: * Overview:
26: * Between processes it is better to use a mutex than a semaphore
27: * to control access to a mutual resourse. A serious draw back
28: * to a semaphore is that any thread can call ReleaseSemaphore
29: * and change its usage count (or access). Another drawback is that
30: * if a thread or process dies before calling ReleaseSemaphore, than
31: * no other process or thread will be able to access it (because the
32: * use count hasn't been updated). When a process controlling
33: * a mutex dies, the mutex is freed for other processes.
34: *
35: * To Use:
36: * Start any number of instances of this application. Each instance
37: * will start a thread which will request access to the mutex.
38: * when the thread has the mutex, it will print a message in the
39: * application window "I HAVE CONTROL OF THE MUTEX!", and then
40: * sleep for two seconds. It will then wakeup, erase the message,
41: * release the mutex; and then sleep for another two seconds before
42: * asking for control again. By starting several instances, you will
43: * see that each instance will often have to wait longer than its two
44: * seconds before it gets control.
45: *
46: \*************************************************************************/
47:
48: #include <windows.h>
49: #include <stdlib.h>
50: #include <stdio.h>
51: #include "mutex.h"
52:
53: // used for error messages.
54: #define WERR(who,where) {sprintf(Buf,"ERROR: %s returned %u, line: %u", who, GetLastError(), __LINE__);\
55: sprintf(Buf2,"From within %s", where);\
56: MessageBox(hWnd, Buf, Buf2, MB_OK);}
57:
58:
59: CHAR Buf[80];
60: CHAR Buf2[80];
61: HANDLE hInst;
62: HWND hWnd;
63:
64:
65:
66:
67: /*************************************************************************\
68: *
69: * FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
70: *
71: * PURPOSE: Calls initialization function, processes message loop.
72: *
73: * COMMENTS: A fairly standard WinMain.
74: *
75: \*************************************************************************/
76:
77: int APIENTRY WinMain (HANDLE hInstance,
78: HANDLE hPrevInstance,
79: LPSTR lpCmdLine,
80: int nCmdShow)
81:
82:
83: {
84:
85: MSG msg;
86: WNDCLASS wc;
87:
88: UNREFERENCED_PARAMETER( lpCmdLine );
89: UNREFERENCED_PARAMETER( hPrevInstance );
90:
91: hInst = hInstance;
92:
93: wc.style = NULL; // Replaces CS_SIZEREDRAW.
94: wc.lpfnWndProc = (WNDPROC)MainWndProc; // The client window procedure.
95: wc.cbClsExtra = 0; // No room reserved for extra data.
96: wc.cbWndExtra = 0;
97: wc.hInstance = hInstance;
98: wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
99: wc.hCursor = LoadCursor (NULL, IDC_ARROW);
100: wc.hbrBackground = GetStockObject (WHITE_BRUSH);
101: wc.lpszMenuName = "";
102: wc.lpszClassName = "MutexWClass";
103:
104: RegisterClass(&wc);
105:
106: hWnd = CreateWindow ("MutexWClass",
107: "Mutex Between Processes Sample",
108: WS_OVERLAPPEDWINDOW,
109: CW_USEDEFAULT,
110: CW_USEDEFAULT,
111: CW_USEDEFAULT,
112: CW_USEDEFAULT,
113: NULL,
114: NULL,
115: hInstance,
116: NULL);
117:
118:
119: ShowWindow (hWnd, nCmdShow);
120:
121: while (GetMessage (&msg, NULL, NULL, NULL))
122: DispatchMessage (&msg); // Dispatch message to window.
123:
124: return (msg.wParam); // Returns value from PostQuitMessage.
125:
126: }
127:
128: /*************************************************************************\
129: *
130: * FUNCTION: MainWndProc (HWND, UINT, UINT, LONG)
131: *
132: * PURPOSE: To process messages. To launch client and server threads
133: * as appropriate.
134: *
135: *
136: * MESSAGES:
137: *
138: * WM_CREATE - Creates a thread.
139: *
140: * WM_DESTROY - Standard, destroys the window.
141: *
142: * CALLED BY:
143: *
144: * WinMain();
145: *
146: * CALLS TO:
147: *
148: * RequestProc() - The thread procedure.
149: *
150: \*************************************************************************/
151:
152: LONG APIENTRY MainWndProc (HWND hwnd,
153: UINT message,
154: UINT wParam,
155: LONG lParam)
156: {
157: DWORD ThreadID;
158: HANDLE hThread;
159:
160: switch (message)
161: {
162:
163: case WM_CREATE:
164:
165: hThread = CreateThread (NULL, 0,
166: (LPTHREAD_START_ROUTINE)RequestProc,
167: (LPVOID)NULL, NULL,
168: (LPDWORD)&ThreadID);
169: if (!hThread)
170: WERR("CreateThread", "WM_CREATE");
171: CloseHandle (hThread);
172: return (0);
173:
174:
175: case WM_DESTROY :
176: PostQuitMessage (0);
177: return (0);
178: }
179: return DefWindowProc (hwnd, message, wParam, lParam);
180: }
181:
182:
183: /*************************************************************************\
184: *
185: * FUNCTION: VOID RequestProc (VOID)
186: *
187: * PURPOSE: This thread tries to create the Mutex. Only the first thread
188: * created will succeed, all others will fail. Then this thread
189: * tries to open the mutex. If successful, it
190: * enters a loop. The loop asks for control of the mutex.
191: * Once it has control, it prints the message in the application
192: * window, and sleeps for two seconds. It then releases
193: * the mutex, erases the message, and sleeps another two
194: * seconds before trying to get control again.
195: *
196: * VARIABLES USED:
197: *
198: * - hMutex:
199: * A handle to the mutex.
200: *
201: * - rect, textRect:
202: * RECT structures. One for the client area, one for the
203: * text location.
204: *
205: * - hDC: The DC of the window.
206: *
207: * - X, Y: Integers/coordinates used to locate the text
208: *
209: * - hBrush:
210: * Handle to a brush, used to erase the old text.
211: *
212: * - size: A SIZE struct, used to determin the size of the font
213: * and message on the window.
214: *
215: *
216: \*************************************************************************/
217: VOID RequestProc(VOID)
218: {
219: HANDLE hMutex;
220: RECT rect, textRect;
221: HDC hDC;
222: LONG X, Y;
223: SIZE size;
224: DWORD retCode;
225:
226:
227:
228: hMutex = CreateMutex (NULL, FALSE, "my_mutex");
229: if (!hMutex)
230: {
231: retCode = GetLastError();
232: if (retCode != ERROR_ALREADY_EXISTS)
233: {
234: SetLastError(retCode);
235: WERR("CreateMutex", "WM_CREATE");
236: PostQuitMessage(0);
237: }
238: }
239:
240: hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "my_mutex");
241: if (!hMutex)
242: {
243: WERR("OpenMutex", "From RequestProc");
244: return;
245: }
246:
247: hDC = GetDC (hWnd);
248: GetTextExtentPoint (hDC, "I HAVE CONTROL OF THE MUTEX!", 28, &size);
249: ReleaseDC (hWnd, hDC);
250:
251: while(!IsWindow(hWnd));
252:
253: while(1)
254: {
255: WaitForSingleObject (hMutex, INFINITE);
256:
257: hDC = GetDC (hWnd);
258: GetClientRect (hWnd, &rect);
259: X = ((rect.right - rect.left) / 2) - (size.cx / 2);
260: Y = (rect.bottom - rect.top) / 2;
261:
262: TextOut (hDC, X, Y, "I HAVE CONTROL OF THE MUTEX!", 28);
263:
264: MessageBeep (0); // Forces a flush of the window buffers.
265: Sleep(2000);
266:
267: textRect.left = X,
268: textRect.right = X + size.cx;
269: textRect.top = Y;
270: textRect.bottom = Y + size.cy;
271: FillRect (hDC, &textRect, GetStockObject(WHITE_BRUSH));
272:
273: ReleaseDC(hWnd, hDC);
274: ReleaseMutex (hMutex);
275: Sleep(2000);
276: }
277: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.