Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561/* * SHLWAPI thread and MT synchronisation functions * * Copyright 2002 Juergen Schmied * Copyright 2002 Jon Griffiths * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */#include <stdarg.h>#include <string.h>
#define COBJMACROS
#include "windef.h"#include "winbase.h"#include "winnls.h"#include "winuser.h"#define NO_SHLWAPI_REG#define NO_SHLWAPI_PATH#define NO_SHLWAPI_GDI#define NO_SHLWAPI_STREAM#define NO_SHLWAPI_USER#include "shlwapi.h"#include "shlobj.h"#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */
INT WINAPI SHStringFromGUIDA(REFGUID,LPSTR,INT);
/************************************************************************** * CreateAllAccessSecurityAttributes [SHLWAPI.356] * * Initialise security attributes from a security descriptor. * * PARAMS * lpAttr [O] Security attributes * lpSec [I] Security descriptor * * RETURNS * Success: lpAttr, initialised using lpSec. * Failure: NULL, if any parameters are invalid. * * NOTES * This function always returns NULL if the underlying OS version * Wine is impersonating does not use security descriptors (i.e. anything * before Windows NT). */LPSECURITY_ATTRIBUTES WINAPI CreateAllAccessSecurityAttributes( LPSECURITY_ATTRIBUTES lpAttr, PSECURITY_DESCRIPTOR lpSec, DWORD p3){ /* This function is used within SHLWAPI only to create security attributes * for shell semaphores. */
TRACE("(%p,%p,%08x)\n", lpAttr, lpSec, p3);
if (!(GetVersion() & 0x80000000)) /* NT */ { if (!lpSec || !lpAttr) return NULL;
if (InitializeSecurityDescriptor(lpSec, 1)) { if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE)) { lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES); lpAttr->lpSecurityDescriptor = lpSec; lpAttr->bInheritHandle = FALSE; return lpAttr; } } } return NULL;}
/************************************************************************* * _SHGetInstanceExplorer [SHLWAPI.@] * * Get an interface to the shell explorer. * * PARAMS * lppUnknown [O] Destination for explorers IUnknown interface. * * RETURNS * Success: S_OK. lppUnknown contains the explorer interface. * Failure: An HRESULT error code. */HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown){ /* This function is used within SHLWAPI only to hold the IE reference * for threads created with the CTF_PROCESS_REF flag set. */ return SHGetInstanceExplorer(lppUnknown);}
/* Internal thread information structure */typedef struct tagSHLWAPI_THREAD_INFO{ LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */ LPTHREAD_START_ROUTINE pfnCallback; /* Thread initialisation */ PVOID pData; /* Application specific data */ BOOL bInitCom; /* Initialise COM for the thread? */ HANDLE hEvent; /* Signal for creator to continue */ IUnknown *refThread; /* Reference to thread creator */ IUnknown *refIE; /* Reference to the IE process */} SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO;
typedef struct{ IUnknown IUnknown_iface; LONG *ref;} threadref;
static inline threadref *impl_from_IUnknown(IUnknown *iface){ return CONTAINING_RECORD(iface, threadref, IUnknown_iface);}
static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj){ threadref * This = impl_from_IUnknown(iface);
TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObj);
if (ppvObj == NULL) return E_POINTER;
if (IsEqualGUID(&IID_IUnknown, riid)) { TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObj); *ppvObj = This; IUnknown_AddRef((IUnknown*)*ppvObj); return S_OK; }
*ppvObj = NULL; FIXME("(%p, %s, %p) interface not supported\n", This, debugstr_guid(riid), ppvObj); return E_NOINTERFACE;}
static ULONG WINAPI threadref_AddRef(IUnknown *iface){ threadref * This = impl_from_IUnknown(iface);
TRACE("(%p)\n", This); return InterlockedIncrement(This->ref);}
static ULONG WINAPI threadref_Release(IUnknown *iface){ LONG refcount; threadref * This = impl_from_IUnknown(iface);
TRACE("(%p)\n", This);
refcount = InterlockedDecrement(This->ref); if (!refcount) HeapFree(GetProcessHeap(), 0, This);
return refcount;}
/* VTable */static const IUnknownVtbl threadref_vt ={ threadref_QueryInterface, threadref_AddRef, threadref_Release,};
/************************************************************************* * SHCreateThreadRef [SHLWAPI.@] * * Create a per-thread IUnknown object * * PARAMS * lprefcount [I] Pointer to a LONG to be used as refcount * lppUnknown [O] Destination to receive the created object reference * * RETURNS * Success: S_OK. lppUnknown is set to the object reference. * Failure: E_INVALIDARG, if a parameter is NULL */HRESULT WINAPI SHCreateThreadRef(LONG *lprefcount, IUnknown **lppUnknown){ threadref * This; TRACE("(%p, %p)\n", lprefcount, lppUnknown);
if (!lprefcount || !lppUnknown) return E_INVALIDARG;
This = HeapAlloc(GetProcessHeap(), 0, sizeof(threadref)); This->IUnknown_iface.lpVtbl = &threadref_vt; This->ref = lprefcount;
*lprefcount = 1; *lppUnknown = &This->IUnknown_iface; TRACE("=> returning S_OK with %p\n", This); return S_OK;}
/************************************************************************* * SHGetThreadRef [SHLWAPI.@] * * Get a per-thread object reference set by SHSetThreadRef(). * * PARAMS * lppUnknown [O] Destination to receive object reference * * RETURNS * Success: S_OK. lppUnknown is set to the object reference. * Failure: E_NOINTERFACE, if an error occurs or no object is set */HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown){ TRACE("(%p)\n", lppUnknown);
if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES) return E_NOINTERFACE;
*lppUnknown = TlsGetValue(SHLWAPI_ThreadRef_index); if (!*lppUnknown) return E_NOINTERFACE;
/* Add a reference. Caller will Release() us when finished */ IUnknown_AddRef(*lppUnknown); return S_OK;}
/************************************************************************* * SHSetThreadRef [SHLWAPI.@] * * Store a per-thread object reference. * * PARAMS * lpUnknown [I] Object reference to store * * RETURNS * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef() * Failure: E_NOINTERFACE, if an error occurs */HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown){ TRACE("(%p)\n", lpUnknown);
if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES) return E_NOINTERFACE;
TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown); return S_OK;}
/************************************************************************* * SHReleaseThreadRef [SHLWAPI.@] * * Release a per-thread object reference. * * PARAMS * None. * * RETURNS * Success: S_OK. The threads object reference is released. * Failure: An HRESULT error code. */HRESULT WINAPI SHReleaseThreadRef(void){ FIXME("() - stub!\n"); return S_OK;}
/************************************************************************* * SHLWAPI_ThreadWrapper * * Internal wrapper for executing user thread functions from SHCreateThread. */static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi){ SHLWAPI_THREAD_INFO ti; HRESULT hCom = E_FAIL; DWORD dwRet;
TRACE("(%p)\n", pTi);
/* We are now executing in the context of the newly created thread. * So we copy the data passed to us (it is on the stack of the function * that called us, which is waiting for us to signal an event before * returning). */ memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO));
/* Initialise COM for the thread, if desired */ if (ti.bInitCom) { hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE);
if (FAILED(hCom)) hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE); }
/* Execute the callback function before returning */ if (ti.pfnCallback) ti.pfnCallback(ti.pData);
/* Signal the thread that created us; it can return now */ SetEvent(ti.hEvent);
/* Execute the callers start code */ dwRet = ti.pfnThreadProc(ti.pData);
/* Release references to the caller and IE process, if held */ if (ti.refThread) IUnknown_Release(ti.refThread);
if (ti.refIE) IUnknown_Release(ti.refIE);
if (SUCCEEDED(hCom)) CoUninitialize();
/* Return the users thread return value */ return dwRet;}
/************************************************************************* * SHCreateThread [SHLWAPI.16] * * Create a new thread. * * PARAMS * pfnThreadProc [I] Function to execute in new thread * pData [I] Application specific data passed to pfnThreadProc * dwFlags [I] CTF_ flags from "shlwapi.h" * pfnCallback [I] Function to execute before pfnThreadProc * * RETURNS * Success: TRUE. pfnThreadProc was executed. * Failure: FALSE. pfnThreadProc was not executed. * * NOTES * If the thread cannot be created, pfnCallback is NULL, and dwFlags * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously. */BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData, DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback){ SHLWAPI_THREAD_INFO ti; BOOL bCalled = FALSE;
TRACE("(%p,%p,0x%X,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback);
/* Set up data to pass to the new thread (On our stack) */ ti.pfnThreadProc = pfnThreadProc; ti.pfnCallback = pfnCallback; ti.pData = pData; ti.bInitCom = (dwFlags & CTF_COINIT) != 0; ti.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
/* Hold references to the current thread and IE process, if desired */ if(dwFlags & CTF_THREAD_REF) SHGetThreadRef(&ti.refThread); else ti.refThread = NULL;
if(dwFlags & CTF_PROCESS_REF) _SHGetInstanceExplorer(&ti.refIE); else ti.refIE = NULL;
/* Create the thread */ if(ti.hEvent) { DWORD dwRetVal; HANDLE hThread;
hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal);
if(hThread) { /* Wait for the thread to signal us to continue */ WaitForSingleObject(ti.hEvent, INFINITE); CloseHandle(hThread); bCalled = TRUE; } CloseHandle(ti.hEvent); }
if (!bCalled) { if (!ti.pfnCallback && dwFlags & CTF_INSIST) { /* Couldn't call, call synchronously */ pfnThreadProc(pData); bCalled = TRUE; } else { /* Free references, since thread hasn't run to do so */ if(ti.refThread) IUnknown_Release(ti.refThread);
if(ti.refIE) IUnknown_Release(ti.refIE); } } return bCalled;}
/************************************************************************* * SHGlobalCounterGetValue [SHLWAPI.223] * * Get the current count of a semaphore. * * PARAMS * hSem [I] Semaphore handle * * RETURNS * The current count of the semaphore. */LONG WINAPI SHGlobalCounterGetValue(HANDLE hSem){ LONG dwOldCount = 0;
TRACE("(%p)\n", hSem); ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */ WaitForSingleObject(hSem, 0); /* -1 */ return dwOldCount;}
/************************************************************************* * SHGlobalCounterIncrement [SHLWAPI.224] * * Claim a semaphore. * * PARAMS * hSem [I] Semaphore handle * * RETURNS * The new count of the semaphore. */LONG WINAPI SHGlobalCounterIncrement(HANDLE hSem){ LONG dwOldCount = 0;
TRACE("(%p)\n", hSem); ReleaseSemaphore(hSem, 1, &dwOldCount); return dwOldCount + 1;}
/************************************************************************* * SHGlobalCounterDecrement [SHLWAPI.424] * * Release a semaphore. * * PARAMS * hSem [I] Semaphore handle * * RETURNS * The new count of the semaphore. */DWORD WINAPI SHGlobalCounterDecrement(HANDLE hSem){ DWORD dwOldCount = 0;
TRACE("(%p)\n", hSem);
dwOldCount = SHGlobalCounterGetValue(hSem); WaitForSingleObject(hSem, 0); return dwOldCount - 1;}
/************************************************************************* * SHGlobalCounterCreateNamedW [SHLWAPI.423] * * Unicode version of SHGlobalCounterCreateNamedA. */HANDLE WINAPI SHGlobalCounterCreateNamedW(LPCWSTR lpszName, DWORD iInitial){ static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' }; const int iPrefixLen = 6; WCHAR szBuff[MAX_PATH]; const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR); SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sAttr, *pSecAttr; HANDLE hRet;
TRACE("(%s,%d)\n", debugstr_w(lpszName), iInitial);
/* Create Semaphore name */ memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR)); if (lpszName) StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen);
/* Initialise security attributes */ pSecAttr = CreateAllAccessSecurityAttributes(&sAttr, &sd, 0);
if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff))) hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff); return hRet;}
/************************************************************************* * SHGlobalCounterCreateNamedA [SHLWAPI.422] * * Create a semaphore. * * PARAMS * lpszName [I] Name of semaphore * iInitial [I] Initial count for semaphore * * RETURNS * A new semaphore handle. */HANDLE WINAPI SHGlobalCounterCreateNamedA(LPCSTR lpszName, DWORD iInitial){ WCHAR szBuff[MAX_PATH];
TRACE("(%s,%d)\n", debugstr_a(lpszName), iInitial);
if (lpszName) MultiByteToWideChar(CP_ACP, 0, lpszName, -1, szBuff, MAX_PATH); return SHGlobalCounterCreateNamedW(lpszName ? szBuff : NULL, iInitial);}
/************************************************************************* * SHGlobalCounterCreate [SHLWAPI.222] * * Create a semaphore using the name of a GUID. * * PARAMS * guid [I] GUID to use as semaphore name * * RETURNS * A handle to the semaphore. * * NOTES * The initial count of the semaphore is set to 0. */HANDLE WINAPI SHGlobalCounterCreate (REFGUID guid){ char szName[40];
TRACE("(%s)\n", debugstr_guid(guid));
/* Create a named semaphore using the GUID string */ SHStringFromGUIDA(guid, szName, sizeof(szName) - 1); return SHGlobalCounterCreateNamedA(szName, 0);}