-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmessage.c
124 lines (105 loc) · 2.84 KB
/
message.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/* Interrupt handling */
#include "make.h"
#include "job.h"
static HWND window; /* Our invisible message - only window. */
static HANDLE thread; /* Used to suspend the main thread. */
static void (*IntProc)(void);
static void (*TermProc)(void);
static HANDLE msgThread; /* This is only here for cleanup */
static BOOL WINAPI
MsgConsoleH(DWORD ev)
{
void (*proc)(void);
switch (ev) {
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
proc = IntProc;
break;
case CTRL_CLOSE_EVENT:
proc = TermProc;
break;
default:
return FALSE;
}
Job_WaitMutex();
if (SuspendThread(thread) == -1)
Punt("failed to suspend main thread: %s", strerr(GetLastError()));
proc();
if (ResumeThread(thread) == -1)
Punt("failed to resume main thread: %s", strerr(GetLastError()));
Job_ReleaseMutex();
return TRUE;
}
static LRESULT CALLBACK
MsgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_CLOSE:
/* The same as CTRL-C */
MsgConsoleH(CTRL_C_EVENT);
return 0;
default:
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}
}
/*
* Create a new window then go into
* the message loop, notifying the calling
* thread when we are ready.
*/
static DWORD WINAPI
MsgLoop(LPVOID ready)
{
MSG msg;
BOOL ret;
WNDCLASSA wClass = { 0 };
wClass.lpszClassName = progname;
wClass.lpfnWndProc = MsgProc;
wClass.hInstance = GetModuleHandleA(NULL);
if (RegisterClassA(&wClass) == 0)
Punt("failed to register class: %s", strerr(GetLastError()));
if ((window = CreateWindowExA(0, progname, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE,
NULL, wClass.hInstance, NULL)) == NULL)
Punt("failed to create window: %s", strerr(GetLastError()));
*(bool *)ready = true;
while ((ret = GetMessageA(&msg, window, 0, 0)) != 0) {
if (ret == -1)
Punt("failed to get message: %s", strerr(GetLastError()));
DispatchMessageA(&msg);
}
return 0;
}
/*
* Get the handle for the calling thread,
* set the ctrl handler then start a
* new thread at MsgLoop.
*
* Input:
* intProc non-fatal interrupt handler
* termProc fatal interrupt handler
*/
void
Msg_Init(void (*intProc)(void), void (*termProc)(void))
{
volatile bool ready = false;
HANDLE process = GetCurrentProcess();
IntProc = intProc;
TermProc = termProc;
if (DuplicateHandle(process, GetCurrentThread(), process, &thread, 0, FALSE,
DUPLICATE_SAME_ACCESS) == 0)
Punt("failed to duplicate thread handle: %s", strerr(GetLastError()));
if (SetConsoleCtrlHandler(MsgConsoleH, TRUE) == 0)
Punt("failed to set console ctrl handler: %s", strerr(GetLastError()));
if ((msgThread = CreateThread(NULL, 0, MsgLoop, (LPVOID)&ready, 0, NULL)) == NULL)
Punt("failed to start msg thread: %s", strerr(GetLastError()));
while (!ready);
}
void Msg_End(void)
{
#ifdef CLEANUP
PostMessageA(window, WM_QUIT, 0, 0);
SetConsoleCtrlHandler(MsgConsoleH, FALSE);
CloseHandle(thread);
CloseHandle(msgThread);
#endif
}