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