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