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
29 #include "wine/debug.h"
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 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
39 /* Get a function pointer from a DLL handle */
40 #define GET_FUNC(func, module, name, fail) \
43 if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
44 if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \
48 /* DLL handles for late bound calls */
49 extern HMODULE SHLWAPI_hshell32
;
51 /* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
52 static HRESULT (WINAPI
*pSHGetInstanceExplorer
)(IUnknown
**);
54 extern DWORD SHLWAPI_ThreadRef_index
; /* Initialised in shlwapi_main.c */
56 DWORD WINAPI
SHStringFromGUIDA(REFGUID
,LPSTR
,INT
);
58 /**************************************************************************
59 * _CreateAllAccessSecurityAttributes [SHLWAPI.356]
61 * Initialise security attributes from a security descriptor.
64 * lpAttr [O] Security attributes
65 * lpSec [I] Security descriptor
68 * Success: lpAttr, initialised using lpSec.
69 * Failure: NULL, if any parameters are invalid.
72 * This function always returns NULL if the underlying OS version
73 * Wine is impersonating does not use security descriptors (i.e. anything
76 LPSECURITY_ATTRIBUTES WINAPI
_CreateAllAccessSecurityAttributes(
77 LPSECURITY_ATTRIBUTES lpAttr
,
78 PSECURITY_DESCRIPTOR lpSec
,
81 /* This function is used within SHLWAPI only to create security attributes
82 * for shell semaphores. */
84 TRACE("(%p,%p,%08lx)\n", lpAttr
, lpSec
, p3
);
86 if (!(GetVersion() & 0x80000000)) /* NT */
88 if (!lpSec
|| !lpAttr
)
91 if (InitializeSecurityDescriptor(lpSec
, 1))
93 if (SetSecurityDescriptorDacl(lpSec
, TRUE
, NULL
, FALSE
))
95 lpAttr
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
96 lpAttr
->lpSecurityDescriptor
= lpSec
;
97 lpAttr
->bInheritHandle
= FALSE
;
105 /*************************************************************************
106 * _SHGetInstanceExplorer [SHLWAPI.@]
108 * Get an interface to the shell explorer.
111 * lppUnknown [O] Destination for explorers IUnknown interface.
114 * Success: S_OK. lppUnknown contains the explorer interface.
115 * Failure: An HRESULT error code.
117 HRESULT WINAPI
_SHGetInstanceExplorer(IUnknown
**lppUnknown
)
119 /* This function is used within SHLWAPI only to hold the IE reference
120 * for threads created with the CTF_PROCESS_REF flag set. */
122 GET_FUNC(pSHGetInstanceExplorer
, shell32
, "SHGetInstanceExplorer", E_FAIL
);
123 return pSHGetInstanceExplorer(lppUnknown
);
126 /* Internal thread information structure */
127 typedef struct tagSHLWAPI_THREAD_INFO
129 LPTHREAD_START_ROUTINE pfnThreadProc
; /* Thread start */
130 LPTHREAD_START_ROUTINE pfnCallback
; /* Thread initialisation */
131 PVOID pData
; /* Application specific data */
132 BOOL bInitCom
; /* Initialise COM for the thread? */
133 HANDLE hEvent
; /* Signal for creator to continue */
134 IUnknown
*refThread
; /* Reference to thread creator */
135 IUnknown
*refIE
; /* Reference to the IE process */
136 } SHLWAPI_THREAD_INFO
, *LPSHLWAPI_THREAD_INFO
;
139 /*************************************************************************
140 * SHGetThreadRef [SHLWAPI.@]
142 * Get a per-thread object reference set by SHSetThreadRef().
145 * lppUnknown [O] Destination to receive object reference
148 * Success: S_OK. lppUnknown is set to the object reference.
149 * Failure: E_NOINTERFACE, if an error occurs or lppUnknown is NULL.
151 HRESULT WINAPI
SHGetThreadRef(IUnknown
**lppUnknown
)
153 TRACE("(%p)\n", lppUnknown
);
155 if (!lppUnknown
|| SHLWAPI_ThreadRef_index
== TLS_OUT_OF_INDEXES
)
156 return E_NOINTERFACE
;
158 *lppUnknown
= (IUnknown
*)TlsGetValue(SHLWAPI_ThreadRef_index
);
160 return E_NOINTERFACE
;
162 /* Add a reference. Caller will Release() us when finished */
163 IUnknown_AddRef(*lppUnknown
);
167 /*************************************************************************
168 * SHSetThreadRef [SHLWAPI.@]
170 * Store a per-thread object reference.
173 * lpUnknown [I] Object reference to store
176 * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef()
177 * Failure: E_NOINTERFACE, if an error occurs or lpUnknown is NULL.
179 HRESULT WINAPI
SHSetThreadRef(IUnknown
*lpUnknown
)
181 TRACE("(%p)\n", lpUnknown
);
183 if (!lpUnknown
|| SHLWAPI_ThreadRef_index
== 0xffffffff)
184 return E_NOINTERFACE
;
186 TlsSetValue(SHLWAPI_ThreadRef_index
, lpUnknown
);
190 /*************************************************************************
191 * SHReleaseThreadRef [SHLWAPI.@]
193 * Release a per-thread object reference.
199 * Success: S_OK. The threads object reference is released.
200 * Failure: An HRESULT error code.
202 HRESULT WINAPI
SHReleaseThreadRef()
204 FIXME("() - stub!\n");
208 /*************************************************************************
209 * SHLWAPI_ThreadWrapper
211 * Internal wrapper for executing user thread functions from SHCreateThread.
213 static DWORD WINAPI
SHLWAPI_ThreadWrapper(PVOID pTi
)
215 SHLWAPI_THREAD_INFO ti
;
216 HRESULT hCom
= E_FAIL
;
219 TRACE("(%p)\n", pTi
);
221 /* We are now executing in the context of the newly created thread.
222 * So we copy the data passed to us (it is on the stack of the function
223 * that called us, which is waiting for us to signal an event before
225 memcpy(&ti
, pTi
, sizeof(SHLWAPI_THREAD_INFO
));
227 /* Initialise COM for the thread, if desired */
230 hCom
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
|COINIT_DISABLE_OLE1DDE
);
233 hCom
= CoInitializeEx(NULL
, COINIT_DISABLE_OLE1DDE
);
236 /* Execute the callback function before returning */
238 ti
.pfnCallback(ti
.pData
);
240 /* Signal the thread that created us; it can return now */
243 /* Execute the callers start code */
244 dwRet
= ti
.pfnThreadProc(ti
.pData
);
246 /* Release references to the caller and IE process, if held */
248 IUnknown_Release(ti
.refThread
);
251 IUnknown_Release(ti
.refIE
);
256 /* Return the users thread return value */
260 /*************************************************************************
261 * SHCreateThread [SHLWAPI.16]
263 * Create a new thread.
266 * pfnThreadProc [I] Function to execute in new thread
267 * pData [I] Application specific data passed to pfnThreadProc
268 * dwFlags [I] CTF_ flags from "shlwapi.h"
269 * pfnCallback [I] Function to execute before pfnThreadProc
272 * Success: TRUE. pfnThreadProc was executed.
273 * Failure: FALSE. pfnThreadProc was not executed.
276 * If the thread cannot be created, pfnCallback is NULL, and dwFlags
277 * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously.
279 BOOL WINAPI
SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc
, VOID
*pData
,
280 DWORD dwFlags
, LPTHREAD_START_ROUTINE pfnCallback
)
282 SHLWAPI_THREAD_INFO ti
;
283 BOOL bCalled
= FALSE
;
285 TRACE("(%p,%p,0x%lX,%p)\n", pfnThreadProc
, pData
, dwFlags
, pfnCallback
);
287 /* Set up data to pass to the new thread (On our stack) */
288 ti
.pfnThreadProc
= pfnThreadProc
;
289 ti
.pfnCallback
= pfnCallback
;
291 ti
.bInitCom
= dwFlags
& CTF_COINIT
? TRUE
: FALSE
;
292 ti
.hEvent
= CreateEventW(NULL
,FALSE
,FALSE
,NULL
);
294 /* Hold references to the current thread and IE process, if desired */
295 if(dwFlags
& CTF_THREAD_REF
)
296 SHGetThreadRef(&ti
.refThread
);
300 if(dwFlags
& CTF_PROCESS_REF
)
301 _SHGetInstanceExplorer(&ti
.refIE
);
305 /* Create the thread */
311 hThread
= CreateThread(NULL
, 0, SHLWAPI_ThreadWrapper
, &ti
, 0, &dwRetVal
);
315 /* Wait for the thread to signal us to continue */
316 WaitForSingleObject(ti
.hEvent
, INFINITE
);
317 CloseHandle(hThread
);
320 CloseHandle(ti
.hEvent
);
325 if (!ti
.pfnCallback
&& dwFlags
& CTF_INSIST
)
327 /* Couldn't call, call synchronously */
328 pfnThreadProc(pData
);
333 /* Free references, since thread hasn't run to do so */
335 IUnknown_Release(ti
.refThread
);
338 IUnknown_Release(ti
.refIE
);
344 /*************************************************************************
345 * _SHGlobalCounterGetValue [SHLWAPI.223]
347 * Get the current count of a semaphore.
350 * hSem [I] Semaphore handle
353 * The current count of the semaphore.
355 LONG WINAPI
_SHGlobalCounterGetValue(HANDLE hSem
)
359 TRACE("(%p)\n", hSem
);
360 ReleaseSemaphore(hSem
, 1, &dwOldCount
); /* +1 */
361 WaitForSingleObject(hSem
, 0); /* -1 */
365 /*************************************************************************
366 * _SHGlobalCounterIncrement [SHLWAPI.224]
371 * hSem [I] Semaphore handle
374 * The new count of the semaphore.
376 LONG WINAPI
_SHGlobalCounterIncrement(HANDLE hSem
)
380 TRACE("(%p)\n", hSem
);
381 ReleaseSemaphore(hSem
, 1, &dwOldCount
);
382 return dwOldCount
+ 1;
385 /*************************************************************************
386 * _SHGlobalCounterDecrement [SHLWAPI.424]
388 * Release a semaphore.
391 * hSem [I] Semaphore handle
394 * The new count of the semaphore.
396 DWORD WINAPI
_SHGlobalCounterDecrement(HANDLE hSem
)
398 DWORD dwOldCount
= 0;
400 TRACE("(%p)\n", hSem
);
402 dwOldCount
= _SHGlobalCounterGetValue(hSem
);
403 WaitForSingleObject(hSem
, 0);
404 return dwOldCount
- 1;
407 /*************************************************************************
408 * _SHGlobalCounterCreateNamedW [SHLWAPI.423]
410 * Unicode version of _SHGlobalCounterCreateNamedA.
412 HANDLE WINAPI
_SHGlobalCounterCreateNamedW(LPCWSTR lpszName
, DWORD iInitial
)
414 static const WCHAR szPrefix
[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' };
415 const int iPrefixLen
= 6;
416 WCHAR szBuff
[MAX_PATH
];
417 const int iBuffLen
= sizeof(szBuff
)/sizeof(WCHAR
);
418 SECURITY_DESCRIPTOR sd
;
419 SECURITY_ATTRIBUTES sAttr
, *pSecAttr
;
422 TRACE("(%s,%ld)\n", debugstr_w(lpszName
), iInitial
);
424 /* Create Semaphore name */
425 memcpy(szBuff
, szPrefix
, (iPrefixLen
+ 1) * sizeof(WCHAR
));
427 StrCpyNW(szBuff
+ iPrefixLen
, lpszName
, iBuffLen
- iPrefixLen
);
429 /* Initialise security attributes */
430 pSecAttr
= _CreateAllAccessSecurityAttributes(&sAttr
, &sd
, 0);
432 if (!(hRet
= CreateSemaphoreW(pSecAttr
, iInitial
, MAXLONG
, szBuff
)))
433 hRet
= OpenSemaphoreW(SYNCHRONIZE
|SEMAPHORE_MODIFY_STATE
, 0, szBuff
);
437 /*************************************************************************
438 * _SHGlobalCounterCreateNamedA [SHLWAPI.422]
440 * Create a semaphore.
443 * lpszName [I] Name of semaphore
444 * iInitial [I] Initial count for semaphore
447 * A new semaphore handle.
449 HANDLE WINAPI
_SHGlobalCounterCreateNamedA(LPCSTR lpszName
, DWORD iInitial
)
451 WCHAR szBuff
[MAX_PATH
];
453 TRACE("(%s,%ld)\n", debugstr_a(lpszName
), iInitial
);
456 MultiByteToWideChar(0, 0, lpszName
, -1, szBuff
, MAX_PATH
);
457 return _SHGlobalCounterCreateNamedW(lpszName
? szBuff
: NULL
, iInitial
);
460 /*************************************************************************
461 * _SHGlobalCounterCreate [SHLWAPI.222]
463 * Create a semaphore using the name of a GUID.
466 * guid [I] GUID to use as semaphore name
469 * A handle to the semaphore.
472 * The initial count of the semaphore is set to 0.
474 HANDLE WINAPI
_SHGlobalCounterCreate (REFGUID guid
)
478 TRACE("(%s)\n", debugstr_guid(guid
));
480 /* Create a named semaphore using the GUID string */
481 SHStringFromGUIDA(guid
, szName
, sizeof(szName
) - 1);
482 return _SHGlobalCounterCreateNamedA(szName
, 0);