wine/dlls/shlwapi/thread.c
2004-01-27 00:01:43 +00:00

481 lines
13 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "wine/debug.h"
#define NO_SHLWAPI_REG
#define NO_SHLWAPI_PATH
#define NO_SHLWAPI_GDI
#define NO_SHLWAPI_STREAM
#define NO_SHLWAPI_USER
#include "shlwapi.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
/* Get a function pointer from a DLL handle */
#define GET_FUNC(func, module, name, fail) \
do { \
if (!func) { \
if (!SHLWAPI_h##module && !(SHLWAPI_h##module = LoadLibraryA(#module ".dll"))) return fail; \
if (!(func = (void*)GetProcAddress(SHLWAPI_h##module, name))) return fail; \
} \
} while (0)
/* DLL handles for late bound calls */
extern HMODULE SHLWAPI_hshell32;
/* Function pointers for GET_FUNC macro; these need to be global because of gcc bug */
static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**);
extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */
DWORD 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)
{
/* This function is used within SHLWAPI only to create security attributes
* for shell semaphores. */
TRACE("(%p,%p)\n", lpAttr, lpSec);
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. */
GET_FUNC(pSHGetInstanceExplorer, shell32, "SHGetInstanceExplorer", E_FAIL);
return pSHGetInstanceExplorer(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;
/*************************************************************************
* 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 lppUnknown is NULL.
*/
HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown)
{
TRACE("(%p)\n", lppUnknown);
if (!lppUnknown || SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES)
return E_NOINTERFACE;
*lppUnknown = (IUnknown*)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 or lpUnknown is NULL.
*/
HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown)
{
TRACE("(%p)\n", lpUnknown);
if (!lpUnknown || SHLWAPI_ThreadRef_index == 0xffffffff)
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()
{
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%lX,%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 = CreateEventA(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, -1);
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,%ld)\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);
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,%ld)\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);
}