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