* Sync up to trunk head (r65481).
[reactos.git] / dll / win32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "precomp.h"
23
24 extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */
25
26 INT WINAPI SHStringFromGUIDA(REFGUID,LPSTR,INT);
27
28 /**************************************************************************
29 * CreateAllAccessSecurityAttributes [SHLWAPI.356]
30 *
31 * Initialise security attributes from a security descriptor.
32 *
33 * PARAMS
34 * lpAttr [O] Security attributes
35 * lpSec [I] Security descriptor
36 *
37 * RETURNS
38 * Success: lpAttr, initialised using lpSec.
39 * Failure: NULL, if any parameters are invalid.
40 *
41 * NOTES
42 * This function always returns NULL if the underlying OS version
43 * Wine is impersonating does not use security descriptors (i.e. anything
44 * before Windows NT).
45 */
46 LPSECURITY_ATTRIBUTES WINAPI CreateAllAccessSecurityAttributes(
47 LPSECURITY_ATTRIBUTES lpAttr,
48 PSECURITY_DESCRIPTOR lpSec,
49 DWORD p3)
50 {
51 /* This function is used within SHLWAPI only to create security attributes
52 * for shell semaphores. */
53
54 TRACE("(%p,%p,%08x)\n", lpAttr, lpSec, p3);
55
56 if (!(GetVersion() & 0x80000000)) /* NT */
57 {
58 if (!lpSec || !lpAttr)
59 return NULL;
60
61 if (InitializeSecurityDescriptor(lpSec, 1))
62 {
63 if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE))
64 {
65 lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
66 lpAttr->lpSecurityDescriptor = lpSec;
67 lpAttr->bInheritHandle = FALSE;
68 return lpAttr;
69 }
70 }
71 }
72 return NULL;
73 }
74
75 /*************************************************************************
76 * _SHGetInstanceExplorer [SHLWAPI.@]
77 *
78 * Get an interface to the shell explorer.
79 *
80 * PARAMS
81 * lppUnknown [O] Destination for explorers IUnknown interface.
82 *
83 * RETURNS
84 * Success: S_OK. lppUnknown contains the explorer interface.
85 * Failure: An HRESULT error code.
86 */
87 HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown)
88 {
89 /* This function is used within SHLWAPI only to hold the IE reference
90 * for threads created with the CTF_PROCESS_REF flag set. */
91 return SHGetInstanceExplorer(lppUnknown);
92 }
93
94 /* Internal thread information structure */
95 typedef struct tagSHLWAPI_THREAD_INFO
96 {
97 LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */
98 LPTHREAD_START_ROUTINE pfnCallback; /* Thread initialisation */
99 PVOID pData; /* Application specific data */
100 BOOL bInitCom; /* Initialise COM for the thread? */
101 HANDLE hEvent; /* Signal for creator to continue */
102 IUnknown *refThread; /* Reference to thread creator */
103 IUnknown *refIE; /* Reference to the IE process */
104 } SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO;
105
106 typedef struct
107 {
108 IUnknown IUnknown_iface;
109 LONG *ref;
110 } threadref;
111
112 static inline threadref *impl_from_IUnknown(IUnknown *iface)
113 {
114 return CONTAINING_RECORD(iface, threadref, IUnknown_iface);
115 }
116
117 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj)
118 {
119 threadref * This = impl_from_IUnknown(iface);
120
121 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObj);
122
123 if (ppvObj == NULL)
124 return E_POINTER;
125
126 if (IsEqualGUID(&IID_IUnknown, riid)) {
127 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObj);
128 *ppvObj = This;
129 IUnknown_AddRef((IUnknown*)*ppvObj);
130 return S_OK;
131 }
132
133 *ppvObj = NULL;
134 FIXME("(%p, %s, %p) interface not supported\n", This, debugstr_guid(riid), ppvObj);
135 return E_NOINTERFACE;
136 }
137
138 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
139 {
140 threadref * This = impl_from_IUnknown(iface);
141
142 TRACE("(%p)\n", This);
143 return InterlockedIncrement(This->ref);
144 }
145
146 static ULONG WINAPI threadref_Release(IUnknown *iface)
147 {
148 LONG refcount;
149 threadref * This = impl_from_IUnknown(iface);
150
151 TRACE("(%p)\n", This);
152
153 refcount = InterlockedDecrement(This->ref);
154 if (!refcount)
155 HeapFree(GetProcessHeap(), 0, This);
156
157 return refcount;
158 }
159
160 /* VTable */
161 static const IUnknownVtbl threadref_vt =
162 {
163 threadref_QueryInterface,
164 threadref_AddRef,
165 threadref_Release,
166 };
167
168 /*************************************************************************
169 * SHCreateThreadRef [SHLWAPI.@]
170 *
171 * Create a per-thread IUnknown object
172 *
173 * PARAMS
174 * lprefcount [I] Pointer to a LONG to be used as refcount
175 * lppUnknown [O] Destination to receive the created object reference
176 *
177 * RETURNS
178 * Success: S_OK. lppUnknown is set to the object reference.
179 * Failure: E_INVALIDARG, if a parameter is NULL
180 */
181 HRESULT WINAPI SHCreateThreadRef(LONG *lprefcount, IUnknown **lppUnknown)
182 {
183 threadref * This;
184 TRACE("(%p, %p)\n", lprefcount, lppUnknown);
185
186 if (!lprefcount || !lppUnknown)
187 return E_INVALIDARG;
188
189 This = HeapAlloc(GetProcessHeap(), 0, sizeof(threadref));
190 This->IUnknown_iface.lpVtbl = &threadref_vt;
191 This->ref = lprefcount;
192
193 *lprefcount = 1;
194 *lppUnknown = &This->IUnknown_iface;
195 TRACE("=> returning S_OK with %p\n", This);
196 return S_OK;
197 }
198
199 /*************************************************************************
200 * SHGetThreadRef [SHLWAPI.@]
201 *
202 * Get a per-thread object reference set by SHSetThreadRef().
203 *
204 * PARAMS
205 * lppUnknown [O] Destination to receive object reference
206 *
207 * RETURNS
208 * Success: S_OK. lppUnknown is set to the object reference.
209 * Failure: E_NOINTERFACE, if an error occurs or no object is set
210 */
211 HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown)
212 {
213 TRACE("(%p)\n", lppUnknown);
214
215 if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES)
216 return E_NOINTERFACE;
217
218 *lppUnknown = TlsGetValue(SHLWAPI_ThreadRef_index);
219 if (!*lppUnknown)
220 return E_NOINTERFACE;
221
222 /* Add a reference. Caller will Release() us when finished */
223 IUnknown_AddRef(*lppUnknown);
224 return S_OK;
225 }
226
227 /*************************************************************************
228 * SHSetThreadRef [SHLWAPI.@]
229 *
230 * Store a per-thread object reference.
231 *
232 * PARAMS
233 * lpUnknown [I] Object reference to store
234 *
235 * RETURNS
236 * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef()
237 * Failure: E_NOINTERFACE, if an error occurs
238 */
239 HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown)
240 {
241 TRACE("(%p)\n", lpUnknown);
242
243 if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES)
244 return E_NOINTERFACE;
245
246 TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown);
247 return S_OK;
248 }
249
250 /*************************************************************************
251 * SHReleaseThreadRef [SHLWAPI.@]
252 *
253 * Release a per-thread object reference.
254 *
255 * PARAMS
256 * None.
257 *
258 * RETURNS
259 * Success: S_OK. The threads object reference is released.
260 * Failure: An HRESULT error code.
261 */
262 HRESULT WINAPI SHReleaseThreadRef(void)
263 {
264 FIXME("() - stub!\n");
265 return S_OK;
266 }
267
268 /*************************************************************************
269 * SHLWAPI_ThreadWrapper
270 *
271 * Internal wrapper for executing user thread functions from SHCreateThread.
272 */
273 static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi)
274 {
275 SHLWAPI_THREAD_INFO ti;
276 HRESULT hCom = E_FAIL;
277 DWORD dwRet;
278
279 TRACE("(%p)\n", pTi);
280
281 /* We are now executing in the context of the newly created thread.
282 * So we copy the data passed to us (it is on the stack of the function
283 * that called us, which is waiting for us to signal an event before
284 * returning). */
285 memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO));
286
287 /* Initialise COM for the thread, if desired */
288 if (ti.bInitCom)
289 {
290 hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE);
291
292 if (FAILED(hCom))
293 hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
294 }
295
296 /* Execute the callback function before returning */
297 if (ti.pfnCallback)
298 ti.pfnCallback(ti.pData);
299
300 /* Signal the thread that created us; it can return now */
301 SetEvent(ti.hEvent);
302
303 /* Execute the callers start code */
304 dwRet = ti.pfnThreadProc(ti.pData);
305
306 /* Release references to the caller and IE process, if held */
307 if (ti.refThread)
308 IUnknown_Release(ti.refThread);
309
310 if (ti.refIE)
311 IUnknown_Release(ti.refIE);
312
313 if (SUCCEEDED(hCom))
314 CoUninitialize();
315
316 /* Return the users thread return value */
317 return dwRet;
318 }
319
320 /*************************************************************************
321 * SHCreateThread [SHLWAPI.16]
322 *
323 * Create a new thread.
324 *
325 * PARAMS
326 * pfnThreadProc [I] Function to execute in new thread
327 * pData [I] Application specific data passed to pfnThreadProc
328 * dwFlags [I] CTF_ flags from "shlwapi.h"
329 * pfnCallback [I] Function to execute before pfnThreadProc
330 *
331 * RETURNS
332 * Success: TRUE. pfnThreadProc was executed.
333 * Failure: FALSE. pfnThreadProc was not executed.
334 *
335 * NOTES
336 * If the thread cannot be created, pfnCallback is NULL, and dwFlags
337 * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously.
338 */
339 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData,
340 DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback)
341 {
342 SHLWAPI_THREAD_INFO ti;
343 BOOL bCalled = FALSE;
344
345 TRACE("(%p,%p,0x%X,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback);
346
347 /* Set up data to pass to the new thread (On our stack) */
348 ti.pfnThreadProc = pfnThreadProc;
349 ti.pfnCallback = pfnCallback;
350 ti.pData = pData;
351 ti.bInitCom = (dwFlags & CTF_COINIT) != 0;
352 ti.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
353
354 /* Hold references to the current thread and IE process, if desired */
355 if(dwFlags & CTF_THREAD_REF)
356 SHGetThreadRef(&ti.refThread);
357 else
358 ti.refThread = NULL;
359
360 if(dwFlags & CTF_PROCESS_REF)
361 _SHGetInstanceExplorer(&ti.refIE);
362 else
363 ti.refIE = NULL;
364
365 /* Create the thread */
366 if(ti.hEvent)
367 {
368 DWORD dwRetVal;
369 HANDLE hThread;
370
371 hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal);
372
373 if(hThread)
374 {
375 /* Wait for the thread to signal us to continue */
376 WaitForSingleObject(ti.hEvent, INFINITE);
377 CloseHandle(hThread);
378 bCalled = TRUE;
379 }
380 CloseHandle(ti.hEvent);
381 }
382
383 if (!bCalled)
384 {
385 if (!ti.pfnCallback && dwFlags & CTF_INSIST)
386 {
387 /* Couldn't call, call synchronously */
388 pfnThreadProc(pData);
389 bCalled = TRUE;
390 }
391 else
392 {
393 /* Free references, since thread hasn't run to do so */
394 if(ti.refThread)
395 IUnknown_Release(ti.refThread);
396
397 if(ti.refIE)
398 IUnknown_Release(ti.refIE);
399 }
400 }
401 return bCalled;
402 }
403
404 /*************************************************************************
405 * SHGlobalCounterGetValue [SHLWAPI.223]
406 *
407 * Get the current count of a semaphore.
408 *
409 * PARAMS
410 * hSem [I] Semaphore handle
411 *
412 * RETURNS
413 * The current count of the semaphore.
414 */
415 LONG WINAPI SHGlobalCounterGetValue(HANDLE hSem)
416 {
417 LONG dwOldCount = 0;
418
419 TRACE("(%p)\n", hSem);
420 ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */
421 WaitForSingleObject(hSem, 0); /* -1 */
422 return dwOldCount;
423 }
424
425 /*************************************************************************
426 * SHGlobalCounterIncrement [SHLWAPI.224]
427 *
428 * Claim a semaphore.
429 *
430 * PARAMS
431 * hSem [I] Semaphore handle
432 *
433 * RETURNS
434 * The new count of the semaphore.
435 */
436 LONG WINAPI SHGlobalCounterIncrement(HANDLE hSem)
437 {
438 LONG dwOldCount = 0;
439
440 TRACE("(%p)\n", hSem);
441 ReleaseSemaphore(hSem, 1, &dwOldCount);
442 return dwOldCount + 1;
443 }
444
445 /*************************************************************************
446 * SHGlobalCounterDecrement [SHLWAPI.424]
447 *
448 * Release a semaphore.
449 *
450 * PARAMS
451 * hSem [I] Semaphore handle
452 *
453 * RETURNS
454 * The new count of the semaphore.
455 */
456 DWORD WINAPI SHGlobalCounterDecrement(HANDLE hSem)
457 {
458 DWORD dwOldCount = 0;
459
460 TRACE("(%p)\n", hSem);
461
462 dwOldCount = SHGlobalCounterGetValue(hSem);
463 WaitForSingleObject(hSem, 0);
464 return dwOldCount - 1;
465 }
466
467 /*************************************************************************
468 * SHGlobalCounterCreateNamedW [SHLWAPI.423]
469 *
470 * Unicode version of SHGlobalCounterCreateNamedA.
471 */
472 HANDLE WINAPI SHGlobalCounterCreateNamedW(LPCWSTR lpszName, DWORD iInitial)
473 {
474 static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' };
475 const int iPrefixLen = 6;
476 WCHAR szBuff[MAX_PATH];
477 const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR);
478 SECURITY_DESCRIPTOR sd;
479 SECURITY_ATTRIBUTES sAttr, *pSecAttr;
480 HANDLE hRet;
481
482 TRACE("(%s,%d)\n", debugstr_w(lpszName), iInitial);
483
484 /* Create Semaphore name */
485 memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR));
486 if (lpszName)
487 StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen);
488
489 /* Initialise security attributes */
490 pSecAttr = CreateAllAccessSecurityAttributes(&sAttr, &sd, 0);
491
492 if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff)))
493 hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff);
494 return hRet;
495 }
496
497 /*************************************************************************
498 * SHGlobalCounterCreateNamedA [SHLWAPI.422]
499 *
500 * Create a semaphore.
501 *
502 * PARAMS
503 * lpszName [I] Name of semaphore
504 * iInitial [I] Initial count for semaphore
505 *
506 * RETURNS
507 * A new semaphore handle.
508 */
509 HANDLE WINAPI SHGlobalCounterCreateNamedA(LPCSTR lpszName, DWORD iInitial)
510 {
511 WCHAR szBuff[MAX_PATH];
512
513 TRACE("(%s,%d)\n", debugstr_a(lpszName), iInitial);
514
515 if (lpszName)
516 MultiByteToWideChar(CP_ACP, 0, lpszName, -1, szBuff, MAX_PATH);
517 return SHGlobalCounterCreateNamedW(lpszName ? szBuff : NULL, iInitial);
518 }
519
520 /*************************************************************************
521 * SHGlobalCounterCreate [SHLWAPI.222]
522 *
523 * Create a semaphore using the name of a GUID.
524 *
525 * PARAMS
526 * guid [I] GUID to use as semaphore name
527 *
528 * RETURNS
529 * A handle to the semaphore.
530 *
531 * NOTES
532 * The initial count of the semaphore is set to 0.
533 */
534 HANDLE WINAPI SHGlobalCounterCreate (REFGUID guid)
535 {
536 char szName[40];
537
538 TRACE("(%s)\n", debugstr_guid(guid));
539
540 /* Create a named semaphore using the GUID string */
541 SHStringFromGUIDA(guid, szName, sizeof(szName) - 1);
542 return SHGlobalCounterCreateNamedA(szName, 0);
543 }