source: trunk/src/user32/auxthread.cpp@ 21602

Last change on this file since 21602 was 21602, checked in by dmik, 14 years ago

shell32: systray: Added support for the "TaskbarCreated" system notificaiton message that Windows broadcasts to all top-level windows when the taskbar (xcenter in case of OS/2) is (re)started. This allows applications supporting this message (including Java applications) recreate their taskbar icons.

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1/*
2 * Auxiliary thread API
3 *
4 * Used to execute code on a dedicated thread.
5 *
6 * Project Odin Software License can be found in LICENSE.TXT
7 *
8 */
9
10#define INCL_PM
11#define INCL_DOS
12#define INCL_DOSERRORS
13#include <os2wrap.h> // Odin32 OS/2 api wrappers
14
15#include <win32api.h>
16
17#include "auxthread.h"
18
19#include "dbglog.h"
20
21struct AUXMSG
22{
23 PAUXTHREADFN pfn;
24 PVOID arg1;
25 PVOID arg2;
26 PVOID arg3;
27 PVOID arg4;
28 BOOL del;
29};
30
31static HEV hevAux = 0;
32static HANDLE hthreadAux = 0;
33static HWND hwndAux = NULLHANDLE;
34
35static MRESULT EXPENTRY AuxWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
36{
37 if (msg == WM_USER)
38 {
39 AUXMSG *msg = (AUXMSG *)mp1;
40 dprintf(("USER32: AuxWndProc: pfn %p, arg1 %x, arg2 %x, arg3 %x, "
41 "arg4 %x, del %d", msg->pfn, msg->arg1, msg->arg2,
42 msg->arg3, msg->arg4, msg->del));
43
44 MRESULT mrc = msg->pfn(msg->arg1, msg->arg2, msg->arg3, msg->arg4);
45 if (msg->del)
46 delete msg;
47 return mrc;
48 }
49
50 return FALSE;
51}
52
53static DWORD CALLBACK AuxThread(LPVOID arg)
54{
55 // take hev from the parameter instead of hevAux which will have gone right
56 // after calling StopAuxThread() so that we won't be able to post it
57 HEV hev = (HEV)arg;
58
59 dprintf(("USER32: AuxThread: Start (hev %x)", hev));
60
61 // Note: Since this thread is started by CreateThread(), hab and hmq are
62 // already created
63
64 if (WinRegisterClass(0, "OdinAuxWnd", AuxWndProc, 0, 0))
65 {
66 hwndAux = WinCreateWindow(HWND_OBJECT, "OdinAuxWnd", NULL,
67 0, 0, 0, 0, 0, NULL, HWND_BOTTOM, 0,
68 NULL, NULL);
69 if (hwndAux)
70 {
71 // report becoming ready (non-NULL hwndAux will indicate success)
72 DosPostEventSem(hev);
73
74 dprintf(("USER32: AuxThread: Enter message loop"));
75
76 QMSG qmsg;
77 while (WinGetMsg(0, &qmsg, NULLHANDLE, 0, 0))
78 WinDispatchMsg(0, &qmsg);
79
80 dprintf(("USER32: AuxThread: Exit message loop"));
81
82 WinDestroyWindow(hwndAux);
83 }
84 else
85 dprintf(("USER32: AuxThread: WinCreateWindow() failed with %x",
86 WinGetLastError(0)));
87
88 }
89 else
90 dprintf(("USER32: AuxThread: WinRegisterClass() failed with %x",
91 WinGetLastError(0)));
92
93 dprintf(("USER32: AuxThread: Stop"));
94
95 // report termination
96 DosPostEventSem(hev);
97
98 return 0;
99}
100
101static BOOL DoRunOnAuxThread(PAUXTHREADFN pfn, PVOID arg1, PVOID arg2,
102 PVOID arg3, PVOID arg4, PVOID *ret)
103{
104 dprintf(("USER32: DoRunOnAuxThread: pfn %p, arg1 %x, arg2 %x, arg3 %x, "
105 "arg4 %x, ret %x", pfn, arg1, arg2, arg3, arg4, ret));
106
107 APIRET arc;
108
109 if (hevAux == 0)
110 {
111 HEV hev;
112 arc = DosCreateEventSem(NULL, &hev, 0, FALSE);
113 if (arc != NO_ERROR)
114 {
115 dprintf(("USER32: DoRunOnAuxThread: DosCreateEventSem failed with %d",
116 arc));
117 return FALSE;
118 }
119
120 // protect from two or more concurrent "first" calls
121 if (InterlockedCompareExchange((PLONG)&hevAux, hev, 0) == 0)
122 {
123 // we are the first, do the rest
124
125 // Note: Use CreateThread() instead of DosCreateThread() so that the
126 // thread gets all initialization necessary to call Win32 APIs which
127 // may be potentially called form PAUXTHREADFN
128 hthreadAux = CreateThread(NULL, 0, AuxThread, (LPVOID)hev, 0, NULL);
129 if (hthreadAux)
130 {
131 // wait for the thread to get ready
132 arc = DosWaitEventSem(hev, SEM_INDEFINITE_WAIT);
133 }
134 else
135 {
136 dprintf(("USER32: DoRunOnAuxThread: CreateThread() failed with %x",
137 GetLastError()));
138
139 // the second caller may be already waiting so inform it
140 DosPostEventSem(hev);
141 }
142 }
143 else
144 {
145 // we are the second, give up our attempt
146 DosCloseEventSem(hev);
147
148 // wait for the thread to get ready
149 arc = DosWaitEventSem(hevAux, SEM_INDEFINITE_WAIT);
150 }
151
152 if (hthreadAux == 0 || arc != NO_ERROR || hwndAux == NULLHANDLE)
153 {
154 StopAuxThread(); // cleanup
155 return FALSE;
156 }
157 }
158
159 if (ret)
160 {
161 AUXMSG msg = { pfn, arg1, arg2, arg3, arg4, FALSE };
162 *ret = WinSendMsg(hwndAux, WM_USER, &msg, 0);
163 return TRUE;
164 }
165
166 AUXMSG *msg = new AUXMSG;
167 msg->pfn = pfn;
168 msg->arg1 = arg1;
169 msg->arg2 = arg2;
170 msg->arg3 = arg3;
171 msg->arg4 = arg4;
172 msg->del = TRUE;
173 if (WinPostMsg(hwndAux, WM_USER, msg, 0))
174 return TRUE;
175
176 delete msg;
177 return FALSE;
178}
179
180/**
181 * Schedules execution of a given user function with given arguments on a
182 * dedicated global helper thread and immediately returns to the caller.
183 *
184 * All calls to RunOnAuxThread() schedule execution of the user function on the
185 * same thread which, once started, gets terminated automatically at process
186 * termination.
187 *
188 * Note that since this thread is global (shared by all requests as described
189 * above), the user function must return as soon as possible as other threads
190 * may be trying to schedule a function call on this thread through
191 * RunOnAuxThread() (or even waiting for the result of the function execution
192 * through RunOnAuxThreadAndWait()) as well.
193 *
194 * The main purpose of this API is to make sure that a series of function calls
195 * is guaranteedly performed on the same thread so that subsequent calls share
196 * the context established by the fisrt call. This, in particular includes
197 * situations when it is necessary to make sure that an object window is
198 * destroyed on the same thead where it was created no matter what thread calls
199 * the create or destroy code. This also implies that this dedicated thread runs
200 * the message loop and therefore may respond to posted messages.
201 *
202 * @author dmik (3/23/2011)
203 *
204 * @param pfn User function to execute.
205 * @param arg1 Function argument 1.
206 * @param arg2 Function argument 2.
207 * @param arg3 Function argument 3.
208 * @param arg4 Function argument 4.
209 *
210 * @return TRUE on success, FALSE otherwise.
211 */
212BOOL WIN32API RunOnAuxThread(PAUXTHREADFN pfn, PVOID arg1, PVOID arg2,
213 PVOID arg3, PVOID arg4)
214{
215 return DoRunOnAuxThread(pfn, arg1, arg2, arg3, arg4, NULL);
216}
217
218/**
219 * Schedules execution of a given user function with given arguments on a
220 * dedicated global helper thread and waits for it to return a value.
221 *
222 * See RunOnAuxThread() for more details on the dedicated thread and purpose of
223 * this API.
224 *
225 * @author dmik (3/23/2011)
226 *
227 * @param pfn User function to execute.
228 * @param arg1 Function argument 1.
229 * @param arg2 Function argument 2.
230 * @param arg3 Function argument 3.
231 * @param arg4 Function argument 4.
232 * @param ret Where to store the user function's return value. May be NULL if
233 * the caller is not interested in the return value.
234 *
235 * @return TRUE on success, FALSE otherwise.
236 */
237BOOL WIN32API RunOnAuxThreadAndWait(PAUXTHREADFN pfn, PVOID arg1, PVOID arg2,
238 PVOID arg3, PVOID arg4, PPVOID ret)
239{
240 PVOID ret2;
241 BOOL brc = DoRunOnAuxThread(pfn, arg1, arg2, arg3, arg4, &ret2);
242 if (ret)
243 *ret = ret2;
244 return brc;
245}
246
247//******************************************************************************
248//
249//******************************************************************************
250VOID StopAuxThread()
251{
252 if (hevAux != 0)
253 {
254 HEV hev = hevAux;
255
256 // protect from two or more concurrent "first" calls
257 if (InterlockedCompareExchange((PLONG)&hevAux, 0, hev) == hev)
258 {
259 // we are the first, do the rest
260
261 // ask to exit the message loop
262 if (hwndAux)
263 {
264 ULONG dummy;
265 DosResetEventSem(hev, &dummy);
266
267 WinPostMsg(hwndAux, WM_QUIT, 0, 0);
268 hwndAux = NULLHANDLE;
269 }
270
271 if (hthreadAux != 0)
272 {
273 // wait for the normal thread termination
274 DosWaitEventSem(hev, 3000);
275 CloseHandle(hthreadAux);
276 hthreadAux = 0;
277 }
278
279 DosCloseEventSem(hev);
280 }
281 }
282}
Note: See TracBrowser for help on using the repository browser.