shell32: Simplify imagelist handling.
[wine.git] / dlls / shell32 / shell32_main.c
blob71225916bbadfc165eb0ff37bef455c06e0636ad
1 /*
2 * Shell basics
4 * Copyright 1998 Marcus Meissner
5 * Copyright 1998 Juergen Schmied (jsch) * <juergen.schmied@metronet.de>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
29 #define COBJMACROS
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winerror.h"
34 #include "winreg.h"
35 #include "dlgs.h"
36 #include "shellapi.h"
37 #include "winuser.h"
38 #include "wingdi.h"
39 #include "shlobj.h"
40 #include "rpcproxy.h"
41 #include "shlwapi.h"
42 #include "propsys.h"
43 #include "commoncontrols.h"
45 #include "undocshell.h"
46 #include "pidl.h"
47 #include "shell32_main.h"
48 #include "version.h"
49 #include "shresdef.h"
50 #include "initguid.h"
51 #include "shfldr.h"
53 #include "wine/debug.h"
54 #include "wine/unicode.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(shell);
58 /*************************************************************************
59 * CommandLineToArgvW [SHELL32.@]
61 * We must interpret the quotes in the command line to rebuild the argv
62 * array correctly:
63 * - arguments are separated by spaces or tabs
64 * - quotes serve as optional argument delimiters
65 * '"a b"' -> 'a b'
66 * - escaped quotes must be converted back to '"'
67 * '\"' -> '"'
68 * - consecutive backslashes preceding a quote see their number halved with
69 * the remainder escaping the quote:
70 * 2n backslashes + quote -> n backslashes + quote as an argument delimiter
71 * 2n+1 backslashes + quote -> n backslashes + literal quote
72 * - backslashes that are not followed by a quote are copied literally:
73 * 'a\b' -> 'a\b'
74 * 'a\\b' -> 'a\\b'
75 * - in quoted strings, consecutive quotes see their number divided by three
76 * with the remainder modulo 3 deciding whether to close the string or not.
77 * Note that the opening quote must be counted in the consecutive quotes,
78 * that's the (1+) below:
79 * (1+) 3n quotes -> n quotes
80 * (1+) 3n+1 quotes -> n quotes plus closes the quoted string
81 * (1+) 3n+2 quotes -> n+1 quotes plus closes the quoted string
82 * - in unquoted strings, the first quote opens the quoted string and the
83 * remaining consecutive quotes follow the above rule.
85 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
87 DWORD argc;
88 LPWSTR *argv;
89 LPCWSTR s;
90 LPWSTR d;
91 LPWSTR cmdline;
92 int qcount,bcount;
94 if(!numargs)
96 SetLastError(ERROR_INVALID_PARAMETER);
97 return NULL;
100 if (*lpCmdline==0)
102 /* Return the path to the executable */
103 DWORD len, deslen=MAX_PATH, size;
105 size = sizeof(LPWSTR)*2 + deslen*sizeof(WCHAR);
106 for (;;)
108 if (!(argv = LocalAlloc(LMEM_FIXED, size))) return NULL;
109 len = GetModuleFileNameW(0, (LPWSTR)(argv+2), deslen);
110 if (!len)
112 LocalFree(argv);
113 return NULL;
115 if (len < deslen) break;
116 deslen*=2;
117 size = sizeof(LPWSTR)*2 + deslen*sizeof(WCHAR);
118 LocalFree( argv );
120 argv[0]=(LPWSTR)(argv+2);
121 argv[1]=NULL;
122 *numargs=1;
124 return argv;
127 /* --- First count the arguments */
128 argc=1;
129 s=lpCmdline;
130 /* The first argument, the executable path, follows special rules */
131 if (*s=='"')
133 /* The executable path ends at the next quote, no matter what */
134 s++;
135 while (*s)
136 if (*s++=='"')
137 break;
139 else
141 /* The executable path ends at the next space, no matter what */
142 while (*s && *s!=' ' && *s!='\t')
143 s++;
145 /* skip to the first argument, if any */
146 while (*s==' ' || *s=='\t')
147 s++;
148 if (*s)
149 argc++;
151 /* Analyze the remaining arguments */
152 qcount=bcount=0;
153 while (*s)
155 if ((*s==' ' || *s=='\t') && qcount==0)
157 /* skip to the next argument and count it if any */
158 while (*s==' ' || *s=='\t')
159 s++;
160 if (*s)
161 argc++;
162 bcount=0;
164 else if (*s=='\\')
166 /* '\', count them */
167 bcount++;
168 s++;
170 else if (*s=='"')
172 /* '"' */
173 if ((bcount & 1)==0)
174 qcount++; /* unescaped '"' */
175 s++;
176 bcount=0;
177 /* consecutive quotes, see comment in copying code below */
178 while (*s=='"')
180 qcount++;
181 s++;
183 qcount=qcount % 3;
184 if (qcount==2)
185 qcount=0;
187 else
189 /* a regular character */
190 bcount=0;
191 s++;
195 /* Allocate in a single lump, the string array, and the strings that go
196 * with it. This way the caller can make a single LocalFree() call to free
197 * both, as per MSDN.
199 argv=LocalAlloc(LMEM_FIXED, (argc+1)*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
200 if (!argv)
201 return NULL;
202 cmdline=(LPWSTR)(argv+argc+1);
203 strcpyW(cmdline, lpCmdline);
205 /* --- Then split and copy the arguments */
206 argv[0]=d=cmdline;
207 argc=1;
208 /* The first argument, the executable path, follows special rules */
209 if (*d=='"')
211 /* The executable path ends at the next quote, no matter what */
212 s=d+1;
213 while (*s)
215 if (*s=='"')
217 s++;
218 break;
220 *d++=*s++;
223 else
225 /* The executable path ends at the next space, no matter what */
226 while (*d && *d!=' ' && *d!='\t')
227 d++;
228 s=d;
229 if (*s)
230 s++;
232 /* close the executable path */
233 *d++=0;
234 /* skip to the first argument and initialize it if any */
235 while (*s==' ' || *s=='\t')
236 s++;
237 if (!*s)
239 /* There are no parameters so we are all done */
240 argv[argc]=NULL;
241 *numargs=argc;
242 return argv;
245 /* Split and copy the remaining arguments */
246 argv[argc++]=d;
247 qcount=bcount=0;
248 while (*s)
250 if ((*s==' ' || *s=='\t') && qcount==0)
252 /* close the argument */
253 *d++=0;
254 bcount=0;
256 /* skip to the next one and initialize it if any */
257 do {
258 s++;
259 } while (*s==' ' || *s=='\t');
260 if (*s)
261 argv[argc++]=d;
263 else if (*s=='\\')
265 *d++=*s++;
266 bcount++;
268 else if (*s=='"')
270 if ((bcount & 1)==0)
272 /* Preceded by an even number of '\', this is half that
273 * number of '\', plus a quote which we erase.
275 d-=bcount/2;
276 qcount++;
278 else
280 /* Preceded by an odd number of '\', this is half that
281 * number of '\' followed by a '"'
283 d=d-bcount/2-1;
284 *d++='"';
286 s++;
287 bcount=0;
288 /* Now count the number of consecutive quotes. Note that qcount
289 * already takes into account the opening quote if any, as well as
290 * the quote that lead us here.
292 while (*s=='"')
294 if (++qcount==3)
296 *d++='"';
297 qcount=0;
299 s++;
301 if (qcount==2)
302 qcount=0;
304 else
306 /* a regular character */
307 *d++=*s++;
308 bcount=0;
311 *d='\0';
312 argv[argc]=NULL;
313 *numargs=argc;
315 return argv;
318 static DWORD shgfi_get_exe_type(LPCWSTR szFullPath)
320 BOOL status = FALSE;
321 HANDLE hfile;
322 DWORD BinaryType;
323 IMAGE_DOS_HEADER mz_header;
324 IMAGE_NT_HEADERS nt;
325 DWORD len;
326 char magic[4];
328 status = GetBinaryTypeW (szFullPath, &BinaryType);
329 if (!status)
330 return 0;
331 if (BinaryType == SCS_DOS_BINARY || BinaryType == SCS_PIF_BINARY)
332 return 0x4d5a;
334 hfile = CreateFileW( szFullPath, GENERIC_READ, FILE_SHARE_READ,
335 NULL, OPEN_EXISTING, 0, 0 );
336 if ( hfile == INVALID_HANDLE_VALUE )
337 return 0;
340 * The next section is adapted from MODULE_GetBinaryType, as we need
341 * to examine the image header to get OS and version information. We
342 * know from calling GetBinaryTypeA that the image is valid and either
343 * an NE or PE, so much error handling can be omitted.
344 * Seek to the start of the file and read the header information.
347 SetFilePointer( hfile, 0, NULL, SEEK_SET );
348 ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL );
350 SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
351 ReadFile( hfile, magic, sizeof(magic), &len, NULL );
352 if ( *(DWORD*)magic == IMAGE_NT_SIGNATURE )
354 SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
355 ReadFile( hfile, &nt, sizeof(nt), &len, NULL );
356 CloseHandle( hfile );
357 /* DLL files are not executable and should return 0 */
358 if (nt.FileHeader.Characteristics & IMAGE_FILE_DLL)
359 return 0;
360 if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)
362 return IMAGE_NT_SIGNATURE |
363 (nt.OptionalHeader.MajorSubsystemVersion << 24) |
364 (nt.OptionalHeader.MinorSubsystemVersion << 16);
366 return IMAGE_NT_SIGNATURE;
368 else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
370 IMAGE_OS2_HEADER ne;
371 SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
372 ReadFile( hfile, &ne, sizeof(ne), &len, NULL );
373 CloseHandle( hfile );
374 if (ne.ne_exetyp == 2)
375 return IMAGE_OS2_SIGNATURE | (ne.ne_expver << 16);
376 return 0;
378 CloseHandle( hfile );
379 return 0;
382 /*************************************************************************
383 * SHELL_IsShortcut [internal]
385 * Decide if an item id list points to a shell shortcut
387 BOOL SHELL_IsShortcut(LPCITEMIDLIST pidlLast)
389 char szTemp[MAX_PATH];
390 HKEY keyCls;
391 BOOL ret = FALSE;
393 if (_ILGetExtension(pidlLast, szTemp, MAX_PATH) &&
394 HCR_MapTypeToValueA(szTemp, szTemp, MAX_PATH, TRUE))
396 if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_CLASSES_ROOT, szTemp, 0, KEY_QUERY_VALUE, &keyCls))
398 if (ERROR_SUCCESS == RegQueryValueExA(keyCls, "IsShortcut", NULL, NULL, NULL, NULL))
399 ret = TRUE;
401 RegCloseKey(keyCls);
405 return ret;
408 #define SHGFI_KNOWN_FLAGS \
409 (SHGFI_SMALLICON | SHGFI_OPENICON | SHGFI_SHELLICONSIZE | SHGFI_PIDL | \
410 SHGFI_USEFILEATTRIBUTES | SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX | \
411 SHGFI_ICON | SHGFI_DISPLAYNAME | SHGFI_TYPENAME | SHGFI_ATTRIBUTES | \
412 SHGFI_ICONLOCATION | SHGFI_EXETYPE | SHGFI_SYSICONINDEX | \
413 SHGFI_LINKOVERLAY | SHGFI_SELECTED | SHGFI_ATTR_SPECIFIED)
415 /*************************************************************************
416 * SHGetFileInfoW [SHELL32.@]
419 DWORD_PTR WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
420 SHFILEINFOW *psfi, UINT sizeofpsfi, UINT flags )
422 WCHAR szLocation[MAX_PATH], szFullPath[MAX_PATH];
423 int iIndex;
424 DWORD_PTR ret = TRUE;
425 DWORD dwAttributes = 0;
426 IShellFolder * psfParent = NULL;
427 IExtractIconW * pei = NULL;
428 LPITEMIDLIST pidlLast = NULL, pidl = NULL;
429 HRESULT hr = S_OK;
430 BOOL IconNotYetLoaded=TRUE;
431 UINT uGilFlags = 0;
433 TRACE("%s fattr=0x%x sfi=%p(attr=0x%08x) size=0x%x flags=0x%x\n",
434 (flags & SHGFI_PIDL)? "pidl" : debugstr_w(path), dwFileAttributes,
435 psfi, psfi->dwAttributes, sizeofpsfi, flags);
437 if (!path)
438 return FALSE;
440 /* windows initializes these values regardless of the flags */
441 if (psfi != NULL)
443 psfi->szDisplayName[0] = '\0';
444 psfi->szTypeName[0] = '\0';
445 psfi->iIcon = 0;
448 if (!(flags & SHGFI_PIDL))
450 /* SHGetFileInfo should work with absolute and relative paths */
451 if (PathIsRelativeW(path))
453 GetCurrentDirectoryW(MAX_PATH, szLocation);
454 PathCombineW(szFullPath, szLocation, path);
456 else
458 lstrcpynW(szFullPath, path, MAX_PATH);
462 if (flags & SHGFI_EXETYPE)
464 if (flags != SHGFI_EXETYPE)
465 return 0;
466 return shgfi_get_exe_type(szFullPath);
470 * psfi is NULL normally to query EXE type. If it is NULL, none of the
471 * below makes sense anyway. Windows allows this and just returns FALSE
473 if (psfi == NULL)
474 return FALSE;
477 * translate the path into a pidl only when SHGFI_USEFILEATTRIBUTES
478 * is not specified.
479 * The pidl functions fail on not existing file names
482 if (flags & SHGFI_PIDL)
484 pidl = ILClone((LPCITEMIDLIST)path);
486 else if (!(flags & SHGFI_USEFILEATTRIBUTES))
488 hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes);
491 if ((flags & SHGFI_PIDL) || !(flags & SHGFI_USEFILEATTRIBUTES))
493 /* get the parent shellfolder */
494 if (pidl)
496 hr = SHBindToParent( pidl, &IID_IShellFolder, (LPVOID*)&psfParent,
497 (LPCITEMIDLIST*)&pidlLast );
498 if (SUCCEEDED(hr))
499 pidlLast = ILClone(pidlLast);
500 ILFree(pidl);
502 else
504 ERR("pidl is null!\n");
505 return FALSE;
509 /* get the attributes of the child */
510 if (SUCCEEDED(hr) && (flags & SHGFI_ATTRIBUTES))
512 if (!(flags & SHGFI_ATTR_SPECIFIED))
514 psfi->dwAttributes = 0xffffffff;
516 if (psfParent)
517 IShellFolder_GetAttributesOf( psfParent, 1, (LPCITEMIDLIST*)&pidlLast,
518 &(psfi->dwAttributes) );
521 /* get the displayname */
522 if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME))
524 if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
526 lstrcpyW (psfi->szDisplayName, PathFindFileNameW(szFullPath));
528 else
530 STRRET str;
531 hr = IShellFolder_GetDisplayNameOf( psfParent, pidlLast,
532 SHGDN_INFOLDER, &str);
533 StrRetToStrNW (psfi->szDisplayName, MAX_PATH, &str, pidlLast);
537 /* get the type name */
538 if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME))
540 static const WCHAR szFolder[] = { 'F','o','l','d','e','r',0 };
541 static const WCHAR szFile[] = { 'F','i','l','e',0 };
542 static const WCHAR szSpaceFile[] = { ' ','f','i','l','e',0 };
544 if (!(flags & SHGFI_USEFILEATTRIBUTES) || (flags & SHGFI_PIDL))
546 char ftype[80];
548 _ILGetFileType(pidlLast, ftype, 80);
549 MultiByteToWideChar(CP_ACP, 0, ftype, -1, psfi->szTypeName, 80 );
551 else
553 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
554 strcatW (psfi->szTypeName, szFolder);
555 else
557 WCHAR sTemp[64];
559 lstrcpyW(sTemp,PathFindExtensionW(szFullPath));
560 if (sTemp[0] == 0 || (sTemp[0] == '.' && sTemp[1] == 0))
562 /* "name" or "name." => "File" */
563 lstrcpynW (psfi->szTypeName, szFile, 64);
565 else if (!( HCR_MapTypeToValueW(sTemp, sTemp, 64, TRUE) &&
566 HCR_MapTypeToValueW(sTemp, psfi->szTypeName, 80, FALSE )))
568 if (sTemp[0])
570 lstrcpynW (psfi->szTypeName, sTemp, 64);
571 strcatW (psfi->szTypeName, szSpaceFile);
573 else
575 lstrcpynW (psfi->szTypeName, szFile, 64);
582 /* ### icons ###*/
583 if (flags & SHGFI_OPENICON)
584 uGilFlags |= GIL_OPENICON;
586 if (flags & SHGFI_LINKOVERLAY)
587 uGilFlags |= GIL_FORSHORTCUT;
588 else if ((flags&SHGFI_ADDOVERLAYS) ||
589 (flags&(SHGFI_ICON|SHGFI_SMALLICON))==SHGFI_ICON)
591 if (SHELL_IsShortcut(pidlLast))
592 uGilFlags |= GIL_FORSHORTCUT;
595 if (flags & SHGFI_OVERLAYINDEX)
596 FIXME("SHGFI_OVERLAYINDEX unhandled\n");
598 if (flags & SHGFI_SELECTED)
599 FIXME("set icon to selected, stub\n");
601 if (flags & SHGFI_SHELLICONSIZE)
602 FIXME("set icon to shell size, stub\n");
604 /* get the iconlocation */
605 if (SUCCEEDED(hr) && (flags & SHGFI_ICONLOCATION ))
607 UINT uDummy,uFlags;
609 if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
611 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
613 lstrcpyW(psfi->szDisplayName, swShell32Name);
614 psfi->iIcon = -IDI_SHELL_FOLDER;
616 else
618 WCHAR* szExt;
619 static const WCHAR p1W[] = {'%','1',0};
620 WCHAR sTemp [MAX_PATH];
622 szExt = PathFindExtensionW(szFullPath);
623 TRACE("szExt=%s\n", debugstr_w(szExt));
624 if ( szExt &&
625 HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) &&
626 HCR_GetDefaultIconW(sTemp, sTemp, MAX_PATH, &psfi->iIcon))
628 if (lstrcmpW(p1W, sTemp))
629 strcpyW(psfi->szDisplayName, sTemp);
630 else
632 /* the icon is in the file */
633 strcpyW(psfi->szDisplayName, szFullPath);
636 else
637 ret = FALSE;
640 else
642 hr = IShellFolder_GetUIObjectOf(psfParent, 0, 1,
643 (LPCITEMIDLIST*)&pidlLast, &IID_IExtractIconW,
644 &uDummy, (LPVOID*)&pei);
645 if (SUCCEEDED(hr))
647 hr = IExtractIconW_GetIconLocation(pei, uGilFlags,
648 szLocation, MAX_PATH, &iIndex, &uFlags);
650 if (uFlags & GIL_NOTFILENAME)
651 ret = FALSE;
652 else
654 lstrcpyW (psfi->szDisplayName, szLocation);
655 psfi->iIcon = iIndex;
657 IExtractIconW_Release(pei);
662 /* get icon index (or load icon)*/
663 if (SUCCEEDED(hr) && (flags & (SHGFI_ICON | SHGFI_SYSICONINDEX)))
665 IImageList *icon_list;
666 SHGetImageList( (flags & SHGFI_SMALLICON) ? SHIL_SMALL : SHIL_LARGE, &IID_IImageList, (void **)&icon_list );
668 if (flags & SHGFI_USEFILEATTRIBUTES && !(flags & SHGFI_PIDL))
670 WCHAR sTemp [MAX_PATH];
671 WCHAR * szExt;
672 int icon_idx=0;
674 lstrcpynW(sTemp, szFullPath, MAX_PATH);
676 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
677 psfi->iIcon = SIC_GetIconIndex(swShell32Name, -IDI_SHELL_FOLDER, 0);
678 else
680 static const WCHAR p1W[] = {'%','1',0};
682 psfi->iIcon = 0;
683 szExt = PathFindExtensionW(sTemp);
684 if ( szExt &&
685 HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE) &&
686 HCR_GetDefaultIconW(sTemp, sTemp, MAX_PATH, &icon_idx))
688 if (!lstrcmpW(p1W,sTemp)) /* icon is in the file */
689 strcpyW(sTemp, szFullPath);
691 if (flags & SHGFI_SYSICONINDEX)
693 psfi->iIcon = SIC_GetIconIndex(sTemp,icon_idx,0);
694 if (psfi->iIcon == -1)
695 psfi->iIcon = 0;
697 else
699 UINT ret;
700 if (flags & SHGFI_SMALLICON)
701 ret = PrivateExtractIconsW( sTemp,icon_idx,
702 GetSystemMetrics( SM_CXSMICON ),
703 GetSystemMetrics( SM_CYSMICON ),
704 &psfi->hIcon, 0, 1, 0);
705 else
706 ret = PrivateExtractIconsW( sTemp, icon_idx,
707 GetSystemMetrics( SM_CXICON),
708 GetSystemMetrics( SM_CYICON),
709 &psfi->hIcon, 0, 1, 0);
710 if (ret != 0 && ret != (UINT)-1)
712 IconNotYetLoaded=FALSE;
713 psfi->iIcon = icon_idx;
719 else
721 if (!(PidlToSicIndex(psfParent, pidlLast, !(flags & SHGFI_SMALLICON),
722 uGilFlags, &(psfi->iIcon))))
724 ret = FALSE;
727 if (ret && (flags & SHGFI_SYSICONINDEX))
729 IImageList_AddRef( icon_list );
730 ret = (DWORD_PTR)icon_list;
732 if (ret && (flags & SHGFI_ICON))
734 hr = IImageList_GetIcon( icon_list, psfi->iIcon, ILD_NORMAL, &psfi->hIcon );
736 IImageList_Release( icon_list );
739 if (flags & ~SHGFI_KNOWN_FLAGS)
740 FIXME("unknown flags %08x\n", flags & ~SHGFI_KNOWN_FLAGS);
742 if (psfParent)
743 IShellFolder_Release(psfParent);
745 if (hr != S_OK)
746 ret = FALSE;
748 SHFree(pidlLast);
750 TRACE ("icon=%p index=0x%08x attr=0x%08x name=%s type=%s ret=0x%08lx\n",
751 psfi->hIcon, psfi->iIcon, psfi->dwAttributes,
752 debugstr_w(psfi->szDisplayName), debugstr_w(psfi->szTypeName), ret);
754 return ret;
757 /*************************************************************************
758 * SHGetFileInfoA [SHELL32.@]
760 * Note:
761 * MSVBVM60.__vbaNew2 expects this function to return a value in range
762 * 1 .. 0x7fff when the function succeeds and flags does not contain
763 * SHGFI_EXETYPE or SHGFI_SYSICONINDEX (see bug 7701)
765 DWORD_PTR WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes,
766 SHFILEINFOA *psfi, UINT sizeofpsfi,
767 UINT flags )
769 INT len;
770 LPWSTR temppath = NULL;
771 LPCWSTR pathW;
772 DWORD_PTR ret;
773 SHFILEINFOW temppsfi;
775 if (flags & SHGFI_PIDL)
777 /* path contains a pidl */
778 pathW = (LPCWSTR)path;
780 else
782 len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
783 temppath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
784 MultiByteToWideChar(CP_ACP, 0, path, -1, temppath, len);
785 pathW = temppath;
788 if (psfi && (flags & SHGFI_ATTR_SPECIFIED))
789 temppsfi.dwAttributes=psfi->dwAttributes;
791 if (psfi == NULL)
792 ret = SHGetFileInfoW(pathW, dwFileAttributes, NULL, sizeof(temppsfi), flags);
793 else
794 ret = SHGetFileInfoW(pathW, dwFileAttributes, &temppsfi, sizeof(temppsfi), flags);
796 if (psfi)
798 if(flags & SHGFI_ICON)
799 psfi->hIcon=temppsfi.hIcon;
800 if(flags & (SHGFI_SYSICONINDEX|SHGFI_ICON|SHGFI_ICONLOCATION))
801 psfi->iIcon=temppsfi.iIcon;
802 if(flags & SHGFI_ATTRIBUTES)
803 psfi->dwAttributes=temppsfi.dwAttributes;
804 if(flags & (SHGFI_DISPLAYNAME|SHGFI_ICONLOCATION))
806 WideCharToMultiByte(CP_ACP, 0, temppsfi.szDisplayName, -1,
807 psfi->szDisplayName, sizeof(psfi->szDisplayName), NULL, NULL);
809 if(flags & SHGFI_TYPENAME)
811 WideCharToMultiByte(CP_ACP, 0, temppsfi.szTypeName, -1,
812 psfi->szTypeName, sizeof(psfi->szTypeName), NULL, NULL);
816 HeapFree(GetProcessHeap(), 0, temppath);
818 return ret;
821 /*************************************************************************
822 * DuplicateIcon [SHELL32.@]
824 HICON WINAPI DuplicateIcon( HINSTANCE hInstance, HICON hIcon)
826 ICONINFO IconInfo;
827 HICON hDupIcon = 0;
829 TRACE("%p %p\n", hInstance, hIcon);
831 if (GetIconInfo(hIcon, &IconInfo))
833 hDupIcon = CreateIconIndirect(&IconInfo);
835 /* clean up hbmMask and hbmColor */
836 DeleteObject(IconInfo.hbmMask);
837 DeleteObject(IconInfo.hbmColor);
840 return hDupIcon;
843 /*************************************************************************
844 * ExtractIconA [SHELL32.@]
846 HICON WINAPI ExtractIconA(HINSTANCE hInstance, LPCSTR lpszFile, UINT nIconIndex)
848 HICON ret;
849 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
850 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
852 TRACE("%p %s %d\n", hInstance, lpszFile, nIconIndex);
854 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
855 ret = ExtractIconW(hInstance, lpwstrFile, nIconIndex);
856 HeapFree(GetProcessHeap(), 0, lpwstrFile);
858 return ret;
861 /*************************************************************************
862 * ExtractIconW [SHELL32.@]
864 HICON WINAPI ExtractIconW(HINSTANCE hInstance, LPCWSTR lpszFile, UINT nIconIndex)
866 HICON hIcon = NULL;
867 UINT ret;
868 UINT cx = GetSystemMetrics(SM_CXICON), cy = GetSystemMetrics(SM_CYICON);
870 TRACE("%p %s %d\n", hInstance, debugstr_w(lpszFile), nIconIndex);
872 if (nIconIndex == (UINT)-1)
874 ret = PrivateExtractIconsW(lpszFile, 0, cx, cy, NULL, NULL, 0, LR_DEFAULTCOLOR);
875 if (ret != (UINT)-1 && ret)
876 return (HICON)(UINT_PTR)ret;
877 return NULL;
879 else
880 ret = PrivateExtractIconsW(lpszFile, nIconIndex, cx, cy, &hIcon, NULL, 1, LR_DEFAULTCOLOR);
882 if (ret == (UINT)-1)
883 return (HICON)1;
884 else if (ret > 0 && hIcon)
885 return hIcon;
887 return NULL;
890 HRESULT WINAPI SHCreateFileExtractIconW(LPCWSTR file, DWORD attribs, REFIID riid, void **ppv)
892 FIXME("%s, %x, %s, %p\n", debugstr_w(file), attribs, debugstr_guid(riid), ppv);
893 *ppv = NULL;
894 return E_NOTIMPL;
897 /*************************************************************************
898 * Printer_LoadIconsW [SHELL32.205]
900 VOID WINAPI Printer_LoadIconsW(LPCWSTR wsPrinterName, HICON * pLargeIcon, HICON * pSmallIcon)
902 INT iconindex=IDI_SHELL_PRINTER;
904 TRACE("(%s, %p, %p)\n", debugstr_w(wsPrinterName), pLargeIcon, pSmallIcon);
906 /* We should check if wsPrinterName is
907 1. the Default Printer or not
908 2. connected or not
909 3. a Local Printer or a Network-Printer
910 and use different Icons
912 if((wsPrinterName != NULL) && (wsPrinterName[0] != 0))
914 FIXME("(select Icon by PrinterName %s not implemented)\n", debugstr_w(wsPrinterName));
917 if(pLargeIcon != NULL)
918 *pLargeIcon = LoadImageW(shell32_hInstance,
919 (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON,
920 0, 0, LR_DEFAULTCOLOR|LR_DEFAULTSIZE);
922 if(pSmallIcon != NULL)
923 *pSmallIcon = LoadImageW(shell32_hInstance,
924 (LPCWSTR) MAKEINTRESOURCE(iconindex), IMAGE_ICON,
925 16, 16, LR_DEFAULTCOLOR);
928 /*************************************************************************
929 * Printers_RegisterWindowW [SHELL32.213]
930 * used by "printui.dll":
931 * find the Window of the given Type for the specific Printer and
932 * return the already existent hwnd or open a new window
934 BOOL WINAPI Printers_RegisterWindowW(LPCWSTR wsPrinter, DWORD dwType,
935 HANDLE * phClassPidl, HWND * phwnd)
937 FIXME("(%s, %x, %p (%p), %p (%p)) stub!\n", debugstr_w(wsPrinter), dwType,
938 phClassPidl, (phClassPidl != NULL) ? *(phClassPidl) : NULL,
939 phwnd, (phwnd != NULL) ? *(phwnd) : NULL);
941 return FALSE;
944 /*************************************************************************
945 * Printers_UnregisterWindow [SHELL32.214]
947 VOID WINAPI Printers_UnregisterWindow(HANDLE hClassPidl, HWND hwnd)
949 FIXME("(%p, %p) stub!\n", hClassPidl, hwnd);
952 /*************************************************************************
953 * SHGetPropertyStoreForWindow [SHELL32.@]
955 HRESULT WINAPI SHGetPropertyStoreForWindow(HWND hwnd, REFIID riid, void **ppv)
957 FIXME("(%p %p %p) stub!\n", hwnd, riid, ppv);
958 return E_NOTIMPL;
961 /*************************************************************************/
963 typedef struct
965 LPCWSTR szApp;
966 LPCWSTR szOtherStuff;
967 HICON hIcon;
968 HFONT hFont;
969 } ABOUT_INFO;
971 #define DROP_FIELD_TOP (-12)
973 static void paint_dropline( HDC hdc, HWND hWnd )
975 HWND hWndCtl = GetDlgItem(hWnd, IDC_ABOUT_WINE_TEXT);
976 RECT rect;
978 if (!hWndCtl) return;
979 GetWindowRect( hWndCtl, &rect );
980 MapWindowPoints( 0, hWnd, (LPPOINT)&rect, 2 );
981 rect.top += DROP_FIELD_TOP;
982 rect.bottom = rect.top + 2;
983 DrawEdge( hdc, &rect, BDR_SUNKENOUTER, BF_RECT );
986 /*************************************************************************
987 * SHHelpShortcuts_RunDLLA [SHELL32.@]
990 DWORD WINAPI SHHelpShortcuts_RunDLLA(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
992 FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4);
993 return 0;
996 /*************************************************************************
997 * SHHelpShortcuts_RunDLLA [SHELL32.@]
1000 DWORD WINAPI SHHelpShortcuts_RunDLLW(DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
1002 FIXME("(%x, %x, %x, %x) stub!\n", dwArg1, dwArg2, dwArg3, dwArg4);
1003 return 0;
1006 /*************************************************************************
1007 * SHLoadInProc [SHELL32.@]
1008 * Create an instance of specified object class from within
1009 * the shell process and release it immediately
1011 HRESULT WINAPI SHLoadInProc (REFCLSID rclsid)
1013 void *ptr = NULL;
1015 TRACE("%s\n", debugstr_guid(rclsid));
1017 CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown,&ptr);
1018 if(ptr)
1020 IUnknown * pUnk = ptr;
1021 IUnknown_Release(pUnk);
1022 return S_OK;
1024 return DISP_E_MEMBERNOTFOUND;
1027 static void add_authors( HWND list )
1029 static const WCHAR eol[] = {'\r','\n',0};
1030 static const WCHAR authors[] = {'A','U','T','H','O','R','S',0};
1031 WCHAR *strW, *start, *end;
1032 HRSRC rsrc = FindResourceW( shell32_hInstance, authors, (LPCWSTR)RT_RCDATA );
1033 char *strA = LockResource( LoadResource( shell32_hInstance, rsrc ));
1034 DWORD sizeW, sizeA = SizeofResource( shell32_hInstance, rsrc );
1036 if (!strA) return;
1037 sizeW = MultiByteToWideChar( CP_UTF8, 0, strA, sizeA, NULL, 0 ) + 1;
1038 if (!(strW = HeapAlloc( GetProcessHeap(), 0, sizeW * sizeof(WCHAR) ))) return;
1039 MultiByteToWideChar( CP_UTF8, 0, strA, sizeA, strW, sizeW );
1040 strW[sizeW - 1] = 0;
1042 start = strpbrkW( strW, eol ); /* skip the header line */
1043 while (start)
1045 while (*start && strchrW( eol, *start )) start++;
1046 if (!*start) break;
1047 end = strpbrkW( start, eol );
1048 if (end) *end++ = 0;
1049 SendMessageW( list, LB_ADDSTRING, -1, (LPARAM)start );
1050 start = end;
1052 HeapFree( GetProcessHeap(), 0, strW );
1055 /*************************************************************************
1056 * AboutDlgProc (internal)
1058 static INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam,
1059 LPARAM lParam )
1061 HWND hWndCtl;
1063 TRACE("\n");
1065 switch(msg)
1067 case WM_INITDIALOG:
1069 ABOUT_INFO *info = (ABOUT_INFO *)lParam;
1070 WCHAR template[512], buffer[512], version[64];
1071 extern const char *wine_get_build_id(void);
1073 if (info)
1075 SendDlgItemMessageW(hWnd, stc1, STM_SETICON,(WPARAM)info->hIcon, 0);
1076 GetWindowTextW( hWnd, template, sizeof(template)/sizeof(WCHAR) );
1077 sprintfW( buffer, template, info->szApp );
1078 SetWindowTextW( hWnd, buffer );
1079 SetWindowTextW( GetDlgItem(hWnd, IDC_ABOUT_STATIC_TEXT1), info->szApp );
1080 SetWindowTextW( GetDlgItem(hWnd, IDC_ABOUT_STATIC_TEXT2), info->szOtherStuff );
1081 GetWindowTextW( GetDlgItem(hWnd, IDC_ABOUT_STATIC_TEXT3),
1082 template, sizeof(template)/sizeof(WCHAR) );
1083 MultiByteToWideChar( CP_UTF8, 0, wine_get_build_id(), -1,
1084 version, sizeof(version)/sizeof(WCHAR) );
1085 sprintfW( buffer, template, version );
1086 SetWindowTextW( GetDlgItem(hWnd, IDC_ABOUT_STATIC_TEXT3), buffer );
1087 hWndCtl = GetDlgItem(hWnd, IDC_ABOUT_LISTBOX);
1088 SendMessageW( hWndCtl, WM_SETREDRAW, 0, 0 );
1089 SendMessageW( hWndCtl, WM_SETFONT, (WPARAM)info->hFont, 0 );
1090 add_authors( hWndCtl );
1091 SendMessageW( hWndCtl, WM_SETREDRAW, 1, 0 );
1094 return 1;
1096 case WM_PAINT:
1098 PAINTSTRUCT ps;
1099 HDC hDC = BeginPaint( hWnd, &ps );
1100 paint_dropline( hDC, hWnd );
1101 EndPaint( hWnd, &ps );
1103 break;
1105 case WM_COMMAND:
1106 if (wParam == IDOK || wParam == IDCANCEL)
1108 EndDialog(hWnd, TRUE);
1109 return TRUE;
1111 if (wParam == IDC_ABOUT_LICENSE)
1113 MSGBOXPARAMSW params;
1115 params.cbSize = sizeof(params);
1116 params.hwndOwner = hWnd;
1117 params.hInstance = shell32_hInstance;
1118 params.lpszText = MAKEINTRESOURCEW(IDS_LICENSE);
1119 params.lpszCaption = MAKEINTRESOURCEW(IDS_LICENSE_CAPTION);
1120 params.dwStyle = MB_ICONINFORMATION | MB_OK;
1121 params.lpszIcon = 0;
1122 params.dwContextHelpId = 0;
1123 params.lpfnMsgBoxCallback = NULL;
1124 params.dwLanguageId = LANG_NEUTRAL;
1125 MessageBoxIndirectW( &params );
1127 break;
1128 case WM_CLOSE:
1129 EndDialog(hWnd, TRUE);
1130 break;
1133 return 0;
1137 /*************************************************************************
1138 * ShellAboutA [SHELL32.288]
1140 BOOL WINAPI ShellAboutA( HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon )
1142 BOOL ret;
1143 LPWSTR appW = NULL, otherW = NULL;
1144 int len;
1146 if (szApp)
1148 len = MultiByteToWideChar(CP_ACP, 0, szApp, -1, NULL, 0);
1149 appW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1150 MultiByteToWideChar(CP_ACP, 0, szApp, -1, appW, len);
1152 if (szOtherStuff)
1154 len = MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, NULL, 0);
1155 otherW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1156 MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, otherW, len);
1159 ret = ShellAboutW(hWnd, appW, otherW, hIcon);
1161 HeapFree(GetProcessHeap(), 0, otherW);
1162 HeapFree(GetProcessHeap(), 0, appW);
1163 return ret;
1167 /*************************************************************************
1168 * ShellAboutW [SHELL32.289]
1170 BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
1171 HICON hIcon )
1173 ABOUT_INFO info;
1174 LOGFONTW logFont;
1175 BOOL bRet;
1176 static const WCHAR wszSHELL_ABOUT_MSGBOX[] =
1177 {'S','H','E','L','L','_','A','B','O','U','T','_','M','S','G','B','O','X',0};
1179 TRACE("\n");
1181 if (!hIcon) hIcon = LoadImageW( 0, (LPWSTR)IDI_WINLOGO, IMAGE_ICON, 48, 48, LR_SHARED );
1182 info.szApp = szApp;
1183 info.szOtherStuff = szOtherStuff;
1184 info.hIcon = hIcon;
1186 SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 );
1187 info.hFont = CreateFontIndirectW( &logFont );
1189 bRet = DialogBoxParamW( shell32_hInstance, wszSHELL_ABOUT_MSGBOX, hWnd, AboutDlgProc, (LPARAM)&info );
1190 DeleteObject(info.hFont);
1191 return bRet;
1194 /*************************************************************************
1195 * FreeIconList (SHELL32.@)
1197 void WINAPI FreeIconList( DWORD dw )
1199 FIXME("%x: stub\n",dw);
1202 /*************************************************************************
1203 * SHLoadNonloadedIconOverlayIdentifiers (SHELL32.@)
1205 HRESULT WINAPI SHLoadNonloadedIconOverlayIdentifiers( VOID )
1207 FIXME("stub\n");
1208 return S_OK;
1211 /***********************************************************************
1212 * DllGetVersion [SHELL32.@]
1214 * Retrieves version information of the 'SHELL32.DLL'
1216 * PARAMS
1217 * pdvi [O] pointer to version information structure.
1219 * RETURNS
1220 * Success: S_OK
1221 * Failure: E_INVALIDARG
1223 * NOTES
1224 * Returns version of a shell32.dll from IE4.01 SP1.
1227 HRESULT WINAPI DllGetVersion (DLLVERSIONINFO *pdvi)
1229 /* FIXME: shouldn't these values come from the version resource? */
1230 if (pdvi->cbSize == sizeof(DLLVERSIONINFO) ||
1231 pdvi->cbSize == sizeof(DLLVERSIONINFO2))
1233 pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR;
1234 pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR;
1235 pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD;
1236 pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID;
1237 if (pdvi->cbSize == sizeof(DLLVERSIONINFO2))
1239 DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi;
1241 pdvi2->dwFlags = 0;
1242 pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR,
1243 WINE_FILEVERSION_MINOR,
1244 WINE_FILEVERSION_BUILD,
1245 WINE_FILEVERSION_PLATFORMID);
1247 TRACE("%u.%u.%u.%u\n",
1248 pdvi->dwMajorVersion, pdvi->dwMinorVersion,
1249 pdvi->dwBuildNumber, pdvi->dwPlatformID);
1250 return S_OK;
1252 else
1254 WARN("wrong DLLVERSIONINFO size from app\n");
1255 return E_INVALIDARG;
1259 /*************************************************************************
1260 * global variables of the shell32.dll
1261 * all are once per process
1264 HINSTANCE shell32_hInstance = 0;
1267 /*************************************************************************
1268 * SHELL32 DllMain
1270 * NOTES
1271 * calling oleinitialize here breaks some apps.
1273 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
1275 TRACE("%p 0x%x %p\n", hinstDLL, fdwReason, fImpLoad);
1277 switch (fdwReason)
1279 case DLL_PROCESS_ATTACH:
1280 shell32_hInstance = hinstDLL;
1281 DisableThreadLibraryCalls(shell32_hInstance);
1283 /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */
1284 GetModuleFileNameW(hinstDLL, swShell32Name, MAX_PATH);
1285 swShell32Name[MAX_PATH - 1] = '\0';
1287 InitChangeNotifications();
1288 break;
1290 case DLL_PROCESS_DETACH:
1291 if (fImpLoad) break;
1292 SIC_Destroy();
1293 FreeChangeNotifications();
1294 release_desktop_folder();
1295 release_typelib();
1296 break;
1298 return TRUE;
1301 /*************************************************************************
1302 * DllInstall [SHELL32.@]
1304 * PARAMETERS
1306 * BOOL bInstall - TRUE for install, FALSE for uninstall
1307 * LPCWSTR pszCmdLine - command line (unused by shell32?)
1310 HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
1312 FIXME("%s %s: stub\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
1313 return S_OK; /* indicate success */
1316 /***********************************************************************
1317 * DllCanUnloadNow (SHELL32.@)
1319 HRESULT WINAPI DllCanUnloadNow(void)
1321 return S_FALSE;
1324 /***********************************************************************
1325 * DllRegisterServer (SHELL32.@)
1327 HRESULT WINAPI DllRegisterServer(void)
1329 HRESULT hr = __wine_register_resources( shell32_hInstance );
1330 if (SUCCEEDED(hr)) hr = SHELL_RegisterShellFolders();
1331 return hr;
1334 /***********************************************************************
1335 * DllUnregisterServer (SHELL32.@)
1337 HRESULT WINAPI DllUnregisterServer(void)
1339 return __wine_unregister_resources( shell32_hInstance );
1342 /***********************************************************************
1343 * ExtractVersionResource16W (SHELL32.@)
1345 BOOL WINAPI ExtractVersionResource16W(LPWSTR s, DWORD d)
1347 FIXME("(%s %x) stub!\n", debugstr_w(s), d);
1348 return FALSE;
1351 /***********************************************************************
1352 * InitNetworkAddressControl (SHELL32.@)
1354 BOOL WINAPI InitNetworkAddressControl(void)
1356 FIXME("stub\n");
1357 return FALSE;
1360 /***********************************************************************
1361 * ShellHookProc (SHELL32.@)
1363 LRESULT CALLBACK ShellHookProc(DWORD a, DWORD b, DWORD c)
1365 FIXME("Stub\n");
1366 return 0;
1369 /***********************************************************************
1370 * SHGetLocalizedName (SHELL32.@)
1372 HRESULT WINAPI SHGetLocalizedName(LPCWSTR path, LPWSTR module, UINT size, INT *res)
1374 FIXME("%s %p %u %p: stub\n", debugstr_w(path), module, size, res);
1375 return E_NOTIMPL;
1378 /***********************************************************************
1379 * SetCurrentProcessExplicitAppUserModelID (SHELL32.@)
1381 HRESULT WINAPI SetCurrentProcessExplicitAppUserModelID(PCWSTR appid)
1383 FIXME("%s: stub\n", debugstr_w(appid));
1384 return E_NOTIMPL;
1387 /***********************************************************************
1388 * GetCurrentProcessExplicitAppUserModelID (SHELL32.@)
1390 HRESULT WINAPI GetCurrentProcessExplicitAppUserModelID(PWSTR *appid)
1392 FIXME("%p: stub\n", appid);
1393 *appid = NULL;
1394 return E_NOTIMPL;
1397 /***********************************************************************
1398 * SHSetUnreadMailCountW (SHELL32.@)
1400 HRESULT WINAPI SHSetUnreadMailCountW(LPCWSTR mailaddress, DWORD count, LPCWSTR executecommand)
1402 FIXME("%s %x %s: stub\n", debugstr_w(mailaddress), count, debugstr_w(executecommand));
1403 return E_NOTIMPL;
1406 /***********************************************************************
1407 * SHEnumerateUnreadMailAccountsW (SHELL32.@)
1409 HRESULT WINAPI SHEnumerateUnreadMailAccountsW(HKEY user, DWORD idx, LPWSTR mailaddress, INT mailaddresslen)
1411 FIXME("%p %d %p %d: stub\n", user, idx, mailaddress, mailaddresslen);
1412 return E_NOTIMPL;
1415 /***********************************************************************
1416 * SHQueryUserNotificationState (SHELL32.@)
1418 HRESULT WINAPI SHQueryUserNotificationState(QUERY_USER_NOTIFICATION_STATE *state)
1420 FIXME("%p: stub\n", state);
1421 *state = QUNS_ACCEPTS_NOTIFICATIONS;
1422 return S_OK;