ae482df3572409160c89501c0ccf3ab85a1ec417
[reactos.git] / reactos / lib / shlwapi / thread.c
1 /*
2 * SHLWAPI thread and MT synchronisation functions
3 *
4 * Copyright 2002 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 #include <stdarg.h>
22 #include <string.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnls.h"
29 #include "wine/debug.h"
30 #define NO_SHLWAPI_REG
31 #define NO_SHLWAPI_PATH
32 #define NO_SHLWAPI_GDI
33 #define NO_SHLWAPI_STREAM
34 #define NO_SHLWAPI_USER
35 #include "shlwapi.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(shell);
38
39 /* Get a function pointer from a DLL handle */
40 #define GET_FUNC(func, module, name, fail) \
41 do { \
42 if (!func) { \
43 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
44 if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \
45 } \
46 } while (0)
47
48 /* DLL handles for late bound calls */
49 extern HMODULE SHLWAPI_hshell32;
50
51 /* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
52 static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**);
53
54 extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */
55
56 DWORD WINAPI SHStringFromGUIDA(REFGUID,LPSTR,INT);
57
58 /**************************************************************************
59 * _CreateAllAccessSecurityAttributes [SHLWAPI.356]
60 *
61 * Initialise security attributes from a security descriptor.
62 *
63 * PARAMS
64 * lpAttr [O] Security attributes
65 * lpSec [I] Security descriptor
66 *
67 * RETURNS
68 * Success: lpAttr, initialised using lpSec.
69 * Failure: NULL, if any parameters are invalid.
70 *
71 * NOTES
72 * This function always returns NULL if the underlying OS version
73 * Wine is impersonating does not use security descriptors (i.e. anything
74 * before Windows NT).
75 */
76 LPSECURITY_ATTRIBUTES WINAPI _CreateAllAccessSecurityAttributes(
77 LPSECURITY_ATTRIBUTES lpAttr,
78 PSECURITY_DESCRIPTOR lpSec)
79 {
80 /* This function is used within SHLWAPI only to create security attributes
81 * for shell semaphores. */
82
83 TRACE("(%p,%p)\n", lpAttr, lpSec);
84
85 if (!(GetVersion() & 0x80000000)) /* NT */
86 {
87 if (!lpSec || !lpAttr)
88 return NULL;
89
90 if (InitializeSecurityDescriptor(lpSec, 1))
91 {
92 if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE))
93 {
94 lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
95 lpAttr->lpSecurityDescriptor = lpSec;
96 lpAttr->bInheritHandle = FALSE;
97 return lpAttr;
98 }
99 }
100 }
101 return NULL;
102 }
103
104 /*************************************************************************
105 * _SHGetInstanceExplorer [SHLWAPI.@]
106 *
107 * Get an interface to the shell explorer.
108 *
109 * PARAMS
110 * lppUnknown [O] Destination for explorers IUnknown interface.
111 *
112 * RETURNS
113 * Success: S_OK. lppUnknown contains the explorer interface.
114 * Failure: An HRESULT error code.
115 */
116 HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown)
117 {
118 /* This function is used within SHLWAPI only to hold the IE reference
119 * for threads created with the CTF_PROCESS_REF flag set. */
120
121 GET_FUNC(pSHGetInstanceExplorer, shell32, "SHGetInstanceExplorer", E_FAIL);
122 return pSHGetInstanceExplorer(lppUnknown);
123 }
124
125 /* Internal thread information structure */
126 typedef struct tagSHLWAPI_THREAD_INFO
127 {
128 LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */
129 LPTHREAD_START_ROUTINE pfnCallback; /* Thread initialisation */
130 PVOID pData; /* Application specific data */
131 BOOL bInitCom; /* Initialise COM for the thread? */
132 HANDLE hEvent; /* Signal for creator to continue */
133 IUnknown *refThread; /* Reference to thread creator */
134 IUnknown *refIE; /* Reference to the IE process */
135 } SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO;
136
137
138 /*************************************************************************
139 * SHGetThreadRef [SHLWAPI.@]
140 *
141 * Get a per-thread object reference set by SHSetThreadRef().
142 *
143 * PARAMS
144 * lppUnknown [O] Destination to receive object reference
145 *
146 * RETURNS
147 * Success: S_OK. lppUnknown is set to the object reference.
148 * Failure: E_NOINTERFACE, if an error occurs or lppUnknown is NULL.
149 */
150 HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown)
151 {
152 TRACE("(%p)\n", lppUnknown);
153
154 if (!lppUnknown || SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES)
155 return E_NOINTERFACE;
156
157 *lppUnknown = (IUnknown*)TlsGetValue(SHLWAPI_ThreadRef_index);
158 if (!*lppUnknown)
159 return E_NOINTERFACE;
160
161 /* Add a reference. Caller will Release() us when finished */
162 IUnknown_AddRef(*lppUnknown);
163 return S_OK;
164 }
165
166 /*************************************************************************
167 * SHSetThreadRef [SHLWAPI.@]
168 *
169 * Store a per-thread object reference.
170 *
171 * PARAMS
172 * lpUnknown [I] Object reference to store
173 *
174 * RETURNS
175 * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef()
176 * Failure: E_NOINTERFACE, if an error occurs or lpUnknown is NULL.
177 */
178 HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown)
179 {
180 TRACE("(%p)\n", lpUnknown);
181
182 if (!lpUnknown || SHLWAPI_ThreadRef_index == 0xffffffff)
183 return E_NOINTERFACE;
184
185 TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown);
186 return S_OK;
187 }
188
189 /*************************************************************************
190 * SHReleaseThreadRef [SHLWAPI.@]
191 *
192 * Release a per-thread object reference.
193 *
194 * PARAMS
195 * None.
196 *
197 * RETURNS
198 * Success: S_OK. The threads object reference is released.
199 * Failure: An HRESULT error code.
200 */
201 HRESULT WINAPI SHReleaseThreadRef()
202 {
203 FIXME("() - stub!\n");
204 return S_OK;
205 }
206
207 /*************************************************************************
208 * SHLWAPI_ThreadWrapper
209 *
210 * Internal wrapper for executing user thread functions from SHCreateThread.
211 */
212 static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi)
213 {
214 SHLWAPI_THREAD_INFO ti;
215 HRESULT hCom = E_FAIL;
216 DWORD dwRet;
217
218 TRACE("(%p)\n", pTi);
219
220 /* We are now executing in the context of the newly created thread.
221 * So we copy the data passed to us (it is on the stack of the function
222 * that called us, which is waiting for us to signal an event before
223 * returning). */
224 memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO));
225
226 /* Initialise COM for the thread, if desired */
227 if (ti.bInitCom)
228 {
229 hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE);
230
231 if (FAILED(hCom))
232 hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
233 }
234
235 /* Execute the callback function before returning */
236 if (ti.pfnCallback)
237 ti.pfnCallback(ti.pData);
238
239 /* Signal the thread that created us; it can return now */
240 SetEvent(ti.hEvent);
241
242 /* Execute the callers start code */
243 dwRet = ti.pfnThreadProc(ti.pData);
244
245 /* Release references to the caller and IE process, if held */
246 if (ti.refThread)
247 IUnknown_Release(ti.refThread);
248
249 if (ti.refIE)
250 IUnknown_Release(ti.refIE);
251
252 if (SUCCEEDED(hCom))
253 CoUninitialize();
254
255 /* Return the users thread return value */
256 return dwRet;
257 }
258
259 /*************************************************************************
260 * SHCreateThread [SHLWAPI.16]
261 *
262 * Create a new thread.
263 *
264 * PARAMS
265 * pfnThreadProc [I] Function to execute in new thread
266 * pData [I] Application specific data passed to pfnThreadProc
267 * dwFlags [I] CTF_ flags from "shlwapi.h"
268 * pfnCallback [I] Function to execute before pfnThreadProc
269 *
270 * RETURNS
271 * Success: TRUE. pfnThreadProc was executed.
272 * Failure: FALSE. pfnThreadProc was not executed.
273 *
274 * NOTES
275 * If the thread cannot be created, pfnCallback is NULL, and dwFlags
276 * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously.
277 */
278 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData,
279 DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback)
280 {
281 SHLWAPI_THREAD_INFO ti;
282 BOOL bCalled = FALSE;
283
284 TRACE("(%p,%p,0x%lX,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback);
285
286 /* Set up data to pass to the new thread (On our stack) */
287 ti.pfnThreadProc = pfnThreadProc;
288 ti.pfnCallback = pfnCallback;
289 ti.pData = pData;
290 ti.bInitCom = dwFlags & CTF_COINIT ? TRUE : FALSE;
291 ti.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
292
293 /* Hold references to the current thread and IE process, if desired */
294 if(dwFlags & CTF_THREAD_REF)
295 SHGetThreadRef(&ti.refThread);
296 else
297 ti.refThread = NULL;
298
299 if(dwFlags & CTF_PROCESS_REF)
300 _SHGetInstanceExplorer(&ti.refIE);
301 else
302 ti.refIE = NULL;
303
304 /* Create the thread */
305 if(ti.hEvent)
306 {
307 DWORD dwRetVal;
308 HANDLE hThread;
309
310 hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal);
311
312 if(hThread)
313 {
314 /* Wait for the thread to signal us to continue */
315 WaitForSingleObject(ti.hEvent, INFINITE);
316 CloseHandle(hThread);
317 bCalled = TRUE;
318 }
319 CloseHandle(ti.hEvent);
320 }
321
322 if (!bCalled)
323 {
324 if (!ti.pfnCallback && dwFlags & CTF_INSIST)
325 {
326 /* Couldn't call, call synchronously */
327 pfnThreadProc(pData);
328 bCalled = TRUE;
329 }
330 else
331 {
332 /* Free references, since thread hasn't run to do so */
333 if(ti.refThread)
334 IUnknown_Release(ti.refThread);
335
336 if(ti.refIE)
337 IUnknown_Release(ti.refIE);
338 }
339 }
340 return bCalled;
341 }
342
343 /*************************************************************************
344 * _SHGlobalCounterGetValue [SHLWAPI.223]
345 *
346 * Get the current count of a semaphore.
347 *
348 * PARAMS
349 * hSem [I] Semaphore handle
350 *
351 * RETURNS
352 * The current count of the semaphore.
353 */
354 LONG WINAPI _SHGlobalCounterGetValue(HANDLE hSem)
355 {
356 LONG dwOldCount = 0;
357
358 TRACE("(%p)\n", hSem);
359 ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */
360 WaitForSingleObject(hSem, 0); /* -1 */
361 return dwOldCount;
362 }
363
364 /*************************************************************************
365 * _SHGlobalCounterIncrement [SHLWAPI.224]
366 *
367 * Claim a semaphore.
368 *
369 * PARAMS
370 * hSem [I] Semaphore handle
371 *
372 * RETURNS
373 * The new count of the semaphore.
374 */
375 LONG WINAPI _SHGlobalCounterIncrement(HANDLE hSem)
376 {
377 LONG dwOldCount = 0;
378
379 TRACE("(%p)\n", hSem);
380 ReleaseSemaphore(hSem, 1, &dwOldCount);
381 return dwOldCount + 1;
382 }
383
384 /*************************************************************************
385 * _SHGlobalCounterDecrement [SHLWAPI.424]
386 *
387 * Release a semaphore.
388 *
389 * PARAMS
390 * hSem [I] Semaphore handle
391 *
392 * RETURNS
393 * The new count of the semaphore.
394 */
395 DWORD WINAPI _SHGlobalCounterDecrement(HANDLE hSem)
396 {
397 DWORD dwOldCount = 0;
398
399 TRACE("(%p)\n", hSem);
400
401 dwOldCount = _SHGlobalCounterGetValue(hSem);
402 WaitForSingleObject(hSem, 0);
403 return dwOldCount - 1;
404 }
405
406 /*************************************************************************
407 * _SHGlobalCounterCreateNamedW [SHLWAPI.423]
408 *
409 * Unicode version of _SHGlobalCounterCreateNamedA.
410 */
411 HANDLE WINAPI _SHGlobalCounterCreateNamedW(LPCWSTR lpszName, DWORD iInitial)
412 {
413 static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' };
414 const int iPrefixLen = 6;
415 WCHAR szBuff[MAX_PATH];
416 const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR);
417 SECURITY_DESCRIPTOR sd;
418 SECURITY_ATTRIBUTES sAttr, *pSecAttr;
419 HANDLE hRet;
420
421 TRACE("(%s,%ld)\n", debugstr_w(lpszName), iInitial);
422
423 /* Create Semaphore name */
424 memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR));
425 if (lpszName)
426 StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen);
427
428 /* Initialise security attributes */
429 pSecAttr = _CreateAllAccessSecurityAttributes(&sAttr, &sd);
430
431 if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff)))
432 hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff);
433 return hRet;
434 }
435
436 /*************************************************************************
437 * _SHGlobalCounterCreateNamedA [SHLWAPI.422]
438 *
439 * Create a semaphore.
440 *
441 * PARAMS
442 * lpszName [I] Name of semaphore
443 * iInitial [I] Initial count for semaphore
444 *
445 * RETURNS
446 * A new semaphore handle.
447 */
448 HANDLE WINAPI _SHGlobalCounterCreateNamedA(LPCSTR lpszName, DWORD iInitial)
449 {
450 WCHAR szBuff[MAX_PATH];
451
452 TRACE("(%s,%ld)\n", debugstr_a(lpszName), iInitial);
453
454 if (lpszName)
455 MultiByteToWideChar(0, 0, lpszName, -1, szBuff, MAX_PATH);
456 return _SHGlobalCounterCreateNamedW(lpszName ? szBuff : NULL, iInitial);
457 }
458
459 /*************************************************************************
460 * _SHGlobalCounterCreate [SHLWAPI.222]
461 *
462 * Create a semaphore using the name of a GUID.
463 *
464 * PARAMS
465 * guid [I] GUID to use as semaphore name
466 *
467 * RETURNS
468 * A handle to the semaphore.
469 *
470 * NOTES
471 * The initial count of the semaphore is set to 0.
472 */
473 HANDLE WINAPI _SHGlobalCounterCreate (REFGUID guid)
474 {
475 char szName[40];
476
477 TRACE("(%s)\n", debugstr_guid(guid));
478
479 /* Create a named semaphore using the GUID string */
480 SHStringFromGUIDA(guid, szName, sizeof(szName) - 1);
481 return _SHGlobalCounterCreateNamedA(szName, 0);
482 }