Move thread related functions to new file.
Implement SHCreateThread,@224,@424, stub SHReleaseThreadRef.
Fix: SHGetThreadRef() calls AddRef(), @356 param count wrong.
diff --git a/dlls/shlwapi/thread.c b/dlls/shlwapi/thread.c
new file mode 100644
index 0000000..f169766
--- /dev/null
+++ b/dlls/shlwapi/thread.c
@@ -0,0 +1,466 @@
+/*
+ * 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 <string.h>
+
+#include "windef.h"
+#include "winnls.h"
+#include "wine/obj_base.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"
+#include "ordinal.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(shell);
+
+extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */
+
+static HRESULT (WINAPI *pSHGetInstanceExplorer)(IUnknown**);
+
+DWORD WINAPI SHLWAPI_23(REFGUID,LPSTR,INT);
+
+/**************************************************************************
+ * @ [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 returns NULL if the underlying OS version
+ * Wine is impersonating does not use security descriptors (i.e. anything
+ * before Windows NT).
+ */
+LPSECURITY_ATTRIBUTES
+WINAPI SHLWAPI_356(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 (0) /* FIXME: SHWAPI_OsIsUnicode, as per shell32 */
+ {
+ 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
+ * lpUnknown [O] pointer to recieve 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. lppUnk is set to the object reference.
+ * Failure: E_NOINTERFACE, if an error occurs or lppUnk is invalid.
+ */
+HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown)
+{
+ TRACE("(%p)\n", lppUnknown);
+
+ if (!lppUnknown || SHLWAPI_ThreadRef_index == -1u)
+ 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
+ * lpUnk [I] Object reference to store
+ *
+ * RETURNS
+ * Success: S_OK. lpUnk is stored and can be retrieved by SHGetThreadRef()
+ * Failure: E_NOINTERFACE, if an error occurs or lpUnk is invalid.
+ */
+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 obbject 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)", 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] Initialisation to perform in the new thread
+ * 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;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.223]
+ *
+ * Get the current count of a semaphore.
+ *
+ * PARAMS
+ * hSem [I] Semaphore handle
+ *
+ * RETURNS
+ * The current count of the semaphore.
+ */
+DWORD WINAPI SHLWAPI_223(HANDLE hSem)
+{
+ DWORD dwOldCount = 0;
+
+ TRACE("(0x%08x)\n", hSem);
+ ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */
+ WaitForSingleObject(hSem, 0); /* -1 */
+ return dwOldCount;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.224]
+ *
+ * Claim a semaphore.
+ *
+ * PARAMS
+ * hSem [I] Semaphore handle
+ *
+ * RETURNS
+ * The new count of the semaphore.
+ */
+DWORD WINAPI SHLWAPI_224(HANDLE hSem)
+{
+ DWORD dwOldCount = 0;
+
+ TRACE("(0x%08x)\n", hSem);
+ ReleaseSemaphore(hSem, 1, &dwOldCount);
+ return dwOldCount + 1;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.424]
+ *
+ * Release a semaphore.
+ *
+ * PARAMS
+ * hSem [I] Semaphore handle
+ *
+ * RETURNS
+ * The new count of the semaphore.
+ */
+DWORD WINAPI SHLWAPI_424(HANDLE hSem)
+{
+ DWORD dwOldCount = 0;
+
+ TRACE("(0x%08x)\n", hSem);
+
+ dwOldCount = SHLWAPI_223(hSem);
+ WaitForSingleObject(hSem, 0);
+ return dwOldCount - 1;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.423]
+ *
+ * Unicode version of SHLWAPI_422.
+ */
+HANDLE WINAPI SHLWAPI_423(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 = SHLWAPI_356(&sAttr, &sd);
+
+ if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff)))
+ hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff);
+ return hRet;
+}
+
+/*************************************************************************
+ * @ [SHLWAPI.422]
+ *
+ * Create a semaphore.
+ *
+ * PARAMS
+ * lpszName [I] Name of semaphore
+ * iInitial [I] Initial count for semaphore
+ *
+ * RETURNS
+ * A new semaphore handle.
+ */
+HANDLE WINAPI SHLWAPI_422(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 SHLWAPI_423(lpszName ? szBuff : NULL, iInitial);
+}
+
+/*************************************************************************
+ * @ [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 SHLWAPI_222(REFGUID guid)
+{
+ char szName[40];
+
+ TRACE("(%s)\n", debugstr_guid(guid));
+
+ /* Create a named semaphore using the GUID string */
+ SHLWAPI_23(guid, szName, sizeof(szName) - 1);
+ return SHLWAPI_422(szName, 0);
+}