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