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