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 /* FIXME: !!! move CREATEMRULIST and flags to header file !!! */ 49 /* !!! it is in both here and comctl32undoc.c !!! */ 50 typedef struct tagCREATEMRULIST 51 { 52 DWORD cbSize; /* size of struct */ 53 DWORD nMaxItems; /* max no. of items in list */ 54 DWORD dwFlags; /* see below */ 55 HKEY hKey; /* root reg. key under which list is saved */ 56 LPCSTR lpszSubKey; /* reg. subkey */ 57 int (CALLBACK *lpfnCompare)(LPCVOID, LPCVOID, DWORD); /* item compare proc */ 58 } CREATEMRULISTA, *LPCREATEMRULISTA; 59 60 /* dwFlags */ 61 #define MRUF_STRING_LIST 0 /* list will contain strings */ 62 #define MRUF_BINARY_LIST 1 /* list will contain binary data */ 63 #define MRUF_DELAYED_SAVE 2 /* only save list order to reg. is FreeMRUList */ 64 65 extern HANDLE WINAPI CreateMRUListA(LPCREATEMRULISTA lpcml); 66 extern VOID WINAPI FreeMRUList(HANDLE hMRUList); 67 extern INT WINAPI AddMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData); 68 extern INT WINAPI FindMRUData(HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum); 69 extern INT WINAPI EnumMRUListA(HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize); 70 71 72 /************************************************************************* 73 * ParseFieldA [internal] 74 * 75 * copies a field from a ',' delimited string 76 * 77 * first field is nField = 1 78 */ 79 DWORD WINAPI ParseFieldA( 80 LPCSTR src, 81 DWORD nField, 82 LPSTR dst, 83 DWORD len) 84 { 85 WARN("(%s,0x%08x,%p,%d) semi-stub.\n",debugstr_a(src),nField,dst,len); 86 87 if (!src || !src[0] || !dst || !len) 88 return 0; 89 90 /* skip n fields delimited by ',' */ 91 while (nField > 1) 92 { 93 if (*src=='\0') return FALSE; 94 if (*(src++)==',') nField--; 95 } 96 97 /* copy part till the next ',' to dst */ 98 while ( *src!='\0' && *src!=',' && (len--)>0 ) *(dst++)=*(src++); 99 100 /* finalize the string */ 101 *dst=0x0; 102 103 return TRUE; 104 } 105 106 /************************************************************************* 107 * ParseFieldW [internal] 108 * 109 * copies a field from a ',' delimited string 110 * 111 * first field is nField = 1 112 */ 113 DWORD WINAPI ParseFieldW(LPCWSTR src, DWORD nField, LPWSTR dst, DWORD len) 114 { 115 WARN("(%s,0x%08x,%p,%d) semi-stub.\n", debugstr_w(src), nField, dst, len); 116 117 if (!src || !src[0] || !dst || !len) 118 return 0; 119 120 /* skip n fields delimited by ',' */ 121 while (nField > 1) 122 { 123 if (*src == 0x0) return FALSE; 124 if (*src++ == ',') nField--; 125 } 126 127 /* copy part till the next ',' to dst */ 128 while ( *src != 0x0 && *src != ',' && (len--)>0 ) *(dst++) = *(src++); 129 130 /* finalize the string */ 131 *dst = 0x0; 132 133 return TRUE; 134 } 135 136 /************************************************************************* 137 * ParseField [SHELL32.58] 138 */ 139 DWORD WINAPI ParseFieldAW(LPCVOID src, DWORD nField, LPVOID dst, DWORD len) 140 { 141 if (SHELL_OsIsUnicode()) 142 return ParseFieldW(src, nField, dst, len); 143 return ParseFieldA(src, nField, dst, len); 144 } 145 146 /************************************************************************* 147 * GetFileNameFromBrowse [SHELL32.63] 148 * 149 */ 150 BOOL WINAPI GetFileNameFromBrowse( 151 HWND hwndOwner, 152 LPWSTR lpstrFile, 153 UINT nMaxFile, 154 LPCWSTR lpstrInitialDir, 155 LPCWSTR lpstrDefExt, 156 LPCWSTR lpstrFilter, 157 LPCWSTR lpstrTitle) 158 { 159 typedef BOOL (WINAPI *GetOpenFileNameProc)(OPENFILENAMEW *ofn); 160 HMODULE hmodule; 161 GetOpenFileNameProc pGetOpenFileNameW; 162 OPENFILENAMEW ofn; 163 BOOL ret; 164 165 TRACE("%p, %s, %d, %s, %s, %s, %s)\n", 166 hwndOwner, debugstr_w(lpstrFile), nMaxFile, lpstrInitialDir, lpstrDefExt, 167 lpstrFilter, lpstrTitle); 168 169 hmodule = LoadLibraryW(L"comdlg32.dll"); 170 if(!hmodule) return FALSE; 171 pGetOpenFileNameW = (GetOpenFileNameProc)GetProcAddress(hmodule, "GetOpenFileNameW"); 172 if(!pGetOpenFileNameW) 173 { 174 FreeLibrary(hmodule); 175 return FALSE; 176 } 177 178 memset(&ofn, 0, sizeof(ofn)); 179 180 ofn.lStructSize = sizeof(ofn); 181 ofn.hwndOwner = hwndOwner; 182 ofn.lpstrFilter = lpstrFilter; 183 ofn.lpstrFile = lpstrFile; 184 ofn.nMaxFile = nMaxFile; 185 ofn.lpstrInitialDir = lpstrInitialDir; 186 ofn.lpstrTitle = lpstrTitle; 187 ofn.lpstrDefExt = lpstrDefExt; 188 ofn.Flags = OFN_EXPLORER | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; 189 ret = pGetOpenFileNameW(&ofn); 190 191 FreeLibrary(hmodule); 192 return ret; 193 } 194 195 /************************************************************************* 196 * SHGetSetSettings [SHELL32.68] 197 */ 198 VOID WINAPI SHGetSetSettings(LPSHELLSTATE lpss, DWORD dwMask, BOOL bSet) 199 { 200 if(bSet) 201 { 202 FIXME("%p 0x%08x TRUE\n", lpss, dwMask); 203 } 204 else 205 { 206 SHGetSettings((LPSHELLFLAGSTATE)lpss,dwMask); 207 } 208 } 209 210 /************************************************************************* 211 * SHGetSettings [SHELL32.@] 212 * 213 * NOTES 214 * the registry path are for win98 (tested) 215 * and possibly are the same in nt40 216 * 217 */ 218 VOID WINAPI SHGetSettings(LPSHELLFLAGSTATE lpsfs, DWORD dwMask) 219 { 220 HKEY hKey; 221 DWORD dwData; 222 DWORD dwDataSize = sizeof (DWORD); 223 224 TRACE("(%p 0x%08x)\n",lpsfs,dwMask); 225 226 if (RegCreateKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced", 227 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) 228 return; 229 230 if ( (SSF_SHOWEXTENSIONS & dwMask) && !RegQueryValueExA(hKey, "HideFileExt", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 231 lpsfs->fShowExtensions = ((dwData == 0) ? 0 : 1); 232 233 if ( (SSF_SHOWINFOTIP & dwMask) && !RegQueryValueExA(hKey, "ShowInfoTip", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 234 lpsfs->fShowInfoTip = ((dwData == 0) ? 0 : 1); 235 236 if ( (SSF_DONTPRETTYPATH & dwMask) && !RegQueryValueExA(hKey, "DontPrettyPath", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 237 lpsfs->fDontPrettyPath = ((dwData == 0) ? 0 : 1); 238 239 if ( (SSF_HIDEICONS & dwMask) && !RegQueryValueExA(hKey, "HideIcons", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 240 lpsfs->fHideIcons = ((dwData == 0) ? 0 : 1); 241 242 if ( (SSF_MAPNETDRVBUTTON & dwMask) && !RegQueryValueExA(hKey, "MapNetDrvBtn", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 243 lpsfs->fMapNetDrvBtn = ((dwData == 0) ? 0 : 1); 244 245 if ( (SSF_SHOWATTRIBCOL & dwMask) && !RegQueryValueExA(hKey, "ShowAttribCol", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 246 lpsfs->fShowAttribCol = ((dwData == 0) ? 0 : 1); 247 248 if (((SSF_SHOWALLOBJECTS | SSF_SHOWSYSFILES) & dwMask) && !RegQueryValueExA(hKey, "Hidden", 0, 0, (LPBYTE)&dwData, &dwDataSize)) 249 { if (dwData == 0) 250 { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 0; 251 if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 0; 252 } 253 else if (dwData == 1) 254 { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 1; 255 if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 0; 256 } 257 else if (dwData == 2) 258 { if (SSF_SHOWALLOBJECTS & dwMask) lpsfs->fShowAllObjects = 0; 259 if (SSF_SHOWSYSFILES & dwMask) lpsfs->fShowSysFiles = 1; 260 } 261 } 262 RegCloseKey (hKey); 263 264 TRACE("-- 0x%04x\n", *(WORD*)lpsfs); 265 } 266 267 /************************************************************************* 268 * SHShellFolderView_Message [SHELL32.73] 269 * 270 * Send a message to an explorer cabinet window. 271 * 272 * PARAMS 273 * hwndCabinet [I] The window containing the shellview to communicate with 274 * dwMessage [I] The SFVM message to send 275 * dwParam [I] Message parameter 276 * 277 * RETURNS 278 * fixme. 279 * 280 * NOTES 281 * Message SFVM_REARRANGE = 1 282 * 283 * This message gets sent when a column gets clicked to instruct the 284 * shell view to re-sort the item list. dwParam identifies the column 285 * that was clicked. 286 */ 287 LRESULT WINAPI SHShellFolderView_Message( 288 HWND hwndCabinet, 289 UINT uMessage, 290 LPARAM lParam) 291 { 292 FIXME("%p %08x %08lx stub\n",hwndCabinet, uMessage, lParam); 293 return 0; 294 } 295 296 /************************************************************************* 297 * RegisterShellHook [SHELL32.181] 298 * 299 * Register a shell hook. 300 * 301 * PARAMS 302 * hwnd [I] Window handle 303 * dwType [I] Type of hook. 304 * 305 * NOTES 306 * Exported by ordinal 307 */ 308 BOOL WINAPI RegisterShellHook( 309 HWND hWnd, 310 DWORD dwType) 311 { 312 if (dwType == 3) 313 { 314 SetTaskmanWindow(hWnd); 315 return RegisterShellHookWindow(hWnd); 316 } 317 else if (dwType == 0) 318 { 319 return DeregisterShellHookWindow(hWnd); 320 } 321 322 ERR("Unsupported argument"); 323 return FALSE; 324 } 325 326 /************************************************************************* 327 * ShellMessageBoxW [SHELL32.182] 328 * 329 * See ShellMessageBoxA. 330 * 331 * NOTE: 332 * shlwapi.ShellMessageBoxWrapW is a duplicate of shell32.ShellMessageBoxW 333 * because we can't forward to it in the .spec file since it's exported by 334 * ordinal. If you change the implementation here please update the code in 335 * shlwapi as well. 336 */ 337 int ShellMessageBoxW( 338 HINSTANCE hInstance, 339 HWND hWnd, 340 LPCWSTR lpText, 341 LPCWSTR lpCaption, 342 UINT uType, 343 ...) 344 { 345 WCHAR szText[100],szTitle[100]; 346 LPCWSTR pszText = szText, pszTitle = szTitle; 347 LPWSTR pszTemp; 348 __ms_va_list args; 349 int ret; 350 351 __ms_va_start(args, uType); 352 /* wvsprintfA(buf,fmt, args); */ 353 354 TRACE("(%p,%p,%p,%p,%08x)\n", 355 hInstance,hWnd,lpText,lpCaption,uType); 356 357 if (IS_INTRESOURCE(lpCaption)) 358 LoadStringW(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)/sizeof(szTitle[0])); 359 else 360 pszTitle = lpCaption; 361 362 if (IS_INTRESOURCE(lpText)) 363 LoadStringW(hInstance, LOWORD(lpText), szText, sizeof(szText)/sizeof(szText[0])); 364 else 365 pszText = lpText; 366 367 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, 368 pszText, 0, 0, (LPWSTR)&pszTemp, 0, &args); 369 370 __ms_va_end(args); 371 372 ret = MessageBoxW(hWnd,pszTemp,pszTitle,uType); 373 LocalFree(pszTemp); 374 return ret; 375 } 376 377 /************************************************************************* 378 * ShellMessageBoxA [SHELL32.183] 379 * 380 * Format and output an error message. 381 * 382 * PARAMS 383 * hInstance [I] Instance handle of message creator 384 * hWnd [I] Window handle of message creator 385 * lpText [I] Resource Id of title or LPSTR 386 * lpCaption [I] Resource Id of title or LPSTR 387 * uType [I] Type of error message 388 * 389 * RETURNS 390 * A return value from MessageBoxA(). 391 * 392 * NOTES 393 * Exported by ordinal 394 */ 395 int ShellMessageBoxA( 396 HINSTANCE hInstance, 397 HWND hWnd, 398 LPCSTR lpText, 399 LPCSTR lpCaption, 400 UINT uType, 401 ...) 402 { 403 char szText[100],szTitle[100]; 404 LPCSTR pszText = szText, pszTitle = szTitle; 405 LPSTR pszTemp; 406 __ms_va_list args; 407 int ret; 408 409 __ms_va_start(args, uType); 410 /* wvsprintfA(buf,fmt, args); */ 411 412 TRACE("(%p,%p,%p,%p,%08x)\n", 413 hInstance,hWnd,lpText,lpCaption,uType); 414 415 if (IS_INTRESOURCE(lpCaption)) 416 LoadStringA(hInstance, LOWORD(lpCaption), szTitle, sizeof(szTitle)); 417 else 418 pszTitle = lpCaption; 419 420 if (IS_INTRESOURCE(lpText)) 421 LoadStringA(hInstance, LOWORD(lpText), szText, sizeof(szText)); 422 else 423 pszText = lpText; 424 425 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING, 426 pszText, 0, 0, (LPSTR)&pszTemp, 0, &args); 427 428 __ms_va_end(args); 429 430 ret = MessageBoxA(hWnd,pszTemp,pszTitle,uType); 431 LocalFree(pszTemp); 432 return ret; 433 } 434 435 /************************************************************************* 436 * SHRegisterDragDrop [SHELL32.86] 437 * 438 * Probably equivalent to RegisterDragDrop but under Windows 95 it could use the 439 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 440 * for details. Under Windows 98 this function initializes the true OLE when called 441 * the first time, on XP always returns E_OUTOFMEMORY and it got removed from Vista. 442 * 443 * We follow Windows 98 behaviour. 444 * 445 * NOTES 446 * exported by ordinal 447 * 448 * SEE ALSO 449 * RegisterDragDrop, SHLoadOLE 450 */ 451 HRESULT WINAPI SHRegisterDragDrop( 452 HWND hWnd, 453 LPDROPTARGET pDropTarget) 454 { 455 static BOOL ole_initialized = FALSE; 456 HRESULT hr; 457 458 TRACE("(%p,%p)\n", hWnd, pDropTarget); 459 460 if (!ole_initialized) 461 { 462 hr = OleInitialize(NULL); 463 if (FAILED(hr)) 464 return hr; 465 ole_initialized = TRUE; 466 } 467 return RegisterDragDrop(hWnd, pDropTarget); 468 } 469 470 /************************************************************************* 471 * SHRevokeDragDrop [SHELL32.87] 472 * 473 * Probably equivalent to RevokeDragDrop but under Windows 95 it could use the 474 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 475 * for details. Function removed from Windows Vista. 476 * 477 * We call ole32 RevokeDragDrop which seems to work even if OleInitialize was 478 * not called. 479 * 480 * NOTES 481 * exported by ordinal 482 * 483 * SEE ALSO 484 * RevokeDragDrop, SHLoadOLE 485 */ 486 HRESULT WINAPI SHRevokeDragDrop(HWND hWnd) 487 { 488 TRACE("(%p)\n", hWnd); 489 return RevokeDragDrop(hWnd); 490 } 491 492 /************************************************************************* 493 * SHDoDragDrop [SHELL32.88] 494 * 495 * Probably equivalent to DoDragDrop but under Windows 9x it could use the 496 * shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 497 * for details 498 * 499 * NOTES 500 * exported by ordinal 501 * 502 * SEE ALSO 503 * DoDragDrop, SHLoadOLE 504 */ 505 HRESULT WINAPI SHDoDragDrop( 506 HWND hWnd, 507 LPDATAOBJECT lpDataObject, 508 LPDROPSOURCE lpDropSource, 509 DWORD dwOKEffect, 510 LPDWORD pdwEffect) 511 { 512 FIXME("(%p %p %p 0x%08x %p):stub.\n", 513 hWnd, lpDataObject, lpDropSource, dwOKEffect, pdwEffect); 514 return DoDragDrop(lpDataObject, lpDropSource, dwOKEffect, pdwEffect); 515 } 516 517 /************************************************************************* 518 * ArrangeWindows [SHELL32.184] 519 * 520 */ 521 WORD WINAPI ArrangeWindows(HWND hwndParent, DWORD dwReserved, const RECT *lpRect, 522 WORD cKids, const HWND *lpKids) 523 { 524 /* Unimplemented in WinXP SP3 */ 525 TRACE("(%p 0x%08x %p 0x%04x %p):stub.\n", 526 hwndParent, dwReserved, lpRect, cKids, lpKids); 527 return 0; 528 } 529 530 /************************************************************************* 531 * SignalFileOpen [SHELL32.103] 532 * 533 * NOTES 534 * exported by ordinal 535 */ 536 BOOL WINAPI 537 SignalFileOpen (PCIDLIST_ABSOLUTE pidl) 538 { 539 FIXME("(%p):stub.\n", pidl); 540 541 return FALSE; 542 } 543 544 /************************************************************************* 545 * SHADD_get_policy - helper function for SHAddToRecentDocs 546 * 547 * PARAMETERS 548 * policy [IN] policy name (null termed string) to find 549 * type [OUT] ptr to DWORD to receive type 550 * buffer [OUT] ptr to area to hold data retrieved 551 * len [IN/OUT] ptr to DWORD holding size of buffer and getting 552 * length filled 553 * 554 * RETURNS 555 * result of the SHQueryValueEx call 556 */ 557 static INT SHADD_get_policy(LPCSTR policy, LPDWORD type, LPVOID buffer, LPDWORD len) 558 { 559 HKEY Policy_basekey; 560 INT ret; 561 562 /* Get the key for the policies location in the registry 563 */ 564 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, 565 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 566 0, KEY_READ, &Policy_basekey)) { 567 568 if (RegOpenKeyExA(HKEY_CURRENT_USER, 569 "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer", 570 0, KEY_READ, &Policy_basekey)) { 571 TRACE("No Explorer Policies location exists. Policy wanted=%s\n", 572 policy); 573 *len = 0; 574 return ERROR_FILE_NOT_FOUND; 575 } 576 } 577 578 /* Retrieve the data if it exists 579 */ 580 ret = SHQueryValueExA(Policy_basekey, policy, 0, type, buffer, len); 581 RegCloseKey(Policy_basekey); 582 return ret; 583 } 584 585 586 /************************************************************************* 587 * SHADD_compare_mru - helper function for SHAddToRecentDocs 588 * 589 * PARAMETERS 590 * data1 [IN] data being looked for 591 * data2 [IN] data in MRU 592 * cbdata [IN] length from FindMRUData call (not used) 593 * 594 * RETURNS 595 * position within MRU list that data was added. 596 */ 597 static INT CALLBACK SHADD_compare_mru(LPCVOID data1, LPCVOID data2, DWORD cbData) 598 { 599 return lstrcmpiA(data1, data2); 600 } 601 602 /************************************************************************* 603 * SHADD_create_add_mru_data - helper function for SHAddToRecentDocs 604 * 605 * PARAMETERS 606 * mruhandle [IN] handle for created MRU list 607 * doc_name [IN] null termed pure doc name 608 * new_lnk_name [IN] null termed path and file name for .lnk file 609 * buffer [IN/OUT] 2048 byte area to construct MRU data 610 * len [OUT] ptr to int to receive space used in buffer 611 * 612 * RETURNS 613 * position within MRU list that data was added. 614 */ 615 static INT SHADD_create_add_mru_data(HANDLE mruhandle, LPCSTR doc_name, LPCSTR new_lnk_name, 616 LPSTR buffer, INT *len) 617 { 618 LPSTR ptr; 619 INT wlen; 620 621 /*FIXME: Document: 622 * RecentDocs MRU data structure seems to be: 623 * +0h document file name w/ terminating 0h 624 * +nh short int w/ size of remaining 625 * +n+2h 02h 30h, or 01h 30h, or 00h 30h - unknown 626 * +n+4h 10 bytes zeros - unknown 627 * +n+eh shortcut file name w/ terminating 0h 628 * +n+e+nh 3 zero bytes - unknown 629 */ 630 631 /* Create the MRU data structure for "RecentDocs" 632 */ 633 ptr = buffer; 634 lstrcpyA(ptr, doc_name); 635 ptr += (lstrlenA(buffer) + 1); 636 wlen= lstrlenA(new_lnk_name) + 1 + 12; 637 *((short int*)ptr) = wlen; 638 ptr += 2; /* step past the length */ 639 *(ptr++) = 0x30; /* unknown reason */ 640 *(ptr++) = 0; /* unknown, but can be 0x00, 0x01, 0x02 */ 641 memset(ptr, 0, 10); 642 ptr += 10; 643 lstrcpyA(ptr, new_lnk_name); 644 ptr += (lstrlenA(new_lnk_name) + 1); 645 memset(ptr, 0, 3); 646 ptr += 3; 647 *len = ptr - buffer; 648 649 /* Add the new entry into the MRU list 650 */ 651 return AddMRUData(mruhandle, buffer, *len); 652 } 653 654 /************************************************************************* 655 * SHAddToRecentDocs [SHELL32.@] 656 * 657 * Modify (add/clear) Shell's list of recently used documents. 658 * 659 * PARAMETERS 660 * uFlags [IN] SHARD_PATHA, SHARD_PATHW or SHARD_PIDL 661 * pv [IN] string or pidl, NULL clears the list 662 * 663 * NOTES 664 * exported by name 665 * 666 * FIXME 667 * convert to unicode 668 */ 669 void WINAPI SHAddToRecentDocs (UINT uFlags,LPCVOID pv) 670 { 671 /* If list is a string list lpfnCompare has the following prototype 672 * int CALLBACK MRUCompareString(LPCSTR s1, LPCSTR s2) 673 * for binary lists the prototype is 674 * int CALLBACK MRUCompareBinary(LPCVOID data1, LPCVOID data2, DWORD cbData) 675 * where cbData is the no. of bytes to compare. 676 * Need to check what return value means identical - 0? 677 */ 678 679 680 UINT olderrormode; 681 HKEY HCUbasekey; 682 CHAR doc_name[MAX_PATH]; 683 CHAR link_dir[MAX_PATH]; 684 CHAR new_lnk_filepath[MAX_PATH]; 685 CHAR new_lnk_name[MAX_PATH]; 686 CHAR * ext; 687 IMalloc *ppM; 688 LPITEMIDLIST pidl; 689 HWND hwnd = 0; /* FIXME: get real window handle */ 690 INT ret; 691 DWORD data[64], datalen, type; 692 693 TRACE("%04x %p\n", uFlags, pv); 694 695 /*FIXME: Document: 696 * RecentDocs MRU data structure seems to be: 697 * +0h document file name w/ terminating 0h 698 * +nh short int w/ size of remaining 699 * +n+2h 02h 30h, or 01h 30h, or 00h 30h - unknown 700 * +n+4h 10 bytes zeros - unknown 701 * +n+eh shortcut file name w/ terminating 0h 702 * +n+e+nh 3 zero bytes - unknown 703 */ 704 705 /* See if we need to do anything. 706 */ 707 datalen = 64; 708 ret=SHADD_get_policy( "NoRecentDocsHistory", &type, data, &datalen); 709 if ((ret > 0) && (ret != ERROR_FILE_NOT_FOUND)) { 710 ERR("Error %d getting policy \"NoRecentDocsHistory\"\n", ret); 711 return; 712 } 713 if (ret == ERROR_SUCCESS) { 714 if (!( (type == REG_DWORD) || 715 ((type == REG_BINARY) && (datalen == 4)) )) { 716 ERR("Error policy data for \"NoRecentDocsHistory\" not formatted correctly, type=%d, len=%d\n", 717 type, datalen); 718 return; 719 } 720 721 TRACE("policy value for NoRecentDocsHistory = %08x\n", data[0]); 722 /* now test the actual policy value */ 723 if ( data[0] != 0) 724 return; 725 } 726 727 /* Open key to where the necessary info is 728 */ 729 /* FIXME: This should be done during DLL PROCESS_ATTACH (or THREAD_ATTACH) 730 * and the close should be done during the _DETACH. The resulting 731 * key is stored in the DLL global data. 732 */ 733 if (RegCreateKeyExA(HKEY_CURRENT_USER, 734 "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", 735 0, 0, 0, KEY_READ, 0, &HCUbasekey, 0)) { 736 ERR("Failed to create 'Software\\Microsoft\\Windows\\CurrentVersion\\Explorer'\n"); 737 return; 738 } 739 740 /* Get path to user's "Recent" directory 741 */ 742 if(SUCCEEDED(SHGetMalloc(&ppM))) { 743 if (SUCCEEDED(SHGetSpecialFolderLocation(hwnd, CSIDL_RECENT, 744 &pidl))) { 745 SHGetPathFromIDListA(pidl, link_dir); 746 IMalloc_Free(ppM, pidl); 747 } 748 else { 749 /* serious issues */ 750 link_dir[0] = 0; 751 ERR("serious issues 1\n"); 752 } 753 IMalloc_Release(ppM); 754 } 755 else { 756 /* serious issues */ 757 link_dir[0] = 0; 758 ERR("serious issues 2\n"); 759 } 760 TRACE("Users Recent dir %s\n", link_dir); 761 762 /* If no input, then go clear the lists */ 763 if (!pv) { 764 /* clear user's Recent dir 765 */ 766 767 /* FIXME: delete all files in "link_dir" 768 * 769 * while( more files ) { 770 * lstrcpyA(old_lnk_name, link_dir); 771 * PathAppendA(old_lnk_name, filenam); 772 * DeleteFileA(old_lnk_name); 773 * } 774 */ 775 FIXME("should delete all files in %s\\\n", link_dir); 776 777 /* clear MRU list 778 */ 779 /* MS Bug ?? v4.72.3612.1700 of shell32 does the delete against 780 * HKEY_LOCAL_MACHINE version of ...CurrentVersion\Explorer 781 * and naturally it fails w/ rc=2. It should do it against 782 * HKEY_CURRENT_USER which is where it is stored, and where 783 * the MRU routines expect it!!!! 784 */ 785 RegDeleteKeyA(HCUbasekey, "RecentDocs"); 786 RegCloseKey(HCUbasekey); 787 return; 788 } 789 790 /* Have data to add, the jobs to be done: 791 * 1. Add document to MRU list in registry "HKCU\Software\ 792 * Microsoft\Windows\CurrentVersion\Explorer\RecentDocs". 793 * 2. Add shortcut to document in the user's Recent directory 794 * (CSIDL_RECENT). 795 * 3. Add shortcut to Start menu's Documents submenu. 796 */ 797 798 /* Get the pure document name from the input 799 */ 800 switch (uFlags) 801 { 802 case SHARD_PIDL: 803 if (!SHGetPathFromIDListA(pv, doc_name)) 804 { 805 WARN("can't get path from PIDL\n"); 806 return; 807 } 808 break; 809 810 case SHARD_PATHA: 811 lstrcpynA(doc_name, pv, MAX_PATH); 812 break; 813 814 case SHARD_PATHW: 815 WideCharToMultiByte(CP_ACP, 0, pv, -1, doc_name, MAX_PATH, NULL, NULL); 816 break; 817 818 default: 819 FIXME("Unsupported flags: %u\n", uFlags); 820 return; 821 } 822 823 TRACE("full document name %s\n", debugstr_a(doc_name)); 824 825 #ifdef __REACTOS__ 826 /* check if file is a shortcut */ 827 ext = strrchr(doc_name, '.'); 828 if (!lstrcmpiA(ext, ".lnk")) 829 { 830 WCHAR doc_nameW[MAX_PATH]; 831 IShellLinkA* ShellLink; 832 int nLength = MultiByteToWideChar(CP_ACP, 0, doc_name, -1, doc_nameW, MAX_PATH); 833 if (nLength == 0) 834 return; 835 836 IShellLink_ConstructFromPath(doc_nameW, &IID_IShellLinkA, (LPVOID*)&ShellLink); 837 IShellLinkA_GetPath(ShellLink, doc_name, MAX_PATH, NULL, 0); 838 IShellLinkA_Release(ShellLink); 839 } 840 841 ext = strrchr(doc_name, '.'); 842 if (!lstrcmpiA(ext, ".exe")) 843 { 844 /* executables are not added */ 845 return; 846 } 847 #endif 848 849 PathStripPathA(doc_name); 850 TRACE("stripped document name %s\n", debugstr_a(doc_name)); 851 852 853 /* *** JOB 1: Update registry for ...\Explorer\RecentDocs list *** */ 854 855 { /* on input needs: 856 * doc_name - pure file-spec, no path 857 * link_dir - path to the user's Recent directory 858 * HCUbasekey - key of ...Windows\CurrentVersion\Explorer" node 859 * creates: 860 * new_lnk_name- pure file-spec, no path for new .lnk file 861 * new_lnk_filepath 862 * - path and file name of new .lnk file 863 */ 864 CREATEMRULISTA mymru; 865 HANDLE mruhandle; 866 INT len, pos, bufused, err; 867 INT i; 868 DWORD attr; 869 CHAR buffer[2048]; 870 CHAR *ptr; 871 CHAR old_lnk_name[MAX_PATH]; 872 short int slen; 873 874 mymru.cbSize = sizeof(CREATEMRULISTA); 875 mymru.nMaxItems = 15; 876 mymru.dwFlags = MRUF_BINARY_LIST | MRUF_DELAYED_SAVE; 877 mymru.hKey = HCUbasekey; 878 mymru.lpszSubKey = "RecentDocs"; 879 mymru.lpfnCompare = SHADD_compare_mru; 880 mruhandle = CreateMRUListA(&mymru); 881 if (!mruhandle) { 882 /* MRU failed */ 883 ERR("MRU processing failed, handle zero\n"); 884 RegCloseKey(HCUbasekey); 885 return; 886 } 887 len = lstrlenA(doc_name); 888 pos = FindMRUData(mruhandle, doc_name, len, 0); 889 890 /* Now get the MRU entry that will be replaced 891 * and delete the .lnk file for it 892 */ 893 if ((bufused = EnumMRUListA(mruhandle, (pos == -1) ? 14 : pos, 894 buffer, 2048)) != -1) { 895 ptr = buffer; 896 ptr += (lstrlenA(buffer) + 1); 897 slen = *((short int*)ptr); 898 ptr += 2; /* skip the length area */ 899 if (bufused >= slen + (ptr-buffer)) { 900 /* buffer size looks good */ 901 ptr += 12; /* get to string */ 902 len = bufused - (ptr-buffer); /* get length of buf remaining */ 903 if (ptr[0] && (lstrlenA(ptr) <= len-1)) { 904 /* appears to be good string */ 905 lstrcpyA(old_lnk_name, link_dir); 906 PathAppendA(old_lnk_name, ptr); 907 if (!DeleteFileA(old_lnk_name)) { 908 if ((attr = GetFileAttributesA(old_lnk_name)) == INVALID_FILE_ATTRIBUTES) { 909 if ((err = GetLastError()) != ERROR_FILE_NOT_FOUND) { 910 ERR("Delete for %s failed, err=%d, attr=%08x\n", 911 old_lnk_name, err, attr); 912 } 913 else { 914 TRACE("old .lnk file %s did not exist\n", 915 old_lnk_name); 916 } 917 } 918 else { 919 ERR("Delete for %s failed, attr=%08x\n", 920 old_lnk_name, attr); 921 } 922 } 923 else { 924 TRACE("deleted old .lnk file %s\n", old_lnk_name); 925 } 926 } 927 } 928 } 929 930 /* Create usable .lnk file name for the "Recent" directory 931 */ 932 wsprintfA(new_lnk_name, "%s.lnk", doc_name); 933 lstrcpyA(new_lnk_filepath, link_dir); 934 PathAppendA(new_lnk_filepath, new_lnk_name); 935 i = 1; 936 olderrormode = SetErrorMode(SEM_FAILCRITICALERRORS); 937 while (GetFileAttributesA(new_lnk_filepath) != INVALID_FILE_ATTRIBUTES) { 938 i++; 939 wsprintfA(new_lnk_name, "%s (%u).lnk", doc_name, i); 940 lstrcpyA(new_lnk_filepath, link_dir); 941 PathAppendA(new_lnk_filepath, new_lnk_name); 942 } 943 SetErrorMode(olderrormode); 944 TRACE("new shortcut will be %s\n", new_lnk_filepath); 945 946 /* Now add the new MRU entry and data 947 */ 948 pos = SHADD_create_add_mru_data(mruhandle, doc_name, new_lnk_name, 949 buffer, &len); 950 FreeMRUList(mruhandle); 951 TRACE("Updated MRU list, new doc is position %d\n", pos); 952 } 953 954 /* *** JOB 2: Create shortcut in user's "Recent" directory *** */ 955 956 { /* on input needs: 957 * doc_name - pure file-spec, no path 958 * new_lnk_filepath 959 * - path and file name of new .lnk file 960 * uFlags[in] - flags on call to SHAddToRecentDocs 961 * pv[in] - document path/pidl on call to SHAddToRecentDocs 962 */ 963 IShellLinkA *psl = NULL; 964 IPersistFile *pPf = NULL; 965 HRESULT hres; 966 CHAR desc[MAX_PATH]; 967 WCHAR widelink[MAX_PATH]; 968 969 CoInitialize(0); 970 971 hres = CoCreateInstance( &CLSID_ShellLink, 972 NULL, 973 CLSCTX_INPROC_SERVER, 974 &IID_IShellLinkA, 975 (LPVOID )&psl); 976 if(SUCCEEDED(hres)) { 977 978 hres = IShellLinkA_QueryInterface(psl, &IID_IPersistFile, 979 (LPVOID *)&pPf); 980 if(FAILED(hres)) { 981 /* bombed */ 982 ERR("failed QueryInterface for IPersistFile %08x\n", hres); 983 goto fail; 984 } 985 986 /* Set the document path or pidl */ 987 if (uFlags == SHARD_PIDL) { 988 hres = IShellLinkA_SetIDList(psl, pv); 989 } else { 990 hres = IShellLinkA_SetPath(psl, pv); 991 } 992 if(FAILED(hres)) { 993 /* bombed */ 994 ERR("failed Set{IDList|Path} %08x\n", hres); 995 goto fail; 996 } 997 998 lstrcpyA(desc, "Shortcut to "); 999 lstrcatA(desc, doc_name); 1000 hres = IShellLinkA_SetDescription(psl, desc); 1001 if(FAILED(hres)) { 1002 /* bombed */ 1003 ERR("failed SetDescription %08x\n", hres); 1004 goto fail; 1005 } 1006 1007 MultiByteToWideChar(CP_ACP, 0, new_lnk_filepath, -1, 1008 widelink, MAX_PATH); 1009 /* create the short cut */ 1010 hres = IPersistFile_Save(pPf, widelink, TRUE); 1011 if(FAILED(hres)) { 1012 /* bombed */ 1013 ERR("failed IPersistFile::Save %08x\n", hres); 1014 IPersistFile_Release(pPf); 1015 IShellLinkA_Release(psl); 1016 goto fail; 1017 } 1018 hres = IPersistFile_SaveCompleted(pPf, widelink); 1019 IPersistFile_Release(pPf); 1020 IShellLinkA_Release(psl); 1021 TRACE("shortcut %s has been created, result=%08x\n", 1022 new_lnk_filepath, hres); 1023 } 1024 else { 1025 ERR("CoCreateInstance failed, hres=%08x\n", hres); 1026 } 1027 } 1028 1029 fail: 1030 CoUninitialize(); 1031 1032 /* all done */ 1033 RegCloseKey(HCUbasekey); 1034 return; 1035 } 1036 1037 /************************************************************************* 1038 * SHCreateShellFolderViewEx [SHELL32.174] 1039 * 1040 * Create a new instance of the default Shell folder view object. 1041 * 1042 * RETURNS 1043 * Success: S_OK 1044 * Failure: error value 1045 * 1046 * NOTES 1047 * see IShellFolder::CreateViewObject 1048 */ 1049 #ifndef __REACTOS__ 1050 1051 HRESULT WINAPI SHCreateShellFolderViewEx( 1052 LPCSFV psvcbi, /* [in] shelltemplate struct */ 1053 IShellView **ppv) /* [out] IShellView pointer */ 1054 { 1055 IShellView * psf; 1056 HRESULT hRes; 1057 1058 TRACE("sf=%p pidl=%p cb=%p mode=0x%08x parm=%p\n", 1059 psvcbi->pshf, psvcbi->pidl, psvcbi->pfnCallback, 1060 psvcbi->fvm, psvcbi->psvOuter); 1061 1062 *ppv = NULL; 1063 hRes = IShellView_Constructor(psvcbi->pshf, &psf); 1064 1065 if (FAILED(hRes)) 1066 return hRes; 1067 1068 hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppv); 1069 IShellView_Release(psf); 1070 1071 return hRes; 1072 } 1073 #endif 1074 1075 /************************************************************************* 1076 * SHWinHelp [SHELL32.127] 1077 * 1078 */ 1079 HRESULT WINAPI SHWinHelp (DWORD v, DWORD w, DWORD x, DWORD z) 1080 { FIXME("0x%08x 0x%08x 0x%08x 0x%08x stub\n",v,w,x,z); 1081 return 0; 1082 } 1083 /************************************************************************* 1084 * SHRunControlPanel [SHELL32.161] 1085 * 1086 */ 1087 BOOL WINAPI SHRunControlPanel (LPCWSTR commandLine, HWND parent) 1088 { 1089 FIXME("(%s, %p): stub\n", debugstr_w(commandLine), parent); 1090 return FALSE; 1091 } 1092 1093 static LPUNKNOWN SHELL32_IExplorerInterface=0; 1094 /************************************************************************* 1095 * SHSetInstanceExplorer [SHELL32.176] 1096 * 1097 * NOTES 1098 * Sets the interface 1099 */ 1100 VOID WINAPI SHSetInstanceExplorer (LPUNKNOWN lpUnknown) 1101 { TRACE("%p\n", lpUnknown); 1102 SHELL32_IExplorerInterface = lpUnknown; 1103 } 1104 /************************************************************************* 1105 * SHGetInstanceExplorer [SHELL32.@] 1106 * 1107 * NOTES 1108 * gets the interface pointer of the explorer and a reference 1109 */ 1110 HRESULT WINAPI SHGetInstanceExplorer (IUnknown **lpUnknown) 1111 { TRACE("%p\n", lpUnknown); 1112 1113 *lpUnknown = SHELL32_IExplorerInterface; 1114 1115 if (!SHELL32_IExplorerInterface) 1116 return E_FAIL; 1117 1118 IUnknown_AddRef(SHELL32_IExplorerInterface); 1119 return S_OK; 1120 } 1121 /************************************************************************* 1122 * SHFreeUnusedLibraries [SHELL32.123] 1123 * 1124 * Probably equivalent to CoFreeUnusedLibraries but under Windows 9x it could use 1125 * the shell32 built-in "mini-COM" without the need to load ole32.dll - see SHLoadOLE 1126 * for details 1127 * 1128 * NOTES 1129 * exported by ordinal 1130 * 1131 * SEE ALSO 1132 * CoFreeUnusedLibraries, SHLoadOLE 1133 */ 1134 void WINAPI SHFreeUnusedLibraries (void) 1135 { 1136 FIXME("stub\n"); 1137 CoFreeUnusedLibraries(); 1138 } 1139 /************************************************************************* 1140 * DAD_AutoScroll [SHELL32.129] 1141 * 1142 */ 1143 BOOL WINAPI DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *samples, const POINT * pt) 1144 { 1145 FIXME("hwnd = %p %p %p\n",hwnd,samples,pt); 1146 return FALSE; 1147 } 1148 /************************************************************************* 1149 * DAD_DragEnter [SHELL32.130] 1150 * 1151 */ 1152 BOOL WINAPI DAD_DragEnter(HWND hwnd) 1153 { 1154 FIXME("hwnd = %p\n",hwnd); 1155 return FALSE; 1156 } 1157 /************************************************************************* 1158 * DAD_DragEnterEx [SHELL32.131] 1159 * 1160 */ 1161 BOOL WINAPI DAD_DragEnterEx(HWND hwnd, POINT p) 1162 { 1163 FIXME("hwnd = %p (%d,%d)\n",hwnd,p.x,p.y); 1164 return FALSE; 1165 } 1166 /************************************************************************* 1167 * DAD_DragMove [SHELL32.134] 1168 * 1169 */ 1170 BOOL WINAPI DAD_DragMove(POINT p) 1171 { 1172 FIXME("(%d,%d)\n",p.x,p.y); 1173 return FALSE; 1174 } 1175 /************************************************************************* 1176 * DAD_DragLeave [SHELL32.132] 1177 * 1178 */ 1179 BOOL WINAPI DAD_DragLeave(VOID) 1180 { 1181 FIXME("\n"); 1182 return FALSE; 1183 } 1184 /************************************************************************* 1185 * DAD_SetDragImage [SHELL32.136] 1186 * 1187 * NOTES 1188 * exported by name 1189 */ 1190 BOOL WINAPI DAD_SetDragImage( 1191 HIMAGELIST himlTrack, 1192 LPPOINT lppt) 1193 { 1194 FIXME("%p %p stub\n",himlTrack, lppt); 1195 return FALSE; 1196 } 1197 /************************************************************************* 1198 * DAD_ShowDragImage [SHELL32.137] 1199 * 1200 * NOTES 1201 * exported by name 1202 */ 1203 BOOL WINAPI DAD_ShowDragImage(BOOL bShow) 1204 { 1205 FIXME("0x%08x stub\n",bShow); 1206 return FALSE; 1207 } 1208 1209 static const WCHAR szwCabLocation[] = { 1210 'S','o','f','t','w','a','r','e','\\', 1211 'M','i','c','r','o','s','o','f','t','\\', 1212 'W','i','n','d','o','w','s','\\', 1213 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\', 1214 'E','x','p','l','o','r','e','r','\\', 1215 'C','a','b','i','n','e','t','S','t','a','t','e',0 1216 }; 1217 1218 static const WCHAR szwSettings[] = { 'S','e','t','t','i','n','g','s',0 }; 1219 1220 /************************************************************************* 1221 * ReadCabinetState [SHELL32.651] NT 4.0 1222 * 1223 */ 1224 BOOL WINAPI ReadCabinetState(CABINETSTATE *cs, int length) 1225 { 1226 HKEY hkey = 0; 1227 DWORD type, r; 1228 1229 TRACE("%p %d\n", cs, length); 1230 1231 if( (cs == NULL) || (length < (int)sizeof(*cs)) ) 1232 return FALSE; 1233 1234 r = RegOpenKeyW( HKEY_CURRENT_USER, szwCabLocation, &hkey ); 1235 if( r == ERROR_SUCCESS ) 1236 { 1237 type = REG_BINARY; 1238 r = RegQueryValueExW( hkey, szwSettings, 1239 NULL, &type, (LPBYTE)cs, (LPDWORD)&length ); 1240 RegCloseKey( hkey ); 1241 1242 } 1243 1244 /* if we can't read from the registry, create default values */ 1245 if ( (r != ERROR_SUCCESS) || (cs->cLength < sizeof(*cs)) || 1246 (cs->cLength != length) ) 1247 { 1248 TRACE("Initializing shell cabinet settings\n"); 1249 memset(cs, 0, sizeof(*cs)); 1250 cs->cLength = sizeof(*cs); 1251 cs->nVersion = 2; 1252 cs->fFullPathTitle = FALSE; 1253 cs->fSaveLocalView = TRUE; 1254 cs->fNotShell = FALSE; 1255 cs->fSimpleDefault = TRUE; 1256 cs->fDontShowDescBar = FALSE; 1257 cs->fNewWindowMode = FALSE; 1258 cs->fShowCompColor = FALSE; 1259 cs->fDontPrettyNames = FALSE; 1260 cs->fAdminsCreateCommonGroups = TRUE; 1261 cs->fMenuEnumFilter = 96; 1262 } 1263 1264 return TRUE; 1265 } 1266 1267 /************************************************************************* 1268 * WriteCabinetState [SHELL32.652] NT 4.0 1269 * 1270 */ 1271 BOOL WINAPI WriteCabinetState(CABINETSTATE *cs) 1272 { 1273 DWORD r; 1274 HKEY hkey = 0; 1275 1276 TRACE("%p\n",cs); 1277 1278 if( cs == NULL ) 1279 return FALSE; 1280 1281 r = RegCreateKeyExW( HKEY_CURRENT_USER, szwCabLocation, 0, 1282 NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL); 1283 if( r == ERROR_SUCCESS ) 1284 { 1285 r = RegSetValueExW( hkey, szwSettings, 0, 1286 REG_BINARY, (LPBYTE) cs, cs->cLength); 1287 1288 RegCloseKey( hkey ); 1289 } 1290 1291 return (r==ERROR_SUCCESS); 1292 } 1293 1294 /************************************************************************* 1295 * FileIconInit [SHELL32.660] 1296 * 1297 */ 1298 BOOL WINAPI FileIconInit(BOOL bFullInit) 1299 { 1300 return SIC_Initialize(); 1301 } 1302 1303 /************************************************************************* 1304 * SetAppStartingCursor [SHELL32.99] 1305 */ 1306 HRESULT WINAPI SetAppStartingCursor(HWND u, DWORD v) 1307 { FIXME("hwnd=%p 0x%04x stub\n",u,v ); 1308 return 0; 1309 } 1310 1311 /************************************************************************* 1312 * SHLoadOLE [SHELL32.151] 1313 * 1314 * To reduce the memory usage of Windows 95, its shell32 contained an 1315 * internal implementation of a part of COM (see e.g. SHGetMalloc, SHCoCreateInstance, 1316 * SHRegisterDragDrop etc.) that allowed to use in-process STA objects without 1317 * the need to load OLE32.DLL. If OLE32.DLL was already loaded, the SH* function 1318 * would just call the Co* functions. 1319 * 1320 * The SHLoadOLE was called when OLE32.DLL was being loaded to transfer all the 1321 * information from the shell32 "mini-COM" to ole32.dll. 1322 * 1323 * See http://blogs.msdn.com/oldnewthing/archive/2004/07/05/173226.aspx for a 1324 * detailed description. 1325 * 1326 * Under wine ole32.dll is always loaded as it is imported by shlwapi.dll which is 1327 * imported by shell32 and no "mini-COM" is used (except for the "LoadWithoutCOM" 1328 * hack in SHCoCreateInstance) 1329 */ 1330 HRESULT WINAPI SHLoadOLE(LPARAM lParam) 1331 { FIXME("0x%08lx stub\n",lParam); 1332 return S_OK; 1333 } 1334 /************************************************************************* 1335 * DriveType [SHELL32.64] 1336 * 1337 */ 1338 int WINAPI DriveType(int DriveType) 1339 { 1340 WCHAR root[] = L"A:\\"; 1341 root[0] = L'A' + DriveType; 1342 return GetDriveTypeW(root); 1343 } 1344 /************************************************************************* 1345 * InvalidateDriveType [SHELL32.65] 1346 * Unimplemented in XP SP3 1347 */ 1348 int WINAPI InvalidateDriveType(int u) 1349 { 1350 TRACE("0x%08x stub\n",u); 1351 return 0; 1352 } 1353 /************************************************************************* 1354 * SHAbortInvokeCommand [SHELL32.198] 1355 * 1356 */ 1357 HRESULT WINAPI SHAbortInvokeCommand(void) 1358 { FIXME("stub\n"); 1359 return 1; 1360 } 1361 /************************************************************************* 1362 * SHOutOfMemoryMessageBox [SHELL32.126] 1363 * 1364 */ 1365 int WINAPI SHOutOfMemoryMessageBox( 1366 HWND hwndOwner, 1367 LPCSTR lpCaption, 1368 UINT uType) 1369 { 1370 FIXME("%p %s 0x%08x stub\n",hwndOwner, lpCaption, uType); 1371 return 0; 1372 } 1373 /************************************************************************* 1374 * SHFlushClipboard [SHELL32.121] 1375 * 1376 */ 1377 HRESULT WINAPI SHFlushClipboard(void) 1378 { 1379 return OleFlushClipboard(); 1380 } 1381 1382 /************************************************************************* 1383 * SHWaitForFileToOpen [SHELL32.97] 1384 * 1385 */ 1386 BOOL WINAPI SHWaitForFileToOpen( 1387 LPCITEMIDLIST pidl, 1388 DWORD dwFlags, 1389 DWORD dwTimeout) 1390 { 1391 FIXME("%p 0x%08x 0x%08x stub\n", pidl, dwFlags, dwTimeout); 1392 return FALSE; 1393 } 1394 1395 /************************************************************************ 1396 * RLBuildListOfPaths [SHELL32.146] 1397 * 1398 * NOTES 1399 * builds a DPA 1400 */ 1401 DWORD WINAPI RLBuildListOfPaths (void) 1402 { FIXME("stub\n"); 1403 return 0; 1404 } 1405 /************************************************************************ 1406 * SHValidateUNC [SHELL32.173] 1407 * 1408 */ 1409 BOOL WINAPI SHValidateUNC (HWND hwndOwner, PWSTR pszFile, UINT fConnect) 1410 { 1411 FIXME("(%p, %s, 0x%08x): stub\n", hwndOwner, debugstr_w(pszFile), fConnect); 1412 return FALSE; 1413 } 1414 1415 /************************************************************************ 1416 * DoEnvironmentSubstA [SHELL32.@] 1417 * 1418 * See DoEnvironmentSubstW. 1419 */ 1420 DWORD WINAPI DoEnvironmentSubstA(LPSTR pszString, UINT cchString) 1421 { 1422 LPSTR dst; 1423 BOOL res = FALSE; 1424 DWORD len = cchString; 1425 1426 TRACE("(%s, %d)\n", debugstr_a(pszString), cchString); 1427 if (pszString == NULL) /* Really return 0? */ 1428 return 0; 1429 if ((dst = (LPSTR)HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(CHAR)))) 1430 { 1431 len = ExpandEnvironmentStringsA(pszString, dst, cchString); 1432 /* len includes the terminating 0 */ 1433 if (len && len < cchString) 1434 { 1435 res = TRUE; 1436 memcpy(pszString, dst, len); 1437 } 1438 else 1439 len = cchString; 1440 1441 HeapFree(GetProcessHeap(), 0, dst); 1442 } 1443 return MAKELONG(len, res); 1444 } 1445 1446 /************************************************************************ 1447 * DoEnvironmentSubstW [SHELL32.@] 1448 * 1449 * Replace all %KEYWORD% in the string with the value of the named 1450 * environment variable. If the buffer is too small, the string is not modified. 1451 * 1452 * PARAMS 1453 * pszString [I] '\0' terminated string with %keyword%. 1454 * [O] '\0' terminated string with %keyword% substituted. 1455 * cchString [I] size of str. 1456 * 1457 * RETURNS 1458 * Success: The string in the buffer is updated 1459 * HIWORD: TRUE 1460 * LOWORD: characters used in the buffer, including space for the terminating 0 1461 * Failure: buffer too small. The string is not modified. 1462 * HIWORD: FALSE 1463 * LOWORD: provided size of the buffer in characters 1464 */ 1465 DWORD WINAPI DoEnvironmentSubstW(LPWSTR pszString, UINT cchString) 1466 { 1467 LPWSTR dst; 1468 BOOL res = FALSE; 1469 DWORD len = cchString; 1470 1471 TRACE("(%s, %d)\n", debugstr_w(pszString), cchString); 1472 1473 if ((cchString < MAXLONG) && (dst = HeapAlloc(GetProcessHeap(), 0, cchString * sizeof(WCHAR)))) 1474 { 1475 len = ExpandEnvironmentStringsW(pszString, dst, cchString); 1476 /* len includes the terminating 0 */ 1477 if (len && len <= cchString) 1478 { 1479 res = TRUE; 1480 memcpy(pszString, dst, len * sizeof(WCHAR)); 1481 } 1482 else 1483 len = cchString; 1484 1485 HeapFree(GetProcessHeap(), 0, dst); 1486 } 1487 return MAKELONG(len, res); 1488 } 1489 1490 /************************************************************************ 1491 * DoEnvironmentSubst [SHELL32.53] 1492 * 1493 * See DoEnvironmentSubstA. 1494 */ 1495 DWORD WINAPI DoEnvironmentSubstAW(LPVOID x, UINT y) 1496 { 1497 if (SHELL_OsIsUnicode()) 1498 return DoEnvironmentSubstW(x, y); 1499 return DoEnvironmentSubstA(x, y); 1500 } 1501 1502 /************************************************************************* 1503 * GUIDFromStringA [SHELL32.703] 1504 */ 1505 BOOL WINAPI GUIDFromStringA(LPCSTR str, LPGUID guid) 1506 { 1507 TRACE("GUIDFromStringA() stub\n"); 1508 return FALSE; 1509 } 1510 1511 /************************************************************************* 1512 * GUIDFromStringW [SHELL32.704] 1513 */ 1514 BOOL WINAPI GUIDFromStringW(LPCWSTR str, LPGUID guid) 1515 { 1516 UNICODE_STRING guid_str; 1517 1518 RtlInitUnicodeString(&guid_str, str); 1519 return !RtlGUIDFromString(&guid_str, guid); 1520 } 1521 1522 /************************************************************************* 1523 * PathIsTemporaryA [SHELL32.713] 1524 */ 1525 BOOL WINAPI PathIsTemporaryA(LPSTR Str) 1526 { 1527 FIXME("(%s)stub\n", debugstr_a(Str)); 1528 return FALSE; 1529 } 1530 1531 /************************************************************************* 1532 * PathIsTemporaryW [SHELL32.714] 1533 */ 1534 BOOL WINAPI PathIsTemporaryW(LPWSTR Str) 1535 { 1536 FIXME("(%s)stub\n", debugstr_w(Str)); 1537 return FALSE; 1538 } 1539 1540 typedef struct _PSXA 1541 { 1542 UINT uiCount; 1543 UINT uiAllocated; 1544 IShellPropSheetExt *pspsx[1]; 1545 } PSXA, *PPSXA; 1546 1547 typedef struct _PSXA_CALL 1548 { 1549 LPFNADDPROPSHEETPAGE lpfnAddReplaceWith; 1550 LPARAM lParam; 1551 BOOL bCalled; 1552 BOOL bMultiple; 1553 UINT uiCount; 1554 } PSXA_CALL, *PPSXA_CALL; 1555 1556 static BOOL CALLBACK PsxaCall(HPROPSHEETPAGE hpage, LPARAM lParam) 1557 { 1558 PPSXA_CALL Call = (PPSXA_CALL)lParam; 1559 1560 if (Call != NULL) 1561 { 1562 if ((Call->bMultiple || !Call->bCalled) && 1563 Call->lpfnAddReplaceWith(hpage, Call->lParam)) 1564 { 1565 Call->bCalled = TRUE; 1566 Call->uiCount++; 1567 return TRUE; 1568 } 1569 } 1570 1571 return FALSE; 1572 } 1573 1574 /************************************************************************* 1575 * SHAddFromPropSheetExtArray [SHELL32.167] 1576 */ 1577 UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) 1578 { 1579 PSXA_CALL Call; 1580 UINT i; 1581 PPSXA psxa = (PPSXA)hpsxa; 1582 1583 TRACE("(%p,%p,%08lx)\n", hpsxa, lpfnAddPage, lParam); 1584 1585 if (psxa) 1586 { 1587 ZeroMemory(&Call, sizeof(Call)); 1588 Call.lpfnAddReplaceWith = lpfnAddPage; 1589 Call.lParam = lParam; 1590 Call.bMultiple = TRUE; 1591 1592 /* Call the AddPage method of all registered IShellPropSheetExt interfaces */ 1593 for (i = 0; i != psxa->uiCount; i++) 1594 { 1595 psxa->pspsx[i]->lpVtbl->AddPages(psxa->pspsx[i], PsxaCall, (LPARAM)&Call); 1596 } 1597 1598 return Call.uiCount; 1599 } 1600 1601 return 0; 1602 } 1603 1604 /************************************************************************* 1605 * SHCreatePropSheetExtArray [SHELL32.168] 1606 */ 1607 HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) 1608 { 1609 return SHCreatePropSheetExtArrayEx(hKey, pszSubKey, max_iface, NULL); 1610 } 1611 1612 /************************************************************************* 1613 * SHCreatePropSheetExtArrayEx [SHELL32.194] 1614 */ 1615 HPSXA WINAPI SHCreatePropSheetExtArrayEx(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface, LPDATAOBJECT pDataObj) 1616 { 1617 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}; 1618 WCHAR szHandler[64]; 1619 DWORD dwHandlerLen; 1620 WCHAR szClsidHandler[39]; 1621 DWORD dwClsidSize; 1622 CLSID clsid; 1623 LONG lRet; 1624 DWORD dwIndex; 1625 IShellExtInit *psxi; 1626 IShellPropSheetExt *pspsx; 1627 HKEY hkBase, hkPropSheetHandlers; 1628 PPSXA psxa = NULL; 1629 1630 TRACE("(%p,%s,%u)\n", hKey, debugstr_w(pszSubKey), max_iface); 1631 1632 if (max_iface == 0) 1633 return NULL; 1634 1635 /* Open the registry key */ 1636 lRet = RegOpenKeyW(hKey, pszSubKey, &hkBase); 1637 if (lRet != ERROR_SUCCESS) 1638 return NULL; 1639 1640 lRet = RegOpenKeyExW(hkBase, szPropSheetSubKey, 0, KEY_ENUMERATE_SUB_KEYS, &hkPropSheetHandlers); 1641 RegCloseKey(hkBase); 1642 if (lRet == ERROR_SUCCESS) 1643 { 1644 /* Create and initialize the Property Sheet Extensions Array */ 1645 psxa = LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface])); 1646 if (psxa) 1647 { 1648 ZeroMemory(psxa, FIELD_OFFSET(PSXA, pspsx[max_iface])); 1649 psxa->uiAllocated = max_iface; 1650 1651 /* Enumerate all subkeys and attempt to load the shell extensions */ 1652 dwIndex = 0; 1653 do 1654 { 1655 dwHandlerLen = sizeof(szHandler) / sizeof(szHandler[0]); 1656 lRet = RegEnumKeyExW(hkPropSheetHandlers, dwIndex++, szHandler, &dwHandlerLen, NULL, NULL, NULL, NULL); 1657 if (lRet != ERROR_SUCCESS) 1658 { 1659 if (lRet == ERROR_MORE_DATA) 1660 continue; 1661 1662 if (lRet == ERROR_NO_MORE_ITEMS) 1663 lRet = ERROR_SUCCESS; 1664 break; 1665 } 1666 1667 /* The CLSID is stored either in the key itself or in its default value. */ 1668 if (FAILED(lRet = SHCLSIDFromStringW(szHandler, &clsid))) 1669 { 1670 dwClsidSize = sizeof(szClsidHandler); 1671 if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS) 1672 { 1673 /* Force a NULL-termination and convert the string */ 1674 szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0; 1675 lRet = SHCLSIDFromStringW(szClsidHandler, &clsid); 1676 } 1677 } 1678 1679 if (SUCCEEDED(lRet)) 1680 { 1681 /* Attempt to get an IShellPropSheetExt and an IShellExtInit instance. 1682 Only if both interfaces are supported it's a real shell extension. 1683 Then call IShellExtInit's Initialize method. */ 1684 if (SUCCEEDED(CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER/* | CLSCTX_NO_CODE_DOWNLOAD */, &IID_IShellPropSheetExt, (LPVOID *)&pspsx))) 1685 { 1686 if (SUCCEEDED(pspsx->lpVtbl->QueryInterface(pspsx, &IID_IShellExtInit, (PVOID *)&psxi))) 1687 { 1688 if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, pDataObj, hKey))) 1689 { 1690 /* Add the IShellPropSheetExt instance to the array */ 1691 psxa->pspsx[psxa->uiCount++] = pspsx; 1692 } 1693 else 1694 { 1695 psxi->lpVtbl->Release(psxi); 1696 pspsx->lpVtbl->Release(pspsx); 1697 } 1698 } 1699 else 1700 pspsx->lpVtbl->Release(pspsx); 1701 } 1702 } 1703 1704 } while (psxa->uiCount != psxa->uiAllocated); 1705 } 1706 else 1707 lRet = ERROR_NOT_ENOUGH_MEMORY; 1708 1709 RegCloseKey(hkPropSheetHandlers); 1710 } 1711 1712 if (lRet != ERROR_SUCCESS && psxa) 1713 { 1714 SHDestroyPropSheetExtArray((HPSXA)psxa); 1715 psxa = NULL; 1716 } 1717 1718 return (HPSXA)psxa; 1719 } 1720 1721 /************************************************************************* 1722 * SHReplaceFromPropSheetExtArray [SHELL32.170] 1723 */ 1724 UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam) 1725 { 1726 PSXA_CALL Call; 1727 UINT i; 1728 PPSXA psxa = (PPSXA)hpsxa; 1729 1730 TRACE("(%p,%u,%p,%08lx)\n", hpsxa, uPageID, lpfnReplaceWith, lParam); 1731 1732 if (psxa) 1733 { 1734 ZeroMemory(&Call, sizeof(Call)); 1735 Call.lpfnAddReplaceWith = lpfnReplaceWith; 1736 Call.lParam = lParam; 1737 1738 /* Call the ReplacePage method of all registered IShellPropSheetExt interfaces. 1739 Each shell extension is only allowed to call the callback once during the callback. */ 1740 for (i = 0; i != psxa->uiCount; i++) 1741 { 1742 Call.bCalled = FALSE; 1743 psxa->pspsx[i]->lpVtbl->ReplacePage(psxa->pspsx[i], uPageID, PsxaCall, (LPARAM)&Call); 1744 } 1745 1746 return Call.uiCount; 1747 } 1748 1749 return 0; 1750 } 1751 1752 /************************************************************************* 1753 * SHDestroyPropSheetExtArray [SHELL32.169] 1754 */ 1755 void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa) 1756 { 1757 UINT i; 1758 PPSXA psxa = (PPSXA)hpsxa; 1759 1760 TRACE("(%p)\n", hpsxa); 1761 1762 if (psxa) 1763 { 1764 for (i = 0; i != psxa->uiCount; i++) 1765 { 1766 psxa->pspsx[i]->lpVtbl->Release(psxa->pspsx[i]); 1767 } 1768 1769 LocalFree(psxa); 1770 } 1771 } 1772 1773 /************************************************************************* 1774 * CIDLData_CreateFromIDArray [SHELL32.83] 1775 * 1776 * Create IDataObject from PIDLs?? 1777 */ 1778 HRESULT WINAPI CIDLData_CreateFromIDArray( 1779 PCIDLIST_ABSOLUTE pidlFolder, 1780 UINT cpidlFiles, 1781 PCUIDLIST_RELATIVE_ARRAY lppidlFiles, 1782 LPDATAOBJECT *ppdataObject) 1783 { 1784 UINT i; 1785 HWND hwnd = 0; /*FIXME: who should be hwnd of owner? set to desktop */ 1786 HRESULT hResult; 1787 1788 TRACE("(%p, %d, %p, %p)\n", pidlFolder, cpidlFiles, lppidlFiles, ppdataObject); 1789 if (TRACE_ON(pidl)) 1790 { 1791 pdump (pidlFolder); 1792 for (i=0; i<cpidlFiles; i++) pdump (lppidlFiles[i]); 1793 } 1794 hResult = IDataObject_Constructor(hwnd, pidlFolder, lppidlFiles, cpidlFiles, ppdataObject); 1795 return hResult; 1796 } 1797 1798 /************************************************************************* 1799 * SHCreateStdEnumFmtEtc [SHELL32.74] 1800 * 1801 * NOTES 1802 * 1803 */ 1804 HRESULT WINAPI SHCreateStdEnumFmtEtc( 1805 UINT cFormats, 1806 const FORMATETC *lpFormats, 1807 LPENUMFORMATETC *ppenumFormatetc) 1808 { 1809 IEnumFORMATETC *pef; 1810 HRESULT hRes; 1811 TRACE("cf=%d fe=%p pef=%p\n", cFormats, lpFormats, ppenumFormatetc); 1812 1813 hRes = IEnumFORMATETC_Constructor(cFormats, lpFormats, &pef); 1814 if (FAILED(hRes)) 1815 return hRes; 1816 1817 IEnumFORMATETC_AddRef(pef); 1818 hRes = IEnumFORMATETC_QueryInterface(pef, &IID_IEnumFORMATETC, (LPVOID*)ppenumFormatetc); 1819 IEnumFORMATETC_Release(pef); 1820 1821 return hRes; 1822 } 1823 1824 /************************************************************************* 1825 * SHFindFiles (SHELL32.90) 1826 */ 1827 BOOL WINAPI SHFindFiles( LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlSaveFile ) 1828 { 1829 FIXME("%p %p\n", pidlFolder, pidlSaveFile ); 1830 return FALSE; 1831 } 1832 1833 /************************************************************************* 1834 * SHUpdateImageW (SHELL32.192) 1835 * 1836 * Notifies the shell that an icon in the system image list has been changed. 1837 * 1838 * PARAMS 1839 * pszHashItem [I] Path to file that contains the icon. 1840 * iIndex [I] Zero-based index of the icon in the file. 1841 * uFlags [I] Flags determining the icon attributes. See notes. 1842 * iImageIndex [I] Index of the icon in the system image list. 1843 * 1844 * RETURNS 1845 * Nothing 1846 * 1847 * NOTES 1848 * uFlags can be one or more of the following flags: 1849 * GIL_NOTFILENAME - pszHashItem is not a file name. 1850 * GIL_SIMULATEDOC - Create a document icon using the specified icon. 1851 */ 1852 void WINAPI SHUpdateImageW(LPCWSTR pszHashItem, int iIndex, UINT uFlags, int iImageIndex) 1853 { 1854 FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_w(pszHashItem), iIndex, uFlags, iImageIndex); 1855 } 1856 1857 /************************************************************************* 1858 * SHUpdateImageA (SHELL32.191) 1859 * 1860 * See SHUpdateImageW. 1861 */ 1862 VOID WINAPI SHUpdateImageA(LPCSTR pszHashItem, INT iIndex, UINT uFlags, INT iImageIndex) 1863 { 1864 FIXME("%s, %d, 0x%x, %d - stub\n", debugstr_a(pszHashItem), iIndex, uFlags, iImageIndex); 1865 } 1866 1867 INT WINAPI SHHandleUpdateImage(LPCITEMIDLIST pidlExtra) 1868 { 1869 FIXME("%p - stub\n", pidlExtra); 1870 1871 return -1; 1872 } 1873 1874 BOOL WINAPI SHObjectProperties(HWND hwnd, DWORD dwType, LPCWSTR szObject, LPCWSTR szPage) 1875 { 1876 FIXME("%p, 0x%08x, %s, %s - stub\n", hwnd, dwType, debugstr_w(szObject), debugstr_w(szPage)); 1877 1878 return TRUE; 1879 } 1880 1881 BOOL WINAPI SHGetNewLinkInfoA(LPCSTR pszLinkTo, LPCSTR pszDir, LPSTR pszName, BOOL *pfMustCopy, 1882 UINT uFlags) 1883 { 1884 WCHAR wszLinkTo[MAX_PATH]; 1885 WCHAR wszDir[MAX_PATH]; 1886 WCHAR wszName[MAX_PATH]; 1887 BOOL res; 1888 1889 MultiByteToWideChar(CP_ACP, 0, pszLinkTo, -1, wszLinkTo, MAX_PATH); 1890 MultiByteToWideChar(CP_ACP, 0, pszDir, -1, wszDir, MAX_PATH); 1891 1892 res = SHGetNewLinkInfoW(wszLinkTo, wszDir, wszName, pfMustCopy, uFlags); 1893 1894 if (res) 1895 WideCharToMultiByte(CP_ACP, 0, wszName, -1, pszName, MAX_PATH, NULL, NULL); 1896 1897 return res; 1898 } 1899 1900 BOOL WINAPI SHGetNewLinkInfoW(LPCWSTR pszLinkTo, LPCWSTR pszDir, LPWSTR pszName, BOOL *pfMustCopy, 1901 UINT uFlags) 1902 { 1903 const WCHAR *basename; 1904 WCHAR *dst_basename; 1905 int i=2; 1906 static const WCHAR lnkformat[] = {'%','s','.','l','n','k',0}; 1907 static const WCHAR lnkformatnum[] = {'%','s',' ','(','%','d',')','.','l','n','k',0}; 1908 1909 TRACE("(%s, %s, %p, %p, 0x%08x)\n", debugstr_w(pszLinkTo), debugstr_w(pszDir), 1910 pszName, pfMustCopy, uFlags); 1911 1912 *pfMustCopy = FALSE; 1913 1914 if (uFlags & SHGNLI_PIDL) 1915 { 1916 FIXME("SHGNLI_PIDL flag unsupported\n"); 1917 return FALSE; 1918 } 1919 1920 if (uFlags) 1921 FIXME("ignoring flags: 0x%08x\n", uFlags); 1922 1923 /* FIXME: should test if the file is a shortcut or DOS program */ 1924 if (GetFileAttributesW(pszLinkTo) == INVALID_FILE_ATTRIBUTES) 1925 return FALSE; 1926 1927 basename = strrchrW(pszLinkTo, '\\'); 1928 if (basename) 1929 basename = basename+1; 1930 else 1931 basename = pszLinkTo; 1932 1933 lstrcpynW(pszName, pszDir, MAX_PATH); 1934 if (!PathAddBackslashW(pszName)) 1935 return FALSE; 1936 1937 dst_basename = pszName + strlenW(pszName); 1938 1939 snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformat, basename); 1940 1941 while (GetFileAttributesW(pszName) != INVALID_FILE_ATTRIBUTES) 1942 { 1943 snprintfW(dst_basename, pszName + MAX_PATH - dst_basename, lnkformatnum, basename, i); 1944 i++; 1945 } 1946 1947 return TRUE; 1948 } 1949 1950 HRESULT WINAPI SHStartNetConnectionDialog(HWND hwnd, LPCSTR pszRemoteName, DWORD dwType) 1951 { 1952 FIXME("%p, %s, 0x%08x - stub\n", hwnd, debugstr_a(pszRemoteName), dwType); 1953 1954 return S_OK; 1955 } 1956 /************************************************************************* 1957 * SHSetLocalizedName (SHELL32.@) 1958 */ 1959 HRESULT WINAPI SHSetLocalizedName(LPCWSTR pszPath, LPCWSTR pszResModule, int idsRes) 1960 { 1961 FIXME("%p, %s, %d - stub\n", pszPath, debugstr_w(pszResModule), idsRes); 1962 1963 return S_OK; 1964 } 1965 1966 /************************************************************************* 1967 * LinkWindow_RegisterClass (SHELL32.258) 1968 */ 1969 BOOL WINAPI LinkWindow_RegisterClass(void) 1970 { 1971 FIXME("()\n"); 1972 return TRUE; 1973 } 1974 1975 /************************************************************************* 1976 * LinkWindow_UnregisterClass (SHELL32.259) 1977 */ 1978 BOOL WINAPI LinkWindow_UnregisterClass(DWORD dwUnused) 1979 { 1980 FIXME("()\n"); 1981 return TRUE; 1982 } 1983 1984 /************************************************************************* 1985 * SHFlushSFCache (SHELL32.526) 1986 * 1987 * Notifies the shell that a user-specified special folder location has changed. 1988 * 1989 * NOTES 1990 * In Wine, the shell folder registry values are not cached, so this function 1991 * has no effect. 1992 */ 1993 void WINAPI SHFlushSFCache(void) 1994 { 1995 } 1996 1997 /************************************************************************* 1998 * SHGetImageList (SHELL32.727) 1999 * 2000 * Returns a copy of a shell image list. 2001 * 2002 * NOTES 2003 * Windows XP features 4 sizes of image list, and Vista 5. Wine currently 2004 * only supports the traditional small and large image lists, so requests 2005 * for the others will currently fail. 2006 */ 2007 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv) 2008 { 2009 HIMAGELIST hLarge, hSmall; 2010 HIMAGELIST hNew; 2011 HRESULT ret = E_FAIL; 2012 2013 /* Wine currently only maintains large and small image lists */ 2014 if ((iImageList != SHIL_LARGE) && (iImageList != SHIL_SMALL) && (iImageList != SHIL_SYSSMALL)) 2015 { 2016 FIXME("Unsupported image list %i requested\n", iImageList); 2017 return E_FAIL; 2018 } 2019 2020 Shell_GetImageLists(&hLarge, &hSmall); 2021 #ifndef __REACTOS__ 2022 hNew = ImageList_Duplicate(iImageList == SHIL_LARGE ? hLarge : hSmall); 2023 2024 /* Get the interface for the new image list */ 2025 if (hNew) 2026 { 2027 ret = HIMAGELIST_QueryInterface(hNew, riid, ppv); 2028 ImageList_Destroy(hNew); 2029 } 2030 #else 2031 /* Duplicating the imagelist causes the start menu items not to draw on 2032 * the first show. Was the Duplicate necessary for some reason? I believe 2033 * Windows returns the raw pointer here. */ 2034 hNew = (iImageList == SHIL_LARGE ? hLarge : hSmall); 2035 ret = IImageList2_QueryInterface((IImageList2 *) hNew, riid, ppv); 2036 #endif 2037 2038 return ret; 2039 } 2040 2041 #ifndef __REACTOS__ 2042 2043 /************************************************************************* 2044 * SHCreateShellFolderView [SHELL32.256] 2045 * 2046 * Create a new instance of the default Shell folder view object. 2047 * 2048 * RETURNS 2049 * Success: S_OK 2050 * Failure: error value 2051 * 2052 * NOTES 2053 * see IShellFolder::CreateViewObject 2054 */ 2055 HRESULT WINAPI SHCreateShellFolderView(const SFV_CREATE *pcsfv, 2056 IShellView **ppsv) 2057 { 2058 IShellView * psf; 2059 HRESULT hRes; 2060 2061 *ppsv = NULL; 2062 if (!pcsfv || pcsfv->cbSize != sizeof(*pcsfv)) 2063 return E_INVALIDARG; 2064 2065 TRACE("sf=%p outer=%p callback=%p\n", 2066 pcsfv->pshf, pcsfv->psvOuter, pcsfv->psfvcb); 2067 2068 hRes = IShellView_Constructor(pcsfv->pshf, &psf); 2069 if (FAILED(hRes)) 2070 return hRes; 2071 2072 hRes = IShellView_QueryInterface(psf, &IID_IShellView, (LPVOID *)ppsv); 2073 IShellView_Release(psf); 2074 2075 return hRes; 2076 } 2077 #endif 2078 2079 2080 /************************************************************************* 2081 * SHTestTokenMembership [SHELL32.245] 2082 * 2083 * Checks whether a given token is a mamber of a local group with the 2084 * specified RID. 2085 * 2086 */ 2087 EXTERN_C BOOL 2088 WINAPI 2089 SHTestTokenMembership(HANDLE TokenHandle, ULONG ulRID) 2090 { 2091 SID_IDENTIFIER_AUTHORITY ntAuth = {SECURITY_NT_AUTHORITY}; 2092 DWORD nSubAuthority0, nSubAuthority1; 2093 DWORD nSubAuthorityCount; 2094 PSID SidToCheck; 2095 BOOL IsMember = FALSE; 2096 2097 if ((ulRID == SECURITY_SERVICE_RID) || ulRID == SECURITY_LOCAL_SYSTEM_RID) 2098 { 2099 nSubAuthority0 = ulRID; 2100 nSubAuthority1 = 0; 2101 nSubAuthorityCount= 1; 2102 } 2103 else 2104 { 2105 nSubAuthority0 = SECURITY_BUILTIN_DOMAIN_RID; 2106 nSubAuthority1 = ulRID; 2107 nSubAuthorityCount= 2; 2108 } 2109 2110 if (!AllocateAndInitializeSid(&ntAuth, 2111 nSubAuthorityCount, 2112 nSubAuthority0, 2113 nSubAuthority1, 2114 0, 0, 0, 0, 0, 0, 2115 &SidToCheck)) 2116 { 2117 return FALSE; 2118 } 2119 2120 if (!CheckTokenMembership(TokenHandle, SidToCheck, &IsMember)) 2121 { 2122 IsMember = FALSE; 2123 } 2124 2125 FreeSid(SidToCheck); 2126 return IsMember; 2127 } 2128 2129 /************************************************************************* 2130 * IsUserAnAdmin [SHELL32.680] NT 4.0 2131 * 2132 * Checks whether the current user is a member of the Administrators group. 2133 * 2134 * PARAMS 2135 * None 2136 * 2137 * RETURNS 2138 * Success: TRUE 2139 * Failure: FALSE 2140 */ 2141 BOOL WINAPI IsUserAnAdmin(VOID) 2142 { 2143 return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS); 2144 }