mirror of
https://github.com/reactos/wine.git
synced 2024-12-07 19:37:28 +00:00
561 lines
15 KiB
C
561 lines
15 KiB
C
/*
|
|
* 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 ? TRUE : FALSE;
|
|
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(0, 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);
|
|
}
|