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