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