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