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
21 #define WIN32_NO_STATUS
23 #define COM_NO_WINDOWS_H
33 //#include "winuser.h"
34 #define NO_SHLWAPI_REG
35 #define NO_SHLWAPI_PATH
36 #define NO_SHLWAPI_GDI
37 #define NO_SHLWAPI_STREAM
38 #define NO_SHLWAPI_USER
41 #include <wine/debug.h>
43 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
45 extern DWORD SHLWAPI_ThreadRef_index
; /* Initialised in shlwapi_main.c */
47 INT WINAPI
SHStringFromGUIDA(REFGUID
,LPSTR
,INT
);
49 /**************************************************************************
50 * CreateAllAccessSecurityAttributes [SHLWAPI.356]
52 * Initialise security attributes from a security descriptor.
55 * lpAttr [O] Security attributes
56 * lpSec [I] Security descriptor
59 * Success: lpAttr, initialised using lpSec.
60 * Failure: NULL, if any parameters are invalid.
63 * This function always returns NULL if the underlying OS version
64 * Wine is impersonating does not use security descriptors (i.e. anything
67 LPSECURITY_ATTRIBUTES WINAPI
CreateAllAccessSecurityAttributes(
68 LPSECURITY_ATTRIBUTES lpAttr
,
69 PSECURITY_DESCRIPTOR lpSec
,
72 /* This function is used within SHLWAPI only to create security attributes
73 * for shell semaphores. */
75 TRACE("(%p,%p,%08x)\n", lpAttr
, lpSec
, p3
);
77 if (!(GetVersion() & 0x80000000)) /* NT */
79 if (!lpSec
|| !lpAttr
)
82 if (InitializeSecurityDescriptor(lpSec
, 1))
84 if (SetSecurityDescriptorDacl(lpSec
, TRUE
, NULL
, FALSE
))
86 lpAttr
->nLength
= sizeof(SECURITY_ATTRIBUTES
);
87 lpAttr
->lpSecurityDescriptor
= lpSec
;
88 lpAttr
->bInheritHandle
= FALSE
;
96 /*************************************************************************
97 * _SHGetInstanceExplorer [SHLWAPI.@]
99 * Get an interface to the shell explorer.
102 * lppUnknown [O] Destination for explorers IUnknown interface.
105 * Success: S_OK. lppUnknown contains the explorer interface.
106 * Failure: An HRESULT error code.
108 HRESULT WINAPI
_SHGetInstanceExplorer(IUnknown
**lppUnknown
)
110 /* This function is used within SHLWAPI only to hold the IE reference
111 * for threads created with the CTF_PROCESS_REF flag set. */
112 return SHGetInstanceExplorer(lppUnknown
);
115 /* Internal thread information structure */
116 typedef struct tagSHLWAPI_THREAD_INFO
118 LPTHREAD_START_ROUTINE pfnThreadProc
; /* Thread start */
119 LPTHREAD_START_ROUTINE pfnCallback
; /* Thread initialisation */
120 PVOID pData
; /* Application specific data */
121 BOOL bInitCom
; /* Initialise COM for the thread? */
122 HANDLE hEvent
; /* Signal for creator to continue */
123 IUnknown
*refThread
; /* Reference to thread creator */
124 IUnknown
*refIE
; /* Reference to the IE process */
125 } SHLWAPI_THREAD_INFO
, *LPSHLWAPI_THREAD_INFO
;
129 IUnknown IUnknown_iface
;
133 static inline threadref
*impl_from_IUnknown(IUnknown
*iface
)
135 return CONTAINING_RECORD(iface
, threadref
, IUnknown_iface
);
138 static HRESULT WINAPI
threadref_QueryInterface(IUnknown
*iface
, REFIID riid
, LPVOID
*ppvObj
)
140 threadref
* This
= impl_from_IUnknown(iface
);
142 TRACE("(%p, %s, %p)\n", This
, debugstr_guid(riid
), ppvObj
);
147 if (IsEqualGUID(&IID_IUnknown
, riid
)) {
148 TRACE("(%p)->(IID_IUnknown %p)\n", This
, ppvObj
);
150 IUnknown_AddRef((IUnknown
*)*ppvObj
);
155 FIXME("(%p, %s, %p) interface not supported\n", This
, debugstr_guid(riid
), ppvObj
);
156 return E_NOINTERFACE
;
159 static ULONG WINAPI
threadref_AddRef(IUnknown
*iface
)
161 threadref
* This
= impl_from_IUnknown(iface
);
163 TRACE("(%p)\n", This
);
164 return InterlockedIncrement(This
->ref
);
167 static ULONG WINAPI
threadref_Release(IUnknown
*iface
)
170 threadref
* This
= impl_from_IUnknown(iface
);
172 TRACE("(%p)\n", This
);
174 refcount
= InterlockedDecrement(This
->ref
);
176 HeapFree(GetProcessHeap(), 0, This
);
182 static const IUnknownVtbl threadref_vt
=
184 threadref_QueryInterface
,
189 /*************************************************************************
190 * SHCreateThreadRef [SHLWAPI.@]
192 * Create a per-thread IUnknown object
195 * lprefcount [I] Pointer to a LONG to be used as refcount
196 * lppUnknown [O] Destination to receive the created object reference
199 * Success: S_OK. lppUnknown is set to the object reference.
200 * Failure: E_INVALIDARG, if a parameter is NULL
202 HRESULT WINAPI
SHCreateThreadRef(LONG
*lprefcount
, IUnknown
**lppUnknown
)
205 TRACE("(%p, %p)\n", lprefcount
, lppUnknown
);
207 if (!lprefcount
|| !lppUnknown
)
210 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(threadref
));
211 This
->IUnknown_iface
.lpVtbl
= &threadref_vt
;
212 This
->ref
= lprefcount
;
215 *lppUnknown
= &This
->IUnknown_iface
;
216 TRACE("=> returning S_OK with %p\n", This
);
220 /*************************************************************************
221 * SHGetThreadRef [SHLWAPI.@]
223 * Get a per-thread object reference set by SHSetThreadRef().
226 * lppUnknown [O] Destination to receive object reference
229 * Success: S_OK. lppUnknown is set to the object reference.
230 * Failure: E_NOINTERFACE, if an error occurs or no object is set
232 HRESULT WINAPI
SHGetThreadRef(IUnknown
**lppUnknown
)
234 TRACE("(%p)\n", lppUnknown
);
236 if (SHLWAPI_ThreadRef_index
== TLS_OUT_OF_INDEXES
)
237 return E_NOINTERFACE
;
239 *lppUnknown
= TlsGetValue(SHLWAPI_ThreadRef_index
);
241 return E_NOINTERFACE
;
243 /* Add a reference. Caller will Release() us when finished */
244 IUnknown_AddRef(*lppUnknown
);
248 /*************************************************************************
249 * SHSetThreadRef [SHLWAPI.@]
251 * Store a per-thread object reference.
254 * lpUnknown [I] Object reference to store
257 * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef()
258 * Failure: E_NOINTERFACE, if an error occurs
260 HRESULT WINAPI
SHSetThreadRef(IUnknown
*lpUnknown
)
262 TRACE("(%p)\n", lpUnknown
);
264 if (SHLWAPI_ThreadRef_index
== TLS_OUT_OF_INDEXES
)
265 return E_NOINTERFACE
;
267 TlsSetValue(SHLWAPI_ThreadRef_index
, lpUnknown
);
271 /*************************************************************************
272 * SHReleaseThreadRef [SHLWAPI.@]
274 * Release a per-thread object reference.
280 * Success: S_OK. The threads object reference is released.
281 * Failure: An HRESULT error code.
283 HRESULT WINAPI
SHReleaseThreadRef(void)
285 FIXME("() - stub!\n");
289 /*************************************************************************
290 * SHLWAPI_ThreadWrapper
292 * Internal wrapper for executing user thread functions from SHCreateThread.
294 static DWORD WINAPI
SHLWAPI_ThreadWrapper(PVOID pTi
)
296 SHLWAPI_THREAD_INFO ti
;
297 HRESULT hCom
= E_FAIL
;
300 TRACE("(%p)\n", pTi
);
302 /* We are now executing in the context of the newly created thread.
303 * So we copy the data passed to us (it is on the stack of the function
304 * that called us, which is waiting for us to signal an event before
306 memcpy(&ti
, pTi
, sizeof(SHLWAPI_THREAD_INFO
));
308 /* Initialise COM for the thread, if desired */
311 hCom
= CoInitializeEx(NULL
, COINIT_APARTMENTTHREADED
|COINIT_DISABLE_OLE1DDE
);
314 hCom
= CoInitializeEx(NULL
, COINIT_DISABLE_OLE1DDE
);
317 /* Execute the callback function before returning */
319 ti
.pfnCallback(ti
.pData
);
321 /* Signal the thread that created us; it can return now */
324 /* Execute the callers start code */
325 dwRet
= ti
.pfnThreadProc(ti
.pData
);
327 /* Release references to the caller and IE process, if held */
329 IUnknown_Release(ti
.refThread
);
332 IUnknown_Release(ti
.refIE
);
337 /* Return the users thread return value */
341 /*************************************************************************
342 * SHCreateThread [SHLWAPI.16]
344 * Create a new thread.
347 * pfnThreadProc [I] Function to execute in new thread
348 * pData [I] Application specific data passed to pfnThreadProc
349 * dwFlags [I] CTF_ flags from "shlwapi.h"
350 * pfnCallback [I] Function to execute before pfnThreadProc
353 * Success: TRUE. pfnThreadProc was executed.
354 * Failure: FALSE. pfnThreadProc was not executed.
357 * If the thread cannot be created, pfnCallback is NULL, and dwFlags
358 * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously.
360 BOOL WINAPI
SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc
, VOID
*pData
,
361 DWORD dwFlags
, LPTHREAD_START_ROUTINE pfnCallback
)
363 SHLWAPI_THREAD_INFO ti
;
364 BOOL bCalled
= FALSE
;
366 TRACE("(%p,%p,0x%X,%p)\n", pfnThreadProc
, pData
, dwFlags
, pfnCallback
);
368 /* Set up data to pass to the new thread (On our stack) */
369 ti
.pfnThreadProc
= pfnThreadProc
;
370 ti
.pfnCallback
= pfnCallback
;
372 ti
.bInitCom
= (dwFlags
& CTF_COINIT
) != 0;
373 ti
.hEvent
= CreateEventW(NULL
,FALSE
,FALSE
,NULL
);
375 /* Hold references to the current thread and IE process, if desired */
376 if(dwFlags
& CTF_THREAD_REF
)
377 SHGetThreadRef(&ti
.refThread
);
381 if(dwFlags
& CTF_PROCESS_REF
)
382 _SHGetInstanceExplorer(&ti
.refIE
);
386 /* Create the thread */
392 hThread
= CreateThread(NULL
, 0, SHLWAPI_ThreadWrapper
, &ti
, 0, &dwRetVal
);
396 /* Wait for the thread to signal us to continue */
397 WaitForSingleObject(ti
.hEvent
, INFINITE
);
398 CloseHandle(hThread
);
401 CloseHandle(ti
.hEvent
);
406 if (!ti
.pfnCallback
&& dwFlags
& CTF_INSIST
)
408 /* Couldn't call, call synchronously */
409 pfnThreadProc(pData
);
414 /* Free references, since thread hasn't run to do so */
416 IUnknown_Release(ti
.refThread
);
419 IUnknown_Release(ti
.refIE
);
425 /*************************************************************************
426 * SHGlobalCounterGetValue [SHLWAPI.223]
428 * Get the current count of a semaphore.
431 * hSem [I] Semaphore handle
434 * The current count of the semaphore.
436 LONG WINAPI
SHGlobalCounterGetValue(HANDLE hSem
)
440 TRACE("(%p)\n", hSem
);
441 ReleaseSemaphore(hSem
, 1, &dwOldCount
); /* +1 */
442 WaitForSingleObject(hSem
, 0); /* -1 */
446 /*************************************************************************
447 * SHGlobalCounterIncrement [SHLWAPI.224]
452 * hSem [I] Semaphore handle
455 * The new count of the semaphore.
457 LONG WINAPI
SHGlobalCounterIncrement(HANDLE hSem
)
461 TRACE("(%p)\n", hSem
);
462 ReleaseSemaphore(hSem
, 1, &dwOldCount
);
463 return dwOldCount
+ 1;
466 /*************************************************************************
467 * SHGlobalCounterDecrement [SHLWAPI.424]
469 * Release a semaphore.
472 * hSem [I] Semaphore handle
475 * The new count of the semaphore.
477 DWORD WINAPI
SHGlobalCounterDecrement(HANDLE hSem
)
479 DWORD dwOldCount
= 0;
481 TRACE("(%p)\n", hSem
);
483 dwOldCount
= SHGlobalCounterGetValue(hSem
);
484 WaitForSingleObject(hSem
, 0);
485 return dwOldCount
- 1;
488 /*************************************************************************
489 * SHGlobalCounterCreateNamedW [SHLWAPI.423]
491 * Unicode version of SHGlobalCounterCreateNamedA.
493 HANDLE WINAPI
SHGlobalCounterCreateNamedW(LPCWSTR lpszName
, DWORD iInitial
)
495 static const WCHAR szPrefix
[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' };
496 const int iPrefixLen
= 6;
497 WCHAR szBuff
[MAX_PATH
];
498 const int iBuffLen
= sizeof(szBuff
)/sizeof(WCHAR
);
499 SECURITY_DESCRIPTOR sd
;
500 SECURITY_ATTRIBUTES sAttr
, *pSecAttr
;
503 TRACE("(%s,%d)\n", debugstr_w(lpszName
), iInitial
);
505 /* Create Semaphore name */
506 memcpy(szBuff
, szPrefix
, (iPrefixLen
+ 1) * sizeof(WCHAR
));
508 StrCpyNW(szBuff
+ iPrefixLen
, lpszName
, iBuffLen
- iPrefixLen
);
510 /* Initialise security attributes */
511 pSecAttr
= CreateAllAccessSecurityAttributes(&sAttr
, &sd
, 0);
513 if (!(hRet
= CreateSemaphoreW(pSecAttr
, iInitial
, MAXLONG
, szBuff
)))
514 hRet
= OpenSemaphoreW(SYNCHRONIZE
|SEMAPHORE_MODIFY_STATE
, 0, szBuff
);
518 /*************************************************************************
519 * SHGlobalCounterCreateNamedA [SHLWAPI.422]
521 * Create a semaphore.
524 * lpszName [I] Name of semaphore
525 * iInitial [I] Initial count for semaphore
528 * A new semaphore handle.
530 HANDLE WINAPI
SHGlobalCounterCreateNamedA(LPCSTR lpszName
, DWORD iInitial
)
532 WCHAR szBuff
[MAX_PATH
];
534 TRACE("(%s,%d)\n", debugstr_a(lpszName
), iInitial
);
537 MultiByteToWideChar(CP_ACP
, 0, lpszName
, -1, szBuff
, MAX_PATH
);
538 return SHGlobalCounterCreateNamedW(lpszName
? szBuff
: NULL
, iInitial
);
541 /*************************************************************************
542 * SHGlobalCounterCreate [SHLWAPI.222]
544 * Create a semaphore using the name of a GUID.
547 * guid [I] GUID to use as semaphore name
550 * A handle to the semaphore.
553 * The initial count of the semaphore is set to 0.
555 HANDLE WINAPI
SHGlobalCounterCreate (REFGUID guid
)
559 TRACE("(%s)\n", debugstr_guid(guid
));
561 /* Create a named semaphore using the GUID string */
562 SHStringFromGUIDA(guid
, szName
, sizeof(szName
) - 1);
563 return SHGlobalCounterCreateNamedA(szName
, 0);