5b9ca5eae8351e7476cfc04664da738baac1a545
[reactos.git] / dll / win32 / shell32 / wine / shell32_main.c
1 /*
2 * Shell basics
3 *
4 * Copyright 1998 Marcus Meissner
5 * Copyright 1998 Juergen Schmied (jsch) * <juergen.schmied@metronet.de>
6 * Copyright 2017 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
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 <shellapi.h>
32 #include <shlobj.h>
33 #include <shlwapi.h>
34
35 #include "undocshell.h"
36 #include "pidl.h"
37 #include "shell32_main.h"
38 #include "shresdef.h"
39
40 #include <wine/debug.h>
41 #include <wine/unicode.h>
42
43 #include <reactos/version.h>
44
45 WINE_DEFAULT_DEBUG_CHANNEL(shell);
46
47 const char * const SHELL_Authors[] = { "Copyright 1993-"COPYRIGHT_YEAR" WINE team", "Copyright 1998-"COPYRIGHT_YEAR" ReactOS Team", 0 };
48
49 /*************************************************************************
50 * CommandLineToArgvW [SHELL32.@]
51 *
52 * We must interpret the quotes in the command line to rebuild the argv
53 * array correctly:
54 * - arguments are separated by spaces or tabs
55 * - quotes serve as optional argument delimiters
56 * '"a b"' -> 'a b'
57 * - escaped quotes must be converted back to '"'
58 * '\"' -> '"'
59 * - consecutive backslashes preceding a quote see their number halved with
60 * the remainder escaping the quote:
61 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
62 * 2n+1 backslashes + quote -> n backslashes + literal quote
63 * - backslashes that are not followed by a quote are copied literally:
64 * 'a\b' -> 'a\b'
65 * 'a\\b' -> 'a\\b'
66 * - in quoted strings, consecutive quotes see their number divided by three
67 * with the remainder modulo 3 deciding whether to close the string or not.
68 * Note that the opening quote must be counted in the consecutive quotes,
69 * that's the (1+) below:
70 * (1+) 3n quotes -> n quotes
71 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
72 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
73 * - in unquoted strings, the first quote opens the quoted string and the
74 * remaining consecutive quotes follow the above rule.
75 */
76 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
77 {
78 DWORD argc;
79 LPWSTR *argv;
80 LPCWSTR s;
81 LPWSTR d;
82 LPWSTR cmdline;
83 int qcount,bcount;
84
85 if(!numargs)
86 {
87 SetLastError(ERROR_INVALID_PARAMETER);
88 return NULL;
89 }
90
91 if (*lpCmdline==0)
92 {
93 /* Return the path to the executable */
94 DWORD len, deslen=MAX_PATH, size;
95
96 size = sizeof(LPWSTR)*2 + deslen*sizeof(WCHAR);
97 for (;;)
98 {
99 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
100 len = GetModuleFileNameW(0, (LPWSTR)(argv+2), deslen);
101 if (!len)
102 {
103 LocalFree(argv);
104 return NULL;
105 }
106 if (len < deslen) break;
107 deslen*=2;
108 size = sizeof(LPWSTR)*2 + deslen*sizeof(WCHAR);
109 LocalFree( argv );
110 }
111 argv[0]=(LPWSTR)(argv+2);
112 argv[1]=NULL;
113 *numargs=1;
114
115 return argv;
116 }
117
118 /* --- First count the arguments */
119 argc=1;
120 s=lpCmdline;
121 /* The first argument, the executable path, follows special rules */
122 if (*s=='"')
123 {
124 /* The executable path ends at the next quote, no matter what */
125 s++;
126 while (*s)
127 if (*s++=='"')
128 break;
129 }
130 else
131 {
132 /* The executable path ends at the next space, no matter what */
133 while (*s && *s!=' ' && *s!='\t')
134 s++;
135 }
136 /* skip to the first argument, if any */
137 while (*s==' ' || *s=='\t')
138 s++;
139 if (*s)
140 argc++;
141
142 /* Analyze the remaining arguments */
143 qcount=bcount=0;
144 while (*s)
145 {
146 if ((*s==' ' || *s=='\t') && qcount==0)
147 {
148 /* skip to the next argument and count it if any */
149 while (*s==' ' || *s=='\t')
150 s++;
151 if (*s)
152 argc++;
153 bcount=0;
154 }
155 else if (*s=='\\')
156 {
157 /* '\', count them */
158 bcount++;
159 s++;
160 }
161 else if (*s=='"')
162 {
163 /* '"' */
164 if ((bcount & 1)==0)
165 qcount++; /* unescaped '"' */
166 s++;
167 bcount=0;
168 /* consecutive quotes, see comment in copying code below */
169 while (*s=='"')
170 {
171 qcount++;
172 s++;
173 }
174 qcount=qcount % 3;
175 if (qcount==2)
176 qcount=0;
177 }
178 else
179 {
180 /* a regular character */
181 bcount=0;
182 s++;
183 }
184 }
185
186 /* Allocate in a single lump, the string array, and the strings that go
187 * with it. This way the caller can make a single LocalFree() call to free
188 * both, as per MSDN.
189 */
190 argv=LocalAlloc(LMEM_FIXED, (argc+1)*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
191 if (!argv)
192 return NULL;
193 cmdline=(LPWSTR)(argv+argc+1);
194 strcpyW(cmdline, lpCmdline);
195
196 /* --- Then split and copy the arguments */
197 argv[0]=d=cmdline;
198 argc=1;
199 /* The first argument, the executable path, follows special rules */
200 if (*d=='"')
201 {
202 /* The executable path ends at the next quote, no matter what */
203 s=d+1;
204 while (*s)
205 {
206 if (*s=='"')
207 {
208 s++;
209 break;
210 }
211 *d++=*s++;
212 }
213 }
214 else
215 {
216 /* The executable path ends at the next space, no matter what */
217 while (*d && *d!=' ' && *d!='\t')
218 d++;
219 s=d;
220 if (*s)
221 s++;
222 }
223 /* close the executable path */
224 *d++=0;
225 /* skip to the first argument and initialize it if any */
226 while (*s==' ' || *s=='\t')
227 s++;
228 if (!*s)
229 {
230 /* There are no parameters so we are all done */
231 argv[argc]=NULL;
232 *numargs=argc;
233 return argv;
234 }
235
236 /* Split and copy the remaining arguments */
237 argv[argc++]=d;
238 qcount=bcount=0;
239 while (*s)
240 {
241 if ((*s==' ' || *s=='\t') && qcount==0)
242 {
243 /* close the argument */
244 *d++=0;
245 bcount=0;
246
247 /* skip to the next one and initialize it if any */
248 do {
249 s++;
250 } while (*s==' ' || *s=='\t');
251 if (*s)
252 argv[argc++]=d;
253 }
254 else if (*s=='\\')
255 {
256 *d++=*s++;
257 bcount++;
258 }
259 else if (*s=='"')
260 {
261 if ((bcount & 1)==0)
262 {
263 /* Preceded by an even number of '\', this is half that
264 * number of '\', plus a quote which we erase.
265 */
266 d-=bcount/2;
267 qcount++;
268 }
269 else
270 {
271 /* Preceded by an odd number of '\', this is half that
272 * number of '\' followed by a '"'
273 */
274 d=d-bcount/2-1;
275 *d++='"';
276 }
277 s++;
278 bcount=0;
279 /* Now count the number of consecutive quotes. Note that qcount
280 * already takes into account the opening quote if any, as well as
281 * the quote that lead us here.
282 */
283 while (*s=='"')
284 {
285 if (++qcount==3)
286 {
287 *d++='"';
288 qcount=0;
289 }
290 s++;
291 }
292 if (qcount==2)
293 qcount=0;
294 }
295 else
296 {
297 /* a regular character */
298 *d++=*s++;
299 bcount=0;
300 }
301 }
302 *d='\0';
303 argv[argc]=NULL;
304 *numargs=argc;
305
306 return argv;
307 }
308
309 static DWORD shgfi_get_exe_type(LPCWSTR szFullPath)
310 {
311 BOOL status = FALSE;
312 HANDLE hfile;
313 DWORD BinaryType;
314 IMAGE_DOS_HEADER mz_header;
315 IMAGE_NT_HEADERS nt;
316 DWORD len;
317 char magic[4];
318
319 status = GetBinaryTypeW (szFullPath, &BinaryType);
320 if (!status)
321 return 0;
322 if (BinaryType == SCS_DOS_BINARY || BinaryType == SCS_PIF_BINARY)
323 return 0x4d5a;
324
325 hfile = CreateFileW( szFullPath, GENERIC_READ, FILE_SHARE_READ,
326 NULL, OPEN_EXISTING, 0, 0 );
327 if ( hfile == INVALID_HANDLE_VALUE )
328 return 0;
329
330 /*
331 * The next section is adapted from MODULE_GetBinaryType, as we need
332 * to examine the image header to get OS and version information. We
333 * know from calling GetBinaryTypeA that the image is valid and either
334 * an NE or PE, so much error handling can be omitted.
335 * Seek to the start of the file and read the header information.
336 */
337
338 SetFilePointer( hfile, 0, NULL, SEEK_SET );
339 ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL );
340
341 SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
342 ReadFile( hfile, magic, sizeof(magic), &len, NULL );
343 if ( *(DWORD*)magic == IMAGE_NT_SIGNATURE )
344 {
345 SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
346 ReadFile( hfile, &nt, sizeof(nt), &len, NULL );
347 CloseHandle( hfile );
348 /* DLL files are not executable and should return 0 */
349 if (nt.FileHeader.Characteristics & IMAGE_FILE_DLL)
350 return 0;
351 if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
352 {
353 return IMAGE_NT_SIGNATURE |
354 (nt.OptionalHeader.MajorSubsystemVersion << 24) |
355 (nt.OptionalHeader.MinorSubsystemVersion << 16);
356 }
357 return IMAGE_NT_SIGNATURE;
358 }
359 else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
360 {
361 IMAGE_OS2_HEADER ne;
362 SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
363 ReadFile( hfile, &ne, sizeof(ne), &len, NULL );
364 CloseHandle( hfile );
365 if (ne.ne_exetyp == 2)
366 return IMAGE_OS2_SIGNATURE | (ne.ne_expver << 16);
367 return 0;
368 }
369 CloseHandle( hfile );
370 return 0;
371 }
372
373 /*************************************************************************
374 * SHELL_IsShortcut [internal]
375 *
376 * Decide if an item id list points to a shell shortcut
377 */
378 BOOL SHELL_IsShortcut(LPCITEMIDLIST pidlLast)
379 {
380 char szTemp[MAX_PATH];
381 HKEY keyCls;
382 BOOL ret = FALSE;
383
384 if (_ILGetExtension(pidlLast, szTemp, MAX_PATH) &&
385 HCR_MapTypeToValueA(szTemp, szTemp, MAX_PATH, TRUE))
386 {
387 if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE, &keyCls))
388 {
389 if (ERROR_SUCCESS == RegQueryValueExA(keyCls, "IsShortcut", NULL, NULL, NULL, NULL))
390 ret = TRUE;
391
392 RegCloseKey(keyCls);
393 }
394 }
395
396 return ret;
397 }
398
399 #define SHGFI_KNOWN_FLAGS \
400 (SHGFI_SMALLICON | SHGFI_OPENICON | SHGFI_SHELLICONSIZE | SHGFI_PIDL | \
401 SHGFI_USEFILEATTRIBUTES | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX | \
402 SHGFI_ICON | SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_ATTRIBUTES | \
403 SHGFI_ICONLOCATION | SHGFI_EXETYPE | SHGFI_SYSICONINDEX | \
404 SHGFI_LINKOVERLAY | SHGFI_SELECTED | SHGFI_ATTR_SPECIFIED)
405
406 /*************************************************************************
407 * SHGetFileInfoW [SHELL32.@]
408 *
409 */
410 DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
411 SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags )
412 {
413 WCHAR szLocation[MAX_PATH], szFullPath[MAX_PATH];
414 int iIndex;
415 DWORD_PTR ret = TRUE;
416 DWORD dwAttributes = 0;
417 IShellFolder * psfParent = NULL;
418 IExtractIconW * pei = NULL;
419 LPITEMIDLIST pidlLast = NULL, pidl = NULL;
420 HRESULT hr = S_OK;
421 BOOL IconNotYetLoaded=TRUE;
422 UINT uGilFlags = 0;
423 HIMAGELIST big_icons, small_icons;
424
425 TRACE("%s fattr=0x%x sfi=%p(attr=0x%08x) size=0x%x flags=0x%x\n",
426 (flags & SHGFI_PIDL)? "pidl" : debugstr_w(path), dwFileAttributes,
427 psfi, psfi ? psfi->dwAttributes : 0, sizeofpsfi, flags);
428
429 if (!path)
430 return FALSE;
431
432 /* windows initializes these values regardless of the flags */
433 if (psfi != NULL)
434 {
435 psfi->szDisplayName[0] = '\0';
436 psfi->szTypeName[0] = '\0';
437 psfi->hIcon = NULL;
438 }
439
440 if (!(flags & SHGFI_PIDL))
441 {
442 /* SHGetFileInfo should work with absolute and relative paths */
443 if (PathIsRelativeW(path))
444 {
445 GetCurrentDirectoryW(MAX_PATH, szLocation);
446 PathCombineW(szFullPath, szLocation, path);
447 }
448 else
449 {
450 lstrcpynW(szFullPath, path, MAX_PATH);
451 }
452 }
453 else
454 {
455 SHGetPathFromIDListW((LPITEMIDLIST)path, szFullPath);
456 }
457
458 if (flags & SHGFI_EXETYPE)
459 {
460 if (!(flags & SHGFI_SYSICONINDEX))
461 {
462 if (flags & SHGFI_USEFILEATTRIBUTES)
463 {
464 return TRUE;
465 }
466 else if (GetFileAttributesW(szFullPath) != INVALID_FILE_ATTRIBUTES)
467 {
468 return shgfi_get_exe_type(szFullPath);
469 }
470 }
471 }
472
473 /*
474 * psfi is NULL normally to query EXE type. If it is NULL, none of the
475 * below makes sense anyway. Windows allows this and just returns FALSE
476 */
477 if (psfi == NULL)
478 return FALSE;
479
480 /*
481 * translate the path into a pidl only when SHGFI_USEFILEATTRIBUTES
482 * is not specified.
483 * The pidl functions fail on not existing file names
484 */
485
486 if (flags & SHGFI_PIDL)
487 {
488 pidl = ILClone((LPCITEMIDLIST)path);
489 }
490 else if (!(flags & SHGFI_USEFILEATTRIBUTES))
491 {
492 hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes);
493 }
494
495 if ((flags & SHGFI_PIDL) || !(flags & SHGFI_USEFILEATTRIBUTES))
496 {
497 /* get the parent shellfolder */
498 if (pidl)
499 {
500 hr = SHBindToParent( pidl, &IID_IShellFolder, (LPVOID*)&psfParent,
501 (LPCITEMIDLIST*)&pidlLast );
502 if (SUCCEEDED(hr))
503 pidlLast = ILClone(pidlLast);
504 else
505 hr = S_OK;
506 ILFree(pidl);
507 }
508 else
509 {
510 ERR("pidl is null!\n");
511 return FALSE;
512 }
513 }
514
515 /* get the attributes of the child */
516 if (SUCCEEDED(hr) && (flags & SHGFI_ATTRIBUTES))
517 {
518 if (!(flags & SHGFI_ATTR_SPECIFIED))
519 {
520 psfi->dwAttributes = 0xffffffff;
521 }
522 if (psfParent)
523 {
524 IShellFolder_GetAttributesOf(psfParent, 1, (LPCITEMIDLIST*)&pidlLast,
525 &(psfi->dwAttributes));
526 }
527 }
528
529 if (flags & SHGFI_USEFILEATTRIBUTES)
530 {
531 if (flags & SHGFI_ICON)
532 {
533 psfi->dwAttributes = 0;
534 }
535 }
536
537 /* get the displayname */
538 if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME))
539 {
540 if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
541 {
542 lstrcpyW (psfi->szDisplayName, PathFindFileNameW(szFullPath));
543 }
544 else if (psfParent)
545 {
546 STRRET str;
547 hr = IShellFolder_GetDisplayNameOf( psfParent, pidlLast,
548 SHGDN_INFOLDER, &str);
549 StrRetToStrNW (psfi->szDisplayName, MAX_PATH, &str, pidlLast);
550 }
551 }
552
553 /* get the type name */
554 if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME))
555 {
556 static const WCHAR szFolder[] = { 'F','o','l','d','e','r',0 };
557 static const WCHAR szFile[] = { 'F','i','l','e',0 };
558 static const WCHAR szSpaceFile[] = { ' ','f','i','l','e',0 };
559
560 if (!(flags & SHGFI_USEFILEATTRIBUTES) || (flags & SHGFI_PIDL))
561 {
562 char ftype[80];
563
564 _ILGetFileType(pidlLast, ftype, 80);
565 MultiByteToWideChar(CP_ACP, 0, ftype, -1, psfi->szTypeName, 80 );
566 }
567 else
568 {
569 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
570 strcatW (psfi->szTypeName, szFolder);
571 else
572 {
573 WCHAR sTemp[64];
574
575 lstrcpyW(sTemp,PathFindExtensionW(szFullPath));
576 if (sTemp[0] == 0 || (sTemp[0] == '.' && sTemp[1] == 0))
577 {
578 /* "name" or "name." => "File" */
579 lstrcpynW (psfi->szTypeName, szFile, 64);
580 }
581 else if (!( HCR_MapTypeToValueW(sTemp, sTemp, 64, TRUE) &&
582 HCR_MapTypeToValueW(sTemp, psfi->szTypeName, 80, FALSE )))
583 {
584 if (sTemp[0])
585 {
586 lstrcpynW (psfi->szTypeName, sTemp, 64);
587 strcatW (psfi->szTypeName, szSpaceFile);
588 }
589 else
590 {
591 lstrcpynW (psfi->szTypeName, szFile, 64);
592 }
593 }
594 }
595 }
596 }
597
598 /* ### icons ###*/
599
600 Shell_GetImageLists( &big_icons, &small_icons );
601
602 if (flags & SHGFI_OPENICON)
603 uGilFlags |= GIL_OPENICON;
604
605 if (flags & SHGFI_LINKOVERLAY)
606 uGilFlags |= GIL_FORSHORTCUT;
607 else if ((flags&SHGFI_ADDOVERLAYS) ||
608 (flags&(SHGFI_ICON|SHGFI_SMALLICON))==SHGFI_ICON)
609 {
610 if (SHELL_IsShortcut(pidlLast))
611 uGilFlags |= GIL_FORSHORTCUT;
612 }
613
614 if (flags & SHGFI_OVERLAYINDEX)
615 FIXME("SHGFI_OVERLAYINDEX unhandled\n");
616
617 if (flags & SHGFI_SELECTED)
618 FIXME("set icon to selected, stub\n");
619
620 if (flags & SHGFI_SHELLICONSIZE)
621 FIXME("set icon to shell size, stub\n");
622
623 /* get the iconlocation */
624 if (SUCCEEDED(hr) && (flags & SHGFI_ICONLOCATION ))
625 {
626 UINT uDummy,uFlags;
627
628 if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
629 {
630 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
631 {
632 lstrcpyW(psfi->szDisplayName, swShell32Name);
633 psfi->iIcon = -IDI_SHELL_FOLDER;
634 }
635 else
636 {
637 WCHAR* szExt;
638 static const WCHAR p1W[] = {'%','1',0};
639 WCHAR sTemp [MAX_PATH];
640
641 szExt = PathFindExtensionW(szFullPath);
642 TRACE("szExt=%s\n", debugstr_w(szExt));
643 if ( szExt &&
644 HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) &&
645 HCR_GetIconW(sTemp, sTemp, NULL, MAX_PATH, &psfi->iIcon))
646 {
647 if (lstrcmpW(p1W, sTemp))
648 strcpyW(psfi->szDisplayName, sTemp);
649 else
650 {
651 /* the icon is in the file */
652 strcpyW(psfi->szDisplayName, szFullPath);
653 }
654 }
655 else
656 ret = FALSE;
657 }
658 }
659 else if (psfParent)
660 {
661 hr = IShellFolder_GetUIObjectOf(psfParent, 0, 1,
662 (LPCITEMIDLIST*)&pidlLast, &IID_IExtractIconW,
663 &uDummy, (LPVOID*)&pei);
664 if (SUCCEEDED(hr))
665 {
666 hr = IExtractIconW_GetIconLocation(pei, uGilFlags,
667 szLocation, MAX_PATH, &iIndex, &uFlags);
668
669 if (uFlags & GIL_NOTFILENAME)
670 ret = FALSE;
671 else
672 {
673 lstrcpyW (psfi->szDisplayName, szLocation);
674 psfi->iIcon = iIndex;
675 }
676 IExtractIconW_Release(pei);
677 }
678 }
679 }
680
681 /* get icon index (or load icon)*/
682 if (SUCCEEDED(hr) && (flags & (SHGFI_ICON | SHGFI_SYSICONINDEX)))
683 {
684 if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
685 {
686 WCHAR sTemp [MAX_PATH];
687 WCHAR * szExt;
688 int icon_idx=0;
689
690 lstrcpynW(sTemp, szFullPath, MAX_PATH);
691
692 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
693 psfi->iIcon = SIC_GetIconIndex(swShell32Name, -IDI_SHELL_FOLDER, 0);
694 else
695 {
696 static const WCHAR p1W[] = {'%','1',0};
697
698 psfi->iIcon = 0;
699 szExt = PathFindExtensionW(sTemp);
700 if ( szExt &&
701 HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) &&
702 HCR_GetIconW(sTemp, sTemp, NULL, MAX_PATH, &icon_idx))
703 {
704 if (!lstrcmpW(p1W,sTemp)) /* icon is in the file */
705 strcpyW(sTemp, szFullPath);
706
707 if (flags & SHGFI_SYSICONINDEX)
708 {
709 psfi->iIcon = SIC_GetIconIndex(sTemp,icon_idx,0);
710 if (psfi->iIcon == -1)
711 psfi->iIcon = 0;
712 }
713 else
714 {
715 UINT ret;
716 if (flags & SHGFI_SMALLICON)
717 ret = PrivateExtractIconsW( sTemp,icon_idx,
718 GetSystemMetrics( SM_CXSMICON ),
719 GetSystemMetrics( SM_CYSMICON ),
720 &psfi->hIcon, 0, 1, 0);
721 else
722 ret = PrivateExtractIconsW( sTemp, icon_idx,
723 GetSystemMetrics( SM_CXICON),
724 GetSystemMetrics( SM_CYICON),
725 &psfi->hIcon, 0, 1, 0);
726 if (ret != 0 && ret != (UINT)-1)
727 {
728 IconNotYetLoaded=FALSE;
729 psfi->iIcon = icon_idx;
730 }
731 }
732 }
733 }
734 }
735 else if (psfParent)
736 {
737 if (!(PidlToSicIndex(psfParent, pidlLast, !(flags & SHGFI_SMALLICON),
738 uGilFlags, &(psfi->iIcon))))
739 {
740 ret = FALSE;
741 }
742 }
743 if (ret && (flags & SHGFI_SYSICONINDEX))
744 {
745 if (flags & SHGFI_SMALLICON)
746 ret = (DWORD_PTR)small_icons;
747 else
748 ret = (DWORD_PTR)big_icons;
749 }
750 }
751
752 /* icon handle */
753 if (SUCCEEDED(hr) && (flags & SHGFI_ICON) && IconNotYetLoaded)
754 {
755 if (flags & SHGFI_SMALLICON)
756 psfi->hIcon = ImageList_GetIcon( small_icons, psfi->iIcon, ILD_NORMAL);
757 else
758 psfi->hIcon = ImageList_GetIcon( big_icons, psfi->iIcon, ILD_NORMAL);
759 }
760
761 if (flags & ~SHGFI_KNOWN_FLAGS)
762 FIXME("unknown flags %08x\n", flags & ~SHGFI_KNOWN_FLAGS);
763
764 if (psfParent)
765 IShellFolder_Release(psfParent);
766
767 if (hr != S_OK)
768 ret = FALSE;
769
770 SHFree(pidlLast);
771
772 TRACE ("icon=%p index=0x%08x attr=0x%08x name=%s type=%s ret=0x%08lx\n",
773 psfi->hIcon, psfi->iIcon, psfi->dwAttributes,
774 debugstr_w(psfi->szDisplayName), debugstr_w(psfi->szTypeName), ret);
775
776 return ret;
777 }
778
779 /*************************************************************************
780 * SHGetFileInfoA [SHELL32.@]
781 *
782 * Note:
783 * MSVBVM60.__vbaNew2 expects this function to return a value in range
784 * 1 .. 0x7fff when the function succeeds and flags does not contain
785 * SHGFI_EXETYPE or SHGFI_SYSICONINDEX (see bug 7701)
786 */
787 DWORD_PTR WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes,
788 SHFILEINFOA *psfi, UINT sizeofpsfi,
789 UINT flags )
790 {
791 INT len;
792 LPWSTR temppath = NULL;
793 LPCWSTR pathW;
794 DWORD_PTR ret;
795 SHFILEINFOW temppsfi;
796
797 if (flags & SHGFI_PIDL)
798 {
799 /* path contains a pidl */
800 pathW = (LPCWSTR)path;
801 }
802 else
803 {
804 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
805 temppath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
806 MultiByteToWideChar(CP_ACP, 0, path, -1, temppath, len);
807 pathW = temppath;
808 }
809
810 if (psfi)
811 {
812 temppsfi.hIcon = psfi->hIcon;
813 temppsfi.iIcon = psfi->iIcon;
814 temppsfi.dwAttributes = psfi->dwAttributes;
815
816 ret = SHGetFileInfoW(pathW, dwFileAttributes, &temppsfi, sizeof(temppsfi), flags);
817 psfi->hIcon = temppsfi.hIcon;
818 psfi->iIcon = temppsfi.iIcon;
819 psfi->dwAttributes = temppsfi.dwAttributes;
820
821 WideCharToMultiByte(CP_ACP, 0, temppsfi.szDisplayName, -1,
822 psfi->szDisplayName, sizeof(psfi->szDisplayName), NULL, NULL);
823
824 WideCharToMultiByte(CP_ACP, 0, temppsfi.szTypeName, -1,
825 psfi->szTypeName, sizeof(psfi->szTypeName), NULL, NULL);
826 }
827 else
828 ret = SHGetFileInfoW(pathW, dwFileAttributes, NULL, 0, flags);
829
830 HeapFree(GetProcessHeap(), 0, temppath);
831
832 return ret;
833 }
834
835 /*************************************************************************
836 * DuplicateIcon [SHELL32.@]
837 */
838 HICON WINAPI DuplicateIcon( HINSTANCE hInstance, HICON hIcon)
839 {
840 ICONINFO IconInfo;
841 HICON hDupIcon = 0;
842
843 TRACE("%p %p\n", hInstance, hIcon);
844
845 if (GetIconInfo(hIcon, &IconInfo))
846 {
847 hDupIcon = CreateIconIndirect(&IconInfo);
848
849 /* clean up hbmMask and hbmColor */
850 DeleteObject(IconInfo.hbmMask);
851 DeleteObject(IconInfo.hbmColor);
852 }
853
854 return hDupIcon;
855 }
856
857 /*************************************************************************
858 * ExtractIconA [SHELL32.@]
859 */
860 HICON WINAPI ExtractIconA(HINSTANCE hInstance, LPCSTR lpszFile, UINT nIconIndex)
861 {
862 HICON ret;
863 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
864 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
865
866 TRACE("%p %s %d\n", hInstance, lpszFile, nIconIndex);
867
868 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
869 ret = ExtractIconW(hInstance, lpwstrFile, nIconIndex);
870 HeapFree(GetProcessHeap(), 0, lpwstrFile);
871
872 return ret;
873 }
874
875 /*************************************************************************
876 * ExtractIconW [SHELL32.@]
877 */
878 HICON WINAPI ExtractIconW(HINSTANCE hInstance, LPCWSTR lpszFile, UINT nIconIndex)
879 {
880 HICON hIcon = NULL;
881 UINT ret;
882 UINT cx = GetSystemMetrics(SM_CXICON), cy = GetSystemMetrics(SM_CYICON);
883
884 TRACE("%p %s %d\n", hInstance, debugstr_w(lpszFile), nIconIndex);
885
886 if (nIconIndex == (UINT)-1)
887 {
888 ret = PrivateExtractIconsW(lpszFile, 0, cx, cy, NULL, NULL, 0, LR_DEFAULTCOLOR);
889 if (ret != (UINT)-1 && ret)
890 return (HICON)(UINT_PTR)ret;
891 return NULL;
892 }
893 else
894 ret = PrivateExtractIconsW(lpszFile, nIconIndex, cx, cy, &hIcon, NULL, 1, LR_DEFAULTCOLOR);
895
896 if (ret == (UINT)-1)
897 return (HICON)1;
898 else if (ret > 0 && hIcon)
899 return hIcon;
900
901 return NULL;
902 }
903
904 /*************************************************************************
905 * Printer_LoadIconsW [SHELL32.205]
906 */
907 VOID WINAPI Printer_LoadIconsW(LPCWSTR wsPrinterName, HICON * pLargeIcon, HICON * pSmallIcon)
908 {
909 INT iconindex=IDI_SHELL_PRINTERS_FOLDER;
910
911 TRACE("(%s, %p, %p)\n", debugstr_w(wsPrinterName), pLargeIcon, pSmallIcon);
912
913 /* We should check if wsPrinterName is
914 1. the Default Printer or not
915 2. connected or not
916 3. a Local Printer or a Network-Printer
917 and use different Icons
918 */
919 if((wsPrinterName != NULL) && (wsPrinterName[0] != 0))
920 {
921 FIXME("(select Icon by PrinterName %s not implemented)\n", debugstr_w(wsPrinterName));
922 }
923
924 if(pLargeIcon != NULL)
925 *pLargeIcon = LoadImageW(shell32_hInstance,
926 (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON,
927 0, 0, LR_DEFAULTCOLOR|LR_DEFAULTSIZE);
928
929 if(pSmallIcon != NULL)
930 *pSmallIcon = LoadImageW(shell32_hInstance,
931 (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON,
932 16, 16, LR_DEFAULTCOLOR);
933 }
934
935 /*************************************************************************
936 * Printers_RegisterWindowW [SHELL32.213]
937 * used by "printui.dll":
938 * find the Window of the given Type for the specific Printer and
939 * return the already existent hwnd or open a new window
940 */
941 BOOL WINAPI Printers_RegisterWindowW(LPCWSTR wsPrinter, DWORD dwType,
942 HANDLE * phClassPidl, HWND * phwnd)
943 {
944 FIXME("(%s, %x, %p (%p), %p (%p)) stub!\n", debugstr_w(wsPrinter), dwType,
945 phClassPidl, (phClassPidl != NULL) ? *(phClassPidl) : NULL,
946 phwnd, (phwnd != NULL) ? *(phwnd) : NULL);
947
948 return FALSE;
949 }
950
951 /*************************************************************************
952 * Printers_UnregisterWindow [SHELL32.214]
953 */
954 VOID WINAPI Printers_UnregisterWindow(HANDLE hClassPidl, HWND hwnd)
955 {
956 FIXME("(%p, %p) stub!\n", hClassPidl, hwnd);
957 }
958
959 /*************************************************************************/
960
961 typedef struct
962 {
963 LPCWSTR szApp;
964 LPCWSTR szOtherStuff;
965 HICON hIcon;
966 } ABOUT_INFO;
967
968 #define DROP_FIELD_TOP (-15)
969 #define DROP_FIELD_HEIGHT 15
970
971 /*************************************************************************
972 * SHAppBarMessage [SHELL32.@]
973 */
974 UINT_PTR WINAPI SHAppBarMessage(DWORD msg, PAPPBARDATA data)
975 {
976 int width=data->rc.right - data->rc.left;
977 int height=data->rc.bottom - data->rc.top;
978 RECT rec=data->rc;
979
980 TRACE("msg=%d, data={cb=%d, hwnd=%p, callback=%x, edge=%d, rc=%s, lparam=%lx}\n",
981 msg, data->cbSize, data->hWnd, data->uCallbackMessage, data->uEdge,
982 wine_dbgstr_rect(&data->rc), data->lParam);
983
984 switch (msg)
985 {
986 case ABM_GETSTATE:
987 return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
988
989 case ABM_GETTASKBARPOS:
990 GetWindowRect(data->hWnd, &rec);
991 data->rc=rec;
992 return TRUE;
993
994 case ABM_ACTIVATE:
995 SetActiveWindow(data->hWnd);
996 return TRUE;
997
998 case ABM_GETAUTOHIDEBAR:
999 return 0; /* pretend there is no autohide bar */
1000
1001 case ABM_NEW:
1002 /* cbSize, hWnd, and uCallbackMessage are used. All other ignored */
1003 SetWindowPos(data->hWnd,HWND_TOP,0,0,0,0,SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOSIZE);
1004 return TRUE;
1005
1006 case ABM_QUERYPOS:
1007 GetWindowRect(data->hWnd, &(data->rc));
1008 return TRUE;
1009
1010 case ABM_REMOVE:
1011 FIXME("ABM_REMOVE broken\n");
1012 /* FIXME: this is wrong; should it be DestroyWindow instead? */
1013 /*CloseHandle(data->hWnd);*/
1014 return TRUE;
1015
1016 case ABM_SETAUTOHIDEBAR:
1017 SetWindowPos(data->hWnd,HWND_TOP,rec.left+1000,rec.top,
1018 width,height,SWP_SHOWWINDOW);
1019 return TRUE;
1020
1021 case ABM_SETPOS:
1022 data->uEdge=(ABE_RIGHT | ABE_LEFT);
1023 SetWindowPos(data->hWnd,HWND_TOP,data->rc.left,data->rc.top,
1024 width,height,SWP_SHOWWINDOW);
1025 return TRUE;
1026
1027 case ABM_WINDOWPOSCHANGED:
1028 return TRUE;
1029 }
1030
1031 return FALSE;
1032 }
1033
1034 /*************************************************************************
1035 * SHHelpShortcuts_RunDLLA [SHELL32.@]
1036 *
1037 */
1038 DWORD WINAPI SHHelpShortcuts_RunDLLA(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
1039 {
1040 FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4);
1041 return 0;
1042 }
1043
1044 /*************************************************************************
1045 * SHHelpShortcuts_RunDLLA [SHELL32.@]
1046 *
1047 */
1048 DWORD WINAPI SHHelpShortcuts_RunDLLW(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
1049 {
1050 FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4);
1051 return 0;
1052 }
1053
1054 /*************************************************************************
1055 * SHLoadInProc [SHELL32.@]
1056 * Create an instance of specified object class from within
1057 * the shell process and release it immediately
1058 */
1059 HRESULT WINAPI SHLoadInProc (REFCLSID rclsid)
1060 {
1061 void *ptr = NULL;
1062
1063 TRACE("%s\n", debugstr_guid(rclsid));
1064
1065 CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown,&ptr);
1066 if(ptr)
1067 {
1068 IUnknown * pUnk = ptr;
1069 IUnknown_Release(pUnk);
1070 return S_OK;
1071 }
1072 return DISP_E_MEMBERNOTFOUND;
1073 }
1074
1075 static VOID SetRegTextData(HWND hWnd, HKEY hKey, LPCWSTR Value, UINT uID)
1076 {
1077 DWORD dwBufferSize;
1078 DWORD dwType;
1079 LPWSTR lpBuffer;
1080
1081 if( RegQueryValueExW(hKey, Value, NULL, &dwType, NULL, &dwBufferSize) == ERROR_SUCCESS )
1082 {
1083 if(dwType == REG_SZ)
1084 {
1085 lpBuffer = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1086
1087 if(lpBuffer)
1088 {
1089 if( RegQueryValueExW(hKey, Value, NULL, &dwType, (LPBYTE)lpBuffer, &dwBufferSize) == ERROR_SUCCESS )
1090 {
1091 SetDlgItemTextW(hWnd, uID, lpBuffer);
1092 }
1093
1094 HeapFree(GetProcessHeap(), 0, lpBuffer);
1095 }
1096 }
1097 }
1098 }
1099
1100 INT_PTR CALLBACK AboutAuthorsDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
1101 {
1102 switch(msg)
1103 {
1104 case WM_INITDIALOG:
1105 {
1106 const char* const *pstr = SHELL_Authors;
1107
1108 // Add the authors to the list
1109 SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, FALSE, 0 );
1110
1111 while (*pstr)
1112 {
1113 WCHAR name[64];
1114
1115 /* authors list is in utf-8 format */
1116 MultiByteToWideChar( CP_UTF8, 0, *pstr, -1, name, sizeof(name)/sizeof(WCHAR) );
1117 SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, LB_ADDSTRING, (WPARAM)-1, (LPARAM)name );
1118 pstr++;
1119 }
1120
1121 SendDlgItemMessageW( hWnd, IDC_ABOUT_AUTHORS_LISTBOX, WM_SETREDRAW, TRUE, 0 );
1122
1123 return TRUE;
1124 }
1125 }
1126
1127 return FALSE;
1128 }
1129 /*************************************************************************
1130 * AboutDlgProc (internal)
1131 */
1132 static INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
1133 {
1134 static DWORD cxLogoBmp;
1135 static DWORD cyLogoBmp;
1136 static HBITMAP hLogoBmp;
1137 static HWND hWndAuthors;
1138
1139 switch(msg)
1140 {
1141 case WM_INITDIALOG:
1142 {
1143 ABOUT_INFO *info = (ABOUT_INFO *)lParam;
1144
1145 if (info)
1146 {
1147 const WCHAR szRegKey[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
1148 HKEY hRegKey;
1149 MEMORYSTATUSEX MemStat;
1150 WCHAR szAppTitle[512];
1151 WCHAR szAppTitleTemplate[512];
1152 WCHAR szAuthorsText[20];
1153
1154 // Preload the ROS bitmap
1155 hLogoBmp = (HBITMAP)LoadImage(shell32_hInstance, MAKEINTRESOURCE(IDB_REACTOS), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
1156
1157 if(hLogoBmp)
1158 {
1159 BITMAP bmpLogo;
1160
1161 GetObject( hLogoBmp, sizeof(BITMAP), &bmpLogo );
1162
1163 cxLogoBmp = bmpLogo.bmWidth;
1164 cyLogoBmp = bmpLogo.bmHeight;
1165 }
1166
1167 // Set App-specific stuff (icon, app name, szOtherStuff string)
1168 SendDlgItemMessageW(hWnd, IDC_ABOUT_ICON, STM_SETICON, (WPARAM)info->hIcon, 0);
1169
1170 GetWindowTextW( hWnd, szAppTitleTemplate, sizeof(szAppTitleTemplate) / sizeof(WCHAR) );
1171 swprintf( szAppTitle, szAppTitleTemplate, info->szApp );
1172 SetWindowTextW( hWnd, szAppTitle );
1173
1174 SetDlgItemTextW( hWnd, IDC_ABOUT_APPNAME, info->szApp );
1175 SetDlgItemTextW( hWnd, IDC_ABOUT_OTHERSTUFF, info->szOtherStuff );
1176
1177 // Set the registered user and organization name
1178 if(RegOpenKeyExW( HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_QUERY_VALUE, &hRegKey ) == ERROR_SUCCESS)
1179 {
1180 SetRegTextData( hWnd, hRegKey, L"RegisteredOwner", IDC_ABOUT_REG_USERNAME );
1181 SetRegTextData( hWnd, hRegKey, L"RegisteredOrganization", IDC_ABOUT_REG_ORGNAME );
1182
1183 RegCloseKey( hRegKey );
1184 }
1185
1186 // Set the value for the installed physical memory
1187 MemStat.dwLength = sizeof(MemStat);
1188 if( GlobalMemoryStatusEx(&MemStat) )
1189 {
1190 WCHAR szBuf[12];
1191
1192 if (MemStat.ullTotalPhys > 1024 * 1024 * 1024)
1193 {
1194 double dTotalPhys;
1195 WCHAR szDecimalSeparator[4];
1196 WCHAR szUnits[3];
1197
1198 // We're dealing with GBs or more
1199 MemStat.ullTotalPhys /= 1024 * 1024;
1200
1201 if (MemStat.ullTotalPhys > 1024 * 1024)
1202 {
1203 // We're dealing with TBs or more
1204 MemStat.ullTotalPhys /= 1024;
1205
1206 if (MemStat.ullTotalPhys > 1024 * 1024)
1207 {
1208 // We're dealing with PBs or more
1209 MemStat.ullTotalPhys /= 1024;
1210
1211 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
1212 wcscpy( szUnits, L"PB" );
1213 }
1214 else
1215 {
1216 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
1217 wcscpy( szUnits, L"TB" );
1218 }
1219 }
1220 else
1221 {
1222 dTotalPhys = (double)MemStat.ullTotalPhys / 1024;
1223 wcscpy( szUnits, L"GB" );
1224 }
1225
1226 // We need the decimal point of the current locale to display the RAM size correctly
1227 if (GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
1228 szDecimalSeparator,
1229 sizeof(szDecimalSeparator) / sizeof(WCHAR)) > 0)
1230 {
1231 UCHAR uDecimals;
1232 UINT uIntegral;
1233
1234 uIntegral = (UINT)dTotalPhys;
1235 uDecimals = (UCHAR)((UINT)(dTotalPhys * 100) - uIntegral * 100);
1236
1237 // Display the RAM size with 2 decimals
1238 swprintf(szBuf, L"%u%s%02u %s", uIntegral, szDecimalSeparator, uDecimals, szUnits);
1239 }
1240 }
1241 else
1242 {
1243 // We're dealing with MBs, don't show any decimals
1244 swprintf( szBuf, L"%u MB", (UINT)MemStat.ullTotalPhys / 1024 / 1024 );
1245 }
1246
1247 SetDlgItemTextW( hWnd, IDC_ABOUT_PHYSMEM, szBuf);
1248 }
1249
1250 // Add the Authors dialog
1251 hWndAuthors = CreateDialogW( shell32_hInstance, MAKEINTRESOURCEW(IDD_ABOUT_AUTHORS), hWnd, AboutAuthorsDlgProc );
1252 LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_AUTHORS, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) );
1253 SetDlgItemTextW( hWnd, IDC_ABOUT_AUTHORS, szAuthorsText );
1254 }
1255
1256 return TRUE;
1257 }
1258
1259 case WM_PAINT:
1260 {
1261 if(hLogoBmp)
1262 {
1263 PAINTSTRUCT ps;
1264 HDC hdc;
1265 HDC hdcMem;
1266
1267 hdc = BeginPaint(hWnd, &ps);
1268 hdcMem = CreateCompatibleDC(hdc);
1269
1270 if(hdcMem)
1271 {
1272 SelectObject(hdcMem, hLogoBmp);
1273 BitBlt(hdc, 0, 0, cxLogoBmp, cyLogoBmp, hdcMem, 0, 0, SRCCOPY);
1274
1275 DeleteDC(hdcMem);
1276 }
1277
1278 EndPaint(hWnd, &ps);
1279 }
1280 }; break;
1281
1282 case WM_COMMAND:
1283 {
1284 switch(wParam)
1285 {
1286 case IDOK:
1287 case IDCANCEL:
1288 EndDialog(hWnd, TRUE);
1289 return TRUE;
1290
1291 case IDC_ABOUT_AUTHORS:
1292 {
1293 static BOOL bShowingAuthors = FALSE;
1294 WCHAR szAuthorsText[20];
1295
1296 if(bShowingAuthors)
1297 {
1298 LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_AUTHORS, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) );
1299 ShowWindow( hWndAuthors, SW_HIDE );
1300 }
1301 else
1302 {
1303 LoadStringW( shell32_hInstance, IDS_SHELL_ABOUT_BACK, szAuthorsText, sizeof(szAuthorsText) / sizeof(WCHAR) );
1304 ShowWindow( hWndAuthors, SW_SHOW );
1305 }
1306
1307 SetDlgItemTextW( hWnd, IDC_ABOUT_AUTHORS, szAuthorsText );
1308 bShowingAuthors = !bShowingAuthors;
1309 return TRUE;
1310 }
1311 }
1312 }; break;
1313
1314 case WM_CLOSE:
1315 EndDialog(hWnd, TRUE);
1316 break;
1317 }
1318
1319 return 0;
1320 }
1321
1322
1323 /*************************************************************************
1324 * ShellAboutA [SHELL32.288]
1325 */
1326 BOOL WINAPI ShellAboutA( HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon )
1327 {
1328 BOOL ret;
1329 LPWSTR appW = NULL, otherW = NULL;
1330 int len;
1331
1332 if (szApp)
1333 {
1334 len = MultiByteToWideChar(CP_ACP, 0, szApp, -1, NULL, 0);
1335 appW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1336 MultiByteToWideChar(CP_ACP, 0, szApp, -1, appW, len);
1337 }
1338 if (szOtherStuff)
1339 {
1340 len = MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, NULL, 0);
1341 otherW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1342 MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, otherW, len);
1343 }
1344
1345 ret = ShellAboutW(hWnd, appW, otherW, hIcon);
1346
1347 HeapFree(GetProcessHeap(), 0, otherW);
1348 HeapFree(GetProcessHeap(), 0, appW);
1349 return ret;
1350 }
1351
1352
1353 /*************************************************************************
1354 * ShellAboutW [SHELL32.289]
1355 */
1356 BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
1357 HICON hIcon )
1358 {
1359 ABOUT_INFO info;
1360 HRSRC hRes;
1361 DLGTEMPLATE *DlgTemplate;
1362 BOOL bRet;
1363
1364 TRACE("\n");
1365
1366 // DialogBoxIndirectParamW will be called with the hInstance of the calling application, so we have to preload the dialog template
1367 hRes = FindResourceW(shell32_hInstance, MAKEINTRESOURCEW(IDD_ABOUT), (LPWSTR)RT_DIALOG);
1368 if(!hRes)
1369 return FALSE;
1370
1371 DlgTemplate = (DLGTEMPLATE *)LoadResource(shell32_hInstance, hRes);
1372 if(!DlgTemplate)
1373 return FALSE;
1374
1375 info.szApp = szApp;
1376 info.szOtherStuff = szOtherStuff;
1377 info.hIcon = hIcon ? hIcon : LoadIconW( 0, (LPWSTR)IDI_WINLOGO );
1378
1379 bRet = DialogBoxIndirectParamW((HINSTANCE)GetWindowLongPtrW( hWnd, GWLP_HINSTANCE ),
1380 DlgTemplate, hWnd, AboutDlgProc, (LPARAM)&info );
1381 return bRet;
1382 }
1383
1384 /*************************************************************************
1385 * FreeIconList (SHELL32.@)
1386 */
1387 void WINAPI FreeIconList( DWORD dw )
1388 {
1389 FIXME("%x: stub\n",dw);
1390 }
1391
1392 /*************************************************************************
1393 * SHLoadNonloadedIconOverlayIdentifiers (SHELL32.@)
1394 */
1395 HRESULT WINAPI SHLoadNonloadedIconOverlayIdentifiers( VOID )
1396 {
1397 FIXME("stub\n");
1398 return S_OK;
1399 }