1 /* 2 * SHLWAPI thread and MT synchronisation functions 3 * 4 * Copyright 2002 Juergen Schmied 5 * Copyright 2002 Jon Griffiths 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 #include <stdarg.h> 22 #include <string.h> 23 24 #define COBJMACROS 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winnls.h" 29 #include "winuser.h" 30 #define NO_SHLWAPI_REG 31 #define NO_SHLWAPI_PATH 32 #define NO_SHLWAPI_GDI 33 #define NO_SHLWAPI_STREAM 34 #define NO_SHLWAPI_USER 35 #include "shlwapi.h" 36 #include "shlobj.h" 37 #include "wine/debug.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(shell); 40 41 extern DWORD SHLWAPI_ThreadRef_index; /* Initialised in shlwapi_main.c */ 42 43 INT WINAPI SHStringFromGUIDA(REFGUID,LPSTR,INT); 44 45 /************************************************************************** 46 * CreateAllAccessSecurityAttributes [SHLWAPI.356] 47 * 48 * Initialise security attributes from a security descriptor. 49 * 50 * PARAMS 51 * lpAttr [O] Security attributes 52 * lpSec [I] Security descriptor 53 * 54 * RETURNS 55 * Success: lpAttr, initialised using lpSec. 56 * Failure: NULL, if any parameters are invalid. 57 * 58 * NOTES 59 * This function always returns NULL if the underlying OS version 60 * Wine is impersonating does not use security descriptors (i.e. anything 61 * before Windows NT). 62 */ 63 LPSECURITY_ATTRIBUTES WINAPI CreateAllAccessSecurityAttributes( 64 LPSECURITY_ATTRIBUTES lpAttr, 65 PSECURITY_DESCRIPTOR lpSec, 66 DWORD p3) 67 { 68 /* This function is used within SHLWAPI only to create security attributes 69 * for shell semaphores. */ 70 71 TRACE("(%p,%p,%08x)\n", lpAttr, lpSec, p3); 72 73 if (!(GetVersion() & 0x80000000)) /* NT */ 74 { 75 if (!lpSec || !lpAttr) 76 return NULL; 77 78 if (InitializeSecurityDescriptor(lpSec, 1)) 79 { 80 if (SetSecurityDescriptorDacl(lpSec, TRUE, NULL, FALSE)) 81 { 82 lpAttr->nLength = sizeof(SECURITY_ATTRIBUTES); 83 lpAttr->lpSecurityDescriptor = lpSec; 84 lpAttr->bInheritHandle = FALSE; 85 return lpAttr; 86 } 87 } 88 } 89 return NULL; 90 } 91 92 /************************************************************************* 93 * _SHGetInstanceExplorer [SHLWAPI.@] 94 * 95 * Get an interface to the shell explorer. 96 * 97 * PARAMS 98 * lppUnknown [O] Destination for explorers IUnknown interface. 99 * 100 * RETURNS 101 * Success: S_OK. lppUnknown contains the explorer interface. 102 * Failure: An HRESULT error code. 103 */ 104 HRESULT WINAPI _SHGetInstanceExplorer(IUnknown **lppUnknown) 105 { 106 /* This function is used within SHLWAPI only to hold the IE reference 107 * for threads created with the CTF_PROCESS_REF flag set. */ 108 return SHGetInstanceExplorer(lppUnknown); 109 } 110 111 /* Internal thread information structure */ 112 typedef struct tagSHLWAPI_THREAD_INFO 113 { 114 LPTHREAD_START_ROUTINE pfnThreadProc; /* Thread start */ 115 LPTHREAD_START_ROUTINE pfnCallback; /* Thread initialisation */ 116 PVOID pData; /* Application specific data */ 117 BOOL bInitCom; /* Initialise COM for the thread? */ 118 HANDLE hEvent; /* Signal for creator to continue */ 119 IUnknown *refThread; /* Reference to thread creator */ 120 IUnknown *refIE; /* Reference to the IE process */ 121 } SHLWAPI_THREAD_INFO, *LPSHLWAPI_THREAD_INFO; 122 123 typedef struct 124 { 125 IUnknown IUnknown_iface; 126 LONG *ref; 127 } threadref; 128 129 static inline threadref *impl_from_IUnknown(IUnknown *iface) 130 { 131 return CONTAINING_RECORD(iface, threadref, IUnknown_iface); 132 } 133 134 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj) 135 { 136 threadref * This = impl_from_IUnknown(iface); 137 138 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObj); 139 140 if (ppvObj == NULL) 141 return E_POINTER; 142 143 if (IsEqualGUID(&IID_IUnknown, riid)) { 144 TRACE("(%p)->(IID_IUnknown %p)\n", This, ppvObj); 145 *ppvObj = This; 146 IUnknown_AddRef((IUnknown*)*ppvObj); 147 return S_OK; 148 } 149 150 *ppvObj = NULL; 151 FIXME("(%p, %s, %p) interface not supported\n", This, debugstr_guid(riid), ppvObj); 152 return E_NOINTERFACE; 153 } 154 155 static ULONG WINAPI threadref_AddRef(IUnknown *iface) 156 { 157 threadref * This = impl_from_IUnknown(iface); 158 159 TRACE("(%p)\n", This); 160 return InterlockedIncrement(This->ref); 161 } 162 163 static ULONG WINAPI threadref_Release(IUnknown *iface) 164 { 165 LONG refcount; 166 threadref * This = impl_from_IUnknown(iface); 167 168 TRACE("(%p)\n", This); 169 170 refcount = InterlockedDecrement(This->ref); 171 if (!refcount) 172 HeapFree(GetProcessHeap(), 0, This); 173 174 return refcount; 175 } 176 177 /* VTable */ 178 static const IUnknownVtbl threadref_vt = 179 { 180 threadref_QueryInterface, 181 threadref_AddRef, 182 threadref_Release, 183 }; 184 185 /************************************************************************* 186 * SHCreateThreadRef [SHLWAPI.@] 187 * 188 * Create a per-thread IUnknown object 189 * 190 * PARAMS 191 * lprefcount [I] Pointer to a LONG to be used as refcount 192 * lppUnknown [O] Destination to receive the created object reference 193 * 194 * RETURNS 195 * Success: S_OK. lppUnknown is set to the object reference. 196 * Failure: E_INVALIDARG, if a parameter is NULL 197 */ 198 HRESULT WINAPI SHCreateThreadRef(LONG *lprefcount, IUnknown **lppUnknown) 199 { 200 threadref * This; 201 TRACE("(%p, %p)\n", lprefcount, lppUnknown); 202 203 if (!lprefcount || !lppUnknown) 204 return E_INVALIDARG; 205 206 This = HeapAlloc(GetProcessHeap(), 0, sizeof(threadref)); 207 This->IUnknown_iface.lpVtbl = &threadref_vt; 208 This->ref = lprefcount; 209 210 *lprefcount = 1; 211 *lppUnknown = &This->IUnknown_iface; 212 TRACE("=> returning S_OK with %p\n", This); 213 return S_OK; 214 } 215 216 /************************************************************************* 217 * SHGetThreadRef [SHLWAPI.@] 218 * 219 * Get a per-thread object reference set by SHSetThreadRef(). 220 * 221 * PARAMS 222 * lppUnknown [O] Destination to receive object reference 223 * 224 * RETURNS 225 * Success: S_OK. lppUnknown is set to the object reference. 226 * Failure: E_NOINTERFACE, if an error occurs or no object is set 227 */ 228 HRESULT WINAPI SHGetThreadRef(IUnknown **lppUnknown) 229 { 230 TRACE("(%p)\n", lppUnknown); 231 232 if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES) 233 return E_NOINTERFACE; 234 235 *lppUnknown = TlsGetValue(SHLWAPI_ThreadRef_index); 236 if (!*lppUnknown) 237 return E_NOINTERFACE; 238 239 /* Add a reference. Caller will Release() us when finished */ 240 IUnknown_AddRef(*lppUnknown); 241 return S_OK; 242 } 243 244 /************************************************************************* 245 * SHSetThreadRef [SHLWAPI.@] 246 * 247 * Store a per-thread object reference. 248 * 249 * PARAMS 250 * lpUnknown [I] Object reference to store 251 * 252 * RETURNS 253 * Success: S_OK. lpUnknown is stored and can be retrieved by SHGetThreadRef() 254 * Failure: E_NOINTERFACE, if an error occurs 255 */ 256 HRESULT WINAPI SHSetThreadRef(IUnknown *lpUnknown) 257 { 258 TRACE("(%p)\n", lpUnknown); 259 260 if (SHLWAPI_ThreadRef_index == TLS_OUT_OF_INDEXES) 261 return E_NOINTERFACE; 262 263 TlsSetValue(SHLWAPI_ThreadRef_index, lpUnknown); 264 return S_OK; 265 } 266 267 /************************************************************************* 268 * SHReleaseThreadRef [SHLWAPI.@] 269 * 270 * Release a per-thread object reference. 271 * 272 * PARAMS 273 * None. 274 * 275 * RETURNS 276 * Success: S_OK. The threads object reference is released. 277 * Failure: An HRESULT error code. 278 */ 279 HRESULT WINAPI SHReleaseThreadRef(void) 280 { 281 FIXME("() - stub!\n"); 282 return S_OK; 283 } 284 285 /************************************************************************* 286 * SHLWAPI_ThreadWrapper 287 * 288 * Internal wrapper for executing user thread functions from SHCreateThread. 289 */ 290 static DWORD WINAPI SHLWAPI_ThreadWrapper(PVOID pTi) 291 { 292 SHLWAPI_THREAD_INFO ti; 293 HRESULT hCom = E_FAIL; 294 DWORD dwRet; 295 296 TRACE("(%p)\n", pTi); 297 298 /* We are now executing in the context of the newly created thread. 299 * So we copy the data passed to us (it is on the stack of the function 300 * that called us, which is waiting for us to signal an event before 301 * returning). */ 302 memcpy(&ti, pTi, sizeof(SHLWAPI_THREAD_INFO)); 303 304 /* Initialise COM for the thread, if desired */ 305 if (ti.bInitCom) 306 { 307 hCom = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED|COINIT_DISABLE_OLE1DDE); 308 309 if (FAILED(hCom)) 310 hCom = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE); 311 } 312 313 /* Execute the callback function before returning */ 314 if (ti.pfnCallback) 315 ti.pfnCallback(ti.pData); 316 317 /* Signal the thread that created us; it can return now */ 318 SetEvent(ti.hEvent); 319 320 /* Execute the callers start code */ 321 dwRet = ti.pfnThreadProc(ti.pData); 322 323 /* Release references to the caller and IE process, if held */ 324 if (ti.refThread) 325 IUnknown_Release(ti.refThread); 326 327 if (ti.refIE) 328 IUnknown_Release(ti.refIE); 329 330 if (SUCCEEDED(hCom)) 331 CoUninitialize(); 332 333 /* Return the users thread return value */ 334 return dwRet; 335 } 336 337 /************************************************************************* 338 * SHCreateThread [SHLWAPI.16] 339 * 340 * Create a new thread. 341 * 342 * PARAMS 343 * pfnThreadProc [I] Function to execute in new thread 344 * pData [I] Application specific data passed to pfnThreadProc 345 * dwFlags [I] CTF_ flags from "shlwapi.h" 346 * pfnCallback [I] Function to execute before pfnThreadProc 347 * 348 * RETURNS 349 * Success: TRUE. pfnThreadProc was executed. 350 * Failure: FALSE. pfnThreadProc was not executed. 351 * 352 * NOTES 353 * If the thread cannot be created, pfnCallback is NULL, and dwFlags 354 * has bit CTF_INSIST set, pfnThreadProc will be executed synchronously. 355 */ 356 BOOL WINAPI SHCreateThread(LPTHREAD_START_ROUTINE pfnThreadProc, VOID *pData, 357 DWORD dwFlags, LPTHREAD_START_ROUTINE pfnCallback) 358 { 359 SHLWAPI_THREAD_INFO ti; 360 BOOL bCalled = FALSE; 361 362 TRACE("(%p,%p,0x%X,%p)\n", pfnThreadProc, pData, dwFlags, pfnCallback); 363 364 /* Set up data to pass to the new thread (On our stack) */ 365 ti.pfnThreadProc = pfnThreadProc; 366 ti.pfnCallback = pfnCallback; 367 ti.pData = pData; 368 ti.bInitCom = (dwFlags & CTF_COINIT) != 0; 369 ti.hEvent = CreateEventW(NULL,FALSE,FALSE,NULL); 370 371 /* Hold references to the current thread and IE process, if desired */ 372 if(dwFlags & CTF_THREAD_REF) 373 SHGetThreadRef(&ti.refThread); 374 else 375 ti.refThread = NULL; 376 377 if(dwFlags & CTF_PROCESS_REF) 378 _SHGetInstanceExplorer(&ti.refIE); 379 else 380 ti.refIE = NULL; 381 382 /* Create the thread */ 383 if(ti.hEvent) 384 { 385 DWORD dwRetVal; 386 HANDLE hThread; 387 388 hThread = CreateThread(NULL, 0, SHLWAPI_ThreadWrapper, &ti, 0, &dwRetVal); 389 390 if(hThread) 391 { 392 /* Wait for the thread to signal us to continue */ 393 WaitForSingleObject(ti.hEvent, INFINITE); 394 CloseHandle(hThread); 395 bCalled = TRUE; 396 } 397 CloseHandle(ti.hEvent); 398 } 399 400 if (!bCalled) 401 { 402 if (!ti.pfnCallback && dwFlags & CTF_INSIST) 403 { 404 /* Couldn't call, call synchronously */ 405 pfnThreadProc(pData); 406 bCalled = TRUE; 407 } 408 else 409 { 410 /* Free references, since thread hasn't run to do so */ 411 if(ti.refThread) 412 IUnknown_Release(ti.refThread); 413 414 if(ti.refIE) 415 IUnknown_Release(ti.refIE); 416 } 417 } 418 return bCalled; 419 } 420 421 /************************************************************************* 422 * SHGlobalCounterGetValue [SHLWAPI.223] 423 * 424 * Get the current count of a semaphore. 425 * 426 * PARAMS 427 * hSem [I] Semaphore handle 428 * 429 * RETURNS 430 * The current count of the semaphore. 431 */ 432 LONG WINAPI SHGlobalCounterGetValue(HANDLE hSem) 433 { 434 LONG dwOldCount = 0; 435 436 TRACE("(%p)\n", hSem); 437 ReleaseSemaphore(hSem, 1, &dwOldCount); /* +1 */ 438 WaitForSingleObject(hSem, 0); /* -1 */ 439 return dwOldCount; 440 } 441 442 /************************************************************************* 443 * SHGlobalCounterIncrement [SHLWAPI.224] 444 * 445 * Claim a semaphore. 446 * 447 * PARAMS 448 * hSem [I] Semaphore handle 449 * 450 * RETURNS 451 * The new count of the semaphore. 452 */ 453 LONG WINAPI SHGlobalCounterIncrement(HANDLE hSem) 454 { 455 LONG dwOldCount = 0; 456 457 TRACE("(%p)\n", hSem); 458 ReleaseSemaphore(hSem, 1, &dwOldCount); 459 return dwOldCount + 1; 460 } 461 462 /************************************************************************* 463 * SHGlobalCounterDecrement [SHLWAPI.424] 464 * 465 * Release a semaphore. 466 * 467 * PARAMS 468 * hSem [I] Semaphore handle 469 * 470 * RETURNS 471 * The new count of the semaphore. 472 */ 473 DWORD WINAPI SHGlobalCounterDecrement(HANDLE hSem) 474 { 475 DWORD dwOldCount = 0; 476 477 TRACE("(%p)\n", hSem); 478 479 dwOldCount = SHGlobalCounterGetValue(hSem); 480 WaitForSingleObject(hSem, 0); 481 return dwOldCount - 1; 482 } 483 484 /************************************************************************* 485 * SHGlobalCounterCreateNamedW [SHLWAPI.423] 486 * 487 * Unicode version of SHGlobalCounterCreateNamedA. 488 */ 489 HANDLE WINAPI SHGlobalCounterCreateNamedW(LPCWSTR lpszName, DWORD iInitial) 490 { 491 static const WCHAR szPrefix[] = { 's', 'h', 'e', 'l', 'l', '.', '\0' }; 492 const int iPrefixLen = 6; 493 WCHAR szBuff[MAX_PATH]; 494 const int iBuffLen = sizeof(szBuff)/sizeof(WCHAR); 495 SECURITY_DESCRIPTOR sd; 496 SECURITY_ATTRIBUTES sAttr, *pSecAttr; 497 HANDLE hRet; 498 499 TRACE("(%s,%d)\n", debugstr_w(lpszName), iInitial); 500 501 /* Create Semaphore name */ 502 memcpy(szBuff, szPrefix, (iPrefixLen + 1) * sizeof(WCHAR)); 503 if (lpszName) 504 StrCpyNW(szBuff + iPrefixLen, lpszName, iBuffLen - iPrefixLen); 505 506 /* Initialise security attributes */ 507 pSecAttr = CreateAllAccessSecurityAttributes(&sAttr, &sd, 0); 508 509 if (!(hRet = CreateSemaphoreW(pSecAttr , iInitial, MAXLONG, szBuff))) 510 hRet = OpenSemaphoreW(SYNCHRONIZE|SEMAPHORE_MODIFY_STATE, 0, szBuff); 511 return hRet; 512 } 513 514 /************************************************************************* 515 * SHGlobalCounterCreateNamedA [SHLWAPI.422] 516 * 517 * Create a semaphore. 518 * 519 * PARAMS 520 * lpszName [I] Name of semaphore 521 * iInitial [I] Initial count for semaphore 522 * 523 * RETURNS 524 * A new semaphore handle. 525 */ 526 HANDLE WINAPI SHGlobalCounterCreateNamedA(LPCSTR lpszName, DWORD iInitial) 527 { 528 WCHAR szBuff[MAX_PATH]; 529 530 TRACE("(%s,%d)\n", debugstr_a(lpszName), iInitial); 531 532 if (lpszName) 533 MultiByteToWideChar(CP_ACP, 0, lpszName, -1, szBuff, MAX_PATH); 534 return SHGlobalCounterCreateNamedW(lpszName ? szBuff : NULL, iInitial); 535 } 536 537 /************************************************************************* 538 * SHGlobalCounterCreate [SHLWAPI.222] 539 * 540 * Create a semaphore using the name of a GUID. 541 * 542 * PARAMS 543 * guid [I] GUID to use as semaphore name 544 * 545 * RETURNS 546 * A handle to the semaphore. 547 * 548 * NOTES 549 * The initial count of the semaphore is set to 0. 550 */ 551 HANDLE WINAPI SHGlobalCounterCreate (REFGUID guid) 552 { 553 char szName[40]; 554 555 TRACE("(%s)\n", debugstr_guid(guid)); 556 557 /* Create a named semaphore using the GUID string */ 558 SHStringFromGUIDA(guid, szName, sizeof(szName) - 1); 559 return SHGlobalCounterCreateNamedA(szName, 0); 560 } 561