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);
+}