ole32: Release the global interface table in the tests when it is no longer needed.
[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 "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,%08x)\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  == TLS_OUT_OF_INDEXES)
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%X,%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,%d)\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,%d)\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 }