Keep track of per-column information inside the listview.
[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
34 WINE_DEFAULT_DEBUG_CHANNEL(shell);
35
36 /* Get a function pointer from a DLL handle */
37 #define GET_FUNC(func, module, name, fail) \
38   do { \
39     if (!func) { \
40       if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
41       if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \
42     } \
43   } while (0)
44
45 /* DLL handles for late bound calls */
46 extern HMODULE SHLWAPI_hshell32;
47
48 /* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
49 static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**);
50
51 extern DWORD SHLWAPI_ThreadRef_index;  /* Initialised in shlwapi_main.c */
52
53 DWORD WINAPI SHLWAPI_23(REFGUID,LPSTR,INT);
54
55 /**************************************************************************
56  *      @       [SHLWAPI.356]
57  *
58  * Initialise security attributes from a security descriptor.
59  *
60  * PARAMS
61  *  lpAttr [O] Security attributes
62  *  lpSec  [I] Security descriptor
63  *
64  * RETURNS
65  *  Success: lpAttr, initialised using lpSec.
66  *  Failure: NULL, if any parameters are invalid.
67  *
68  * NOTES
69  *  This function always returns returns NULL if the underlying OS version
70  *  Wine is impersonating does not use security descriptors (i.e. anything
71  *  before Windows NT).
72  */
73 LPSECURITY_ATTRIBUTES
74 WINAPI SHLWAPI_356(LPSECURITY_ATTRIBUTES lpAttr, PSECURITY_DESCRIPTOR lpSec)
75 {
76   /* This function is used within SHLWAPI only to create security attributes
77    * for shell semaphores. */
78
79   TRACE("(%p,%p)\n", lpAttr, lpSec);
80
81   if (!(GetVersion() & 0x80000000))  /* NT */
82   {
83     if (!lpSec || !lpAttr)
84       return NULL;
85
86     if (InitializeSecurityDescriptor(lpSec, 1))
87     {
88       if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE))
89       {
90          lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
91          lpAttr->lpSecurityDescriptor = lpSec;
92          lpAttr->bInheritHandle = FALSE;
93          return lpAttr;
94       }
95     }
96   }
97   return NULL;
98 }
99
100 /*************************************************************************
101  *      _SHGetInstanceExplorer  [SHLWAPI.@]
102  *
103  * Get an interface to the shell explorer.
104  *
105  * PARAMS
106  *  lpUnknown [O] pointer to recieve interface.
107  *
108  * RETURNS
109  *  Success: S_OK. lppUnknown contains the explorer interface.
110  *  Failure: An HRESULT error code.
111  */
112 HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown)
113 {
114   /* This function is used within SHLWAPI only to hold the IE reference
115    * for threads created with the CTF_PROCESS_REF flag set. */
116
117   GET_FUNC(pSHGetInstanceExplorer, shell32, "SHGetInstanceExplorer", E_FAIL);
118   return pSHGetInstanceExplorer(lppUnknown);
119 }
120
121 /* Internal thread information structure */
122 typedef struct tagSHLWAPI_THREAD_INFO
123 {
124   LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */
125   LPTHREAD_START_ROUTINE pfnCallback;   /* Thread initialisation */
126   PVOID     pData;                      /* Application specific data */
127   BOOL      bInitCom;                   /* Initialise COM for the thread? */
128   HANDLE    hEvent;                     /* Signal for creator to continue */
129   IUnknown *refThread;                  /* Reference to thread creator */
130   IUnknown *refIE;                      /* Reference to the IE process */
131 } SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO;
132
133
134 /*************************************************************************
135  * SHGetThreadRef       [SHLWAPI.@]
136  *
137  * Get a per-thread object reference set by SHSetThreadRef.
138  *
139  * PARAMS
140  *   lppUnknown [O] Destination to receive object reference
141  *
142  * RETURNS
143  *   Success: S_OK. lppUnk is set to the object reference.
144  *   Failure: E_NOINTERFACE, if an error occurs or lppUnk is invalid.
145  */
146 HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown)
147 {
148   TRACE("(%p)\n", lppUnknown);
149
150   if (!lppUnknown || SHLWAPI_ThreadRef_index == -1u)
151     return E_NOINTERFACE;
152
153   *lppUnknown = (IUnknown*)TlsGetValue(SHLWAPI_ThreadRef_index);
154   if (!*lppUnknown)
155     return E_NOINTERFACE;
156
157   /* Add a reference. Caller will Release() us when finished */
158   IUnknown_AddRef(*lppUnknown);
159   return S_OK;
160 }
161
162 /*************************************************************************
163  * SHSetThreadRef       [SHLWAPI.@]
164  *
165  * Store a per-thread object reference.
166  *
167  * PARAMS
168  *   lpUnk [I] Object reference to store
169  *
170  * RETURNS
171  *   Success: S_OK. lpUnk is stored and can be retrieved by SHGetThreadRef()
172  *   Failure: E_NOINTERFACE, if an error occurs or lpUnk is invalid.
173  */
174 HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown)
175 {
176   TRACE("(%p)\n", lpUnknown);
177
178   if (!lpUnknown || SHLWAPI_ThreadRef_index  == 0xffffffff)
179     return E_NOINTERFACE;
180
181   TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown);
182   return S_OK;
183 }
184
185 /*************************************************************************
186  * SHReleaseThreadRef   [SHLWAPI.@]
187  *
188  * Release a per-thread object reference.
189  *
190  * PARAMS
191  *  None.
192  *
193  * RETURNS
194  *   Success: S_OK. The threads obbject reference is released.
195  *   Failure: An HRESULT error code.
196  */
197 HRESULT WINAPI SHReleaseThreadRef()
198 {
199   FIXME("() - stub!\n");
200   return S_OK;
201 }
202
203 /*************************************************************************
204  * SHLWAPI_ThreadWrapper
205  *
206  * Internal wrapper for executing user thread functions from SHCreateThread.
207  */
208 static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi)
209 {
210   SHLWAPI_THREAD_INFO ti;
211   HRESULT hCom = E_FAIL;
212   DWORD dwRet;
213
214   TRACE("(%p)", pTi);
215
216   /* We are now executing in the context of the newly created thread.
217    * So we copy the data passed to us (it is on the stack of the function
218    * that called us, which is waiting for us to signal an event before
219    * returning). */
220   memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO));
221
222   /* Initialise COM for the thread, if desired */
223   if (ti.bInitCom)
224   {
225     hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE);
226
227     if (FAILED(hCom))
228       hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
229   }
230
231   /* Execute the callback function before returning */
232   if (ti.pfnCallback)
233     ti.pfnCallback(ti.pData);
234
235   /* Signal the thread that created us; it can return now */
236   SetEvent(ti.hEvent);
237
238   /* Execute the callers start code */
239   dwRet = ti.pfnThreadProc(ti.pData);
240
241   /* Release references to the caller and IE process, if held */
242   if (ti.refThread)
243     IUnknown_Release(ti.refThread);
244
245   if (ti.refIE)
246     IUnknown_Release(ti.refIE);
247
248   if (SUCCEEDED(hCom))
249     CoUninitialize();
250
251   /* Return the users thread return value */
252   return dwRet;
253 }
254
255 /*************************************************************************
256  *      @       [SHLWAPI.16]
257  *
258  * SHCreateThread
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] Initialisation to perform in the new thread
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  *      @       [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 DWORD WINAPI SHLWAPI_223(HANDLE hSem)
353 {
354   DWORD dwOldCount = 0;
355
356   TRACE("(0x%08x)\n", hSem);
357   ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */
358   WaitForSingleObject(hSem, 0);           /* -1 */
359   return dwOldCount;
360 }
361
362 /*************************************************************************
363  *      @       [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 DWORD WINAPI SHLWAPI_224(HANDLE hSem)
374 {
375   DWORD dwOldCount = 0;
376
377   TRACE("(0x%08x)\n", hSem);
378   ReleaseSemaphore(hSem, 1, &dwOldCount);
379   return dwOldCount + 1;
380 }
381
382 /*************************************************************************
383  *      @       [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 SHLWAPI_424(HANDLE hSem)
394 {
395   DWORD dwOldCount = 0;
396
397   TRACE("(0x%08x)\n", hSem);
398
399   dwOldCount = SHLWAPI_223(hSem);
400   WaitForSingleObject(hSem, 0);
401   return dwOldCount - 1;
402 }
403
404 /*************************************************************************
405  *      @       [SHLWAPI.423]
406  *
407  * Unicode version of SHLWAPI_422.
408  */
409 HANDLE WINAPI SHLWAPI_423(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 = SHLWAPI_356(&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  *      @       [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 SHLWAPI_422(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 SHLWAPI_423(lpszName ? szBuff : NULL, iInitial);
455 }
456
457 /*************************************************************************
458  *      @       [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 SHLWAPI_222(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   SHLWAPI_23(guid, szName, sizeof(szName) - 1);
479   return SHLWAPI_422(szName, 0);
480 }