Some windres versions don't like POPUP"", change to POPUP "".
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "dlgs.h"
34 #include "shellapi.h"
35 #include "winuser.h"
36 #include "wingdi.h"
37 #include "shlobj.h"
38 #include "shlguid.h"
39 #include "shlwapi.h"
40
41 #include "undocshell.h"
42 #include "pidl.h"
43 #include "shell32_main.h"
44 #include "version.h"
45
46 #include "wine/debug.h"
47 #include "wine/unicode.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(shell);
50
51 extern const char * const SHELL_Authors[];
52
53 #define MORE_DEBUG 1
54 /*************************************************************************
55  * CommandLineToArgvW                   [SHELL32.@]
56  *
57  * We must interpret the quotes in the command line to rebuild the argv
58  * array correctly:
59  * - arguments are separated by spaces or tabs
60  * - quotes serve as optional argument delimiters
61  *   '"a b"'   -> 'a b'
62  * - escaped quotes must be converted back to '"'
63  *   '\"'      -> '"'
64  * - an odd number of '\'s followed by '"' correspond to half that number
65  *   of '\' followed by a '"' (extension of the above)
66  *   '\\\"'    -> '\"'
67  *   '\\\\\"'  -> '\\"'
68  * - an even number of '\'s followed by a '"' correspond to half that number
69  *   of '\', plus a regular quote serving as an argument delimiter (which
70  *   means it does not appear in the result)
71  *   'a\\"b c"'   -> 'a\b c'
72  *   'a\\\\"b c"' -> 'a\\b c'
73  * - '\' that are not followed by a '"' are copied literally
74  *   'a\b'     -> 'a\b'
75  *   'a\\b'    -> 'a\\b'
76  *
77  * Note:
78  * '\t' == 0x0009
79  * ' '  == 0x0020
80  * '"'  == 0x0022
81  * '\\' == 0x005c
82  */
83 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
84 {
85     DWORD argc;
86     HGLOBAL hargv;
87     LPWSTR  *argv;
88     LPCWSTR cs;
89     LPWSTR arg,s,d;
90     LPWSTR cmdline;
91     int in_quotes,bcount;
92
93     if (*lpCmdline==0) {
94         /* Return the path to the executable */
95         DWORD len, size=16;
96
97         hargv=GlobalAlloc(size, 0);
98         argv=GlobalLock(hargv);
99         for (;;) {
100             len = GetModuleFileNameW(0, (LPWSTR)(argv+1), size-sizeof(LPWSTR));
101             if (!len) {
102                 GlobalFree(hargv);
103                 return NULL;
104             }
105             if (len < size) break;
106             size*=2;
107             hargv=GlobalReAlloc(hargv, size, 0);
108             argv=GlobalLock(hargv);
109         }
110         argv[0]=(LPWSTR)(argv+1);
111         if (numargs)
112             *numargs=2;
113
114         return argv;
115     }
116
117     /* to get a writeable copy */
118     argc=0;
119     bcount=0;
120     in_quotes=0;
121     cs=lpCmdline;
122     while (1) {
123         if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes)) {
124             /* space */
125             argc++;
126             /* skip the remaining spaces */
127             while (*cs==0x0009 || *cs==0x0020) {
128                 cs++;
129             }
130             if (*cs==0)
131                 break;
132             bcount=0;
133             continue;
134         } else if (*cs==0x005c) {
135             /* '\', count them */
136             bcount++;
137         } else if ((*cs==0x0022) && ((bcount & 1)==0)) {
138             /* unescaped '"' */
139             in_quotes=!in_quotes;
140             bcount=0;
141         } else {
142             /* a regular character */
143             bcount=0;
144         }
145         cs++;
146     }
147     /* Allocate in a single lump, the string array, and the strings that go with it.
148      * This way the caller can make a single GlobalFree call to free both, as per MSDN.
149      */
150     hargv=GlobalAlloc(0, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
151     argv=GlobalLock(hargv);
152     if (!argv)
153         return NULL;
154     cmdline=(LPWSTR)(argv+argc);
155     strcpyW(cmdline, lpCmdline);
156
157     argc=0;
158     bcount=0;
159     in_quotes=0;
160     arg=d=s=cmdline;
161     while (*s) {
162         if ((*s==0x0009 || *s==0x0020) && !in_quotes) {
163             /* Close the argument and copy it */
164             *d=0;
165             argv[argc++]=arg;
166
167             /* skip the remaining spaces */
168             do {
169                 s++;
170             } while (*s==0x0009 || *s==0x0020);
171
172             /* Start with a new argument */
173             arg=d=s;
174             bcount=0;
175         } else if (*s==0x005c) {
176             /* '\\' */
177             *d++=*s++;
178             bcount++;
179         } else if (*s==0x0022) {
180             /* '"' */
181             if ((bcount & 1)==0) {
182                 /* Preceeded by an even number of '\', this is half that
183                  * number of '\', plus a quote which we erase.
184                  */
185                 d-=bcount/2;
186                 in_quotes=!in_quotes;
187                 s++;
188             } else {
189                 /* Preceeded by an odd number of '\', this is half that
190                  * number of '\' followed by a '"'
191                  */
192                 d=d-bcount/2-1;
193                 *d++='"';
194                 s++;
195             }
196             bcount=0;
197         } else {
198             /* a regular character */
199             *d++=*s++;
200             bcount=0;
201         }
202     }
203     if (*arg) {
204         *d='\0';
205         argv[argc++]=arg;
206     }
207     if (numargs)
208         *numargs=argc;
209
210     return argv;
211 }
212
213 /*************************************************************************
214  * SHGetFileInfoA                       [SHELL32.@]
215  *
216  */
217
218 DWORD WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
219                               SHFILEINFOW *psfi, UINT sizeofpsfi,
220                               UINT flags )
221 {
222         WCHAR szLocation[MAX_PATH], szFullPath[MAX_PATH];
223         int iIndex;
224         DWORD ret = TRUE, dwAttributes = 0;
225         IShellFolder * psfParent = NULL;
226         IExtractIconW * pei = NULL;
227         LPITEMIDLIST    pidlLast = NULL, pidl = NULL;
228         HRESULT hr = S_OK;
229         BOOL IconNotYetLoaded=TRUE;
230
231         TRACE("(%s fattr=0x%lx sfi=%p(attr=0x%08lx) size=0x%x flags=0x%x)\n",
232           (flags & SHGFI_PIDL)? "pidl" : debugstr_w(path), dwFileAttributes, psfi, psfi->dwAttributes, sizeofpsfi, flags);
233
234         if ((flags & SHGFI_USEFILEATTRIBUTES) && (flags & (SHGFI_ATTRIBUTES|SHGFI_EXETYPE|SHGFI_PIDL)))
235           return FALSE;
236
237         /* windows initializes this values regardless of the flags */
238         if (psfi != NULL) {
239             psfi->szDisplayName[0] = '\0';
240             psfi->szTypeName[0] = '\0';
241             psfi->iIcon = 0;
242         }
243
244        if (!(flags & SHGFI_PIDL)){
245             /* SHGitFileInfo should work with absolute and relative paths */
246             if (PathIsRelativeW(path)){
247                 GetCurrentDirectoryW(MAX_PATH, szLocation);
248                 PathCombineW(szFullPath, szLocation, path);
249             } else {
250                 lstrcpynW(szFullPath, path, MAX_PATH);
251             }
252         }
253
254         if (flags & SHGFI_EXETYPE) {
255           BOOL status = FALSE;
256           HANDLE hfile;
257           DWORD BinaryType;
258           IMAGE_DOS_HEADER mz_header;
259           IMAGE_NT_HEADERS nt;
260           DWORD len;
261           char magic[4];
262
263           if (flags != SHGFI_EXETYPE) return 0;
264
265          status = GetBinaryTypeW (szFullPath, &BinaryType);
266           if (!status) return 0;
267           if ((BinaryType == SCS_DOS_BINARY)
268                 || (BinaryType == SCS_PIF_BINARY)) return 0x4d5a;
269
270          hfile = CreateFileW( szFullPath, GENERIC_READ, FILE_SHARE_READ,
271                 NULL, OPEN_EXISTING, 0, 0 );
272           if ( hfile == INVALID_HANDLE_VALUE ) return 0;
273
274         /* The next section is adapted from MODULE_GetBinaryType, as we need
275          * to examine the image header to get OS and version information. We
276          * know from calling GetBinaryTypeA that the image is valid and either
277          * an NE or PE, so much error handling can be omitted.
278          * Seek to the start of the file and read the header information.
279          */
280
281           SetFilePointer( hfile, 0, NULL, SEEK_SET );
282           ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL );
283
284          SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
285          ReadFile( hfile, magic, sizeof(magic), &len, NULL );
286          if ( *(DWORD*)magic      == IMAGE_NT_SIGNATURE )
287          {
288              SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
289              ReadFile( hfile, &nt, sizeof(nt), &len, NULL );
290               CloseHandle( hfile );
291               if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
292                  return IMAGE_NT_SIGNATURE
293                         | (nt.OptionalHeader.MajorSubsystemVersion << 24)
294                         | (nt.OptionalHeader.MinorSubsystemVersion << 16);
295               }
296               return IMAGE_NT_SIGNATURE;
297           }
298          else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
299          {
300              IMAGE_OS2_HEADER ne;
301              SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
302              ReadFile( hfile, &ne, sizeof(ne), &len, NULL );
303               CloseHandle( hfile );
304              if (ne.ne_exetyp == 2) return IMAGE_OS2_SIGNATURE
305                         | (ne.ne_expver << 16);
306               return 0;
307           }
308           CloseHandle( hfile );
309           return 0;
310       }
311
312       /* psfi is NULL normally to query EXE type. If it is NULL, none of the
313        * below makes sense anyway. Windows allows this and just returns FALSE */
314       if (psfi == NULL) return FALSE;
315
316         /* translate the path into a pidl only when SHGFI_USEFILEATTRIBUTES
317          * is not specified.
318            The pidl functions fail on not existing file names */
319
320         if (flags & SHGFI_PIDL) {
321             pidl = ILClone((LPCITEMIDLIST)path);
322         } else if (!(flags & SHGFI_USEFILEATTRIBUTES)) {
323            hr = SHILCreateFromPathW(szFullPath, &pidl, &dwAttributes);
324         }
325
326         if ((flags & SHGFI_PIDL) || !(flags & SHGFI_USEFILEATTRIBUTES))
327         {
328            /* get the parent shellfolder */
329            if (pidl) {
330               hr = SHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&psfParent, (LPCITEMIDLIST*)&pidlLast);
331               ILFree(pidl);
332            } else {
333               ERR("pidl is null!\n");
334               return FALSE;
335            }
336         }
337
338         /* get the attributes of the child */
339         if (SUCCEEDED(hr) && (flags & SHGFI_ATTRIBUTES))
340         {
341           if (!(flags & SHGFI_ATTR_SPECIFIED))
342           {
343             psfi->dwAttributes = 0xffffffff;
344           }
345           IShellFolder_GetAttributesOf(psfParent, 1, (LPCITEMIDLIST*)&pidlLast, &(psfi->dwAttributes));
346         }
347
348         /* get the displayname */
349         if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME))
350         {
351           if (flags & SHGFI_USEFILEATTRIBUTES)
352           {
353            lstrcpyW (psfi->szDisplayName, PathFindFileNameW(szFullPath));
354           }
355           else
356           {
357             STRRET str;
358             hr = IShellFolder_GetDisplayNameOf(psfParent, pidlLast, SHGDN_INFOLDER, &str);
359             StrRetToStrNW (psfi->szDisplayName, MAX_PATH, &str, pidlLast);
360           }
361         }
362
363         /* get the type name */
364         if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME))
365         {
366             static const WCHAR szFile[] = { 'F','i','l','e',0 };
367             static const WCHAR szDashFile[] = { '-','f','i','l','e',0 };
368             if (!(flags & SHGFI_USEFILEATTRIBUTES))
369             {
370                 char ftype[80];
371                 _ILGetFileType(pidlLast, ftype, 80);
372                 MultiByteToWideChar(CP_ACP, 0, ftype, -1, psfi->szTypeName, 80 );
373             }
374             else
375             {
376                 if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
377                    strcatW (psfi->szTypeName, szFile);
378                 else 
379                 {
380                    WCHAR sTemp[64];
381                    lstrcpyW(sTemp,PathFindExtensionW(szFullPath));
382                    if (!( HCR_MapTypeToValueW(sTemp, sTemp, 64, TRUE)
383                         && HCR_MapTypeToValueW(sTemp, psfi->szTypeName, 80, FALSE )))
384                    {
385                        lstrcpynW (psfi->szTypeName, sTemp, 64);
386                        strcatW (psfi->szTypeName, szDashFile);
387                    }
388                 }
389             }
390         }
391
392         /* ### icons ###*/
393         if (flags & SHGFI_LINKOVERLAY)
394           FIXME("set icon to link, stub\n");
395
396         if (flags & SHGFI_SELECTED)
397           FIXME("set icon to selected, stub\n");
398
399         if (flags & SHGFI_SHELLICONSIZE)
400           FIXME("set icon to shell size, stub\n");
401
402         /* get the iconlocation */
403         if (SUCCEEDED(hr) && (flags & SHGFI_ICONLOCATION ))
404         {
405           UINT uDummy,uFlags;
406           hr = IShellFolder_GetUIObjectOf(psfParent, 0, 1, (LPCITEMIDLIST*)&pidlLast, &IID_IExtractIconA, &uDummy, (LPVOID*)&pei);
407
408           if (SUCCEEDED(hr))
409           {
410            hr = IExtractIconW_GetIconLocation(pei, (flags & SHGFI_OPENICON)? GIL_OPENICON : 0,szLocation, MAX_PATH, &iIndex, &uFlags);
411            psfi->iIcon = iIndex;
412
413             if(uFlags != GIL_NOTFILENAME)
414               lstrcpyW (psfi->szDisplayName, szLocation);
415             else
416               ret = FALSE;
417
418             IExtractIconA_Release(pei);
419           }
420         }
421
422         /* get icon index (or load icon)*/
423         if (SUCCEEDED(hr) && (flags & (SHGFI_ICON | SHGFI_SYSICONINDEX)))
424         {
425
426           if (flags & SHGFI_USEFILEATTRIBUTES)
427           {
428             WCHAR sTemp [MAX_PATH];
429             WCHAR * szExt;
430             DWORD dwNr=0;
431
432             lstrcpynW(sTemp, szFullPath, MAX_PATH);
433
434             if (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
435                psfi->iIcon = 2;
436             else
437             {
438                static const WCHAR p1W[] = {'%','1',0};
439                psfi->iIcon = 0;
440                szExt = (LPWSTR) PathFindExtensionW(sTemp);
441                if ( szExt && HCR_MapTypeToValueW(szExt, sTemp, MAX_PATH, TRUE)
442                    && HCR_GetDefaultIconW(sTemp, sTemp, MAX_PATH, &dwNr))
443                {
444                   if (!lstrcmpW(p1W,sTemp))            /* icon is in the file */
445                      strcpyW(sTemp, szFullPath);
446
447                   if (flags & SHGFI_SYSICONINDEX) 
448                   {
449                       psfi->iIcon = SIC_GetIconIndex(sTemp,dwNr);
450                       if (psfi->iIcon == -1) psfi->iIcon = 0;
451                   }
452                   else 
453                   {
454                       IconNotYetLoaded=FALSE;
455                       PrivateExtractIconsW(sTemp,dwNr,(flags & SHGFI_SMALLICON) ? 
456                         GetSystemMetrics(SM_CXSMICON) : GetSystemMetrics(SM_CXICON),
457                         (flags & SHGFI_SMALLICON) ? GetSystemMetrics(SM_CYSMICON) :
458                         GetSystemMetrics(SM_CYICON), &psfi->hIcon,0,1,0);
459                       psfi->iIcon = dwNr;
460                   }
461                }
462             }
463           }
464           else
465           {
466             if (!(PidlToSicIndex(psfParent, pidlLast, !(flags & SHGFI_SMALLICON),
467               (flags & SHGFI_OPENICON)? GIL_OPENICON : 0, &(psfi->iIcon))))
468             {
469               ret = FALSE;
470             }
471           }
472           if (ret)
473           {
474             ret = (DWORD) ((flags & SHGFI_SMALLICON) ? ShellSmallIconList : ShellBigIconList);
475           }
476         }
477
478         /* icon handle */
479         if (SUCCEEDED(hr) && (flags & SHGFI_ICON) && IconNotYetLoaded)
480           psfi->hIcon = ImageList_GetIcon((flags & SHGFI_SMALLICON) ? ShellSmallIconList:ShellBigIconList, psfi->iIcon, ILD_NORMAL);
481
482         if (flags & (SHGFI_UNKNOWN1 | SHGFI_UNKNOWN2 | SHGFI_UNKNOWN3))
483           FIXME("unknown attribute!\n");
484
485         if (psfParent)
486           IShellFolder_Release(psfParent);
487
488         if (hr != S_OK)
489           ret = FALSE;
490
491         if(pidlLast) SHFree(pidlLast);
492 #ifdef MORE_DEBUG
493         TRACE ("icon=%p index=0x%08x attr=0x%08lx name=%s type=%s ret=0x%08lx\n",
494                 psfi->hIcon, psfi->iIcon, psfi->dwAttributes, debugstr_w(psfi->szDisplayName), debugstr_w(psfi->szTypeName), ret);
495 #endif
496         return ret;
497 }
498
499 /*************************************************************************
500  * SHGetFileInfoW                       [SHELL32.@]
501  */
502
503 DWORD WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes,
504                               SHFILEINFOA *psfi, UINT sizeofpsfi,
505                               UINT flags )
506 {
507         INT len;
508         LPWSTR temppath;
509         DWORD ret;
510         SHFILEINFOW temppsfi;
511
512         if (flags & SHGFI_PIDL) {
513           /* path contains a pidl */
514           temppath = (LPWSTR) path;
515         } else {
516           len = MultiByteToWideChar(CP_ACP, 0, path, -1, NULL, 0);
517           temppath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
518           MultiByteToWideChar(CP_ACP, 0, path, -1, temppath, len);
519         }
520
521         if(psfi && (flags & SHGFI_ATTR_SPECIFIED))
522                temppsfi.dwAttributes=psfi->dwAttributes;
523
524         ret = SHGetFileInfoW(temppath, dwFileAttributes, (psfi == NULL)? NULL : &temppsfi, sizeof(temppsfi), flags);
525
526         if (psfi)
527         {
528             if(flags & SHGFI_ICON)
529                 psfi->hIcon=temppsfi.hIcon;
530             if(flags & (SHGFI_SYSICONINDEX|SHGFI_ICON|SHGFI_ICONLOCATION))
531                 psfi->iIcon=temppsfi.iIcon;
532             if(flags & SHGFI_ATTRIBUTES)
533                 psfi->dwAttributes=temppsfi.dwAttributes;
534             if(flags & (SHGFI_DISPLAYNAME|SHGFI_ICONLOCATION))
535                 WideCharToMultiByte(CP_ACP, 0, temppsfi.szDisplayName, -1, psfi->szDisplayName, sizeof(psfi->szDisplayName), NULL, NULL);
536             if(flags & SHGFI_TYPENAME)
537                 WideCharToMultiByte(CP_ACP, 0, temppsfi.szTypeName, -1, psfi->szTypeName, sizeof(psfi->szTypeName), NULL, NULL);
538         }
539         if(!(flags & SHGFI_PIDL)) HeapFree(GetProcessHeap(), 0, temppath);
540         return ret;
541 }
542
543 /*************************************************************************
544  * SHGetFileInfo                        [SHELL32.@]
545  */
546 DWORD WINAPI SHGetFileInfoAW(
547         LPCVOID path,
548         DWORD dwFileAttributes,
549         LPVOID psfi,
550         UINT sizeofpsfi,
551         UINT flags)
552 {
553         if(SHELL_OsIsUnicode())
554           return SHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags );
555         return SHGetFileInfoA(path, dwFileAttributes, psfi, sizeofpsfi, flags );
556 }
557
558 /*************************************************************************
559  * DuplicateIcon                        [SHELL32.@]
560  */
561 HICON WINAPI DuplicateIcon( HINSTANCE hInstance, HICON hIcon)
562 {
563     ICONINFO IconInfo;
564     HICON hDupIcon = 0;
565
566     TRACE("(%p, %p)\n", hInstance, hIcon);
567
568     if(GetIconInfo(hIcon, &IconInfo))
569     {
570         hDupIcon = CreateIconIndirect(&IconInfo);
571
572         /* clean up hbmMask and hbmColor */
573         DeleteObject(IconInfo.hbmMask);
574         DeleteObject(IconInfo.hbmColor);
575     }
576
577     return hDupIcon;
578 }
579
580 /*************************************************************************
581  * ExtractIconA                         [SHELL32.@]
582  */
583 HICON WINAPI ExtractIconA(HINSTANCE hInstance, LPCSTR lpszFile, UINT nIconIndex)
584 {   
585   HICON ret;
586   INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
587   LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
588
589   TRACE("%p %s %d\n", hInstance, lpszFile, nIconIndex);
590
591   MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
592   ret = ExtractIconW(hInstance, lpwstrFile, nIconIndex);
593   HeapFree(GetProcessHeap(), 0, lpwstrFile);
594   return ret;
595 }
596
597 /*************************************************************************
598  * ExtractIconW                         [SHELL32.@]
599  */
600 HICON WINAPI ExtractIconW(HINSTANCE hInstance, LPCWSTR lpszFile, UINT nIconIndex)
601 {
602         HICON  hIcon = NULL;
603         UINT ret;
604         UINT cx = GetSystemMetrics(SM_CXICON), cy = GetSystemMetrics(SM_CYICON);
605
606         TRACE("%p %s %d\n", hInstance, debugstr_w(lpszFile), nIconIndex);
607
608         if (nIconIndex == 0xFFFFFFFF) {
609           ret = PrivateExtractIconsW(lpszFile, 0, cx, cy, NULL, NULL, 0, LR_DEFAULTCOLOR);
610           if (ret != 0xFFFFFFFF && ret)
611             return (HICON)ret;
612           return NULL;
613         }
614         else
615           ret = PrivateExtractIconsW(lpszFile, nIconIndex, cx, cy, &hIcon, NULL, 1, LR_DEFAULTCOLOR);
616
617         if (ret == 0xFFFFFFFF)
618           return (HICON)1;
619         else if (ret > 0 && hIcon)
620           return hIcon;
621         return NULL;
622 }
623
624 typedef struct
625 {
626     LPCWSTR  szApp;
627     LPCWSTR  szOtherStuff;
628     HICON hIcon;
629     HFONT hFont;
630 } ABOUT_INFO;
631
632 #define         IDC_STATIC_TEXT         100
633 #define         IDC_LISTBOX             99
634 #define         IDC_WINE_TEXT           98
635
636 #define         DROP_FIELD_TOP          (-15)
637 #define         DROP_FIELD_HEIGHT       15
638
639 static BOOL __get_dropline( HWND hWnd, LPRECT lprect )
640 { HWND hWndCtl = GetDlgItem(hWnd, IDC_WINE_TEXT);
641     if( hWndCtl )
642   { GetWindowRect( hWndCtl, lprect );
643         MapWindowPoints( 0, hWnd, (LPPOINT)lprect, 2 );
644         lprect->bottom = (lprect->top += DROP_FIELD_TOP);
645         return TRUE;
646     }
647     return FALSE;
648 }
649
650 /*************************************************************************
651  * SHAppBarMessage                      [SHELL32.@]
652  */
653 UINT WINAPI SHAppBarMessage(DWORD msg, PAPPBARDATA data)
654 {
655         int width=data->rc.right - data->rc.left;
656         int height=data->rc.bottom - data->rc.top;
657         RECT rec=data->rc;
658         switch (msg)
659         { case ABM_GETSTATE:
660                return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
661           case ABM_GETTASKBARPOS:
662                GetWindowRect(data->hWnd, &rec);
663                data->rc=rec;
664                return TRUE;
665           case ABM_ACTIVATE:
666                SetActiveWindow(data->hWnd);
667                return TRUE;
668           case ABM_GETAUTOHIDEBAR:
669                data->hWnd=GetActiveWindow();
670                return TRUE;
671           case ABM_NEW:
672                SetWindowPos(data->hWnd,HWND_TOP,rec.left,rec.top,
673                                         width,height,SWP_SHOWWINDOW);
674                return TRUE;
675           case ABM_QUERYPOS:
676                GetWindowRect(data->hWnd, &(data->rc));
677                return TRUE;
678           case ABM_REMOVE:
679                FIXME("ABM_REMOVE broken\n");
680                /* FIXME: this is wrong; should it be DestroyWindow instead? */
681                /*CloseHandle(data->hWnd);*/
682                return TRUE;
683           case ABM_SETAUTOHIDEBAR:
684                SetWindowPos(data->hWnd,HWND_TOP,rec.left+1000,rec.top,
685                                        width,height,SWP_SHOWWINDOW);
686                return TRUE;
687           case ABM_SETPOS:
688                data->uEdge=(ABE_RIGHT | ABE_LEFT);
689                SetWindowPos(data->hWnd,HWND_TOP,data->rc.left,data->rc.top,
690                                   width,height,SWP_SHOWWINDOW);
691                return TRUE;
692           case ABM_WINDOWPOSCHANGED:
693                return TRUE;
694           }
695       return FALSE;
696 }
697
698 /*************************************************************************
699  * SHHelpShortcuts_RunDLL               [SHELL32.@]
700  *
701  */
702 DWORD WINAPI SHHelpShortcuts_RunDLL (DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
703 { FIXME("(%lx, %lx, %lx, %lx) empty stub!\n",
704         dwArg1, dwArg2, dwArg3, dwArg4);
705
706   return 0;
707 }
708
709 /*************************************************************************
710  * SHLoadInProc                         [SHELL32.@]
711  * Create an instance of specified object class from within
712  * the shell process and release it immediately
713  */
714
715 HRESULT WINAPI SHLoadInProc (REFCLSID rclsid)
716 {
717     void *ptr = NULL;
718
719     TRACE("%s\n", debugstr_guid(rclsid));
720
721     CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown,&ptr);
722     if(ptr)
723     {
724         IUnknown * pUnk = ptr;
725         IUnknown_Release(pUnk);
726         return NOERROR;
727     }
728     return DISP_E_MEMBERNOTFOUND;
729 }
730
731 /*************************************************************************
732  * AboutDlgProc                 (internal)
733  */
734 INT_PTR CALLBACK AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam,
735                               LPARAM lParam )
736 {
737     HWND hWndCtl;
738
739     TRACE("\n");
740
741     switch(msg)
742     {
743     case WM_INITDIALOG:
744         {
745             ABOUT_INFO *info = (ABOUT_INFO *)lParam;
746             WCHAR Template[512], AppTitle[512];
747
748             if (info)
749             {
750                 const char* const *pstr = SHELL_Authors;
751                 SendDlgItemMessageW(hWnd, stc1, STM_SETICON,(WPARAM)info->hIcon, 0);
752                 GetWindowTextW( hWnd, Template, sizeof(Template)/sizeof(WCHAR) );
753                 sprintfW( AppTitle, Template, info->szApp );
754                 SetWindowTextW( hWnd, AppTitle );
755                 SetWindowTextW( GetDlgItem(hWnd, IDC_STATIC_TEXT), info->szOtherStuff );
756                 hWndCtl = GetDlgItem(hWnd, IDC_LISTBOX);
757                 SendMessageW( hWndCtl, WM_SETREDRAW, 0, 0 );
758                 SendMessageW( hWndCtl, WM_SETFONT, (WPARAM)info->hFont, 0 );
759                 while (*pstr)
760                 {
761                     WCHAR name[64];
762                     /* authors list is in iso-8859-1 format */
763                     MultiByteToWideChar( 28591, 0, *pstr, -1, name, sizeof(name)/sizeof(WCHAR) );
764                     SendMessageW( hWndCtl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)name );
765                     pstr++;
766                 }
767                 SendMessageW( hWndCtl, WM_SETREDRAW, 1, 0 );
768             }
769         }
770         return 1;
771
772     case WM_PAINT:
773       { RECT rect;
774             PAINTSTRUCT ps;
775             HDC hDC = BeginPaint( hWnd, &ps );
776
777             if( __get_dropline( hWnd, &rect ) ) {
778                 SelectObject( hDC, GetStockObject( BLACK_PEN ) );
779                 MoveToEx( hDC, rect.left, rect.top, NULL );
780                 LineTo( hDC, rect.right, rect.bottom );
781             }
782             EndPaint( hWnd, &ps );
783         }
784         break;
785
786     case WM_COMMAND:
787         if (wParam == IDOK || wParam == IDCANCEL)
788         {
789             EndDialog(hWnd, TRUE);
790             return TRUE;
791         }
792         break;
793     case WM_CLOSE:
794       EndDialog(hWnd, TRUE);
795       break;
796     }
797
798     return 0;
799 }
800
801
802 /*************************************************************************
803  * ShellAboutA                          [SHELL32.288]
804  */
805 BOOL WINAPI ShellAboutA( HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon )
806 {
807     BOOL ret;
808     LPWSTR appW = NULL, otherW = NULL;
809     int len;
810
811     if (szApp)
812     {
813         len = MultiByteToWideChar(CP_ACP, 0, szApp, -1, NULL, 0);
814         appW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
815         MultiByteToWideChar(CP_ACP, 0, szApp, -1, appW, len);
816     }
817     if (szOtherStuff)
818     {
819         len = MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, NULL, 0);
820         otherW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
821         MultiByteToWideChar(CP_ACP, 0, szOtherStuff, -1, otherW, len);
822     }
823
824     ret = ShellAboutW(hWnd, appW, otherW, hIcon);
825
826     if (otherW) HeapFree(GetProcessHeap(), 0, otherW);
827     if (appW) HeapFree(GetProcessHeap(), 0, appW);
828     return ret;
829 }
830
831
832 /*************************************************************************
833  * ShellAboutW                          [SHELL32.289]
834  */
835 BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
836                              HICON hIcon )
837 {
838     ABOUT_INFO info;
839     LOGFONTW logFont;
840     HRSRC hRes;
841     LPVOID template;
842     BOOL bRet;
843
844     TRACE("\n");
845
846     if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_ABOUT_MSGBOX", (LPSTR)RT_DIALOG)))
847         return FALSE;
848     if(!(template = (LPVOID)LoadResource(shell32_hInstance, hRes)))
849         return FALSE;
850     info.szApp        = szApp;
851     info.szOtherStuff = szOtherStuff;
852     info.hIcon        = hIcon ? hIcon : LoadIconW( 0, (LPWSTR)IDI_WINLOGO );
853
854     SystemParametersInfoW( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 );
855     info.hFont = CreateFontIndirectW( &logFont );
856
857     bRet = DialogBoxIndirectParamW((HINSTANCE)GetWindowLongPtrW( hWnd, GWLP_HINSTANCE ),
858                                    template, hWnd, AboutDlgProc, (LPARAM)&info );
859     DeleteObject(info.hFont);
860     return bRet;
861 }
862
863 /*************************************************************************
864  * FreeIconList (SHELL32.@)
865  */
866 void WINAPI FreeIconList( DWORD dw )
867 { FIXME("(%lx): stub\n",dw);
868 }
869
870
871 /*************************************************************************
872  * ShellDDEInit (SHELL32.@)
873  */
874 void WINAPI ShellDDEInit(BOOL start)
875 {
876     FIXME("stub: %d\n", start);
877 }
878
879 /***********************************************************************
880  * DllGetVersion [SHELL32.@]
881  *
882  * Retrieves version information of the 'SHELL32.DLL'
883  *
884  * PARAMS
885  *     pdvi [O] pointer to version information structure.
886  *
887  * RETURNS
888  *     Success: S_OK
889  *     Failure: E_INVALIDARG
890  *
891  * NOTES
892  *     Returns version of a shell32.dll from IE4.01 SP1.
893  */
894
895 HRESULT WINAPI SHELL32_DllGetVersion (DLLVERSIONINFO *pdvi)
896 {
897     /* FIXME: shouldn't these values come from the version resource? */
898     if (pdvi->cbSize == sizeof(DLLVERSIONINFO) ||
899      pdvi->cbSize == sizeof(DLLVERSIONINFO2))
900     {
901         pdvi->dwMajorVersion = WINE_FILEVERSION_MAJOR;
902         pdvi->dwMinorVersion = WINE_FILEVERSION_MINOR;
903         pdvi->dwBuildNumber = WINE_FILEVERSION_BUILD;
904         pdvi->dwPlatformID = WINE_FILEVERSION_PLATFORMID;
905         if (pdvi->cbSize == sizeof(DLLVERSIONINFO2))
906         {
907             DLLVERSIONINFO2 *pdvi2 = (DLLVERSIONINFO2 *)pdvi;
908
909             pdvi2->dwFlags = 0;
910             pdvi2->ullVersion = MAKEDLLVERULL(WINE_FILEVERSION_MAJOR,
911                                               WINE_FILEVERSION_MINOR,
912                                               WINE_FILEVERSION_BUILD,
913                                               WINE_FILEVERSION_PLATFORMID);
914         }
915         TRACE("%lu.%lu.%lu.%lu\n",
916            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
917            pdvi->dwBuildNumber, pdvi->dwPlatformID);
918         return S_OK;
919     }
920     else
921         {
922         WARN("wrong DLLVERSIONINFO size from app\n");
923         return E_INVALIDARG;
924     }
925 }
926 /*************************************************************************
927  * global variables of the shell32.dll
928  * all are once per process
929  *
930  */
931 HINSTANCE       shell32_hInstance = 0;
932 HIMAGELIST      ShellSmallIconList = 0;
933 HIMAGELIST      ShellBigIconList = 0;
934
935
936 /*************************************************************************
937  * SHELL32 DllMain
938  *
939  * NOTES
940  *  calling oleinitialize here breaks sone apps.
941  */
942
943 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
944 {
945         TRACE("%p 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
946
947         switch (fdwReason)
948         {
949           case DLL_PROCESS_ATTACH:
950             shell32_hInstance = hinstDLL;
951             DisableThreadLibraryCalls(shell32_hInstance);
952
953             /* get full path to this DLL for IExtractIconW_fnGetIconLocation() */
954             GetModuleFileNameW(hinstDLL, swShell32Name, MAX_PATH);
955             swShell32Name[MAX_PATH - 1] = '\0';
956
957             InitCommonControlsEx(NULL);
958
959             SIC_Initialize();
960             SYSTRAY_Init();
961             InitChangeNotifications();
962             break;
963
964           case DLL_PROCESS_DETACH:
965               shell32_hInstance = 0;
966               SIC_Destroy();
967               FreeChangeNotifications();
968               break;
969         }
970         return TRUE;
971 }
972
973 /*************************************************************************
974  * DllInstall         [SHELL32.@]
975  *
976  * PARAMETERS
977  *
978  *    BOOL bInstall - TRUE for install, FALSE for uninstall
979  *    LPCWSTR pszCmdLine - command line (unused by shell32?)
980  */
981
982 HRESULT WINAPI SHELL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
983 {
984    FIXME("(%s, %s): stub!\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
985
986    return S_OK;         /* indicate success */
987 }
988
989 /***********************************************************************
990  *              DllCanUnloadNow (SHELL32.@)
991  */
992 HRESULT WINAPI SHELL32_DllCanUnloadNow(void)
993 {
994     FIXME("(void): stub\n");
995
996     return S_FALSE;
997 }