Fixed the behavior for SHGetFileInfo when the SHGFI_USEFILEATTRIBUTES
[wine] / dlls / shell32 / shell32_main.c
1 /*
2  *                              Shell basics
3  *
4  *  1998 Marcus Meissner
5  *  1998 Juergen Schmied (jsch)  *  <juergen.schmied@metronet.de>
6  */
7
8 #include "config.h"
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include <stdio.h>
13
14 #include "dlgs.h"
15 #include "shellapi.h"
16 #include "shlobj.h"
17 #include "shlguid.h"
18 #include "shlwapi.h"
19 #include "windef.h"
20 #include "winerror.h"
21 #include "winreg.h"
22
23 #include "undocshell.h"
24 #include "wine/winuser16.h"
25 #include "authors.h"
26 #include "heap.h"
27 #include "pidl.h"
28 #include "shell32_main.h"
29
30 #include "debugtools.h"
31
32 DEFAULT_DEBUG_CHANNEL(shell);
33
34 #define MORE_DEBUG 1
35 /*************************************************************************
36  * CommandLineToArgvW                   [SHELL32.@]
37  *
38  * We must interpret the quotes in the command line to rebuild the argv 
39  * array correctly:
40  * - arguments are separated by spaces or tabs
41  * - quotes serve as optional argument delimiters
42  *   '"a b"'   -> 'a b'
43  * - escaped quotes must be converted back to '"'
44  *   '\"'      -> '"'
45  * - an odd number of '\'s followed by '"' correspond to half that number 
46  *   of '\' followed by a '"' (extension of the above)
47  *   '\\\"'    -> '\"'
48  *   '\\\\\"'  -> '\\"'
49  * - an even number of '\'s followed by a '"' correspond to half that number
50  *   of '\', plus a regular quote serving as an argument delimiter (which 
51  *   means it does not appear in the result)
52  *   'a\\"b c"'   -> 'a\b c'
53  *   'a\\\\"b c"' -> 'a\\b c'
54  * - '\' that are not followed by a '"' are copied literally
55  *   'a\b'     -> 'a\b'
56  *   'a\\b'    -> 'a\\b'
57  *
58  * Note:
59  * '\t' == 0x0009
60  * ' '  == 0x0020
61  * '"'  == 0x0022
62  * '\\' == 0x005c
63  */
64 LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int* numargs)
65 {
66     DWORD argc;
67     HGLOBAL hargv;
68     LPWSTR  *argv;
69     LPCWSTR cs;
70     LPWSTR arg,s,d;
71     LPWSTR cmdline;
72     int in_quotes,bcount;
73
74     if (*lpCmdline==0) {
75         /* Return the path to the executable */
76         DWORD size;
77
78         hargv=0;
79         size=16;
80         do {
81             size*=2;
82             hargv=GlobalReAlloc(hargv, size, 0);
83             argv=GlobalLock(hargv);
84         } while (GetModuleFileNameW((HMODULE)0, (LPWSTR)(argv+1), size-sizeof(LPWSTR)) == 0);
85         argv[0]=(LPWSTR)(argv+1);
86         if (numargs)
87             *numargs=2;
88
89         return argv;
90     }
91
92     /* to get a writeable copy */
93     argc=0;
94     bcount=0;
95     in_quotes=0;
96     cs=lpCmdline;
97     while (1) {
98         if (*cs==0 || ((*cs==0x0009 || *cs==0x0020) && !in_quotes)) {
99             /* space */
100             argc++;
101             /* skip the remaining spaces */
102             while (*cs==0x0009 || *cs==0x0020) {
103                 cs++;
104             }
105             if (*cs==0)
106                 break;
107             bcount=0;
108             continue;
109         } else if (*cs==0x005c) {
110             /* '\', count them */
111             bcount++;
112         } else if ((*cs==0x0022) && ((bcount & 1)==0)) {
113             /* unescaped '"' */
114             in_quotes=!in_quotes;
115             bcount=0;
116         } else {
117             /* a regular character */
118             bcount=0;
119         }
120         cs++;
121     }
122     /* Allocate in a single lump, the string array, and the strings that go with it.
123      * This way the caller can make a single GlobalFree call to free both, as per MSDN.
124      */
125     hargv=GlobalAlloc(0, argc*sizeof(LPWSTR)+(strlenW(lpCmdline)+1)*sizeof(WCHAR));
126     argv=GlobalLock(hargv);
127     if (!argv)
128         return NULL;
129     cmdline=(LPWSTR)(argv+argc);
130     strcpyW(cmdline, lpCmdline);
131
132     argc=0;
133     bcount=0;
134     in_quotes=0;
135     arg=d=s=cmdline;
136     while (*s) {
137         if ((*s==0x0009 || *s==0x0020) && !in_quotes) {
138             /* Close the argument and copy it */
139             *d=0;
140             argv[argc++]=arg;
141
142             /* skip the remaining spaces */
143             do {
144                 s++;
145             } while (*s==0x0009 || *s==0x0020);
146
147             /* Start with a new argument */
148             arg=d=s;
149             bcount=0;
150         } else if (*s==0x005c) {
151             /* '\\' */
152             *d++=*s++;
153             bcount++;
154         } else if (*s==0x0022) {
155             /* '"' */
156             if ((bcount & 1)==0) {
157                 /* Preceeded by an even number of '\', this is half that 
158                  * number of '\', plus a quote which we erase.
159                  */
160                 d-=bcount/2;
161                 in_quotes=!in_quotes;
162                 s++;
163             } else {
164                 /* Preceeded by an odd number of '\', this is half that 
165                  * number of '\' followed by a '"'
166                  */
167                 d=d-bcount/2-1;
168                 *d++='"';
169                 s++;
170             }
171             bcount=0;
172         } else {
173             /* a regular character */
174             *d++=*s++;
175             bcount=0;
176         }
177     }
178     if (*arg) {
179         *d='\0';
180         argv[argc]=arg;
181     }
182     if (numargs)
183         *numargs=argc;
184
185     return argv;
186 }
187
188 /*************************************************************************
189  * SHGetFileInfoA                       [SHELL32.@]
190  *
191  */
192
193 DWORD WINAPI SHGetFileInfoA(LPCSTR path,DWORD dwFileAttributes,
194                               SHFILEINFOA *psfi, UINT sizeofpsfi,
195                               UINT flags )
196 {
197         char szLoaction[MAX_PATH];
198         int iIndex;
199         DWORD ret = TRUE, dwAttributes = 0;
200         IShellFolder * psfParent = NULL;
201         IExtractIconA * pei = NULL;
202         LPITEMIDLIST    pidlLast = NULL, pidl = NULL;
203         HRESULT hr = S_OK;
204     BOOL IconNotYetLoaded=TRUE;
205
206         TRACE("(%s fattr=0x%lx sfi=%p(attr=0x%08lx) size=0x%x flags=0x%x)\n", 
207           (flags & SHGFI_PIDL)? "pidl" : path, dwFileAttributes, psfi, psfi->dwAttributes, sizeofpsfi, flags);
208
209         if ((flags & SHGFI_USEFILEATTRIBUTES) && (flags & (SHGFI_ATTRIBUTES|SHGFI_EXETYPE|SHGFI_PIDL)))
210           return FALSE;
211         
212         /* windows initializes this values regardless of the flags */
213         psfi->szDisplayName[0] = '\0';
214         psfi->szTypeName[0] = '\0';
215         psfi->iIcon = 0;
216
217         if (flags & SHGFI_EXETYPE) {
218           BOOL status = FALSE;
219           HANDLE hfile;
220           DWORD BinaryType;
221           IMAGE_DOS_HEADER mz_header;
222           IMAGE_NT_HEADERS nt;
223           DWORD len;
224           char magic[4];
225
226           if (flags != SHGFI_EXETYPE) return 0;
227
228           status = GetBinaryTypeA (path, &BinaryType);
229           if (!status) return 0;
230           if ((BinaryType == SCS_DOS_BINARY)
231                 || (BinaryType == SCS_PIF_BINARY)) return 0x4d5a;
232
233           hfile = CreateFileA( path, GENERIC_READ, FILE_SHARE_READ,
234                 NULL, OPEN_EXISTING, 0, 0 );
235           if ( hfile == INVALID_HANDLE_VALUE ) return 0;
236
237         /* The next section is adapted from MODULE_GetBinaryType, as we need
238          * to examine the image header to get OS and version information. We
239          * know from calling GetBinaryTypeA that the image is valid and either
240          * an NE or PE, so much error handling can be omitted.
241          * Seek to the start of the file and read the header information.
242          */
243
244           SetFilePointer( hfile, 0, NULL, SEEK_SET );  
245           ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL );
246
247          SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET );
248          ReadFile( hfile, magic, sizeof(magic), &len, NULL );
249          if ( *(DWORD*)magic      == IMAGE_NT_SIGNATURE )
250          {
251              SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); 
252              ReadFile( hfile, &nt, sizeof(nt), &len, NULL );
253               CloseHandle( hfile );
254               if (nt.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) {
255                  return IMAGE_NT_SIGNATURE
256                         | (nt.OptionalHeader.MajorSubsystemVersion << 24)
257                         | (nt.OptionalHeader.MinorSubsystemVersion << 16);
258               }
259               return IMAGE_NT_SIGNATURE;
260           }
261          else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
262          {
263              IMAGE_OS2_HEADER ne;
264              SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ); 
265              ReadFile( hfile, &ne, sizeof(ne), &len, NULL );
266               CloseHandle( hfile );
267              if (ne.ne_exetyp == 2) return IMAGE_OS2_SIGNATURE
268                         | (ne.ne_expver << 16);
269               return 0;
270           }
271           CloseHandle( hfile );
272           return 0;
273       }
274
275         
276         /* translate the path into a pidl only when SHGFI_USEFILEATTRIBUTES in not specified 
277            the pidl functions fail on not existing file names */
278         if (flags & SHGFI_PIDL)
279         {
280           pidl = (LPCITEMIDLIST) path;
281           if (!pidl )
282           {
283             ERR("pidl is null!\n");
284             return FALSE;
285           }
286         }
287         else if (!(flags & SHGFI_USEFILEATTRIBUTES))
288         {
289           hr = SHILCreateFromPathA ( path, &pidl, &dwAttributes);
290           /* note: the attributes in ISF::ParseDisplayName are not implemented */
291         }
292         
293         /* get the parent shellfolder */
294         if (pidl)
295         {
296           hr = SHBindToParent( pidl, &IID_IShellFolder, (LPVOID*)&psfParent, &pidlLast);
297         }
298         
299         /* get the attributes of the child */
300         if (SUCCEEDED(hr) && (flags & SHGFI_ATTRIBUTES))
301         {
302           if (!(flags & SHGFI_ATTR_SPECIFIED))
303           {
304             psfi->dwAttributes = 0xffffffff;
305           }
306           IShellFolder_GetAttributesOf(psfParent, 1 , &pidlLast, &(psfi->dwAttributes));
307         }
308
309         /* get the displayname */
310         if (SUCCEEDED(hr) && (flags & SHGFI_DISPLAYNAME))
311         { 
312           if (flags & SHGFI_USEFILEATTRIBUTES)
313           {
314             strcpy (psfi->szDisplayName, PathFindFileNameA(path));
315           }
316           else
317           {
318             STRRET str;
319             hr = IShellFolder_GetDisplayNameOf(psfParent, pidlLast, SHGDN_INFOLDER, &str);
320             StrRetToStrNA (psfi->szDisplayName, MAX_PATH, &str, pidlLast);
321           }
322         }
323
324         /* get the type name */
325         if (SUCCEEDED(hr) && (flags & SHGFI_TYPENAME))
326         {
327         if (!flags & SHGFI_USEFILEATTRIBUTES)
328                 _ILGetFileType(pidlLast, psfi->szTypeName, 80);
329         else
330         {
331                 char sTemp[64];
332             strcpy(sTemp,PathFindExtensionA(path));
333                 if (!( HCR_MapTypeToValue(sTemp, sTemp, 64, TRUE)
334                 && HCR_MapTypeToValue(sTemp, psfi->szTypeName, 80, FALSE )))
335                 {
336                     lstrcpynA (psfi->szTypeName, sTemp, 80 - 6);
337                     strcat (psfi->szTypeName, "-file");
338                 }
339         }
340         }
341
342         /* ### icons ###*/
343         if (flags & SHGFI_LINKOVERLAY)
344           FIXME("set icon to link, stub\n");
345
346         if (flags & SHGFI_SELECTED)
347           FIXME("set icon to selected, stub\n");
348
349         if (flags & SHGFI_SHELLICONSIZE)
350           FIXME("set icon to shell size, stub\n");
351
352         /* get the iconlocation */
353         if (SUCCEEDED(hr) && (flags & SHGFI_ICONLOCATION ))
354         {
355           UINT uDummy,uFlags;
356           hr = IShellFolder_GetUIObjectOf(psfParent, 0, 1, &pidlLast, &IID_IExtractIconA, &uDummy, (LPVOID*)&pei);
357
358           if (SUCCEEDED(hr))
359           {
360             hr = IExtractIconA_GetIconLocation(pei, (flags & SHGFI_OPENICON)? GIL_OPENICON : 0,szLoaction, MAX_PATH, &iIndex, &uFlags);
361             /* fixme what to do with the index? */
362
363             if(uFlags != GIL_NOTFILENAME)
364               strcpy (psfi->szDisplayName, szLoaction);
365             else
366               ret = FALSE;
367               
368             IExtractIconA_Release(pei);
369           }
370         }
371
372         /* get icon index (or load icon)*/
373         if (SUCCEEDED(hr) && (flags & (SHGFI_ICON | SHGFI_SYSICONINDEX)))
374         {
375
376           if (flags & SHGFI_USEFILEATTRIBUTES)
377           {
378             char sTemp [MAX_PATH];
379             char * szExt;
380             DWORD dwNr=0;
381
382             lstrcpynA(sTemp, path, MAX_PATH);
383             szExt = (LPSTR) PathFindExtensionA(sTemp);
384             if( szExt && HCR_MapTypeToValue(szExt, sTemp, MAX_PATH, TRUE)
385               && HCR_GetDefaultIcon(sTemp, sTemp, MAX_PATH, &dwNr))
386             {
387               if (!strcmp("%1",sTemp))            /* icon is in the file */
388               {
389                 strcpy(sTemp, path);
390               }
391               IconNotYetLoaded=FALSE;
392               psfi->iIcon = 0;
393               if (SHGFI_LARGEICON)
394                 PrivateExtractIconsA(sTemp,dwNr,GetSystemMetrics(SM_CXICON),
395                                      GetSystemMetrics(SM_CYICON),
396                                      &psfi->hIcon,0,1,0);
397               else
398                 PrivateExtractIconsA(sTemp,dwNr,GetSystemMetrics(SM_CXSMICON),
399                                      GetSystemMetrics(SM_CYSMICON),
400                                      &psfi->hIcon,0,1,0);
401             }
402             else                                  /* default icon */
403             {
404               psfi->iIcon = 0;
405             }          
406           }
407           else
408           {
409             if (!(PidlToSicIndex(psfParent, pidlLast, (flags & SHGFI_LARGEICON), 
410               (flags & SHGFI_OPENICON)? GIL_OPENICON : 0, &(psfi->iIcon))))
411             {
412               ret = FALSE;
413             }
414           }
415           if (ret) 
416           {
417             ret = (DWORD) ((flags & SHGFI_LARGEICON) ? ShellBigIconList : ShellSmallIconList);
418           }
419         }
420
421         /* icon handle */
422         if (SUCCEEDED(hr) && (flags & SHGFI_ICON) && IconNotYetLoaded)
423           psfi->hIcon = ImageList_GetIcon((flags & SHGFI_LARGEICON) ? ShellBigIconList:ShellSmallIconList, psfi->iIcon, ILD_NORMAL);
424
425         if (flags & (SHGFI_UNKNOWN1 | SHGFI_UNKNOWN2 | SHGFI_UNKNOWN3))
426           FIXME("unknown attribute!\n");
427
428         if (psfParent)
429           IShellFolder_Release(psfParent);
430
431         if (hr != S_OK)
432           ret = FALSE;
433
434         if(pidlLast) SHFree(pidlLast);
435 #ifdef MORE_DEBUG
436         TRACE ("icon=0x%08x index=0x%08x attr=0x%08lx name=%s type=%s ret=0x%08lx\n", 
437                 psfi->hIcon, psfi->iIcon, psfi->dwAttributes, psfi->szDisplayName, psfi->szTypeName, ret);
438 #endif
439         return ret;
440 }
441
442 /*************************************************************************
443  * SHGetFileInfoW                       [SHELL32.@]
444  */
445
446 DWORD WINAPI SHGetFileInfoW(LPCWSTR path,DWORD dwFileAttributes,
447                               SHFILEINFOW *psfi, UINT sizeofpsfi,
448                               UINT flags )
449 {
450         INT len;
451         LPSTR temppath;
452         DWORD ret;
453         SHFILEINFOA temppsfi;
454
455         len = WideCharToMultiByte(CP_ACP, 0, path, -1, NULL, 0, NULL, NULL);
456         temppath = HeapAlloc(GetProcessHeap(), 0, len);
457         WideCharToMultiByte(CP_ACP, 0, path, -1, temppath, len, NULL, NULL);
458
459         WideCharToMultiByte(CP_ACP, 0, psfi->szDisplayName, -1, temppsfi.szDisplayName,
460                             sizeof(temppsfi.szDisplayName), NULL, NULL);
461         WideCharToMultiByte(CP_ACP, 0, psfi->szTypeName, -1, temppsfi.szTypeName,
462                             sizeof(temppsfi.szTypeName), NULL, NULL);
463
464         ret = SHGetFileInfoA(temppath, dwFileAttributes, &temppsfi, sizeof(temppsfi), flags);
465
466         HeapFree(GetProcessHeap(), 0, temppath);
467         
468         return ret;
469 }
470
471 /*************************************************************************
472  * SHGetFileInfo                        [SHELL32.@]
473  */
474 DWORD WINAPI SHGetFileInfoAW(
475         LPCVOID path,
476         DWORD dwFileAttributes,
477         LPVOID psfi,
478         UINT sizeofpsfi,
479         UINT flags)
480 {
481         if(SHELL_OsIsUnicode())
482           return SHGetFileInfoW(path, dwFileAttributes, psfi, sizeofpsfi, flags );
483         return SHGetFileInfoA(path, dwFileAttributes, psfi, sizeofpsfi, flags );
484 }
485
486 /*************************************************************************
487  * DuplicateIcon                        [SHELL32.@]
488  */
489 HICON WINAPI DuplicateIcon( HINSTANCE hInstance, HICON hIcon)
490 {
491     ICONINFO IconInfo;
492     HICON hDupIcon = 0;
493
494     TRACE("(%04x, %04x)\n", hInstance, hIcon);
495
496     if(GetIconInfo(hIcon, &IconInfo))
497     {
498         hDupIcon = CreateIconIndirect(&IconInfo);
499
500         /* clean up hbmMask and hbmColor */
501         DeleteObject(IconInfo.hbmMask);        
502         DeleteObject(IconInfo.hbmColor);        
503     }
504  
505     return hDupIcon;
506 }
507     
508
509 /*************************************************************************
510  * ExtractIconA                         [SHELL32.@]
511  *
512  * FIXME
513  *  if the filename is not a file return 1
514  */
515 HICON WINAPI ExtractIconA( HINSTANCE hInstance, LPCSTR lpszExeFileName,
516         UINT nIconIndex )
517 {   HGLOBAL16 handle = InternalExtractIcon16(hInstance,lpszExeFileName,nIconIndex, 1);
518     TRACE("\n");
519     if( handle )
520     {
521         HICON16* ptr = (HICON16*)GlobalLock16(handle);
522         HICON16  hIcon = *ptr;
523
524         GlobalFree16(handle);
525         return hIcon;
526     }
527     return 0;
528 }
529
530 /*************************************************************************
531  * ExtractIconW                         [SHELL32.@]
532  *
533  * fixme
534  *  is the filename is not a file return 1
535  */
536 HICON WINAPI ExtractIconW( HINSTANCE hInstance, LPCWSTR lpszExeFileName,
537         UINT nIconIndex )
538 { LPSTR  exefn;
539   HICON  ret;
540   TRACE("\n");
541
542   exefn = HEAP_strdupWtoA(GetProcessHeap(),0,lpszExeFileName);
543   ret = ExtractIconA(hInstance,exefn,nIconIndex);
544
545         HeapFree(GetProcessHeap(),0,exefn);
546         return ret;
547 }
548
549 /*************************************************************************
550  * FindExecutableA                      [SHELL32.@]
551  */
552 HINSTANCE WINAPI FindExecutableA( LPCSTR lpFile, LPCSTR lpDirectory,
553                                       LPSTR lpResult )
554
555   HINSTANCE retval=31;    /* default - 'No association was found' */
556     char old_dir[1024];
557
558   TRACE("File %s, Dir %s\n", 
559                  (lpFile != NULL?lpFile:"-"), 
560                  (lpDirectory != NULL?lpDirectory:"-"));
561
562     lpResult[0]='\0'; /* Start off with an empty return string */
563
564     /* trap NULL parameters on entry */
565     if (( lpFile == NULL ) || ( lpResult == NULL ))
566   { /* FIXME - should throw a warning, perhaps! */
567         return 2; /* File not found. Close enough, I guess. */
568     }
569
570     if (lpDirectory)
571   { GetCurrentDirectoryA( sizeof(old_dir), old_dir );
572         SetCurrentDirectoryA( lpDirectory );
573     }
574
575     retval = SHELL_FindExecutable( lpFile, "open", lpResult );
576
577   TRACE("returning %s\n", lpResult);
578   if (lpDirectory)
579     SetCurrentDirectoryA( old_dir );
580     return retval;
581 }
582
583 /*************************************************************************
584  * FindExecutableW                      [SHELL32.@]
585  */
586 HINSTANCE WINAPI FindExecutableW(LPCWSTR lpFile, LPCWSTR lpDirectory,
587                                      LPWSTR lpResult)
588 {
589   FIXME("(%p,%p,%p): stub\n", lpFile, lpDirectory, lpResult);
590   return 31;    /* default - 'No association was found' */
591 }
592
593 typedef struct
594 { LPCSTR  szApp;
595     LPCSTR  szOtherStuff;
596     HICON hIcon;
597 } ABOUT_INFO;
598
599 #define         IDC_STATIC_TEXT         100
600 #define         IDC_LISTBOX             99
601 #define         IDC_WINE_TEXT           98
602
603 #define         DROP_FIELD_TOP          (-15)
604 #define         DROP_FIELD_HEIGHT       15
605
606 static HICON hIconTitleFont;
607
608 static BOOL __get_dropline( HWND hWnd, LPRECT lprect )
609 { HWND hWndCtl = GetDlgItem(hWnd, IDC_WINE_TEXT);
610     if( hWndCtl )
611   { GetWindowRect( hWndCtl, lprect );
612         MapWindowPoints( 0, hWnd, (LPPOINT)lprect, 2 );
613         lprect->bottom = (lprect->top += DROP_FIELD_TOP);
614         return TRUE;
615     }
616     return FALSE;
617 }
618
619 /*************************************************************************
620  * SHAppBarMessage                      [SHELL32.@]
621  */
622 UINT WINAPI SHAppBarMessage(DWORD msg, PAPPBARDATA data)
623 {
624         int width=data->rc.right - data->rc.left;
625         int height=data->rc.bottom - data->rc.top;
626         RECT rec=data->rc;
627         switch (msg)
628         { case ABM_GETSTATE:
629                return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
630           case ABM_GETTASKBARPOS:
631                GetWindowRect(data->hWnd, &rec);
632                data->rc=rec;
633                return TRUE;
634           case ABM_ACTIVATE:
635                SetActiveWindow(data->hWnd);
636                return TRUE;
637           case ABM_GETAUTOHIDEBAR:
638                data->hWnd=GetActiveWindow();
639                return TRUE;
640           case ABM_NEW:
641                SetWindowPos(data->hWnd,HWND_TOP,rec.left,rec.top,
642                                         width,height,SWP_SHOWWINDOW);
643                return TRUE;
644           case ABM_QUERYPOS:
645                GetWindowRect(data->hWnd, &(data->rc));
646                return TRUE;
647           case ABM_REMOVE:
648                FIXME("ABM_REMOVE broken\n");
649                /* FIXME: this is wrong; should it be DestroyWindow instead? */
650                /*CloseHandle(data->hWnd);*/
651                return TRUE;
652           case ABM_SETAUTOHIDEBAR:
653                SetWindowPos(data->hWnd,HWND_TOP,rec.left+1000,rec.top,
654                                        width,height,SWP_SHOWWINDOW);          
655                return TRUE;
656           case ABM_SETPOS:
657                data->uEdge=(ABE_RIGHT | ABE_LEFT);
658                SetWindowPos(data->hWnd,HWND_TOP,data->rc.left,data->rc.top,
659                                   width,height,SWP_SHOWWINDOW);
660                return TRUE;
661           case ABM_WINDOWPOSCHANGED:
662                SetWindowPos(data->hWnd,HWND_TOP,rec.left,rec.top,
663                                         width,height,SWP_SHOWWINDOW);
664                return TRUE;
665           }
666       return FALSE;
667 }
668
669 /*************************************************************************
670  * SHHelpShortcuts_RunDLL               [SHELL32.@]
671  *
672  */
673 DWORD WINAPI SHHelpShortcuts_RunDLL (DWORD dwArg1, DWORD dwArg2, DWORD dwArg3, DWORD dwArg4)
674 { FIXME("(%lx, %lx, %lx, %lx) empty stub!\n",
675         dwArg1, dwArg2, dwArg3, dwArg4);
676
677   return 0;
678 }
679
680 /*************************************************************************
681  * SHLoadInProc                         [SHELL32.@]
682  * Create an instance of specified object class from within 
683  * the shell process and release it immediately
684  */
685
686 DWORD WINAPI SHLoadInProc (REFCLSID rclsid)
687 {
688         IUnknown * pUnk = NULL;
689         TRACE("%s\n", debugstr_guid(rclsid));
690
691         CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown,(LPVOID*)pUnk);
692         if(pUnk)
693         {
694           IUnknown_Release(pUnk);
695           return NOERROR;
696         }
697         return DISP_E_MEMBERNOTFOUND;
698 }
699
700 /*************************************************************************
701  * ShellExecuteA                        [SHELL32.290]
702  */
703 HINSTANCE WINAPI ShellExecuteA( HWND hWnd, LPCSTR lpOperation,
704                                     LPCSTR lpFile, LPCSTR lpParameters,
705                                     LPCSTR lpDirectory, INT iShowCmd )
706 {   TRACE("\n");
707     return ShellExecute16( hWnd, lpOperation, lpFile, lpParameters,
708                            lpDirectory, iShowCmd );
709 }
710
711 /*************************************************************************
712  * ShellExecuteW                        [SHELL32.294]
713  * from shellapi.h
714  * WINSHELLAPI HINSTANCE APIENTRY ShellExecuteW(HWND hwnd, LPCWSTR lpOperation, 
715  * LPCWSTR lpFile, LPCWSTR lpParameters, LPCWSTR lpDirectory, INT nShowCmd);   
716  */
717 HINSTANCE WINAPI 
718 ShellExecuteW(
719        HWND hwnd, 
720        LPCWSTR lpOperation, 
721        LPCWSTR lpFile, 
722        LPCWSTR lpParameters, 
723        LPCWSTR lpDirectory, 
724        INT nShowCmd) {
725
726        FIXME(": stub\n");
727        return 0;
728 }
729
730 /*************************************************************************
731  * AboutDlgProc                 (internal)
732  */
733 BOOL WINAPI AboutDlgProc( HWND hWnd, UINT msg, WPARAM wParam,
734                               LPARAM lParam )
735 {   HWND hWndCtl;
736     char Template[512], AppTitle[512];
737
738     TRACE("\n");
739
740     switch(msg)
741     { case WM_INITDIALOG:
742       { ABOUT_INFO *info = (ABOUT_INFO *)lParam;
743             if (info)
744         { const char* const *pstr = SHELL_People;
745                 SendDlgItemMessageA(hWnd, stc1, STM_SETICON,info->hIcon, 0);
746                 GetWindowTextA( hWnd, Template, sizeof(Template) );
747                 sprintf( AppTitle, Template, info->szApp );
748                 SetWindowTextA( hWnd, AppTitle );
749                 SetWindowTextA( GetDlgItem(hWnd, IDC_STATIC_TEXT),
750                                   info->szOtherStuff );
751                 hWndCtl = GetDlgItem(hWnd, IDC_LISTBOX);
752                 SendMessageA( hWndCtl, WM_SETREDRAW, 0, 0 );
753                 if (!hIconTitleFont)
754                 {
755                     LOGFONTA logFont;
756                     SystemParametersInfoA( SPI_GETICONTITLELOGFONT, 0, &logFont, 0 );
757                     hIconTitleFont = CreateFontIndirectA( &logFont );
758                 }
759                 SendMessageA( hWndCtl, WM_SETFONT, hIconTitleFont, 0 );
760                 while (*pstr)
761           { SendMessageA( hWndCtl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)*pstr );
762                     pstr++;
763                 }
764                 SendMessageA( hWndCtl, WM_SETREDRAW, 1, 0 );
765             }
766         }
767         return 1;
768
769     case WM_PAINT:
770       { RECT rect;
771             PAINTSTRUCT ps;
772             HDC hDC = BeginPaint( hWnd, &ps );
773
774             if( __get_dropline( hWnd, &rect ) ) {
775                 SelectObject( hDC, GetStockObject( BLACK_PEN ) );
776                 MoveToEx( hDC, rect.left, rect.top, NULL );
777                 LineTo( hDC, rect.right, rect.bottom );
778             }
779             EndPaint( hWnd, &ps );
780         }
781         break;
782
783 #if 0  /* FIXME: should use DoDragDrop */
784     case WM_LBTRACKPOINT:
785         hWndCtl = GetDlgItem(hWnd, IDC_LISTBOX);
786         if( (INT16)GetKeyState( VK_CONTROL ) < 0 )
787       { if( DragDetect( hWndCtl, *((LPPOINT)&lParam) ) )
788         { INT idx = SendMessageA( hWndCtl, LB_GETCURSEL, 0, 0 );
789                 if( idx != -1 )
790           { INT length = SendMessageA( hWndCtl, LB_GETTEXTLEN, (WPARAM)idx, 0 );
791                     HGLOBAL16 hMemObj = GlobalAlloc16( GMEM_MOVEABLE, length + 1 );
792                     char* pstr = (char*)GlobalLock16( hMemObj );
793
794                     if( pstr )
795             { HCURSOR hCursor = LoadCursorA( 0, MAKEINTRESOURCEA(OCR_DRAGOBJECT) );
796                         SendMessageA( hWndCtl, LB_GETTEXT, (WPARAM)idx, (LPARAM)pstr );
797                         SendMessageA( hWndCtl, LB_DELETESTRING, (WPARAM)idx, 0 );
798                         UpdateWindow( hWndCtl );
799                         if( !DragObject16((HWND16)hWnd, (HWND16)hWnd, DRAGOBJ_DATA, 0, (WORD)hMemObj, hCursor) )
800                             SendMessageA( hWndCtl, LB_ADDSTRING, (WPARAM)-1, (LPARAM)pstr );
801                     }
802             if( hMemObj )
803               GlobalFree16( hMemObj );
804                 }
805             }
806         }
807         break;
808 #endif
809
810     case WM_QUERYDROPOBJECT:
811         if( wParam == 0 )
812       { LPDRAGINFO16 lpDragInfo = MapSL((SEGPTR)lParam);
813             if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA )
814         { RECT rect;
815                 if( __get_dropline( hWnd, &rect ) )
816           { POINT pt;
817             pt.x=lpDragInfo->pt.x;
818             pt.x=lpDragInfo->pt.y;
819                     rect.bottom += DROP_FIELD_HEIGHT;
820                     if( PtInRect( &rect, pt ) )
821             { SetWindowLongA( hWnd, DWL_MSGRESULT, 1 );
822                         return TRUE;
823                     }
824                 }
825             }
826         }
827         break;
828
829     case WM_DROPOBJECT:
830         if( wParam == hWnd )
831       { LPDRAGINFO16 lpDragInfo = MapSL((SEGPTR)lParam);
832             if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA && lpDragInfo->hList )
833         { char* pstr = (char*)GlobalLock16( (HGLOBAL16)(lpDragInfo->hList) );
834                 if( pstr )
835           { static char __appendix_str[] = " with";
836
837                     hWndCtl = GetDlgItem( hWnd, IDC_WINE_TEXT );
838                     SendMessageA( hWndCtl, WM_GETTEXT, 512, (LPARAM)Template );
839                     if( !strncmp( Template, "WINE", 4 ) )
840                         SetWindowTextA( GetDlgItem(hWnd, IDC_STATIC_TEXT), Template );
841                     else
842           { char* pch = Template + strlen(Template) - strlen(__appendix_str);
843                         *pch = '\0';
844                         SendMessageA( GetDlgItem(hWnd, IDC_LISTBOX), LB_ADDSTRING, 
845                                         (WPARAM)-1, (LPARAM)Template );
846                     }
847
848                     strcpy( Template, pstr );
849                     strcat( Template, __appendix_str );
850                     SetWindowTextA( hWndCtl, Template );
851                     SetWindowLongA( hWnd, DWL_MSGRESULT, 1 );
852                     return TRUE;
853                 }
854             }
855         }
856         break;
857
858     case WM_COMMAND:
859         if (wParam == IDOK)
860     {  EndDialog(hWnd, TRUE);
861             return TRUE;
862         }
863         break;
864     case WM_CLOSE:
865       EndDialog(hWnd, TRUE);
866       break;
867     }
868
869     return 0;
870 }
871
872
873 /*************************************************************************
874  * ShellAboutA                          [SHELL32.288]
875  */
876 BOOL WINAPI ShellAboutA( HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
877                              HICON hIcon )
878 {   ABOUT_INFO info;
879     HRSRC hRes;
880     LPVOID template;
881     TRACE("\n");
882
883     if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_ABOUT_MSGBOX", RT_DIALOGA)))
884         return FALSE;
885     if(!(template = (LPVOID)LoadResource(shell32_hInstance, hRes)))
886         return FALSE;
887
888     info.szApp        = szApp;
889     info.szOtherStuff = szOtherStuff;
890     info.hIcon        = hIcon;
891     if (!hIcon) info.hIcon = LoadIconA( 0, IDI_WINLOGOA );
892     return DialogBoxIndirectParamA( GetWindowLongA( hWnd, GWL_HINSTANCE ),
893                                       template, hWnd, AboutDlgProc, (LPARAM)&info );
894 }
895
896
897 /*************************************************************************
898  * ShellAboutW                          [SHELL32.289]
899  */
900 BOOL WINAPI ShellAboutW( HWND hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
901                              HICON hIcon )
902 {   BOOL ret;
903     ABOUT_INFO info;
904     HRSRC hRes;
905     LPVOID template;
906
907     TRACE("\n");
908     
909     if(!(hRes = FindResourceA(shell32_hInstance, "SHELL_ABOUT_MSGBOX", RT_DIALOGA)))
910         return FALSE;
911     if(!(template = (LPVOID)LoadResource(shell32_hInstance, hRes)))
912         return FALSE;
913
914     info.szApp        = HEAP_strdupWtoA( GetProcessHeap(), 0, szApp );
915     info.szOtherStuff = HEAP_strdupWtoA( GetProcessHeap(), 0, szOtherStuff );
916     info.hIcon        = hIcon;
917     if (!hIcon) info.hIcon = LoadIconA( 0, IDI_WINLOGOA );
918     ret = DialogBoxIndirectParamA( GetWindowLongA( hWnd, GWL_HINSTANCE ),
919                                    template, hWnd, AboutDlgProc, (LPARAM)&info );
920     HeapFree( GetProcessHeap(), 0, (LPSTR)info.szApp );
921     HeapFree( GetProcessHeap(), 0, (LPSTR)info.szOtherStuff );
922     return ret;
923 }
924
925 /*************************************************************************
926  * FreeIconList (SHELL32.@)
927  */
928 void WINAPI FreeIconList( DWORD dw )
929 { FIXME("(%lx): stub\n",dw);
930 }
931
932 /***********************************************************************
933  * DllGetVersion [SHELL32.@]
934  *
935  * Retrieves version information of the 'SHELL32.DLL'
936  *
937  * PARAMS
938  *     pdvi [O] pointer to version information structure.
939  *
940  * RETURNS
941  *     Success: S_OK
942  *     Failure: E_INVALIDARG
943  *
944  * NOTES
945  *     Returns version of a shell32.dll from IE4.01 SP1.
946  */
947
948 HRESULT WINAPI SHELL32_DllGetVersion (DLLVERSIONINFO *pdvi)
949 {
950         if (pdvi->cbSize != sizeof(DLLVERSIONINFO))
951         {
952           WARN("wrong DLLVERSIONINFO size from app\n");
953           return E_INVALIDARG;
954         }
955
956         pdvi->dwMajorVersion = 4;
957         pdvi->dwMinorVersion = 72;
958         pdvi->dwBuildNumber = 3110;
959         pdvi->dwPlatformID = 1;
960
961         TRACE("%lu.%lu.%lu.%lu\n",
962            pdvi->dwMajorVersion, pdvi->dwMinorVersion,
963            pdvi->dwBuildNumber, pdvi->dwPlatformID);
964
965         return S_OK;
966 }
967 /*************************************************************************
968  * global variables of the shell32.dll
969  * all are once per process
970  *
971  */
972 void    WINAPI (*pDLLInitComctl)(LPVOID);
973
974 LPVOID  WINAPI (*pCOMCTL32_Alloc) (INT);  
975 BOOL    WINAPI (*pCOMCTL32_Free) (LPVOID);  
976
977 HDPA    WINAPI (*pDPA_Create) (INT);  
978 INT     WINAPI (*pDPA_InsertPtr) (const HDPA, INT, LPVOID); 
979 BOOL    WINAPI (*pDPA_Sort) (const HDPA, PFNDPACOMPARE, LPARAM); 
980 LPVOID  WINAPI (*pDPA_GetPtr) (const HDPA, INT);   
981 BOOL    WINAPI (*pDPA_Destroy) (const HDPA); 
982 INT     WINAPI (*pDPA_Search) (const HDPA, LPVOID, INT, PFNDPACOMPARE, LPARAM, UINT);
983 LPVOID  WINAPI (*pDPA_DeletePtr) (const HDPA hdpa, INT i);
984 HANDLE  WINAPI (*pCreateMRUListA) (LPVOID lpcml);
985 DWORD   WINAPI (*pFreeMRUListA) (HANDLE hMRUList);
986 INT     WINAPI (*pAddMRUData) (HANDLE hList, LPCVOID lpData, DWORD cbData);
987 INT     WINAPI (*pFindMRUData) (HANDLE hList, LPCVOID lpData, DWORD cbData, LPINT lpRegNum);
988 INT     WINAPI (*pEnumMRUListA) (HANDLE hList, INT nItemPos, LPVOID lpBuffer, DWORD nBufferSize);
989
990 static HINSTANCE        hComctl32;
991
992 LONG            shell32_ObjCount = 0;
993 HINSTANCE       shell32_hInstance = 0; 
994 HIMAGELIST      ShellSmallIconList = 0;
995 HIMAGELIST      ShellBigIconList = 0;
996
997
998 /*************************************************************************
999  * SHELL32 LibMain
1000  *
1001  * NOTES
1002  *  calling oleinitialize here breaks sone apps.
1003  */
1004
1005 BOOL WINAPI Shell32LibMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID fImpLoad)
1006 {
1007         TRACE("0x%x 0x%lx %p\n", hinstDLL, fdwReason, fImpLoad);
1008
1009         switch (fdwReason)
1010         {
1011           case DLL_PROCESS_ATTACH:
1012             shell32_hInstance = hinstDLL;
1013             hComctl32 = GetModuleHandleA("COMCTL32.DLL");       
1014             DisableThreadLibraryCalls(shell32_hInstance);
1015
1016             if (!hComctl32)
1017             {
1018               ERR("P A N I C SHELL32 loading failed\n");
1019               return FALSE;
1020             }
1021
1022             /* comctl32 */
1023             pDLLInitComctl=(void*)GetProcAddress(hComctl32,"InitCommonControlsEx");
1024             pCOMCTL32_Alloc=(void*)GetProcAddress(hComctl32, (LPCSTR)71L);
1025             pCOMCTL32_Free=(void*)GetProcAddress(hComctl32, (LPCSTR)73L);
1026             pDPA_Create=(void*)GetProcAddress(hComctl32, (LPCSTR)328L);
1027             pDPA_Destroy=(void*)GetProcAddress(hComctl32, (LPCSTR)329L);
1028             pDPA_GetPtr=(void*)GetProcAddress(hComctl32, (LPCSTR)332L);
1029             pDPA_InsertPtr=(void*)GetProcAddress(hComctl32, (LPCSTR)334L);
1030             pDPA_DeletePtr=(void*)GetProcAddress(hComctl32, (LPCSTR)336L);
1031             pDPA_Sort=(void*)GetProcAddress(hComctl32, (LPCSTR)338L);
1032             pDPA_Search=(void*)GetProcAddress(hComctl32, (LPCSTR)339L);
1033             pCreateMRUListA=(void*)GetProcAddress(hComctl32, (LPCSTR)151L /*"CreateMRUListA"*/);
1034             pFreeMRUListA=(void*)GetProcAddress(hComctl32, (LPCSTR)152L /*"FreeMRUList"*/);
1035             pAddMRUData=(void*)GetProcAddress(hComctl32, (LPCSTR)167L /*"AddMRUData"*/);
1036             pFindMRUData=(void*)GetProcAddress(hComctl32, (LPCSTR)169L /*"FindMRUData"*/);
1037             pEnumMRUListA=(void*)GetProcAddress(hComctl32, (LPCSTR)154L /*"EnumMRUListA"*/);
1038
1039             /* initialize the common controls */
1040             if (pDLLInitComctl)
1041             {
1042               pDLLInitComctl(NULL);
1043             }
1044
1045             SIC_Initialize();
1046             SYSTRAY_Init();
1047             InitChangeNotifications();
1048             SHInitRestricted(NULL, NULL);
1049             break;
1050
1051           case DLL_THREAD_ATTACH:
1052             break;
1053
1054           case DLL_THREAD_DETACH:
1055             break;
1056
1057           case DLL_PROCESS_DETACH:
1058               shell32_hInstance = 0;
1059
1060               if (pdesktopfolder) 
1061               {
1062                 IShellFolder_Release(pdesktopfolder);
1063                 pdesktopfolder = NULL;
1064               }
1065
1066               SIC_Destroy();
1067               FreeChangeNotifications();
1068               
1069               /* this one is here to check if AddRef/Release is balanced */
1070               if (shell32_ObjCount)
1071               {
1072                 WARN("leaving with %lu objects left (memory leak)\n", shell32_ObjCount);
1073               }
1074               break;
1075         }
1076         return TRUE;
1077 }
1078
1079 /*************************************************************************
1080  * DllInstall         [SHELL32.@]
1081  *
1082  * PARAMETERS
1083  *   
1084  *    BOOL bInstall - TRUE for install, FALSE for uninstall
1085  *    LPCWSTR pszCmdLine - command line (unused by shell32?)
1086  */
1087
1088 HRESULT WINAPI SHELL32_DllInstall(BOOL bInstall, LPCWSTR cmdline)
1089 {
1090    FIXME("(%s, %s): stub!\n", bInstall ? "TRUE":"FALSE", debugstr_w(cmdline));
1091
1092    return S_OK;         /* indicate success */
1093 }
1094
1095 /***********************************************************************
1096  *              DllCanUnloadNow (SHELL32.@)
1097  */
1098 HRESULT WINAPI SHELL32_DllCanUnloadNow(void)
1099 {
1100     FIXME("(void): stub\n");
1101
1102     return S_FALSE;
1103 }