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