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