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