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