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