| /* |
| * 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 "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, |
| DWORD p3) |
| { |
| /* This function is used within SHLWAPI only to create security attributes |
| * for shell semaphores. */ |
| |
| TRACE("(%p,%p,%08lx)\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. */ |
| |
| 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 = 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,%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, 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,%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); |
| } |