1 /* 2 * The parameters of many functions changes between different OS versions 3 * (NT uses Unicode strings, 95 uses ASCII strings) 4 * 5 * Copyright 1997 Marcus Meissner 6 * 1998 Jürgen Schmied 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include <wine/config.h> 24 25 #define WIN32_NO_STATUS 26 #define _INC_WINDOWS 27 #define COBJMACROS 28 29 #include <windef.h> 30 #include <winbase.h> 31 #include <wine/winternl.h> 32 #include <shlobj.h> 33 #include <undocshell.h> 34 #include <shlwapi.h> 35 #include <commdlg.h> 36 #include <commoncontrols.h> 37 #include "../shellrecyclebin/recyclebin.h" 38 39 #include <wine/debug.h> 40 #include <wine/unicode.h> 41 42 #include "pidl.h" 43 #include "shell32_main.h" 44 45 WINE_DEFAULT_DEBUG_CHANNEL(shell); 46 WINE_DECLARE_DEBUG_CHANNEL(pidl); 47 48 #ifdef __REACTOS__ 49 #include <comctl32_undoc.h> 50 #else 51 /* FIXME: !!! move CREATEMRULIST and flags to header file !!! */ 52 /* !!! it is in both here and comctl32undoc.c !!! */ 53 typedef struct tagCREATEMRULIST 54 { 55 DWORD cbSize; /* size of struct */ 56 DWORD nMaxItems; /* max no. of items in list */ 57 DWORD dwFlags; /* see below */ 58 HKEY hKey; /* root reg. key under which list is saved */ 59 LPCSTR lpszSubKey; /* reg. subkey */ 60 int (CALLBACK *lpfnCompare)(LPCVOID, LPCVOID, DWORD); /* item compare proc */ 61 } CREATEMRULISTA, *LPCREATEMRULISTA; 62 63 /* dwFlags */ 64 #define MRUF_STRING_LIST 0 /* list will contain strings */ 65 #define MRUF_BINARY_LIST 1 /* list will contain binary data */ 66 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */ 67 68 extern HANDLE WINAPI CreateMRUListA(LPCREATEMRULISTA lpcml); 69 extern VOID WINAPI FreeMRUList(HANDLE hMRUList); 70 extern INT WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData); 71 extern INT WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum); 72 extern INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize); 73 #endif 74 75 /************************************************************************* 76 * ParseFieldA [internal] 77 * 78 * copies a field from a ',' delimited string 79 * 80 * first field is nField = 1 81 */ 82 DWORD WINAPI ParseFieldA( 83 LPCSTR src, 84 DWORD nField, 85 LPSTR dst, 86 DWORD len) 87 { 88 WARN("(%s,0x%08x,%p,%d) semi-stub.\n",debugstr_a(src),nField,dst,len); 89 90 if (!src || !src[0] || !dst || !len) 91 return 0; 92 93 /* skip n fields delimited by ',' */ 94 while (nField > 1) 95 { 96 if (*src=='\0') return FALSE; 97 if (*(src++)==',') nField--; 98 } 99 100 /* copy part till the next ',' to dst */ 101 while ( *src!='\0' && *src!=',' && (len--)>0 ) *(dst++)=*(src++); 102 103 /* finalize the string */ 104 *dst=0x0; 105 106 return TRUE; 107 } 108 109 /************************************************************************* 110 * ParseFieldW [internal] 111 * 112 * copies a field from a ',' delimited string 113 * 114 * first field is nField = 1 115 */ 116 DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len) 117 { 118 WARN("(%s,0x%08x,%p,%d) semi-stub.\n", debugstr_w(src), nField, dst, len); 119 120 if (!src || !src[0] || !dst || !len) 121 return 0; 122 123 /* skip n fields delimited by ',' */ 124 while (nField > 1) 125 { 126 if (*src == 0x0) return FALSE; 127 if (*src++ == ',') nField--; 128 } 129 130 /* copy part till the next ',' to dst */ 131 while ( *src != 0x0 && *src != ',' && (len--)>0 ) *(dst++) = *(src++); 132 133 /* finalize the string */ 134 *dst = 0x0; 135 136 return TRUE; 137 } 138 139 /************************************************************************* 140 * ParseField [SHELL32.58] 141 */ 142 DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len) 143 { 144 if (SHELL_OsIsUnicode()) 145 return ParseFieldW(src, nField, dst, len); 146 return ParseFieldA(src, nField, dst, len); 147 } 148 149 /************************************************************************* 150 * GetFileNameFromBrowse [SHELL32.63] 151 * 152 */ 153 BOOL WINAPI GetFileNameFromBrowse( 154 HWND hwndOwner, 155 LPWSTR lpstrFile, 156 UINT nMaxFile, 157 LPCWSTR lpstrInitialDir, 158 LPCWSTR lpstrDefExt, 159 LPCWSTR lpstrFilter, 160 LPCWSTR lpstrTitle) 161 { 162 typedef BOOL (WINAPI *GetOpenFileNameProc)(OPENFILENAMEW *ofn); 163 HMODULE hmodule; 164 GetOpenFileNameProc pGetOpenFileNameW; 165 OPENFILENAMEW ofn; 166 BOOL ret; 167 168 TRACE("%p, %s, %d, %s, %s, %s, %s)\n", 169 hwndOwner, debugstr_w(lpstrFile), nMaxFile, lpstrInitialDir, lpstrDefExt, 170 lpstrFilter, lpstrTitle); 171 172 hmodule = LoadLibraryW(L"comdlg32.dll"); 173 if(!hmodule) return FALSE; 174 pGetOpenFileNameW = (GetOpenFileNameProc)GetProcAddress(hmodule, "GetOpenFileNameW"); 175 if(!pGetOpenFileNameW) 176 { 177 FreeLibrary(hmodule); 178 return FALSE; 179 } 180 181 memset(&ofn, 0, sizeof(ofn)); 182 183 ofn.lStructSize = sizeof(ofn); 184 ofn.hwndOwner = hwndOwner; 185 ofn.lpstrFilter = lpstrFilter; 186 ofn.lpstrFile = lpstrFile; 187 ofn.nMaxFile = nMaxFile; 188 ofn.lpstrInitialDir = lpstrInitialDir; 189 ofn.lpstrTitle = lpstrTitle; 190 ofn.lpstrDefExt = lpstrDefExt; 191 ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; 192 ret = pGetOpenFileNameW(&ofn); 193 194 FreeLibrary(hmodule); 195 return ret; 196 } 197 198 /************************************************************************* 199 * SHGetSetSettings [SHELL32.68] 200 */ 201 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet) 202 { 203 if(bSet) 204 { 205 FIXME("%p 0x%08x TRUE\n", lpss, dwMask); 206 } 207 else 208 { 209 SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask); 210 } 211 } 212 213 /************************************************************************* 214 * SHGetSettings [SHELL32.@] 215 * 216 * NOTES 217 * the registry path are for win98 (tested) 218 * and possibly are the same in nt40 219 * 220 */ 221 VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask) 222 { 223 HKEY hKey; 224 DWORD dwData; 225 DWORD dwDataSize = sizeof (DWORD); 226 227 TRACE("(%p 0x%08x)\n",lpsfs,dwMask); 228 229 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 230 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) 231 return; 232 233 if ( (SSF_SHOWEXTENSIONS & dwMask) && !RegQueryValueExA(hKey, "HideFileExt", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 234 lpsfs->fShowExtensions = ((dwData == 0) ? 0 : 1); 235 236 if ( (SSF_SHOWINFOTIP & dwMask) && !RegQueryValueExA(hKey, "ShowInfoTip", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 237 lpsfs->fShowInfoTip = ((dwData == 0) ? 0 : 1); 238 239 if ( (SSF_DONTPRETTYPATH & dwMask) && !RegQueryValueExA(hKey, "DontPrettyPath", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 240 lpsfs->fDontPrettyPath = ((dwData == 0) ? 0 : 1); 241 242 if ( (SSF_HIDEICONS & dwMask) && !RegQueryValueExA(hKey, "HideIcons", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 243 lpsfs->fHideIcons = ((dwData == 0) ? 0 : 1); 244 245 if ( (SSF_MAPNETDRVBUTTON & dwMask) && !RegQueryValueExA(hKey, "MapNetDrvBtn", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 246 lpsfs->fMapNetDrvBtn = ((dwData == 0) ? 0 : 1); 247 248 if ( (SSF_SHOWATTRIBCOL & dwMask) && !RegQueryValueExA(hKey, "ShowAttribCol", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 249 lpsfs->fShowAttribCol = ((dwData == 0) ? 0 : 1); 250 251 if (((SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES) & dwMask) && !RegQueryValueExA(hKey, "Hidden", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 252 { if (dwData == 0) 253 { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 0; 254 if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 0; 255 } 256 else if (dwData == 1) 257 { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 1; 258 if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 0; 259 } 260 else if (dwData == 2) 261 { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 0; 262 if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 1; 263 } 264 } 265 RegCloseKey (hKey); 266 267 TRACE("-- 0x%04x\n", *(WORD*)lpsfs); 268 } 269 270 /************************************************************************* 271 * SHShellFolderView_Message [SHELL32.73] 272 * 273 * Send a message to an explorer cabinet window. 274 * 275 * PARAMS 276 * hwndCabinet [I] The window containing the shellview to communicate with 277 * dwMessage [I] The SFVM message to send 278 * dwParam [I] Message parameter 279 * 280 * RETURNS 281 * fixme. 282 * 283 * NOTES 284 * Message SFVM_REARRANGE = 1 285 * 286 * This message gets sent when a column gets clicked to instruct the 287 * shell view to re-sort the item list. dwParam identifies the column 288 * that was clicked. 289 */ 290 LRESULT WINAPI SHShellFolderView_Message( 291 HWND hwndCabinet, 292 UINT uMessage, 293 LPARAM lParam) 294 { 295 FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam); 296 return 0; 297 } 298 299 /************************************************************************* 300 * RegisterShellHook [SHELL32.181] 301 * 302 * Register a shell hook. 303 * 304 * PARAMS 305 * hwnd [I] Window handle 306 * dwType [I] Type of hook. 307 * 308 * NOTES 309 * Exported by ordinal 310 */ 311 BOOL WINAPI RegisterShellHook( 312 HWND hWnd, 313 DWORD dwType) 314 { 315 if (dwType == 3) 316 { 317 SetTaskmanWindow(hWnd); 318 return RegisterShellHookWindow(hWnd); 319 } 320 else if (dwType == 0) 321 { 322 return DeregisterShellHookWindow(hWnd); 323 } 324 325 ERR("Unsupported argument"); 326 return FALSE; 327 } 328 329 /************************************************************************* 330 * ShellMessageBoxW [SHELL32.182] 331 * 332 * See ShellMessageBoxA. 333 * 334 */ 335 #ifdef __REACTOS__ 336 /* 337 * shell32.ShellMessageBoxW directly redirects to shlwapi.ShellMessageBoxWrapW, 338 * while shell32.ShellMessageBoxA is a copy-paste ANSI adaptation of the 339 * shlwapi.ShellMessageBoxWrapW function. 340 * 341 * From Vista+ onwards, all the implementation of ShellMessageBoxA/W that 342 * were existing in shell32 has been completely moved to shlwapi, so that 343 * shell32.ShellMessageBoxA and shell32.ShellMessageBoxW are redirections 344 * to the corresponding shlwapi functions. 345 * 346 */ 347 #else // !__REACTOS__ 348 /* 349 * NOTE: 350 * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW 351 * because we can't forward to it in the .spec file since it's exported by 352 * ordinal. If you change the implementation here please update the code in 353 * shlwapi as well. 354 */ 355 // Wine version, broken. 356 int ShellMessageBoxW( 357 HINSTANCE hInstance, 358 HWND hWnd, 359 LPCWSTR lpText, 360 LPCWSTR lpCaption, 361 UINT uType, 362 ...) 363 { 364 WCHAR szText[100],szTitle[100]; 365 LPCWSTR pszText = szText, pszTitle = szTitle; 366 LPWSTR pszTemp; 367 __ms_va_list args; 368 int ret; 369 370 __ms_va_start(args, uType); 371 /* wvsprintfA(buf,fmt, args); */ 372 373 TRACE("(%p,%p,%p,%p,%08x)\n", 374 hInstance,hWnd,lpText,lpCaption,uType); 375 376 if (IS_INTRESOURCE(lpCaption)) 377 LoadStringW(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle)); 378 else 379 pszTitle = lpCaption; 380 381 if (IS_INTRESOURCE(lpText)) 382 LoadStringW(hInstance, LOWORD(lpText), szText, ARRAY_SIZE(szText)); 383 else 384 pszText = lpText; 385 386 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, 387 pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args); 388 389 __ms_va_end(args); 390 391 ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType); 392 LocalFree(pszTemp); 393 return ret; 394 } 395 #endif 396 397 /************************************************************************* 398 * ShellMessageBoxA [SHELL32.183] 399 * 400 * Format and output an error message. 401 * 402 * PARAMS 403 * hInstance [I] Instance handle of message creator 404 * hWnd [I] Window handle of message creator 405 * lpText [I] Resource Id of title or LPSTR 406 * lpCaption [I] Resource Id of title or LPSTR 407 * uType [I] Type of error message 408 * 409 * RETURNS 410 * A return value from MessageBoxA(). 411 * 412 * NOTES 413 * Exported by ordinal 414 */ 415 #ifdef __REACTOS__ 416 /* 417 * Note that we cannot straightforwardly implement ShellMessageBoxA around 418 * ShellMessageBoxW, by converting some parameters from ANSI to UNICODE, 419 * because there may be some variadic ANSI strings, associated with '%s' 420 * printf-like formatters inside the format string, that would also need 421 * to be converted; however there is no way for us to find these and perform 422 * the conversion ourselves. 423 * Therefore, we re-implement ShellMessageBoxA by doing a copy-paste ANSI 424 * adaptation of the shlwapi.ShellMessageBoxWrapW function. 425 */ 426 #endif 427 int ShellMessageBoxA( 428 HINSTANCE hInstance, 429 HWND hWnd, 430 LPCSTR lpText, 431 LPCSTR lpCaption, 432 UINT uType, 433 ...) 434 { 435 #ifdef __REACTOS__ 436 CHAR *szText = NULL, szTitle[100]; 437 LPCSTR pszText, pszTitle = szTitle; 438 LPSTR pszTemp; 439 __ms_va_list args; 440 int ret; 441 442 __ms_va_start(args, uType); 443 444 TRACE("(%p,%p,%p,%p,%08x)\n", hInstance, hWnd, lpText, lpCaption, uType); 445 446 if (IS_INTRESOURCE(lpCaption)) 447 LoadStringA(hInstance, LOWORD(lpCaption), szTitle, ARRAY_SIZE(szTitle)); 448 else 449 pszTitle = lpCaption; 450 451 if (IS_INTRESOURCE(lpText)) 452 { 453 /* Retrieve the length of the Unicode string and obtain the maximum 454 * possible length for the corresponding ANSI string (not counting 455 * any possible NULL-terminator). */ 456 const WCHAR *ptr; 457 UINT len = LoadStringW(hInstance, LOWORD(lpText), (LPWSTR)&ptr, 0); 458 459 len = WideCharToMultiByte(CP_ACP, 0, ptr, len, 460 NULL, 0, NULL, NULL); 461 462 if (len) 463 { 464 szText = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(CHAR)); 465 if (szText) LoadStringA(hInstance, LOWORD(lpText), szText, len + 1); 466 } 467 pszText = szText; 468 if (!pszText) { 469 WARN("Failed to load id %d\n", LOWORD(lpText)); 470 __ms_va_end(args); 471 return 0; 472 } 473 } 474 else 475 pszText = lpText; 476 477 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, 478 pszText, 0, 0, (LPSTR)&pszTemp, 0, &args); 479 480 __ms_va_end(args); 481 482 ret = MessageBoxA(hWnd, pszTemp, pszTitle, uType | MB_SETFOREGROUND); 483 484 HeapFree(GetProcessHeap(), 0, szText); 485 LocalFree(pszTemp); 486 return ret; 487 488 #else // __REACTOS__ 489 490 // Wine version, broken. 491 char szText[100],szTitle[100]; 492 LPCSTR pszText = szText, pszTitle = szTitle; 493 LPSTR pszTemp; 494 __ms_va_list args; 495 int ret; 496 497 __ms_va_start(args, uType); 498 /* wvsprintfA(buf,fmt, args); */ 499 500 TRACE("(%p,%p,%p,%p,%08x)\n", 501 hInstance,hWnd,lpText,lpCaption,uType); 502 503 if (IS_INTRESOURCE(lpCaption)) 504 LoadStringA(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)); 505 else 506 pszTitle = lpCaption; 507 508 if (IS_INTRESOURCE(lpText)) 509 LoadStringA(hInstance, LOWORD(lpText), szText, sizeof(szText)); 510 else 511 pszText = lpText; 512 513 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, 514 pszText, 0, 0, (LPSTR)&pszTemp, 0, &args); 515 516 __ms_va_end(args); 517 518 ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType); 519 LocalFree(pszTemp); 520 return ret; 521 #endif 522 } 523 524 /************************************************************************* 525 * SHRegisterDragDrop [SHELL32.86] 526 * 527 * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the 528 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 529 * for details. Under Windows 98 this function initializes the true OLE when called 530 * the first time, on XP always returns E_OUTOFMEMORY and it got removed from Vista. 531 * 532 * We follow Windows 98 behaviour. 533 * 534 * NOTES 535 * exported by ordinal 536 * 537 * SEE ALSO 538 * RegisterDragDrop, SHLoadOLE 539 */ 540 HRESULT WINAPI SHRegisterDragDrop( 541 HWND hWnd, 542 LPDROPTARGET pDropTarget) 543 { 544 static BOOL ole_initialized = FALSE; 545 HRESULT hr; 546 547 TRACE("(%p,%p)\n", hWnd, pDropTarget); 548 549 if (!ole_initialized) 550 { 551 hr = OleInitialize(NULL); 552 if (FAILED(hr)) 553 return hr; 554 ole_initialized = TRUE; 555 } 556 return RegisterDragDrop(hWnd, pDropTarget); 557 } 558 559 /************************************************************************* 560 * SHRevokeDragDrop [SHELL32.87] 561 * 562 * Probably equivalent to RevokeDragDrop but under Windows 95 it could use the 563 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 564 * for details. Function removed from Windows Vista. 565 * 566 * We call ole32 RevokeDragDrop which seems to work even if OleInitialize was 567 * not called. 568 * 569 * NOTES 570 * exported by ordinal 571 * 572 * SEE ALSO 573 * RevokeDragDrop, SHLoadOLE 574 */ 575 HRESULT WINAPI SHRevokeDragDrop(HWND hWnd) 576 { 577 TRACE("(%p)\n", hWnd); 578 return RevokeDragDrop(hWnd); 579 } 580 581 /************************************************************************* 582 * SHDoDragDrop [SHELL32.88] 583 * 584 * Probably equivalent to DoDragDrop but under Windows 9x it could use the 585 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 586 * for details 587 * 588 * NOTES 589 * exported by ordinal 590 * 591 * SEE ALSO 592 * DoDragDrop, SHLoadOLE 593 */ 594 HRESULT WINAPI SHDoDragDrop( 595 HWND hWnd, 596 LPDATAOBJECT lpDataObject, 597 LPDROPSOURCE lpDropSource, 598 DWORD dwOKEffect, 599 LPDWORD pdwEffect) 600 { 601 FIXME("(%p %p %p 0x%08x %p):stub.\n", 602 hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect); 603 return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect); 604 } 605 606 /************************************************************************* 607 * ArrangeWindows [SHELL32.184] 608 * 609 */ 610 WORD WINAPI ArrangeWindows(HWND hwndParent, DWORD dwReserved, const RECT *lpRect, 611 WORD cKids, const HWND *lpKids) 612 { 613 /* Unimplemented in WinXP SP3 */ 614 TRACE("(%p 0x%08x %p 0x%04x %p):stub.\n", 615 hwndParent, dwReserved, lpRect, cKids, lpKids); 616 return 0; 617 } 618 619 /************************************************************************* 620 * SignalFileOpen [SHELL32.103] 621 * 622 * NOTES 623 * exported by ordinal 624 */ 625 BOOL WINAPI 626 SignalFileOpen (PCIDLIST_ABSOLUTE pidl) 627 { 628 FIXME("(%p):stub.\n", pidl); 629 630 return FALSE; 631 } 632 633 /************************************************************************* 634 * SHADD_get_policy - helper function for SHAddToRecentDocs 635 * 636 * PARAMETERS 637 * policy [IN] policy name (null termed string) to find 638 * type [OUT] ptr to DWORD to receive type 639 * buffer [OUT] ptr to area to hold data retrieved 640 * len [IN/OUT] ptr to DWORD holding size of buffer and getting 641 * length filled 642 * 643 * RETURNS 644 * result of the SHQueryValueEx call 645 */ 646 static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len) 647 { 648 HKEY Policy_basekey; 649 INT ret; 650 651 /* Get the key for the policies location in the registry 652 */ 653 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, 654 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 655 0, KEY_READ, &Policy_basekey)) { 656 657 if (RegOpenKeyExA(HKEY_CURRENT_USER, 658 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 659 0, KEY_READ, &Policy_basekey)) { 660 TRACE("No Explorer Policies location exists. Policy wanted=%s\n", 661 policy); 662 *len = 0; 663 return ERROR_FILE_NOT_FOUND; 664 } 665 } 666 667 /* Retrieve the data if it exists 668 */ 669 ret = SHQueryValueExA(Policy_basekey, policy, 0, type, buffer, len); 670 RegCloseKey(Policy_basekey); 671 return ret; 672 } 673 674 675 /************************************************************************* 676 * SHADD_compare_mru - helper function for SHAddToRecentDocs 677 * 678 * PARAMETERS 679 * data1 [IN] data being looked for 680 * data2 [IN] data in MRU 681 * cbdata [IN] length from FindMRUData call (not used) 682 * 683 * RETURNS 684 * position within MRU list that data was added. 685 */ 686 static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData) 687 { 688 #ifdef __REACTOS__ 689 LPCWSTR psz1, psz2; 690 INT iCmp = lstrcmpiW(data1, data2); 691 if (iCmp != 0) 692 return iCmp; 693 psz1 = data1; 694 psz2 = data2; 695 psz1 += lstrlenW(psz1) + 1; 696 psz2 += lstrlenW(psz2) + 1; 697 return lstrcmpiW(psz1, psz2); 698 #else 699 return lstrcmpiA(data1, data2); 700 #endif 701 } 702 703 #ifdef __REACTOS__ 704 static BOOL 705 DoStoreMRUData(LPBYTE pbBuffer, LPDWORD pcbBuffer, 706 LPCWSTR pszTargetTitle, LPCWSTR pszTargetPath, LPCWSTR pszLinkTitle) 707 { 708 DWORD ib = 0, cb; 709 INT cchTargetTitle = lstrlenW(pszTargetTitle); 710 INT cchTargetPath = lstrlenW(pszTargetPath); 711 INT cchLinkTitle = lstrlenW(pszLinkTitle); 712 713 cb = (cchTargetTitle + 1 + cchTargetPath + 1 + cchLinkTitle + 2) * sizeof(WCHAR); 714 if (cb > *pcbBuffer) 715 return FALSE; 716 717 ZeroMemory(pbBuffer, *pcbBuffer); 718 719 cb = (cchTargetTitle + 1) * sizeof(WCHAR); 720 if (ib + cb > *pcbBuffer) 721 return FALSE; 722 CopyMemory(&pbBuffer[ib], pszTargetTitle, cb); 723 ib += cb; 724 725 cb = (cchTargetPath + 1) * sizeof(WCHAR); 726 if (ib + cb > *pcbBuffer) 727 return FALSE; 728 CopyMemory(&pbBuffer[ib], pszTargetPath, cb); 729 ib += cb; 730 731 cb = (cchLinkTitle + 1) * sizeof(WCHAR); 732 if (ib + cb > *pcbBuffer) 733 return FALSE; 734 CopyMemory(&pbBuffer[ib], pszLinkTitle, cb); 735 ib += cb; 736 737 *pcbBuffer = ib; 738 return TRUE; 739 } 740 #else 741 /************************************************************************* 742 * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs 743 * 744 * PARAMETERS 745 * mruhandle [IN] handle for created MRU list 746 * doc_name [IN] null termed pure doc name 747 * new_lnk_name [IN] null termed path and file name for .lnk file 748 * buffer [IN/OUT] 2048 byte area to construct MRU data 749 * len [OUT] ptr to int to receive space used in buffer 750 * 751 * RETURNS 752 * position within MRU list that data was added. 753 */ 754 static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name, 755 LPSTR buffer, INT *len) 756 { 757 LPSTR ptr; 758 INT wlen; 759 760 /*FIXME: Document: 761 * RecentDocs MRU data structure seems to be: 762 * +0h document file name w/ terminating 0h 763 * +nh short int w/ size of remaining 764 * +n+2h 02h 30h, or 01h 30h, or 00h 30h - unknown 765 * +n+4h 10 bytes zeros - unknown 766 * +n+eh shortcut file name w/ terminating 0h 767 * +n+e+nh 3 zero bytes - unknown 768 */ 769 770 /* Create the MRU data structure for "RecentDocs" 771 */ 772 ptr = buffer; 773 lstrcpyA(ptr, doc_name); 774 ptr += (lstrlenA(buffer) + 1); 775 wlen= lstrlenA(new_lnk_name) + 1 + 12; 776 *((short int*)ptr) = wlen; 777 ptr += 2; /* step past the length */ 778 *(ptr++) = 0x30; /* unknown reason */ 779 *(ptr++) = 0; /* unknown, but can be 0x00, 0x01, 0x02 */ 780 memset(ptr, 0, 10); 781 ptr += 10; 782 lstrcpyA(ptr, new_lnk_name); 783 ptr += (lstrlenA(new_lnk_name) + 1); 784 memset(ptr, 0, 3); 785 ptr += 3; 786 *len = ptr - buffer; 787 788 /* Add the new entry into the MRU list 789 */ 790 return AddMRUData(mruhandle, buffer, *len); 791 } 792 #endif 793 794 /************************************************************************* 795 * SHAddToRecentDocs [SHELL32.@] 796 * 797 * Modify (add/clear) Shell's list of recently used documents. 798 * 799 * PARAMETERS 800 * uFlags [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL 801 * pv [IN] string or pidl, NULL clears the list 802 * 803 * NOTES 804 * exported by name 805 * 806 * FIXME 807 * convert to unicode 808 */ 809 void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv) 810 { 811 #ifdef __REACTOS__ 812 INT ret; 813 WCHAR szTargetPath[MAX_PATH], szLinkDir[MAX_PATH], szLinkFile[MAX_PATH], szDescription[80]; 814 WCHAR szPath[MAX_PATH]; 815 DWORD cbBuffer, data[64], datalen, type; 816 HANDLE hFind; 817 WIN32_FIND_DATAW find; 818 HKEY hExplorerKey; 819 LONG error; 820 LPWSTR pchDotExt, pchTargetTitle, pchLinkTitle; 821 MRUINFOW mru; 822 HANDLE hMRUList = NULL; 823 IShellLinkW *psl = NULL; 824 IPersistFile *pPf = NULL; 825 HRESULT hr; 826 BYTE Buffer[(MAX_PATH + 64) * sizeof(WCHAR)]; 827 828 TRACE("%04x %p\n", uFlags, pv); 829 830 /* check policy */ 831 ret = SHADD_get_policy("NoRecentDocsHistory", &type, data, &datalen); 832 if (ret > 0 && ret != ERROR_FILE_NOT_FOUND) 833 { 834 ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret); 835 } 836 else if (ret == ERROR_SUCCESS) 837 { 838 if (!(type == REG_DWORD || (type == REG_BINARY && datalen == 4))) 839 { 840 ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n", 841 type, datalen); 842 return; 843 } 844 845 TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]); 846 /* now test the actual policy value */ 847 if (data[0] != 0) 848 return; 849 } 850 851 /* store to szTargetPath */ 852 szTargetPath[0] = 0; 853 if (pv) 854 { 855 switch (uFlags) 856 { 857 case SHARD_PATHA: 858 MultiByteToWideChar(CP_ACP, 0, pv, -1, szLinkDir, ARRAYSIZE(szLinkDir)); 859 GetFullPathNameW(szLinkDir, ARRAYSIZE(szTargetPath), szTargetPath, NULL); 860 break; 861 862 case SHARD_PATHW: 863 GetFullPathNameW(pv, ARRAYSIZE(szTargetPath), szTargetPath, NULL); 864 break; 865 866 case SHARD_PIDL: 867 SHGetPathFromIDListW(pv, szLinkDir); 868 GetFullPathNameW(szLinkDir, ARRAYSIZE(szTargetPath), szTargetPath, NULL); 869 break; 870 871 default: 872 FIXME("Unsupported flags: %u\n", uFlags); 873 return; 874 } 875 } 876 877 /* get recent folder */ 878 if (!SHGetSpecialFolderPathW(NULL, szLinkDir, CSIDL_RECENT, FALSE)) 879 { 880 ERR("serious issues 1\n"); 881 return; 882 } 883 TRACE("Users Recent dir %S\n", szLinkDir); 884 885 /* open Explorer key */ 886 error = RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer", 887 0, NULL, 0, 888 KEY_READ | KEY_WRITE, NULL, &hExplorerKey, NULL); 889 if (error) 890 { 891 ERR("Failed to RegCreateKeyExW: 0x%08X\n", error); 892 return; 893 } 894 895 if (!pv) 896 { 897 TRACE("pv is NULL, so delete all shortcut files in %S\n", szLinkDir); 898 899 lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile)); 900 PathAppendW(szLinkFile, L"*.lnk"); 901 902 hFind = FindFirstFileW(szLinkFile, &find); 903 if (hFind != INVALID_HANDLE_VALUE) 904 { 905 do 906 { 907 lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile)); 908 PathAppendW(szLinkFile, find.cFileName); 909 DeleteFileW(szLinkFile); 910 } while (FindNextFile(hFind, &find)); 911 FindClose(hFind); 912 } 913 914 SHDeleteKeyW(hExplorerKey, L"RecentDocs"); 915 RegCloseKey(hExplorerKey); 916 return; 917 } 918 919 if (szTargetPath[0] == 0 || !PathFileExistsW(szTargetPath) || 920 PathIsDirectoryW(szTargetPath)) 921 { 922 /* path is not normal file */ 923 RegCloseKey(hExplorerKey); 924 return; 925 } 926 927 hr = CoInitialize(NULL); 928 if (FAILED(hr)) 929 { 930 ERR("CoInitialize: %08X\n", hr); 931 RegCloseKey(hExplorerKey); 932 return; 933 } 934 935 /* check if file is a shortcut */ 936 ret = 0; 937 pchDotExt = PathFindExtensionW(szTargetPath); 938 while (lstrcmpiW(pchDotExt, L".lnk") == 0) 939 { 940 hr = IShellLink_ConstructFromPath(szTargetPath, &IID_IShellLinkW, (LPVOID*)&psl); 941 if (FAILED(hr)) 942 { 943 ERR("IShellLink_ConstructFromPath: 0x%08X\n", hr); 944 goto Quit; 945 } 946 947 IShellLinkW_GetPath(psl, szPath, ARRAYSIZE(szPath), NULL, 0); 948 IShellLinkW_Release(psl); 949 psl = NULL; 950 951 lstrcpynW(szTargetPath, szPath, ARRAYSIZE(szTargetPath)); 952 pchDotExt = PathFindExtensionW(szTargetPath); 953 954 if (++ret >= 8) 955 { 956 ERR("Link loop?\n"); 957 goto Quit; 958 } 959 } 960 if (!lstrcmpiW(pchDotExt, L".exe")) 961 { 962 /* executables are not added */ 963 goto Quit; 964 } 965 966 /* *** JOB 0: Build strings *** */ 967 968 pchTargetTitle = PathFindFileNameW(szTargetPath); 969 970 lstrcpyW(szDescription, L"Shortcut to "); 971 StrCatBuffW(szDescription, pchTargetTitle, ARRAYSIZE(szDescription)); 972 973 lstrcpynW(szLinkFile, szLinkDir, ARRAYSIZE(szLinkFile)); 974 PathAppendW(szLinkFile, pchTargetTitle); 975 StrCatBuffW(szLinkFile, L".lnk", ARRAYSIZE(szLinkFile)); 976 pchLinkTitle = PathFindFileNameW(szLinkFile); 977 978 /* *** JOB 1: Update registry for ...\Explorer\RecentDocs list *** */ 979 980 /* store MRU data */ 981 cbBuffer = sizeof(Buffer); 982 ret = DoStoreMRUData(Buffer, &cbBuffer, pchTargetTitle, szTargetPath, pchLinkTitle); 983 if (!ret) 984 { 985 ERR("DoStoreMRUData failed: %d\n", ret); 986 goto Quit; 987 } 988 989 /* create MRU list */ 990 mru.cbSize = sizeof(mru); 991 mru.uMax = 16; 992 mru.fFlags = MRU_BINARY | MRU_CACHEWRITE; 993 mru.hKey = hExplorerKey; 994 mru.lpszSubKey = L"RecentDocs"; 995 mru.lpfnCompare = (MRUCMPPROCW)SHADD_compare_mru; 996 hMRUList = CreateMRUListW(&mru); 997 if (!hMRUList) 998 { 999 ERR("CreateMRUListW failed\n"); 1000 goto Quit; 1001 } 1002 1003 /* already exists? */ 1004 ret = FindMRUData(hMRUList, Buffer, cbBuffer, NULL); 1005 if (ret >= 0) 1006 { 1007 /* Just touch for speed */ 1008 HANDLE hFile; 1009 hFile = CreateFileW(szLinkFile, GENERIC_READ | GENERIC_WRITE, 1010 FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 1011 if (hFile != INVALID_HANDLE_VALUE) 1012 { 1013 TRACE("Just touch file '%S'.\n", szLinkFile); 1014 CloseHandle(hFile); 1015 goto Quit; 1016 } 1017 } 1018 1019 /* add MRU data */ 1020 ret = AddMRUData(hMRUList, Buffer, cbBuffer); 1021 if (ret < 0) 1022 { 1023 ERR("AddMRUData failed: %d\n", ret); 1024 goto Quit; 1025 } 1026 1027 /* *** JOB 2: Create shortcut in user's "Recent" directory *** */ 1028 1029 hr = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, 1030 &IID_IShellLinkW, (LPVOID *)&psl); 1031 if (FAILED(hr)) 1032 { 1033 ERR("CoInitialize for IID_IShellLinkW: %08X\n", hr); 1034 goto Quit; 1035 } 1036 1037 hr = IShellLinkW_QueryInterface(psl, &IID_IPersistFile, (LPVOID *)&pPf); 1038 if (FAILED(hr)) 1039 { 1040 ERR("IShellLinkW_QueryInterface: %08X\n", hr); 1041 goto Quit; 1042 } 1043 1044 if (uFlags == SHARD_PIDL) 1045 hr = IShellLinkW_SetIDList(psl, pv); 1046 else 1047 hr = IShellLinkW_SetPath(psl, pv); 1048 1049 IShellLinkW_SetDescription(psl, szDescription); 1050 1051 hr = IPersistFile_Save(pPf, szLinkFile, TRUE); 1052 if (FAILED(hr)) 1053 { 1054 ERR("IPersistFile_Save: 0x%08X\n", hr); 1055 } 1056 1057 hr = IPersistFile_SaveCompleted(pPf, szLinkFile); 1058 if (FAILED(hr)) 1059 { 1060 ERR("IPersistFile_SaveCompleted: 0x%08X\n", hr); 1061 } 1062 1063 Quit: 1064 if (hMRUList) 1065 FreeMRUList(hMRUList); 1066 if (pPf) 1067 IPersistFile_Release(pPf); 1068 if (psl) 1069 IShellLinkW_Release(psl); 1070 CoUninitialize(); 1071 RegCloseKey(hExplorerKey); 1072 #else 1073 /* If list is a string list lpfnCompare has the following prototype 1074 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2) 1075 * for binary lists the prototype is 1076 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData) 1077 * where cbData is the no. of bytes to compare. 1078 * Need to check what return value means identical - 0? 1079 */ 1080 1081 1082 UINT olderrormode; 1083 HKEY HCUbasekey; 1084 CHAR doc_name[MAX_PATH]; 1085 CHAR link_dir[MAX_PATH]; 1086 CHAR new_lnk_filepath[MAX_PATH]; 1087 CHAR new_lnk_name[MAX_PATH]; 1088 CHAR * ext; 1089 IMalloc *ppM; 1090 LPITEMIDLIST pidl; 1091 HWND hwnd = 0; /* FIXME: get real window handle */ 1092 INT ret; 1093 DWORD data[64], datalen, type; 1094 1095 TRACE("%04x %p\n", uFlags, pv); 1096 1097 /*FIXME: Document: 1098 * RecentDocs MRU data structure seems to be: 1099 * +0h document file name w/ terminating 0h 1100 * +nh short int w/ size of remaining 1101 * +n+2h 02h 30h, or 01h 30h, or 00h 30h - unknown 1102 * +n+4h 10 bytes zeros - unknown 1103 * +n+eh shortcut file name w/ terminating 0h 1104 * +n+e+nh 3 zero bytes - unknown 1105 */ 1106 1107 /* See if we need to do anything. 1108 */ 1109 datalen = 64; 1110 ret=SHADD_get_policy( "NoRecentDocsHistory", &type, data, &datalen); 1111 if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) { 1112 ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret); 1113 return; 1114 } 1115 if (ret == ERROR_SUCCESS) { 1116 if (!( (type == REG_DWORD) || 1117 ((type == REG_BINARY) && (datalen == 4)) )) { 1118 ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n", 1119 type, datalen); 1120 return; 1121 } 1122 1123 TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]); 1124 /* now test the actual policy value */ 1125 if ( data[0] != 0) 1126 return; 1127 } 1128 1129 /* Open key to where the necessary info is 1130 */ 1131 /* FIXME: This should be done during DLL PROCESS_ATTACH (or THREAD_ATTACH) 1132 * and the close should be done during the _DETACH. The resulting 1133 * key is stored in the DLL global data. 1134 */ 1135 if (RegCreateKeyExA(HKEY_CURRENT_USER, 1136 "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 1137 0, 0, 0, KEY_READ, 0, &HCUbasekey, 0)) { 1138 ERR("Failed to create 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n"); 1139 return; 1140 } 1141 1142 /* Get path to user's "Recent" directory 1143 */ 1144 if(SUCCEEDED(SHGetMalloc(&ppM))) { 1145 if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT, 1146 &pidl))) { 1147 SHGetPathFromIDListA(pidl, link_dir); 1148 IMalloc_Free(ppM, pidl); 1149 } 1150 else { 1151 /* serious issues */ 1152 link_dir[0] = 0; 1153 ERR("serious issues 1\n"); 1154 } 1155 IMalloc_Release(ppM); 1156 } 1157 else { 1158 /* serious issues */ 1159 link_dir[0] = 0; 1160 ERR("serious issues 2\n"); 1161 } 1162 TRACE("Users Recent dir %s\n", link_dir); 1163 1164 /* If no input, then go clear the lists */ 1165 if (!pv) { 1166 /* clear user's Recent dir 1167 */ 1168 1169 /* FIXME: delete all files in "link_dir" 1170 * 1171 * while( more files ) { 1172 * lstrcpyA(old_lnk_name, link_dir); 1173 * PathAppendA(old_lnk_name, filenam); 1174 * DeleteFileA(old_lnk_name); 1175 * } 1176 */ 1177 FIXME("should delete all files in %s\\\n", link_dir); 1178 1179 /* clear MRU list 1180 */ 1181 /* MS Bug ?? v4.72.3612.1700 of shell32 does the delete against 1182 * HKEY_LOCAL_MACHINE version of ...CurrentVersion\Explorer 1183 * and naturally it fails w/ rc=2. It should do it against 1184 * HKEY_CURRENT_USER which is where it is stored, and where 1185 * the MRU routines expect it!!!! 1186 */ 1187 RegDeleteKeyA(HCUbasekey, "RecentDocs"); 1188 RegCloseKey(HCUbasekey); 1189 return; 1190 } 1191 1192 /* Have data to add, the jobs to be done: 1193 * 1. Add document to MRU list in registry "HKCU\Software\ 1194 * Microsoft\Windows\CurrentVersion\Explorer\RecentDocs". 1195 * 2. Add shortcut to document in the user's Recent directory 1196 * (CSIDL_RECENT). 1197 * 3. Add shortcut to Start menu's Documents submenu. 1198 */ 1199 1200 /* Get the pure document name from the input 1201 */ 1202 switch (uFlags) 1203 { 1204 case SHARD_PIDL: 1205 if (!SHGetPathFromIDListA(pv, doc_name)) 1206 { 1207 WARN("can't get path from PIDL\n"); 1208 return; 1209 } 1210 break; 1211 1212 case SHARD_PATHA: 1213 lstrcpynA(doc_name, pv, MAX_PATH); 1214 break; 1215 1216 case SHARD_PATHW: 1217 WideCharToMultiByte(CP_ACP, 0, pv, -1, doc_name, MAX_PATH, NULL, NULL); 1218 break; 1219 1220 default: 1221 FIXME("Unsupported flags: %u\n", uFlags); 1222 return; 1223 } 1224 1225 TRACE("full document name %s\n", debugstr_a(doc_name)); 1226 1227 PathStripPathA(doc_name); 1228 TRACE("stripped document name %s\n", debugstr_a(doc_name)); 1229 1230 1231 /* *** JOB 1: Update registry for ...\Explorer\RecentDocs list *** */ 1232 1233 { /* on input needs: 1234 * doc_name - pure file-spec, no path 1235 * link_dir - path to the user's Recent directory 1236 * HCUbasekey - key of ...Windows\CurrentVersion\Explorer" node 1237 * creates: 1238 * new_lnk_name- pure file-spec, no path for new .lnk file 1239 * new_lnk_filepath 1240 * - path and file name of new .lnk file 1241 */ 1242 CREATEMRULISTA mymru; 1243 HANDLE mruhandle; 1244 INT len, pos, bufused, err; 1245 INT i; 1246 DWORD attr; 1247 CHAR buffer[2048]; 1248 CHAR *ptr; 1249 CHAR old_lnk_name[MAX_PATH]; 1250 short int slen; 1251 1252 mymru.cbSize = sizeof(CREATEMRULISTA); 1253 mymru.nMaxItems = 15; 1254 mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE; 1255 mymru.hKey = HCUbasekey; 1256 mymru.lpszSubKey = "RecentDocs"; 1257 mymru.lpfnCompare = SHADD_compare_mru; 1258 mruhandle = CreateMRUListA(&mymru); 1259 if (!mruhandle) { 1260 /* MRU failed */ 1261 ERR("MRU processing failed, handle zero\n"); 1262 RegCloseKey(HCUbasekey); 1263 return; 1264 } 1265 len = lstrlenA(doc_name); 1266 pos = FindMRUData(mruhandle, doc_name, len, 0); 1267 1268 /* Now get the MRU entry that will be replaced 1269 * and delete the .lnk file for it 1270 */ 1271 if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos, 1272 buffer, 2048)) != -1) { 1273 ptr = buffer; 1274 ptr += (lstrlenA(buffer) + 1); 1275 slen = *((short int*)ptr); 1276 ptr += 2; /* skip the length area */ 1277 if (bufused >= slen + (ptr-buffer)) { 1278 /* buffer size looks good */ 1279 ptr += 12; /* get to string */ 1280 len = bufused - (ptr-buffer); /* get length of buf remaining */ 1281 if (ptr[0] && (lstrlenA(ptr) <= len-1)) { 1282 /* appears to be good string */ 1283 lstrcpyA(old_lnk_name, link_dir); 1284 PathAppendA(old_lnk_name, ptr); 1285 if (!DeleteFileA(old_lnk_name)) { 1286 if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) { 1287 if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) { 1288 ERR("Delete for %s failed, err=%d, attr=%08x\n", 1289 old_lnk_name, err, attr); 1290 } 1291 else { 1292 TRACE("old .lnk file %s did not exist\n", 1293 old_lnk_name); 1294 } 1295 } 1296 else { 1297 ERR("Delete for %s failed, attr=%08x\n", 1298 old_lnk_name, attr); 1299 } 1300 } 1301 else { 1302 TRACE("deleted old .lnk file %s\n", old_lnk_name); 1303 } 1304 } 1305 } 1306 } 1307 1308 /* Create usable .lnk file name for the "Recent" directory 1309 */ 1310 wsprintfA(new_lnk_name, "%s.lnk", doc_name); 1311 lstrcpyA(new_lnk_filepath, link_dir); 1312 PathAppendA(new_lnk_filepath, new_lnk_name); 1313 i = 1; 1314 olderrormode = SetErrorMode(SEM_FAILCRITICALERRORS); 1315 while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) { 1316 i++; 1317 wsprintfA(new_lnk_name, "%s (%u).lnk", doc_name, i); 1318 lstrcpyA(new_lnk_filepath, link_dir); 1319 PathAppendA(new_lnk_filepath, new_lnk_name); 1320 } 1321 SetErrorMode(olderrormode); 1322 TRACE("new shortcut will be %s\n", new_lnk_filepath); 1323 1324 /* Now add the new MRU entry and data 1325 */ 1326 pos = SHADD_create_add_mru_data(mruhandle, doc_name, new_lnk_name, 1327 buffer, &len); 1328 FreeMRUList(mruhandle); 1329 TRACE("Updated MRU list, new doc is position %d\n", pos); 1330 } 1331 1332 /* *** JOB 2: Create shortcut in user's "Recent" directory *** */ 1333 1334 { /* on input needs: 1335 * doc_name - pure file-spec, no path 1336 * new_lnk_filepath 1337 * - path and file name of new .lnk file 1338 * uFlags[in] - flags on call to SHAddToRecentDocs 1339 * pv[in] - document path/pidl on call to SHAddToRecentDocs 1340 */ 1341 IShellLinkA *psl = NULL; 1342 IPersistFile *pPf = NULL; 1343 HRESULT hres; 1344 CHAR desc[MAX_PATH]; 1345 WCHAR widelink[MAX_PATH]; 1346 1347 CoInitialize(0); 1348 1349 hres = CoCreateInstance( &CLSID_ShellLink, 1350 NULL, 1351 CLSCTX_INPROC_SERVER, 1352 &IID_IShellLinkA, 1353 (LPVOID )&psl); 1354 if(SUCCEEDED(hres)) { 1355 1356 hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile, 1357 (LPVOID *)&pPf); 1358 if(FAILED(hres)) { 1359 /* bombed */ 1360 ERR("failed QueryInterface for IPersistFile %08x\n", hres); 1361 goto fail; 1362 } 1363 1364 /* Set the document path or pidl */ 1365 if (uFlags == SHARD_PIDL) { 1366 hres = IShellLinkA_SetIDList(psl, pv); 1367 } else { 1368 hres = IShellLinkA_SetPath(psl, pv); 1369 } 1370 if(FAILED(hres)) { 1371 /* bombed */ 1372 ERR("failed Set{IDList|Path} %08x\n", hres); 1373 goto fail; 1374 } 1375 1376 lstrcpyA(desc, "Shortcut to "); 1377 lstrcatA(desc, doc_name); 1378 hres = IShellLinkA_SetDescription(psl, desc); 1379 if(FAILED(hres)) { 1380 /* bombed */ 1381 ERR("failed SetDescription %08x\n", hres); 1382 goto fail; 1383 } 1384 1385 MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1, 1386 widelink, MAX_PATH); 1387 /* create the short cut */ 1388 hres = IPersistFile_Save(pPf, widelink, TRUE); 1389 if(FAILED(hres)) { 1390 /* bombed */ 1391 ERR("failed IPersistFile::Save %08x\n", hres); 1392 IPersistFile_Release(pPf); 1393 IShellLinkA_Release(psl); 1394 goto fail; 1395 } 1396 hres = IPersistFile_SaveCompleted(pPf, widelink); 1397 IPersistFile_Release(pPf); 1398 IShellLinkA_Release(psl); 1399 TRACE("shortcut %s has been created, result=%08x\n", 1400 new_lnk_filepath, hres); 1401 } 1402 else { 1403 ERR("CoCreateInstance failed, hres=%08x\n", hres); 1404 } 1405 } 1406 1407 fail: 1408 CoUninitialize(); 1409 1410 /* all done */ 1411 RegCloseKey(HCUbasekey); 1412 return; 1413 #endif 1414 } 1415 1416 /************************************************************************* 1417 * SHCreateShellFolderViewEx [SHELL32.174] 1418 * 1419 * Create a new instance of the default Shell folder view object. 1420 * 1421 * RETURNS 1422 * Success: S_OK 1423 * Failure: error value 1424 * 1425 * NOTES 1426 * see IShellFolder::CreateViewObject 1427 */ 1428 #ifndef __REACTOS__ 1429 1430 HRESULT WINAPI SHCreateShellFolderViewEx( 1431 LPCSFV psvcbi, /* [in] shelltemplate struct */ 1432 IShellView **ppv) /* [out] IShellView pointer */ 1433 { 1434 IShellView * psf; 1435 HRESULT hRes; 1436 1437 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n", 1438 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback, 1439 psvcbi->fvm, psvcbi->psvOuter); 1440 1441 *ppv = NULL; 1442 hRes = IShellView_Constructor(psvcbi->pshf, &psf); 1443 1444 if (FAILED(hRes)) 1445 return hRes; 1446 1447 hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppv); 1448 IShellView_Release(psf); 1449 1450 return hRes; 1451 } 1452 #endif 1453 1454 /************************************************************************* 1455 * SHWinHelp [SHELL32.127] 1456 * 1457 */ 1458 HRESULT WINAPI SHWinHelp(HWND hwnd, LPCWSTR pszHelp, UINT uCommand, ULONG_PTR dwData) 1459 { 1460 TRACE("(%p, %s, 0x%08x, %p)\n", hwnd, debugstr_w(pszHelp), uCommand, dwData); 1461 if (!WinHelpW(hwnd, pszHelp, uCommand, dwData)) 1462 { 1463 #if 0 1464 ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(9115), 1465 MAKEINTRESOURCEW(9116), MB_ICONSTOP); 1466 #endif 1467 return FALSE; 1468 } 1469 return TRUE; 1470 } 1471 /************************************************************************* 1472 * SHRunControlPanel [SHELL32.161] 1473 * 1474 */ 1475 BOOL WINAPI SHRunControlPanel (_In_ LPCWSTR commandLine, _In_opt_ HWND parent) 1476 { 1477 #ifdef __REACTOS__ 1478 /* 1479 * TODO: Run in-process when possible, using 1480 * HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ControlPanel\InProcCPLs 1481 * and possibly some extra rules. 1482 * See also https://docs.microsoft.com/en-us/windows/win32/api/shlobj/nf-shlobj-shruncontrolpanel 1483 * "If the specified Control Panel item is already running, SHRunControlPanel 1484 * attempts to switch to that instance rather than opening a new instance." 1485 * This function is not supported as of Windows Vista, where it always returns FALSE. 1486 * However we need to keep it "alive" even when ReactOS is compliled as NT6+ 1487 * in order to keep control panel elements launch commands. 1488 */ 1489 WCHAR parameters[MAX_PATH] = L"shell32.dll,Control_RunDLL "; 1490 TRACE("(%s, %p)n", debugstr_w(commandLine), parent); 1491 wcscat(parameters, commandLine); 1492 1493 return ((INT_PTR)ShellExecuteW(parent, L"open", L"rundll32.exe", parameters, NULL, SW_SHOWNORMAL) > 32); 1494 #else 1495 FIXME("(%s, %p): stub\n", debugstr_w(commandLine), parent); 1496 return FALSE; 1497 #endif 1498 } 1499 1500 static LPUNKNOWN SHELL32_IExplorerInterface=0; 1501 /************************************************************************* 1502 * SHSetInstanceExplorer [SHELL32.176] 1503 * 1504 * NOTES 1505 * Sets the interface 1506 */ 1507 VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown) 1508 { TRACE("%p\n", lpUnknown); 1509 SHELL32_IExplorerInterface = lpUnknown; 1510 } 1511 /************************************************************************* 1512 * SHGetInstanceExplorer [SHELL32.@] 1513 * 1514 * NOTES 1515 * gets the interface pointer of the explorer and a reference 1516 */ 1517 HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown) 1518 { TRACE("%p\n", lpUnknown); 1519 1520 *lpUnknown = SHELL32_IExplorerInterface; 1521 1522 if (!SHELL32_IExplorerInterface) 1523 return E_FAIL; 1524 1525 IUnknown_AddRef(SHELL32_IExplorerInterface); 1526 return S_OK; 1527 } 1528 /************************************************************************* 1529 * SHFreeUnusedLibraries [SHELL32.123] 1530 * 1531 * Probably equivalent to CoFreeUnusedLibraries but under Windows 9x it could use 1532 * the shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 1533 * for details 1534 * 1535 * NOTES 1536 * exported by ordinal 1537 * 1538 * SEE ALSO 1539 * CoFreeUnusedLibraries, SHLoadOLE 1540 */ 1541 void WINAPI SHFreeUnusedLibraries (void) 1542 { 1543 FIXME("stub\n"); 1544 CoFreeUnusedLibraries(); 1545 } 1546 /************************************************************************* 1547 * DAD_AutoScroll [SHELL32.129] 1548 * 1549 */ 1550 BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *samples, const POINT * pt) 1551 { 1552 FIXME("hwnd = %p %p %p\n",hwnd,samples,pt); 1553 return FALSE; 1554 } 1555 /************************************************************************* 1556 * DAD_DragEnter [SHELL32.130] 1557 * 1558 */ 1559 BOOL WINAPI DAD_DragEnter(HWND hwnd) 1560 { 1561 FIXME("hwnd = %p\n",hwnd); 1562 return FALSE; 1563 } 1564 /************************************************************************* 1565 * DAD_DragEnterEx [SHELL32.131] 1566 * 1567 */ 1568 BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p) 1569 { 1570 FIXME("hwnd = %p (%d,%d)\n",hwnd,p.x,p.y); 1571 return FALSE; 1572 } 1573 /************************************************************************* 1574 * DAD_DragMove [SHELL32.134] 1575 * 1576 */ 1577 BOOL WINAPI DAD_DragMove(POINT p) 1578 { 1579 FIXME("(%d,%d)\n",p.x,p.y); 1580 return FALSE; 1581 } 1582 /************************************************************************* 1583 * DAD_DragLeave [SHELL32.132] 1584 * 1585 */ 1586 BOOL WINAPI DAD_DragLeave(VOID) 1587 { 1588 FIXME("\n"); 1589 return FALSE; 1590 } 1591 /************************************************************************* 1592 * DAD_SetDragImage [SHELL32.136] 1593 * 1594 * NOTES 1595 * exported by name 1596 */ 1597 BOOL WINAPI DAD_SetDragImage( 1598 HIMAGELIST himlTrack, 1599 LPPOINT lppt) 1600 { 1601 FIXME("%p %p stub\n",himlTrack, lppt); 1602 return FALSE; 1603 } 1604 /************************************************************************* 1605 * DAD_ShowDragImage [SHELL32.137] 1606 * 1607 * NOTES 1608 * exported by name 1609 */ 1610 BOOL WINAPI DAD_ShowDragImage(BOOL bShow) 1611 { 1612 FIXME("0x%08x stub\n",bShow); 1613 return FALSE; 1614 } 1615 1616 /************************************************************************* 1617 * ReadCabinetState [SHELL32.651] NT 4.0 1618 * 1619 */ 1620 BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length) 1621 { 1622 HKEY hkey = 0; 1623 DWORD type, r; 1624 1625 TRACE("%p %d\n", cs, length); 1626 1627 if( (cs == NULL) || (length < (int)sizeof(*cs)) ) 1628 return FALSE; 1629 1630 r = RegOpenKeyW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CabinetState", &hkey ); 1631 if( r == ERROR_SUCCESS ) 1632 { 1633 type = REG_BINARY; 1634 r = RegQueryValueExW( hkey, L"Settings", 1635 NULL, &type, (LPBYTE)cs, (LPDWORD)&length ); 1636 RegCloseKey( hkey ); 1637 1638 } 1639 1640 /* if we can't read from the registry, create default values */ 1641 if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) || 1642 (cs->cLength != length) ) 1643 { 1644 TRACE("Initializing shell cabinet settings\n"); 1645 memset(cs, 0, sizeof(*cs)); 1646 cs->cLength = sizeof(*cs); 1647 cs->nVersion = 2; 1648 cs->fFullPathTitle = FALSE; 1649 cs->fSaveLocalView = TRUE; 1650 cs->fNotShell = FALSE; 1651 cs->fSimpleDefault = TRUE; 1652 cs->fDontShowDescBar = FALSE; 1653 cs->fNewWindowMode = FALSE; 1654 cs->fShowCompColor = FALSE; 1655 cs->fDontPrettyNames = FALSE; 1656 cs->fAdminsCreateCommonGroups = TRUE; 1657 cs->fMenuEnumFilter = 96; 1658 } 1659 1660 return TRUE; 1661 } 1662 1663 /************************************************************************* 1664 * WriteCabinetState [SHELL32.652] NT 4.0 1665 * 1666 */ 1667 BOOL WINAPI WriteCabinetState(CABINETSTATE *cs) 1668 { 1669 DWORD r; 1670 HKEY hkey = 0; 1671 1672 TRACE("%p\n",cs); 1673 1674 if( cs == NULL ) 1675 return FALSE; 1676 1677 r = RegCreateKeyExW( HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CabinetState", 0, 1678 NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL); 1679 if( r == ERROR_SUCCESS ) 1680 { 1681 r = RegSetValueExW( hkey, L"Settings", 0, 1682 REG_BINARY, (LPBYTE) cs, cs->cLength); 1683 1684 RegCloseKey( hkey ); 1685 } 1686 1687 return (r==ERROR_SUCCESS); 1688 } 1689 1690 /************************************************************************* 1691 * FileIconInit [SHELL32.660] 1692 * 1693 */ 1694 BOOL WINAPI FileIconInit(BOOL bFullInit) 1695 { 1696 return SIC_Initialize(); 1697 } 1698 1699 /************************************************************************* 1700 * SetAppStartingCursor [SHELL32.99] 1701 */ 1702 HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v) 1703 { FIXME("hwnd=%p 0x%04x stub\n",u,v ); 1704 return 0; 1705 } 1706 1707 /************************************************************************* 1708 * SHLoadOLE [SHELL32.151] 1709 * 1710 * To reduce the memory usage of Windows 95, its shell32 contained an 1711 * internal implementation of a part of COM (see e.g. SHGetMalloc, SHCoCreateInstance, 1712 * SHRegisterDragDrop etc.) that allowed to use in-process STA objects without 1713 * the need to load OLE32.DLL. If OLE32.DLL was already loaded, the SH* function 1714 * would just call the Co* functions. 1715 * 1716 * The SHLoadOLE was called when OLE32.DLL was being loaded to transfer all the 1717 * information from the shell32 "mini-COM" to ole32.dll. 1718 * 1719 * See http://blogs.msdn.com/oldnewthing/archive/2004/07/05/173226.aspx for a 1720 * detailed description. 1721 * 1722 * Under wine ole32.dll is always loaded as it is imported by shlwapi.dll which is 1723 * imported by shell32 and no "mini-COM" is used (except for the "LoadWithoutCOM" 1724 * hack in SHCoCreateInstance) 1725 */ 1726 HRESULT WINAPI SHLoadOLE(LPARAM lParam) 1727 { FIXME("0x%08lx stub\n",lParam); 1728 return S_OK; 1729 } 1730 /************************************************************************* 1731 * DriveType [SHELL32.64] 1732 * 1733 */ 1734 int WINAPI DriveType(int DriveType) 1735 { 1736 WCHAR root[] = L"A:\\"; 1737 root[0] = L'A' + DriveType; 1738 return GetDriveTypeW(root); 1739 } 1740 /************************************************************************* 1741 * InvalidateDriveType [SHELL32.65] 1742 * Unimplemented in XP SP3 1743 */ 1744 int WINAPI InvalidateDriveType(int u) 1745 { 1746 TRACE("0x%08x stub\n",u); 1747 return 0; 1748 } 1749 /************************************************************************* 1750 * SHAbortInvokeCommand [SHELL32.198] 1751 * 1752 */ 1753 HRESULT WINAPI SHAbortInvokeCommand(void) 1754 { FIXME("stub\n"); 1755 return 1; 1756 } 1757 /************************************************************************* 1758 * SHOutOfMemoryMessageBox [SHELL32.126] 1759 * 1760 */ 1761 int WINAPI SHOutOfMemoryMessageBox( 1762 HWND hwndOwner, 1763 LPCSTR lpCaption, 1764 UINT uType) 1765 { 1766 FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType); 1767 return 0; 1768 } 1769 /************************************************************************* 1770 * SHFlushClipboard [SHELL32.121] 1771 * 1772 */ 1773 HRESULT WINAPI SHFlushClipboard(void) 1774 { 1775 return OleFlushClipboard(); 1776 } 1777 1778 /************************************************************************* 1779 * SHWaitForFileToOpen [SHELL32.97] 1780 * 1781 */ 1782 BOOL WINAPI SHWaitForFileToOpen( 1783 LPCITEMIDLIST pidl, 1784 DWORD dwFlags, 1785 DWORD dwTimeout) 1786 { 1787 FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout); 1788 return FALSE; 1789 } 1790 1791 /************************************************************************ 1792 * RLBuildListOfPaths [SHELL32.146] 1793 * 1794 * NOTES 1795 * builds a DPA 1796 */ 1797 DWORD WINAPI RLBuildListOfPaths (void) 1798 { FIXME("stub\n"); 1799 return 0; 1800 } 1801 /************************************************************************ 1802 * SHValidateUNC [SHELL32.173] 1803 * 1804 */ 1805 BOOL WINAPI SHValidateUNC (HWND hwndOwner, PWSTR pszFile, UINT fConnect) 1806 { 1807 FIXME("(%p, %s, 0x%08x): stub\n", hwndOwner, debugstr_w(pszFile), fConnect); 1808 return FALSE; 1809 } 1810 1811 /************************************************************************ 1812 * DoEnvironmentSubstA [SHELL32.@] 1813 * 1814 * See DoEnvironmentSubstW. 1815 */ 1816 DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString) 1817 { 1818 LPSTR dst; 1819 BOOL res = FALSE; 1820 DWORD len = cchString; 1821 1822 TRACE("(%s, %d)\n", debugstr_a(pszString), cchString); 1823 if (pszString == NULL) /* Really return 0? */ 1824 return 0; 1825 if ((dst = (LPSTR)HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(CHAR)))) 1826 { 1827 len = ExpandEnvironmentStringsA(pszString, dst, cchString); 1828 /* len includes the terminating 0 */ 1829 if (len && len < cchString) 1830 { 1831 res = TRUE; 1832 memcpy(pszString, dst, len); 1833 } 1834 else 1835 len = cchString; 1836 1837 HeapFree(GetProcessHeap(), 0, dst); 1838 } 1839 return MAKELONG(len, res); 1840 } 1841 1842 /************************************************************************ 1843 * DoEnvironmentSubstW [SHELL32.@] 1844 * 1845 * Replace all %KEYWORD% in the string with the value of the named 1846 * environment variable. If the buffer is too small, the string is not modified. 1847 * 1848 * PARAMS 1849 * pszString [I] '\0' terminated string with %keyword%. 1850 * [O] '\0' terminated string with %keyword% substituted. 1851 * cchString [I] size of str. 1852 * 1853 * RETURNS 1854 * Success: The string in the buffer is updated 1855 * HIWORD: TRUE 1856 * LOWORD: characters used in the buffer, including space for the terminating 0 1857 * Failure: buffer too small. The string is not modified. 1858 * HIWORD: FALSE 1859 * LOWORD: provided size of the buffer in characters 1860 */ 1861 DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString) 1862 { 1863 LPWSTR dst; 1864 BOOL res = FALSE; 1865 DWORD len = cchString; 1866 1867 TRACE("(%s, %d)\n", debugstr_w(pszString), cchString); 1868 1869 if ((cchString < MAXLONG) && (dst = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(WCHAR)))) 1870 { 1871 len = ExpandEnvironmentStringsW(pszString, dst, cchString); 1872 /* len includes the terminating 0 */ 1873 if (len && len <= cchString) 1874 { 1875 res = TRUE; 1876 memcpy(pszString, dst, len * sizeof(WCHAR)); 1877 } 1878 else 1879 len = cchString; 1880 1881 HeapFree(GetProcessHeap(), 0, dst); 1882 } 1883 return MAKELONG(len, res); 1884 } 1885 1886 /************************************************************************ 1887 * DoEnvironmentSubst [SHELL32.53] 1888 * 1889 * See DoEnvironmentSubstA. 1890 */ 1891 DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y) 1892 { 1893 if (SHELL_OsIsUnicode()) 1894 return DoEnvironmentSubstW(x, y); 1895 return DoEnvironmentSubstA(x, y); 1896 } 1897 1898 /************************************************************************* 1899 * GUIDFromStringA [SHELL32.703] 1900 */ 1901 BOOL WINAPI GUIDFromStringA(LPCSTR str, LPGUID guid) 1902 { 1903 TRACE("GUIDFromStringA() stub\n"); 1904 return FALSE; 1905 } 1906 1907 /************************************************************************* 1908 * GUIDFromStringW [SHELL32.704] 1909 */ 1910 BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid) 1911 { 1912 UNICODE_STRING guid_str; 1913 1914 RtlInitUnicodeString(&guid_str, str); 1915 return !RtlGUIDFromString(&guid_str, guid); 1916 } 1917 1918 /************************************************************************* 1919 * PathIsTemporaryA [SHELL32.713] 1920 */ 1921 BOOL WINAPI PathIsTemporaryA(LPSTR Str) 1922 { 1923 FIXME("(%s)stub\n", debugstr_a(Str)); 1924 return FALSE; 1925 } 1926 1927 /************************************************************************* 1928 * PathIsTemporaryW [SHELL32.714] 1929 */ 1930 BOOL WINAPI PathIsTemporaryW(LPWSTR Str) 1931 { 1932 FIXME("(%s)stub\n", debugstr_w(Str)); 1933 return FALSE; 1934 } 1935 1936 typedef struct _PSXA 1937 { 1938 UINT uiCount; 1939 UINT uiAllocated; 1940 IShellPropSheetExt *pspsx[1]; 1941 } PSXA, *PPSXA; 1942 1943 typedef struct _PSXA_CALL 1944 { 1945 LPFNADDPROPSHEETPAGE lpfnAddReplaceWith; 1946 LPARAM lParam; 1947 BOOL bCalled; 1948 BOOL bMultiple; 1949 UINT uiCount; 1950 } PSXA_CALL, *PPSXA_CALL; 1951 1952 static BOOL CALLBACK PsxaCall(HPROPSHEETPAGE hpage, LPARAM lParam) 1953 { 1954 PPSXA_CALL Call = (PPSXA_CALL)lParam; 1955 1956 if (Call != NULL) 1957 { 1958 if ((Call->bMultiple || !Call->bCalled) && 1959 Call->lpfnAddReplaceWith(hpage, Call->lParam)) 1960 { 1961 Call->bCalled = TRUE; 1962 Call->uiCount++; 1963 return TRUE; 1964 } 1965 } 1966 1967 return FALSE; 1968 } 1969 1970 /************************************************************************* 1971 * SHAddFromPropSheetExtArray [SHELL32.167] 1972 */ 1973 UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) 1974 { 1975 PSXA_CALL Call; 1976 UINT i; 1977 PPSXA psxa = (PPSXA)hpsxa; 1978 1979 TRACE("(%p,%p,%08lx)\n", hpsxa, lpfnAddPage, lParam); 1980 1981 if (psxa) 1982 { 1983 ZeroMemory(&Call, sizeof(Call)); 1984 Call.lpfnAddReplaceWith = lpfnAddPage; 1985 Call.lParam = lParam; 1986 Call.bMultiple = TRUE; 1987 1988 /* Call the AddPage method of all registered IShellPropSheetExt interfaces */ 1989 for (i = 0; i != psxa->uiCount; i++) 1990 { 1991 psxa->pspsx[i]->lpVtbl->AddPages(psxa->pspsx[i], PsxaCall, (LPARAM)&Call); 1992 } 1993 1994 return Call.uiCount; 1995 } 1996 1997 return 0; 1998 } 1999 2000 /************************************************************************* 2001 * SHCreatePropSheetExtArray [SHELL32.168] 2002 */ 2003 HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) 2004 { 2005 return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL); 2006 } 2007 2008 /************************************************************************* 2009 * SHCreatePropSheetExtArrayEx [SHELL32.194] 2010 */ 2011 HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj) 2012 { 2013 WCHAR szHandler[64]; 2014 DWORD dwHandlerLen; 2015 WCHAR szClsidHandler[39]; 2016 DWORD dwClsidSize; 2017 CLSID clsid; 2018 LONG lRet; 2019 DWORD dwIndex; 2020 IShellExtInit *psxi; 2021 IShellPropSheetExt *pspsx; 2022 HKEY hkBase, hkPropSheetHandlers; 2023 PPSXA psxa = NULL; 2024 2025 TRACE("(%p,%s,%u)\n", hKey, debugstr_w(pszSubKey), max_iface); 2026 2027 if (max_iface == 0) 2028 return NULL; 2029 2030 /* Open the registry key */ 2031 lRet = RegOpenKeyW(hKey, pszSubKey, &hkBase); 2032 if (lRet != ERROR_SUCCESS) 2033 return NULL; 2034 2035 lRet = RegOpenKeyExW(hkBase, L"shellex\\PropertySheetHandlers", 0, KEY_ENUMERATE_SUB_KEYS, &hkPropSheetHandlers); 2036 RegCloseKey(hkBase); 2037 if (lRet == ERROR_SUCCESS) 2038 { 2039 /* Create and initialize the Property Sheet Extensions Array */ 2040 psxa = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface])); 2041 if (psxa) 2042 { 2043 ZeroMemory(psxa, FIELD_OFFSET(PSXA, pspsx[max_iface])); 2044 psxa->uiAllocated = max_iface; 2045 2046 /* Enumerate all subkeys and attempt to load the shell extensions */ 2047 dwIndex = 0; 2048 do 2049 { 2050 dwHandlerLen = sizeof(szHandler) / sizeof(szHandler[0]); 2051 lRet = RegEnumKeyExW(hkPropSheetHandlers, dwIndex++, szHandler, &dwHandlerLen, NULL, NULL, NULL, NULL); 2052 if (lRet != ERROR_SUCCESS) 2053 { 2054 if (lRet == ERROR_MORE_DATA) 2055 continue; 2056 2057 if (lRet == ERROR_NO_MORE_ITEMS) 2058 lRet = ERROR_SUCCESS; 2059 break; 2060 } 2061 2062 /* The CLSID is stored either in the key itself or in its default value. */ 2063 if (FAILED(lRet = SHCLSIDFromStringW(szHandler, &clsid))) 2064 { 2065 dwClsidSize = sizeof(szClsidHandler); 2066 if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS) 2067 { 2068 /* Force a NULL-termination and convert the string */ 2069 szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0; 2070 lRet = SHCLSIDFromStringW(szClsidHandler, &clsid); 2071 } 2072 } 2073 2074 if (SUCCEEDED(lRet)) 2075 { 2076 /* Attempt to get an IShellPropSheetExt and an IShellExtInit instance. 2077 Only if both interfaces are supported it's a real shell extension. 2078 Then call IShellExtInit's Initialize method. */ 2079 if (SUCCEEDED(CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER/* | CLSCTX_NO_CODE_DOWNLOAD */, &IID_IShellPropSheetExt, (LPVOID *)&pspsx))) 2080 { 2081 if (SUCCEEDED(pspsx->lpVtbl->QueryInterface(pspsx, &IID_IShellExtInit, (PVOID *)&psxi))) 2082 { 2083 if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey))) 2084 { 2085 /* Add the IShellPropSheetExt instance to the array */ 2086 psxa->pspsx[psxa->uiCount++] = pspsx; 2087 } 2088 else 2089 { 2090 psxi->lpVtbl->Release(psxi); 2091 pspsx->lpVtbl->Release(pspsx); 2092 } 2093 } 2094 else 2095 pspsx->lpVtbl->Release(pspsx); 2096 } 2097 } 2098 2099 } while (psxa->uiCount != psxa->uiAllocated); 2100 } 2101 else 2102 lRet = ERROR_NOT_ENOUGH_MEMORY; 2103 2104 RegCloseKey(hkPropSheetHandlers); 2105 } 2106 2107 if (lRet != ERROR_SUCCESS && psxa) 2108 { 2109 SHDestroyPropSheetExtArray((HPSXA)psxa); 2110 psxa = NULL; 2111 } 2112 2113 return (HPSXA)psxa; 2114 } 2115 2116 /************************************************************************* 2117 * SHReplaceFromPropSheetExtArray [SHELL32.170] 2118 */ 2119 UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam) 2120 { 2121 PSXA_CALL Call; 2122 UINT i; 2123 PPSXA psxa = (PPSXA)hpsxa; 2124 2125 TRACE("(%p,%u,%p,%08lx)\n", hpsxa, uPageID, lpfnReplaceWith, lParam); 2126 2127 if (psxa) 2128 { 2129 ZeroMemory(&Call, sizeof(Call)); 2130 Call.lpfnAddReplaceWith = lpfnReplaceWith; 2131 Call.lParam = lParam; 2132 2133 /* Call the ReplacePage method of all registered IShellPropSheetExt interfaces. 2134 Each shell extension is only allowed to call the callback once during the callback. */ 2135 for (i = 0; i != psxa->uiCount; i++) 2136 { 2137 Call.bCalled = FALSE; 2138 psxa->pspsx[i]->lpVtbl->ReplacePage(psxa->pspsx[i], uPageID, PsxaCall, (LPARAM)&Call); 2139 } 2140 2141 return Call.uiCount; 2142 } 2143 2144 return 0; 2145 } 2146 2147 /************************************************************************* 2148 * SHDestroyPropSheetExtArray [SHELL32.169] 2149 */ 2150 void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa) 2151 { 2152 UINT i; 2153 PPSXA psxa = (PPSXA)hpsxa; 2154 2155 TRACE("(%p)\n", hpsxa); 2156 2157 if (psxa) 2158 { 2159 for (i = 0; i != psxa->uiCount; i++) 2160 { 2161 psxa->pspsx[i]->lpVtbl->Release(psxa->pspsx[i]); 2162 } 2163 2164 LocalFree(psxa); 2165 } 2166 } 2167 2168 /************************************************************************* 2169 * CIDLData_CreateFromIDArray [SHELL32.83] 2170 * 2171 * Create IDataObject from PIDLs?? 2172 */ 2173 HRESULT WINAPI CIDLData_CreateFromIDArray( 2174 PCIDLIST_ABSOLUTE pidlFolder, 2175 UINT cpidlFiles, 2176 PCUIDLIST_RELATIVE_ARRAY lppidlFiles, 2177 LPDATAOBJECT *ppdataObject) 2178 { 2179 UINT i; 2180 HWND hwnd = 0; /*FIXME: who should be hwnd of owner? set to desktop */ 2181 HRESULT hResult; 2182 2183 TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject); 2184 if (TRACE_ON(pidl)) 2185 { 2186 pdump (pidlFolder); 2187 for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]); 2188 } 2189 hResult = IDataObject_Constructor(hwnd, pidlFolder, lppidlFiles, cpidlFiles, FALSE, ppdataObject); 2190 return hResult; 2191 } 2192 2193 /************************************************************************* 2194 * SHCreateStdEnumFmtEtc [SHELL32.74] 2195 * 2196 * NOTES 2197 * 2198 */ 2199 HRESULT WINAPI SHCreateStdEnumFmtEtc( 2200 UINT cFormats, 2201 const FORMATETC *lpFormats, 2202 LPENUMFORMATETC *ppenumFormatetc) 2203 { 2204 IEnumFORMATETC *pef; 2205 HRESULT hRes; 2206 TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc); 2207 2208 hRes = IEnumFORMATETC_Constructor(cFormats, lpFormats, &pef); 2209 if (FAILED(hRes)) 2210 return hRes; 2211 2212 IEnumFORMATETC_AddRef(pef); 2213 hRes = IEnumFORMATETC_QueryInterface(pef, &IID_IEnumFORMATETC, (LPVOID*)ppenumFormatetc); 2214 IEnumFORMATETC_Release(pef); 2215 2216 return hRes; 2217 } 2218 2219 /************************************************************************* 2220 * SHFindFiles (SHELL32.90) 2221 */ 2222 BOOL WINAPI SHFindFiles( PCIDLIST_ABSOLUTE pidlFolder, PCIDLIST_ABSOLUTE pidlSaveFile ) 2223 { 2224 FIXME("params ignored: %p %p\n", pidlFolder, pidlSaveFile); 2225 if (SHRestricted(REST_NOFIND)) 2226 { 2227 return FALSE; 2228 } 2229 /* Open the search results folder */ 2230 /* FIXME: CSearchBar should be opened as well */ 2231 return ShellExecuteW(NULL, NULL, L"explorer.exe", L"::{E17D4FC0-5564-11D1-83F2-00A0C90DC849}", NULL, SW_SHOWNORMAL) > (HINSTANCE)32; 2232 } 2233 2234 /************************************************************************* 2235 * SHUpdateImageW (SHELL32.192) 2236 * 2237 * Notifies the shell that an icon in the system image list has been changed. 2238 * 2239 * PARAMS 2240 * pszHashItem [I] Path to file that contains the icon. 2241 * iIndex [I] Zero-based index of the icon in the file. 2242 * uFlags [I] Flags determining the icon attributes. See notes. 2243 * iImageIndex [I] Index of the icon in the system image list. 2244 * 2245 * RETURNS 2246 * Nothing 2247 * 2248 * NOTES 2249 * uFlags can be one or more of the following flags: 2250 * GIL_NOTFILENAME - pszHashItem is not a file name. 2251 * GIL_SIMULATEDOC - Create a document icon using the specified icon. 2252 */ 2253 void WINAPI SHUpdateImageW(LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex) 2254 { 2255 FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex); 2256 } 2257 2258 /************************************************************************* 2259 * SHUpdateImageA (SHELL32.191) 2260 * 2261 * See SHUpdateImageW. 2262 */ 2263 VOID WINAPI SHUpdateImageA(LPCSTR pszHashItem, INT iIndex, UINT uFlags, INT iImageIndex) 2264 { 2265 FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_a(pszHashItem), iIndex, uFlags, iImageIndex); 2266 } 2267 2268 INT WINAPI SHHandleUpdateImage(PCIDLIST_ABSOLUTE pidlExtra) 2269 { 2270 FIXME("%p - stub\n", pidlExtra); 2271 2272 return -1; 2273 } 2274 2275 BOOL WINAPI SHObjectProperties(HWND hwnd, DWORD dwType, LPCWSTR szObject, LPCWSTR szPage) 2276 { 2277 FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage)); 2278 2279 return TRUE; 2280 } 2281 2282 BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy, 2283 UINT uFlags) 2284 { 2285 WCHAR wszLinkTo[MAX_PATH]; 2286 WCHAR wszDir[MAX_PATH]; 2287 WCHAR wszName[MAX_PATH]; 2288 BOOL res; 2289 2290 MultiByteToWideChar(CP_ACP, 0, pszLinkTo, -1, wszLinkTo, MAX_PATH); 2291 MultiByteToWideChar(CP_ACP, 0, pszDir, -1, wszDir, MAX_PATH); 2292 2293 res = SHGetNewLinkInfoW(wszLinkTo, wszDir, wszName, pfMustCopy, uFlags); 2294 2295 if (res) 2296 WideCharToMultiByte(CP_ACP, 0, wszName, -1, pszName, MAX_PATH, NULL, NULL); 2297 2298 return res; 2299 } 2300 2301 BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy, 2302 UINT uFlags) 2303 { 2304 const WCHAR *basename; 2305 WCHAR *dst_basename; 2306 int i=2; 2307 2308 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(pszLinkTo), debugstr_w(pszDir), 2309 pszName, pfMustCopy, uFlags); 2310 2311 *pfMustCopy = FALSE; 2312 2313 if (uFlags & SHGNLI_PIDL) 2314 { 2315 FIXME("SHGNLI_PIDL flag unsupported\n"); 2316 return FALSE; 2317 } 2318 2319 if (uFlags) 2320 FIXME("ignoring flags: 0x%08x\n", uFlags); 2321 2322 /* FIXME: should test if the file is a shortcut or DOS program */ 2323 if (GetFileAttributesW(pszLinkTo) == INVALID_FILE_ATTRIBUTES) 2324 return FALSE; 2325 2326 basename = strrchrW(pszLinkTo, '\\'); 2327 if (basename) 2328 basename = basename+1; 2329 else 2330 basename = pszLinkTo; 2331 2332 lstrcpynW(pszName, pszDir, MAX_PATH); 2333 if (!PathAddBackslashW(pszName)) 2334 return FALSE; 2335 2336 dst_basename = pszName + strlenW(pszName); 2337 2338 snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, L"%s.lnk", basename); 2339 2340 while (GetFileAttributesW(pszName) != INVALID_FILE_ATTRIBUTES) 2341 { 2342 snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, L"%s (%d).lnk", basename, i); 2343 i++; 2344 } 2345 2346 return TRUE; 2347 } 2348 2349 HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType) 2350 { 2351 #ifdef __REACTOS__ 2352 if (SHELL_OsIsUnicode()) 2353 return SHStartNetConnectionDialogW(hwnd, (LPCWSTR)pszRemoteName, dwType); 2354 return SHStartNetConnectionDialogA(hwnd, pszRemoteName, dwType); 2355 #else 2356 FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType); 2357 2358 return S_OK; 2359 #endif 2360 } 2361 /************************************************************************* 2362 * SHSetLocalizedName (SHELL32.@) 2363 */ 2364 HRESULT WINAPI SHSetLocalizedName(LPCWSTR pszPath, LPCWSTR pszResModule, int idsRes) 2365 { 2366 FIXME("%p, %s, %d - stub\n", pszPath, debugstr_w(pszResModule), idsRes); 2367 2368 return S_OK; 2369 } 2370 2371 /************************************************************************* 2372 * LinkWindow_RegisterClass (SHELL32.258) 2373 */ 2374 BOOL WINAPI LinkWindow_RegisterClass(void) 2375 { 2376 FIXME("()\n"); 2377 return TRUE; 2378 } 2379 2380 /************************************************************************* 2381 * LinkWindow_UnregisterClass (SHELL32.259) 2382 */ 2383 BOOL WINAPI LinkWindow_UnregisterClass(DWORD dwUnused) 2384 { 2385 FIXME("()\n"); 2386 return TRUE; 2387 } 2388 2389 /************************************************************************* 2390 * SHFlushSFCache (SHELL32.526) 2391 * 2392 * Notifies the shell that a user-specified special folder location has changed. 2393 * 2394 * NOTES 2395 * In Wine, the shell folder registry values are not cached, so this function 2396 * has no effect. 2397 */ 2398 void WINAPI SHFlushSFCache(void) 2399 { 2400 } 2401 2402 /************************************************************************* 2403 * SHGetImageList (SHELL32.727) 2404 * 2405 * Returns a copy of a shell image list. 2406 * 2407 * NOTES 2408 * Windows XP features 4 sizes of image list, and Vista 5. Wine currently 2409 * only supports the traditional small and large image lists, so requests 2410 * for the others will currently fail. 2411 */ 2412 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv) 2413 { 2414 HIMAGELIST hLarge, hSmall; 2415 HIMAGELIST hNew; 2416 HRESULT ret = E_FAIL; 2417 2418 /* Wine currently only maintains large and small image lists */ 2419 if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL)) 2420 { 2421 FIXME("Unsupported image list %i requested\n", iImageList); 2422 return E_FAIL; 2423 } 2424 2425 Shell_GetImageLists(&hLarge, &hSmall); 2426 #ifndef __REACTOS__ 2427 hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall); 2428 2429 /* Get the interface for the new image list */ 2430 if (hNew) 2431 { 2432 ret = HIMAGELIST_QueryInterface(hNew, riid, ppv); 2433 ImageList_Destroy(hNew); 2434 } 2435 #else 2436 /* Duplicating the imagelist causes the start menu items not to draw on 2437 * the first show. Was the Duplicate necessary for some reason? I believe 2438 * Windows returns the raw pointer here. */ 2439 hNew = (iImageList == SHIL_LARGE ? hLarge : hSmall); 2440 ret = IImageList2_QueryInterface((IImageList2 *) hNew, riid, ppv); 2441 #endif 2442 2443 return ret; 2444 } 2445 2446 #ifndef __REACTOS__ 2447 2448 /************************************************************************* 2449 * SHCreateShellFolderView [SHELL32.256] 2450 * 2451 * Create a new instance of the default Shell folder view object. 2452 * 2453 * RETURNS 2454 * Success: S_OK 2455 * Failure: error value 2456 * 2457 * NOTES 2458 * see IShellFolder::CreateViewObject 2459 */ 2460 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, 2461 IShellView **ppsv) 2462 { 2463 IShellView * psf; 2464 HRESULT hRes; 2465 2466 *ppsv = NULL; 2467 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv)) 2468 return E_INVALIDARG; 2469 2470 TRACE("sf=%p outer=%p callback=%p\n", 2471 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb); 2472 2473 hRes = IShellView_Constructor(pcsfv->pshf, &psf); 2474 if (FAILED(hRes)) 2475 return hRes; 2476 2477 hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppsv); 2478 IShellView_Release(psf); 2479 2480 return hRes; 2481 } 2482 #endif 2483 2484 2485 /************************************************************************* 2486 * SHTestTokenMembership [SHELL32.245] 2487 * 2488 * Checks whether a given token is a mamber of a local group with the 2489 * specified RID. 2490 * 2491 */ 2492 EXTERN_C BOOL 2493 WINAPI 2494 SHTestTokenMembership(HANDLE TokenHandle, ULONG ulRID) 2495 { 2496 SID_IDENTIFIER_AUTHORITY ntAuth = {SECURITY_NT_AUTHORITY}; 2497 DWORD nSubAuthority0, nSubAuthority1; 2498 DWORD nSubAuthorityCount; 2499 PSID SidToCheck; 2500 BOOL IsMember = FALSE; 2501 2502 if ((ulRID == SECURITY_SERVICE_RID) || ulRID == SECURITY_LOCAL_SYSTEM_RID) 2503 { 2504 nSubAuthority0 = ulRID; 2505 nSubAuthority1 = 0; 2506 nSubAuthorityCount= 1; 2507 } 2508 else 2509 { 2510 nSubAuthority0 = SECURITY_BUILTIN_DOMAIN_RID; 2511 nSubAuthority1 = ulRID; 2512 nSubAuthorityCount= 2; 2513 } 2514 2515 if (!AllocateAndInitializeSid(&ntAuth, 2516 nSubAuthorityCount, 2517 nSubAuthority0, 2518 nSubAuthority1, 2519 0, 0, 0, 0, 0, 0, 2520 &SidToCheck)) 2521 { 2522 return FALSE; 2523 } 2524 2525 if (!CheckTokenMembership(TokenHandle, SidToCheck, &IsMember)) 2526 { 2527 IsMember = FALSE; 2528 } 2529 2530 FreeSid(SidToCheck); 2531 return IsMember; 2532 } 2533 2534 /************************************************************************* 2535 * IsUserAnAdmin [SHELL32.680] NT 4.0 2536 * 2537 * Checks whether the current user is a member of the Administrators group. 2538 * 2539 * PARAMS 2540 * None 2541 * 2542 * RETURNS 2543 * Success: TRUE 2544 * Failure: FALSE 2545 */ 2546 BOOL WINAPI IsUserAnAdmin(VOID) 2547 { 2548 return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS); 2549 } 2550 2551 /************************************************************************* 2552 * SHLimitInputEdit(SHELL32.@) 2553 */ 2554 2555 /* TODO: Show baloon popup window with TTS_BALLOON */ 2556 2557 typedef struct UxSubclassInfo 2558 { 2559 HWND hwnd; 2560 WNDPROC fnWndProc; 2561 LPWSTR pwszValidChars; 2562 LPWSTR pwszInvalidChars; 2563 } UxSubclassInfo; 2564 2565 static void 2566 UxSubclassInfo_Destroy(UxSubclassInfo *pInfo) 2567 { 2568 if (!pInfo) 2569 return; 2570 2571 RemovePropW(pInfo->hwnd, L"UxSubclassInfo"); 2572 2573 CoTaskMemFree(pInfo->pwszValidChars); 2574 CoTaskMemFree(pInfo->pwszInvalidChars); 2575 2576 SetWindowLongPtrW(pInfo->hwnd, GWLP_WNDPROC, (LONG_PTR)pInfo->fnWndProc); 2577 2578 HeapFree(GetProcessHeap(), 0, pInfo); 2579 } 2580 2581 static BOOL 2582 DoSanitizeText(LPWSTR pszSanitized, LPCWSTR pszInvalidChars, LPCWSTR pszValidChars) 2583 { 2584 LPWSTR pch1, pch2; 2585 BOOL bFound = FALSE; 2586 2587 for (pch1 = pch2 = pszSanitized; *pch1; ++pch1) 2588 { 2589 if (pszInvalidChars) 2590 { 2591 if (wcschr(pszInvalidChars, *pch1) != NULL) 2592 { 2593 bFound = TRUE; 2594 continue; 2595 } 2596 } 2597 else if (pszValidChars) 2598 { 2599 if (wcschr(pszValidChars, *pch1) == NULL) 2600 { 2601 bFound = TRUE; 2602 continue; 2603 } 2604 } 2605 2606 *pch2 = *pch1; 2607 ++pch2; 2608 } 2609 *pch2 = 0; 2610 2611 return bFound; 2612 } 2613 2614 static void 2615 DoSanitizeClipboard(HWND hwnd, UxSubclassInfo *pInfo) 2616 { 2617 HGLOBAL hData; 2618 LPWSTR pszText, pszSanitized; 2619 DWORD cbData; 2620 2621 if (GetWindowLongPtrW(hwnd, GWL_STYLE) & ES_READONLY) 2622 return; 2623 if (!OpenClipboard(hwnd)) 2624 return; 2625 2626 hData = GetClipboardData(CF_UNICODETEXT); 2627 pszText = GlobalLock(hData); 2628 if (!pszText) 2629 { 2630 CloseClipboard(); 2631 return; 2632 } 2633 SHStrDupW(pszText, &pszSanitized); 2634 GlobalUnlock(hData); 2635 2636 if (pszSanitized && 2637 DoSanitizeText(pszSanitized, pInfo->pwszInvalidChars, pInfo->pwszValidChars)) 2638 { 2639 MessageBeep(0xFFFFFFFF); 2640 2641 /* Update clipboard text */ 2642 cbData = (lstrlenW(pszSanitized) + 1) * sizeof(WCHAR); 2643 hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, cbData); 2644 pszText = GlobalLock(hData); 2645 if (pszText) 2646 { 2647 CopyMemory(pszText, pszSanitized, cbData); 2648 GlobalUnlock(hData); 2649 2650 SetClipboardData(CF_UNICODETEXT, hData); 2651 } 2652 } 2653 2654 CoTaskMemFree(pszSanitized); 2655 CloseClipboard(); 2656 } 2657 2658 static LRESULT CALLBACK 2659 LimitEditWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 2660 { 2661 WNDPROC fnWndProc; 2662 WCHAR wch; 2663 UxSubclassInfo *pInfo = GetPropW(hwnd, L"UxSubclassInfo"); 2664 if (!pInfo) 2665 return DefWindowProcW(hwnd, uMsg, wParam, lParam); 2666 2667 fnWndProc = pInfo->fnWndProc; 2668 2669 switch (uMsg) 2670 { 2671 case WM_KEYDOWN: 2672 if (GetKeyState(VK_SHIFT) < 0 && wParam == VK_INSERT) 2673 DoSanitizeClipboard(hwnd, pInfo); 2674 else if (GetKeyState(VK_CONTROL) < 0 && wParam == L'V') 2675 DoSanitizeClipboard(hwnd, pInfo); 2676 2677 return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam); 2678 2679 case WM_PASTE: 2680 DoSanitizeClipboard(hwnd, pInfo); 2681 return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam); 2682 2683 case WM_CHAR: 2684 if (GetKeyState(VK_CONTROL) < 0 && wParam == L'V') 2685 break; 2686 2687 if (pInfo->pwszInvalidChars) 2688 { 2689 if (wcschr(pInfo->pwszInvalidChars, (WCHAR)wParam) != NULL) 2690 { 2691 MessageBeep(0xFFFFFFFF); 2692 break; 2693 } 2694 } 2695 else if (pInfo->pwszValidChars) 2696 { 2697 if (wcschr(pInfo->pwszValidChars, (WCHAR)wParam) == NULL) 2698 { 2699 MessageBeep(0xFFFFFFFF); 2700 break; 2701 } 2702 } 2703 return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam); 2704 2705 case WM_UNICHAR: 2706 if (wParam == UNICODE_NOCHAR) 2707 return TRUE; 2708 2709 /* FALL THROUGH */ 2710 2711 case WM_IME_CHAR: 2712 wch = (WCHAR)wParam; 2713 if (GetKeyState(VK_CONTROL) < 0 && wch == L'V') 2714 break; 2715 2716 if (!IsWindowUnicode(hwnd) && HIBYTE(wch) != 0) 2717 { 2718 CHAR data[] = {HIBYTE(wch), LOBYTE(wch)}; 2719 MultiByteToWideChar(CP_ACP, 0, data, 2, &wch, 1); 2720 } 2721 2722 if (pInfo->pwszInvalidChars) 2723 { 2724 if (wcschr(pInfo->pwszInvalidChars, wch) != NULL) 2725 { 2726 MessageBeep(0xFFFFFFFF); 2727 break; 2728 } 2729 } 2730 else if (pInfo->pwszValidChars) 2731 { 2732 if (wcschr(pInfo->pwszValidChars, wch) == NULL) 2733 { 2734 MessageBeep(0xFFFFFFFF); 2735 break; 2736 } 2737 } 2738 return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam); 2739 2740 case WM_NCDESTROY: 2741 UxSubclassInfo_Destroy(pInfo); 2742 return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam); 2743 2744 default: 2745 return CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam); 2746 } 2747 2748 return 0; 2749 } 2750 2751 static UxSubclassInfo * 2752 UxSubclassInfo_Create(HWND hwnd, LPWSTR valid, LPWSTR invalid) 2753 { 2754 UxSubclassInfo *pInfo; 2755 pInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(UxSubclassInfo)); 2756 if (!pInfo) 2757 { 2758 ERR("HeapAlloc failed.\n"); 2759 CoTaskMemFree(valid); 2760 CoTaskMemFree(invalid); 2761 return NULL; 2762 } 2763 2764 pInfo->fnWndProc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)LimitEditWindowProc); 2765 if (!pInfo->fnWndProc) 2766 { 2767 ERR("SetWindowLongPtrW failed\n"); 2768 CoTaskMemFree(valid); 2769 CoTaskMemFree(invalid); 2770 HeapFree(GetProcessHeap(), 0, pInfo); 2771 return NULL; 2772 } 2773 2774 pInfo->hwnd = hwnd; 2775 pInfo->pwszValidChars = valid; 2776 pInfo->pwszInvalidChars = invalid; 2777 if (!SetPropW(hwnd, L"UxSubclassInfo", pInfo)) 2778 { 2779 UxSubclassInfo_Destroy(pInfo); 2780 pInfo = NULL; 2781 } 2782 return pInfo; 2783 } 2784 2785 HRESULT WINAPI 2786 SHLimitInputEdit(HWND hWnd, IShellFolder *psf) 2787 { 2788 IItemNameLimits *pLimits; 2789 HRESULT hr; 2790 LPWSTR pwszValidChars, pwszInvalidChars; 2791 UxSubclassInfo *pInfo; 2792 2793 pInfo = GetPropW(hWnd, L"UxSubclassInfo"); 2794 if (pInfo) 2795 { 2796 UxSubclassInfo_Destroy(pInfo); 2797 pInfo = NULL; 2798 } 2799 2800 hr = psf->lpVtbl->QueryInterface(psf, &IID_IItemNameLimits, (LPVOID *)&pLimits); 2801 if (FAILED(hr)) 2802 { 2803 ERR("hr: %x\n", hr); 2804 return hr; 2805 } 2806 2807 pwszValidChars = pwszInvalidChars = NULL; 2808 hr = pLimits->lpVtbl->GetValidCharacters(pLimits, &pwszValidChars, &pwszInvalidChars); 2809 if (FAILED(hr)) 2810 { 2811 ERR("hr: %x\n", hr); 2812 pLimits->lpVtbl->Release(pLimits); 2813 return hr; 2814 } 2815 2816 pInfo = UxSubclassInfo_Create(hWnd, pwszValidChars, pwszInvalidChars); 2817 if (!pInfo) 2818 hr = E_FAIL; 2819 2820 pLimits->lpVtbl->Release(pLimits); 2821 2822 return hr; 2823 } 2824 2825 #ifdef __REACTOS__ 2826 /************************************************************************* 2827 * SHLimitInputCombo [SHELL32.748] 2828 * 2829 * Sets limits on valid characters for a combobox control. 2830 * This function works like SHLimitInputEdit, but the target is a combobox 2831 * instead of a textbox. 2832 */ 2833 HRESULT WINAPI 2834 SHLimitInputCombo(HWND hWnd, IShellFolder *psf) 2835 { 2836 HWND hwndEdit; 2837 2838 TRACE("%p %p\n", hWnd, psf); 2839 2840 hwndEdit = GetTopWindow(hWnd); 2841 if (!hwndEdit) 2842 return E_FAIL; 2843 2844 return SHLimitInputEdit(hwndEdit, psf); 2845 } 2846 #endif 2847