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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
35 WINE_DEFAULT_DEBUG_CHANNEL(shell);
37 extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */
39 static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**);
41 DWORD WINAPI SHLWAPI_23(REFGUID,LPSTR,INT);
43 /**************************************************************************
46 * Initialise security attributes from a security descriptor.
49 * lpAttr [O] Security attributes
50 * lpSec [I] Security descriptor
53 * Success: lpAttr, initialised using lpSec.
54 * Failure: NULL, if any parameters are invalid.
57 * This function always returns returns NULL if the underlying OS version
58 * Wine is impersonating does not use security descriptors (i.e. anything
62 WINAPI SHLWAPI_356(LPSECURITY_ATTRIBUTES lpAttr, PSECURITY_DESCRIPTOR lpSec)
64 /* This function is used within SHLWAPI only to create security attributes
65 * for shell semaphores. */
67 TRACE("(%p,%p)\n", lpAttr, lpSec);
69 if (0) /* FIXME: SHWAPI_OsIsUnicode, as per shell32 */
71 if (!lpSec || !lpAttr)
74 if (InitializeSecurityDescriptor(lpSec, 1))
76 if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE))
78 lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES);
79 lpAttr->lpSecurityDescriptor = lpSec;
80 lpAttr->bInheritHandle = FALSE;
88 /*************************************************************************
89 * _SHGetInstanceExplorer [SHLWAPI.@]
91 * Get an interface to the shell explorer.
94 * lpUnknown [O] pointer to recieve interface.
97 * Success: S_OK. lppUnknown contains the explorer interface.
98 * Failure: An HRESULT error code.
100 HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown)
102 /* This function is used within SHLWAPI only to hold the IE reference
103 * for threads created with the CTF_PROCESS_REF flag set. */
105 GET_FUNC(pSHGetInstanceExplorer, shell32, "SHGetInstanceExplorer", E_FAIL);
106 return pSHGetInstanceExplorer(lppUnknown);
109 /* Internal thread information structure */
110 typedef struct tagSHLWAPI_THREAD_INFO
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;
122 /*************************************************************************
123 * SHGetThreadRef [SHLWAPI.@]
125 * Get a per-thread object reference set by SHSetThreadRef.
128 * lppUnknown [O] Destination to receive object reference
131 * Success: S_OK. lppUnk is set to the object reference.
132 * Failure: E_NOINTERFACE, if an error occurs or lppUnk is invalid.
134 HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown)
136 TRACE("(%p)\n", lppUnknown);
138 if (!lppUnknown || SHLWAPI_ThreadRef_index == -1u)
139 return E_NOINTERFACE;
141 *lppUnknown = (IUnknown*)TlsGetValue(SHLWAPI_ThreadRef_index);
143 return E_NOINTERFACE;
145 /* Add a reference. Caller will Release() us when finished */
146 IUnknown_AddRef(*lppUnknown);
150 /*************************************************************************
151 * SHSetThreadRef [SHLWAPI.@]
153 * Store a per-thread object reference.
156 * lpUnk [I] Object reference to store
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.
162 HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown)
164 TRACE("(%p)\n", lpUnknown);
166 if (!lpUnknown || SHLWAPI_ThreadRef_index == 0xffffffff)
167 return E_NOINTERFACE;
169 TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown);
173 /*************************************************************************
174 * SHReleaseThreadRef [SHLWAPI.@]
176 * Release a per-thread object reference.
182 * Success: S_OK. The threads obbject reference is released.
183 * Failure: An HRESULT error code.
185 HRESULT WINAPI SHReleaseThreadRef()
187 FIXME("() - stub!\n");
191 /*************************************************************************
192 * SHLWAPI_ThreadWrapper
194 * Internal wrapper for executing user thread functions from SHCreateThread.
196 static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi)
198 SHLWAPI_THREAD_INFO ti;
199 HRESULT hCom = E_FAIL;
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
208 memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO));
210 /* Initialise COM for the thread, if desired */
213 hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE);
216 hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE);
219 /* Execute the callback function before returning */
221 ti.pfnCallback(ti.pData);
223 /* Signal the thread that created us; it can return now */
226 /* Execute the callers start code */
227 dwRet = ti.pfnThreadProc(ti.pData);
229 /* Release references to the caller and IE process, if held */
231 IUnknown_Release(ti.refThread);
234 IUnknown_Release(ti.refIE);
239 /* Return the users thread return value */
243 /*************************************************************************
248 * Create a new thread.
251 * pfnThreadProc [I] Function to execute in new thread
252 * pData [I] Application specific data passed to pfnThreadProc
253 * dwFlags [I] Initialisation to perform in the new thread
254 * pfnCallback [I] Function to execute before pfnThreadProc
257 * Success: TRUE. pfnThreadProc was executed.
258 * Failure: FALSE. pfnThreadProc was not executed.
261 * If the thread cannot be created, pfnCallback is NULL, and dwFlags
262 * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously.
264 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData,
265 DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback)
267 SHLWAPI_THREAD_INFO ti;
268 BOOL bCalled = FALSE;
270 TRACE("(%p,%p,0x%lX,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback);
272 /* Set up data to pass to the new thread (On our stack) */
273 ti.pfnThreadProc = pfnThreadProc;
274 ti.pfnCallback = pfnCallback;
276 ti.bInitCom = dwFlags & CTF_COINIT ? TRUE : FALSE;
277 ti.hEvent = CreateEventA(NULL,FALSE,FALSE,NULL);
279 /* Hold references to the current thread and IE process, if desired */
280 if(dwFlags & CTF_THREAD_REF)
281 SHGetThreadRef(&ti.refThread);
285 if(dwFlags & CTF_PROCESS_REF)
286 _SHGetInstanceExplorer(&ti.refIE);
290 /* Create the thread */
296 hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal);
300 /* Wait for the thread to signal us to continue */
301 WaitForSingleObject(ti.hEvent, -1);
302 CloseHandle(hThread);
305 CloseHandle(ti.hEvent);
310 if (!ti.pfnCallback && dwFlags & CTF_INSIST)
312 /* Couldn't call, call synchronously */
313 pfnThreadProc(pData);
318 /* Free references, since thread hasn't run to do so */
320 IUnknown_Release(ti.refThread);
323 IUnknown_Release(ti.refIE);
329 /*************************************************************************
332 * Get the current count of a semaphore.
335 * hSem [I] Semaphore handle
338 * The current count of the semaphore.
340 DWORD WINAPI SHLWAPI_223(HANDLE hSem)
342 DWORD dwOldCount = 0;
344 TRACE("(0x%08x)\n", hSem);
345 ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */
346 WaitForSingleObject(hSem, 0); /* -1 */
350 /*************************************************************************
356 * hSem [I] Semaphore handle
359 * The new count of the semaphore.
361 DWORD WINAPI SHLWAPI_224(HANDLE hSem)
363 DWORD dwOldCount = 0;
365 TRACE("(0x%08x)\n", hSem);
366 ReleaseSemaphore(hSem, 1, &dwOldCount);
367 return dwOldCount + 1;
370 /*************************************************************************
373 * Release a semaphore.
376 * hSem [I] Semaphore handle
379 * The new count of the semaphore.
381 DWORD WINAPI SHLWAPI_424(HANDLE hSem)
383 DWORD dwOldCount = 0;
385 TRACE("(0x%08x)\n", hSem);
387 dwOldCount = SHLWAPI_223(hSem);
388 WaitForSingleObject(hSem, 0);
389 return dwOldCount - 1;
392 /*************************************************************************
395 * Unicode version of SHLWAPI_422.
397 HANDLE WINAPI SHLWAPI_423(LPCWSTR lpszName, DWORD iInitial)
399 static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' };
400 const int iPrefixLen = 6;
401 WCHAR szBuff[MAX_PATH];
402 const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR);
403 SECURITY_DESCRIPTOR sd;
404 SECURITY_ATTRIBUTES sAttr, *pSecAttr;
407 TRACE("(%s,%ld)\n", debugstr_w(lpszName), iInitial);
409 /* Create Semaphore name */
410 memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR));
412 StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen);
414 /* Initialise security attributes */
415 pSecAttr = SHLWAPI_356(&sAttr, &sd);
417 if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff)))
418 hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff);
422 /*************************************************************************
425 * Create a semaphore.
428 * lpszName [I] Name of semaphore
429 * iInitial [I] Initial count for semaphore
432 * A new semaphore handle.
434 HANDLE WINAPI SHLWAPI_422(LPCSTR lpszName, DWORD iInitial)
436 WCHAR szBuff[MAX_PATH];
438 TRACE("(%s,%ld)\n", debugstr_a(lpszName), iInitial);
441 MultiByteToWideChar(0, 0, lpszName, -1, szBuff, MAX_PATH);
442 return SHLWAPI_423(lpszName ? szBuff : NULL, iInitial);
445 /*************************************************************************
448 * Create a semaphore using the name of a GUID.
451 * guid [I] GUID to use as semaphore name
454 * A handle to the semaphore.
457 * The initial count of the semaphore is set to 0.
459 HANDLE WINAPI SHLWAPI_222(REFGUID guid)
463 TRACE("(%s)\n", debugstr_guid(guid));
465 /* Create a named semaphore using the GUID string */
466 SHLWAPI_23(guid, szName, sizeof(szName) - 1);
467 return SHLWAPI_422(szName, 0);