2 * SHLWAPI thread and MT synchronisation functions
4 * Copyright 2002 Juergen Schmied
5 * Copyright 2002 Jon Griffiths
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(shell);
41 extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */
43 INT WINAPI SHStringFromGUIDA(REFGUID,LPSTR,INT);
45 /**************************************************************************
46 * CreateAllAccessSecurityAttributes [SHLWAPI.356]
48 * Initialise security attributes from a security descriptor.
51 * lpAttr [O] Security attributes
52 * lpSec [I] Security descriptor
55 * Success: lpAttr, initialised using lpSec.
56 * Failure: NULL, if any parameters are invalid.
59 * This function always returns NULL if the underlying OS version
60 * Wine is impersonating does not use security descriptors (i.e. anything
63 LPSECURITY_ATTRIBUTES WINAPI CreateAllAccessSecurityAttributes(
64 LPSECURITY_ATTRIBUTES lpAttr,
65 PSECURITY_DESCRIPTOR lpSec,
68 /* This function is used within SHLWAPI only to create security attributes
69 * for shell semaphores. */
71 TRACE("(%p,%p,%08x)\n", lpAttr, lpSec, p3);
73 if (!(GetVersion() & 0x80000000)) /* NT */
75 if (!lpSec || !lpAttr)
78 if (InitializeSecurityDescriptor(lpSec, 1))
80 if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE))
82 lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
83 lpAttr->lpSecurityDescriptor = lpSec;
84 lpAttr->bInheritHandle = FALSE;
92 /*************************************************************************
93 * _SHGetInstanceExplorer [SHLWAPI.@]
95 * Get an interface to the shell explorer.
98 * lppUnknown [O] Destination for explorers IUnknown interface.
101 * Success: S_OK. lppUnknown contains the explorer interface.
102 * Failure: An HRESULT error code.
104 HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown)
106 /* This function is used within SHLWAPI only to hold the IE reference
107 * for threads created with the CTF_PROCESS_REF flag set. */
108 return SHGetInstanceExplorer(lppUnknown);
111 /* Internal thread information structure */
112 typedef struct tagSHLWAPI_THREAD_INFO
114 LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */
115 LPTHREAD_START_ROUTINE pfnCallback; /* Thread initialisation */
116 PVOID pData; /* Application specific data */
117 BOOL bInitCom; /* Initialise COM for the thread? */
118 HANDLE hEvent; /* Signal for creator to continue */
119 IUnknown *refThread; /* Reference to thread creator */
120 IUnknown *refIE; /* Reference to the IE process */
121 } SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO;
125 IUnknown IUnknown_iface;
129 static inline threadref *impl_from_IUnknown(IUnknown *iface)
131 return CONTAINING_RECORD(iface, threadref, IUnknown_iface);
134 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj)
136 threadref * This = impl_from_IUnknown(iface);
138 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObj);
143 if (IsEqualGUID(&IID_IUnknown, riid)) {
144 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObj);
146 IUnknown_AddRef((IUnknown*)*ppvObj);
151 FIXME("(%p, %s, %p) interface not supported\n", This, debugstr_guid(riid), ppvObj);
152 return E_NOINTERFACE;
155 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
157 threadref * This = impl_from_IUnknown(iface);
159 TRACE("(%p)\n", This);
160 return InterlockedIncrement(This->ref);
163 static ULONG WINAPI threadref_Release(IUnknown *iface)
166 threadref * This = impl_from_IUnknown(iface);
168 TRACE("(%p)\n", This);
170 refcount = InterlockedDecrement(This->ref);
172 HeapFree(GetProcessHeap(), 0, This);
178 static const IUnknownVtbl threadref_vt =
180 threadref_QueryInterface,
185 /*************************************************************************
186 * SHCreateThreadRef [SHLWAPI.@]
188 * Create a per-thread IUnknown object
191 * lprefcount [I] Pointer to a LONG to be used as refcount
192 * lppUnknown [O] Destination to receive the created object reference
195 * Success: S_OK. lppUnknown is set to the object reference.
196 * Failure: E_INVALIDARG, if a parameter is NULL
198 HRESULT WINAPI SHCreateThreadRef(LONG *lprefcount, IUnknown **lppUnknown)
201 TRACE("(%p, %p)\n", lprefcount, lppUnknown);
203 if (!lprefcount || !lppUnknown)
206 This = HeapAlloc(GetProcessHeap(), 0, sizeof(threadref));
207 This->IUnknown_iface.lpVtbl = &threadref_vt;
208 This->ref = lprefcount;
211 *lppUnknown = &This->IUnknown_iface;
212 TRACE("=> returning S_OK with %p\n", This);
216 /*************************************************************************
217 * SHGetThreadRef [SHLWAPI.@]
219 * Get a per-thread object reference set by SHSetThreadRef().
222 * lppUnknown [O] Destination to receive object reference
225 * Success: S_OK. lppUnknown is set to the object reference.
226 * Failure: E_NOINTERFACE, if an error occurs or no object is set
228 HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown)
230 TRACE("(%p)\n", lppUnknown);
232 if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES)
233 return E_NOINTERFACE;
235 *lppUnknown = TlsGetValue(SHLWAPI_ThreadRef_index);
237 return E_NOINTERFACE;
239 /* Add a reference. Caller will Release() us when finished */
240 IUnknown_AddRef(*lppUnknown);
244 /*************************************************************************
245 * SHSetThreadRef [SHLWAPI.@]
247 * Store a per-thread object reference.
250 * lpUnknown [I] Object reference to store
253 * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef()
254 * Failure: E_NOINTERFACE, if an error occurs
256 HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown)
258 TRACE("(%p)\n", lpUnknown);
260 if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES)
261 return E_NOINTERFACE;
263 TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown);
267 /*************************************************************************
268 * SHReleaseThreadRef [SHLWAPI.@]
270 * Release a per-thread object reference.
276 * Success: S_OK. The threads object reference is released.
277 * Failure: An HRESULT error code.
279 HRESULT WINAPI SHReleaseThreadRef(void)
281 FIXME("() - stub!\n");
285 /*************************************************************************
286 * SHLWAPI_ThreadWrapper
288 * Internal wrapper for executing user thread functions from SHCreateThread.
290 static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi)
292 SHLWAPI_THREAD_INFO ti;
293 HRESULT hCom = E_FAIL;
296 TRACE("(%p)\n", pTi);
298 /* We are now executing in the context of the newly created thread.
299 * So we copy the data passed to us (it is on the stack of the function
300 * that called us, which is waiting for us to signal an event before
302 memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO));
304 /* Initialise COM for the thread, if desired */
307 hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE);
310 hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
313 /* Execute the callback function before returning */
315 ti.pfnCallback(ti.pData);
317 /* Signal the thread that created us; it can return now */
320 /* Execute the callers start code */
321 dwRet = ti.pfnThreadProc(ti.pData);
323 /* Release references to the caller and IE process, if held */
325 IUnknown_Release(ti.refThread);
328 IUnknown_Release(ti.refIE);
333 /* Return the users thread return value */
337 /*************************************************************************
338 * SHCreateThread [SHLWAPI.16]
340 * Create a new thread.
343 * pfnThreadProc [I] Function to execute in new thread
344 * pData [I] Application specific data passed to pfnThreadProc
345 * dwFlags [I] CTF_ flags from "shlwapi.h"
346 * pfnCallback [I] Function to execute before pfnThreadProc
349 * Success: TRUE. pfnThreadProc was executed.
350 * Failure: FALSE. pfnThreadProc was not executed.
353 * If the thread cannot be created, pfnCallback is NULL, and dwFlags
354 * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously.
356 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData,
357 DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback)
359 SHLWAPI_THREAD_INFO ti;
360 BOOL bCalled = FALSE;
362 TRACE("(%p,%p,0x%X,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback);
364 /* Set up data to pass to the new thread (On our stack) */
365 ti.pfnThreadProc = pfnThreadProc;
366 ti.pfnCallback = pfnCallback;
368 ti.bInitCom = (dwFlags & CTF_COINIT) != 0;
369 ti.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
371 /* Hold references to the current thread and IE process, if desired */
372 if(dwFlags & CTF_THREAD_REF)
373 SHGetThreadRef(&ti.refThread);
377 if(dwFlags & CTF_PROCESS_REF)
378 _SHGetInstanceExplorer(&ti.refIE);
382 /* Create the thread */
388 hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal);
392 /* Wait for the thread to signal us to continue */
393 WaitForSingleObject(ti.hEvent, INFINITE);
394 CloseHandle(hThread);
397 CloseHandle(ti.hEvent);
402 if (!ti.pfnCallback && dwFlags & CTF_INSIST)
404 /* Couldn't call, call synchronously */
405 pfnThreadProc(pData);
410 /* Free references, since thread hasn't run to do so */
412 IUnknown_Release(ti.refThread);
415 IUnknown_Release(ti.refIE);
421 /*************************************************************************
422 * SHGlobalCounterGetValue [SHLWAPI.223]
424 * Get the current count of a semaphore.
427 * hSem [I] Semaphore handle
430 * The current count of the semaphore.
432 LONG WINAPI SHGlobalCounterGetValue(HANDLE hSem)
436 TRACE("(%p)\n", hSem);
437 ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */
438 WaitForSingleObject(hSem, 0); /* -1 */
442 /*************************************************************************
443 * SHGlobalCounterIncrement [SHLWAPI.224]
448 * hSem [I] Semaphore handle
451 * The new count of the semaphore.
453 LONG WINAPI SHGlobalCounterIncrement(HANDLE hSem)
457 TRACE("(%p)\n", hSem);
458 ReleaseSemaphore(hSem, 1, &dwOldCount);
459 return dwOldCount + 1;
462 /*************************************************************************
463 * SHGlobalCounterDecrement [SHLWAPI.424]
465 * Release a semaphore.
468 * hSem [I] Semaphore handle
471 * The new count of the semaphore.
473 DWORD WINAPI SHGlobalCounterDecrement(HANDLE hSem)
475 DWORD dwOldCount = 0;
477 TRACE("(%p)\n", hSem);
479 dwOldCount = SHGlobalCounterGetValue(hSem);
480 WaitForSingleObject(hSem, 0);
481 return dwOldCount - 1;
484 /*************************************************************************
485 * SHGlobalCounterCreateNamedW [SHLWAPI.423]
487 * Unicode version of SHGlobalCounterCreateNamedA.
489 HANDLE WINAPI SHGlobalCounterCreateNamedW(LPCWSTR lpszName, DWORD iInitial)
491 static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' };
492 const int iPrefixLen = 6;
493 WCHAR szBuff[MAX_PATH];
494 const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR);
495 SECURITY_DESCRIPTOR sd;
496 SECURITY_ATTRIBUTES sAttr, *pSecAttr;
499 TRACE("(%s,%d)\n", debugstr_w(lpszName), iInitial);
501 /* Create Semaphore name */
502 memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR));
504 StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen);
506 /* Initialise security attributes */
507 pSecAttr = CreateAllAccessSecurityAttributes(&sAttr, &sd, 0);
509 if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff)))
510 hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff);
514 /*************************************************************************
515 * SHGlobalCounterCreateNamedA [SHLWAPI.422]
517 * Create a semaphore.
520 * lpszName [I] Name of semaphore
521 * iInitial [I] Initial count for semaphore
524 * A new semaphore handle.
526 HANDLE WINAPI SHGlobalCounterCreateNamedA(LPCSTR lpszName, DWORD iInitial)
528 WCHAR szBuff[MAX_PATH];
530 TRACE("(%s,%d)\n", debugstr_a(lpszName), iInitial);
533 MultiByteToWideChar(CP_ACP, 0, lpszName, -1, szBuff, MAX_PATH);
534 return SHGlobalCounterCreateNamedW(lpszName ? szBuff : NULL, iInitial);
537 /*************************************************************************
538 * SHGlobalCounterCreate [SHLWAPI.222]
540 * Create a semaphore using the name of a GUID.
543 * guid [I] GUID to use as semaphore name
546 * A handle to the semaphore.
549 * The initial count of the semaphore is set to 0.
551 HANDLE WINAPI SHGlobalCounterCreate (REFGUID guid)
555 TRACE("(%s)\n", debugstr_guid(guid));
557 /* Create a named semaphore using the GUID string */
558 SHStringFromGUIDA(guid, szName, sizeof(szName) - 1);
559 return SHGlobalCounterCreateNamedA(szName, 0);