Release 980601
[wine] / misc / shell.c
1 /*
2  *                              Shell Library Functions
3  */
4 #include <assert.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <ctype.h>
9 #include "windows.h"
10 #include "winerror.h"
11 #include "file.h"
12 #include "shell.h"
13 #include "heap.h"
14 #include "module.h"
15 #include "neexe.h"
16 #include "resource.h"
17 #include "dlgs.h"
18 #include "win.h"
19 #include "graphics.h"
20 #include "cursoricon.h"
21 #include "interfaces.h"
22 #include "sysmetrics.h"
23 #include "shlobj.h"
24 #include "debug.h"
25 #include "winreg.h"
26
27 static const char * const SHELL_People[] =
28 {
29     "Bob Amstadt",
30     "Dag Asheim",
31     "Martin Ayotte",
32     "Karl Backstr\366m",
33     "Peter Bajusz",
34     "Marcel Baur",
35     "Georg Beyerle",
36     "Ross Biro",
37     "Martin Boehme",
38     "Uwe Bonnes",
39     "Erik Bos",
40     "Fons Botman",
41     "John Brezak",
42     "Andrew Bulhak",
43     "John Burton",
44     "Niels de Carpentier",
45     "Gordon Chaffee",
46     "Jimen Ching",
47     "Pascal Cuoq",
48     "David A. Cuthbert",
49     "Huw D. M. Davies",
50     "Roman Dolejsi",
51     "Frans van Dorsselaer",
52     "Chris Faherty",
53     "Carsten Fallesen",
54     "Paul Falstad",
55     "David Faure",
56     "Claus Fischer",
57     "Olaf Flebbe",
58     "Chad Fraleigh",
59     "Matthew Francis",
60     "Peter Galbavy",
61     "Ramon Garcia",
62     "Matthew Ghio",
63     "Jody Goldberg",
64     "Hans de Graaff",
65     "Charles M. Hannum",
66     "Adrian Harvey",
67     "John Harvey",
68     "Bill Hawes",
69     "Cameron Heide",
70     "Jochen Hoenicke",
71     "Onno Hovers",
72     "Jeffrey Hsu",
73     "Miguel de Icaza",
74     "Jukka Iivonen",
75     "Lee Jaekil",
76     "Alexandre Julliard",
77     "Bang Jun-Young",
78     "Pavel Kankovsky",
79     "Jochen Karrer",
80     "Andreas Kirschbaum",
81     "Albrecht Kleine",
82     "Eric Kohl",
83     "Jon Konrath",
84     "Alex Korobka",
85     "Greg Kreider",
86     "Anand Kumria",
87     "Scott A. Laird",
88     "David Lee Lambert",
89     "Andrew Lewycky",
90     "Martin von Loewis",
91     "Michiel van Loon",
92     "Kenneth MacDonald",
93     "Peter MacDonald",
94     "William Magro",
95     "Juergen Marquardt",
96     "Ricardo Massaro",
97     "Marcus Meissner",
98     "Graham Menhennitt",
99     "David Metcalfe",
100     "Bruce Milner",
101     "Steffen Moeller",
102     "Andreas Mohr",
103     "James Moody",
104     "Philippe De Muyter",
105     "Itai Nahshon",
106     "Kristian Nielsen",
107     "Henrik Olsen",
108     "Michael Patra",
109     "Dimitrie O. Paun",
110     "Jim Peterson",
111     "Robert Pouliot",
112     "Keith Reynolds",
113     "Slaven Rezic",
114     "John Richardson",
115     "Rick Richardson",
116     "Doug Ridgway",
117     "Bernhard Rosenkraenzer",
118     "Johannes Ruscheinski",
119     "Thomas Sandford",
120     "Constantine Sapuntzakis",
121     "Pablo Saratxaga",
122     "Daniel Schepler",
123     "Peter Schlaile",
124     "Ulrich Schmid",
125     "Bernd Schmidt",
126     "Ingo Schneider",
127     "Victor Schneider",
128     "Yngvi Sigurjonsson",
129     "Stephen Simmons",
130     "Rick Sladkey",
131     "William Smith",
132     "Dominik Strasser",
133     "Vadim Strizhevsky",
134     "Bertho Stultiens",
135     "Erik Svendsen",
136     "Tristan Tarrant",
137     "Andrew Taylor",
138     "Duncan C Thomson",
139     "Goran Thyni",
140     "Jimmy Tirtawangsa",
141     "Jon Tombs",
142     "Linus Torvalds",
143     "Gregory Trubetskoy",
144     "Petri Tuomola",
145     "Michael Veksler",
146     "Sven Verdoolaege",
147     "Ronan Waide",
148     "Eric Warnke",
149     "Manfred Weichel",
150     "Ulrich Weigand",
151     "Morten Welinder",
152     "Len White",
153     "Lawson Whitney",
154     "Jan Willamowius",
155     "Carl Williams",
156     "Karl Guenter Wuensch",
157     "Eric Youngdale",
158     "James Youngman",
159     "Nikita V. Youshchenko",
160     "Mikolaj Zalewski",
161     "John Zero",
162     "Luiz Otavio L. Zorzella",
163     NULL
164 };
165
166
167 /* .ICO file ICONDIR definitions */
168
169 #pragma pack(1)
170
171 typedef struct
172 {
173     BYTE        bWidth;          /* Width, in pixels, of the image      */
174     BYTE        bHeight;         /* Height, in pixels, of the image     */
175     BYTE        bColorCount;     /* Number of colors in image (0 if >=8bpp) */
176     BYTE        bReserved;       /* Reserved ( must be 0)               */
177     WORD        wPlanes;         /* Color Planes                        */
178     WORD        wBitCount;       /* Bits per pixel                      */
179     DWORD       dwBytesInRes;    /* How many bytes in this resource?    */
180     DWORD       dwImageOffset;   /* Where in the file is this image?    */
181 } icoICONDIRENTRY, *LPicoICONDIRENTRY;
182
183 typedef struct
184 {
185     WORD            idReserved;   /* Reserved (must be 0)               */
186     WORD            idType;       /* Resource Type (1 for icons)        */
187     WORD            idCount;      /* How many images?                   */
188     icoICONDIRENTRY idEntries[1]; /* An entry for each image (idCount of 'em) */
189 } icoICONDIR, *LPicoICONDIR;
190
191 #pragma pack(4)
192
193 static const char*      lpstrMsgWndCreated = "OTHERWINDOWCREATED";
194 static const char*      lpstrMsgWndDestroyed = "OTHERWINDOWDESTROYED";
195 static const char*      lpstrMsgShellActivate = "ACTIVATESHELLWINDOW";
196
197 static HWND16   SHELL_hWnd = 0;
198 static HHOOK    SHELL_hHook = 0;
199 static UINT16   uMsgWndCreated = 0;
200 static UINT16   uMsgWndDestroyed = 0;
201 static UINT16   uMsgShellActivate = 0;
202
203 /*************************************************************************
204  *                              DragAcceptFiles         [SHELL.9]
205  */
206 void WINAPI DragAcceptFiles(HWND16 hWnd, BOOL16 b)
207 {
208     WND* wnd = WIN_FindWndPtr(hWnd);
209
210     if( wnd )
211         wnd->dwExStyle = b? wnd->dwExStyle | WS_EX_ACCEPTFILES
212                           : wnd->dwExStyle & ~WS_EX_ACCEPTFILES;
213 }
214
215
216 /*************************************************************************
217  *                              DragQueryFile           [SHELL.11]
218  */
219 UINT16 WINAPI DragQueryFile(HDROP16 hDrop, WORD wFile, LPSTR lpszFile,
220                             WORD wLength)
221 {
222     /* hDrop is a global memory block allocated with GMEM_SHARE 
223      * with DROPFILESTRUCT as a header and filenames following
224      * it, zero length filename is in the end */       
225     
226     LPDROPFILESTRUCT lpDropFileStruct;
227     LPSTR lpCurrent;
228     WORD  i;
229     
230     TRACE(reg,"(%04x, %i, %p, %u)\n",
231                 hDrop,wFile,lpszFile,wLength);
232     
233     lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop); 
234     if(!lpDropFileStruct) return 0;
235
236     lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
237     
238     i = 0;
239     while (i++ < wFile)
240     {
241         while (*lpCurrent++);  /* skip filename */
242         if (!*lpCurrent) 
243             return (wFile == 0xFFFF) ? i : 0;  
244     }
245     
246     i = strlen(lpCurrent); 
247     if (!lpszFile) return i+1;   /* needed buffer size */
248     
249     i = (wLength > i) ? i : wLength-1;
250     strncpy(lpszFile, lpCurrent, i);
251     lpszFile[i] = '\0';
252
253     GlobalUnlock16(hDrop);
254     return i;
255 }
256
257
258 /*************************************************************************
259  *                              DragFinish              [SHELL.12]
260  */
261 void WINAPI DragFinish(HDROP16 h)
262 {
263     GlobalFree16((HGLOBAL16)h);
264 }
265
266
267 /*************************************************************************
268  *                              DragQueryPoint          [SHELL.13]
269  */
270 BOOL16 WINAPI DragQueryPoint(HDROP16 hDrop, POINT16 *p)
271 {
272     LPDROPFILESTRUCT lpDropFileStruct;  
273     BOOL16           bRet;
274
275     lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
276
277     memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT16));
278     bRet = lpDropFileStruct->fInNonClientArea;
279
280     GlobalUnlock16(hDrop);
281     return bRet;
282 }
283
284 /*************************************************************************
285  *      SHELL_FindExecutable [Internal]
286  *
287  * Utility for code sharing between FindExecutable and ShellExecute
288  */
289 static HINSTANCE32 SHELL_FindExecutable( LPCSTR lpFile, 
290                                          LPCSTR lpOperation,
291                                          LPSTR lpResult)
292 {
293     char *extension = NULL; /* pointer to file extension */
294     char tmpext[5];         /* local copy to mung as we please */
295     char filetype[256];     /* registry name for this filetype */
296     LONG filetypelen=256;   /* length of above */
297     char command[256];      /* command from registry */
298     LONG commandlen=256;    /* This is the most DOS can handle :) */
299     char buffer[256];       /* Used to GetProfileString */
300     HINSTANCE32 retval=31;  /* default - 'No association was found' */
301     char *tok;              /* token pointer */
302     int i;                  /* random counter */
303     char xlpFile[256];      /* result of SearchPath */
304
305     TRACE(exec, "%s\n", (lpFile != NULL?lpFile:"-") );
306
307     lpResult[0]='\0'; /* Start off with an empty return string */
308
309     /* trap NULL parameters on entry */
310     if (( lpFile == NULL ) || ( lpResult == NULL ) || ( lpOperation == NULL ))
311     {
312         WARN(exec, "(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
313            lpFile, lpOperation, lpResult);
314         return 2; /* File not found. Close enough, I guess. */
315     }
316
317     if (SearchPath32A( NULL, lpFile,".exe",sizeof(xlpFile),xlpFile,NULL))
318     {
319         TRACE(exec, "SearchPath32A returned non-zero\n");
320         lpFile = xlpFile;
321     }
322
323     /* First thing we need is the file's extension */
324     extension = strrchr( xlpFile, '.' ); /* Assume last "." is the one; */
325                                         /* File->Run in progman uses */
326                                         /* .\FILE.EXE :( */
327     TRACE(exec, "xlpFile=%s,extension=%s\n", xlpFile, extension);
328
329     if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)]))
330     {
331         WARN(exec, "Returning 31 - No association\n");
332         return 31; /* no association */
333     }
334
335     /* Make local copy & lowercase it for reg & 'programs=' lookup */
336     lstrcpyn32A( tmpext, extension, 5 );
337     CharLower32A( tmpext );
338     TRACE(exec, "%s file\n", tmpext);
339     
340     /* Three places to check: */
341     /* 1. win.ini, [windows], programs (NB no leading '.') */
342     /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
343     /* 3. win.ini, [extensions], extension (NB no leading '.' */
344     /* All I know of the order is that registry is checked before */
345     /* extensions; however, it'd make sense to check the programs */
346     /* section first, so that's what happens here. */
347
348     /* See if it's a program - if GetProfileString fails, we skip this
349      * section. Actually, if GetProfileString fails, we've probably
350      * got a lot more to worry about than running a program... */
351     if ( GetProfileString32A("windows", "programs", "exe pif bat com",
352                                                   buffer, sizeof(buffer)) > 0 )
353           {
354                 for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
355
356                 tok = strtok(buffer, " \t"); /* ? */
357                 while( tok!= NULL)
358                   {
359                         if (strcmp(tok, &tmpext[1])==0) /* have to skip the leading "." */
360                           {
361                                 strcpy(lpResult, xlpFile);
362                                 /* Need to perhaps check that the file has a path
363                                  * attached */
364                                 TRACE(exec, "found %s\n",
365                                                          lpResult);
366                                 return 33;
367
368                 /* Greater than 32 to indicate success FIXME According to the
369                  * docs, I should be returning a handle for the
370                  * executable. Does this mean I'm supposed to open the
371                  * executable file or something? More RTFM, I guess... */
372                           }
373                         tok=strtok(NULL, " \t");
374                   }
375           }
376
377     /* Check registry */
378     if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, tmpext, filetype,
379                          &filetypelen ) == SHELL_ERROR_SUCCESS )
380     {
381         filetype[filetypelen]='\0';
382         TRACE(exec, "File type: %s\n",
383                      filetype);
384
385         /* Looking for ...buffer\shell\lpOperation\command */
386         strcat( filetype, "\\shell\\" );
387         strcat( filetype, lpOperation );
388         strcat( filetype, "\\command" );
389         
390         if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, filetype, command,
391                              &commandlen ) == SHELL_ERROR_SUCCESS )
392         {
393             /* Is there a replace() function anywhere? */
394             command[commandlen]='\0';
395             strcpy( lpResult, command );
396             tok=strstr( lpResult, "%1" );
397             if (tok != NULL)
398             {
399                 tok[0]='\0'; /* truncate string at the percent */
400                 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
401                 tok=strstr( command, "%1" );
402                 if ((tok!=NULL) && (strlen(tok)>2))
403                 {
404                     strcat( lpResult, &tok[2] );
405                 }
406             }
407             retval=33; /* FIXME see above */
408         }
409     }
410     else /* Check win.ini */
411     {
412         /* Toss the leading dot */
413         extension++;
414         if ( GetProfileString32A( "extensions", extension, "", command,
415                                   sizeof(command)) > 0)
416           {
417                 if (strlen(command)!=0)
418                   {
419                         strcpy( lpResult, command );
420                         tok=strstr( lpResult, "^" ); /* should be ^.extension? */
421                         if (tok != NULL)
422                           {
423                                 tok[0]='\0';
424                                 strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
425                                 tok=strstr( command, "^" ); /* see above */
426                                 if ((tok != NULL) && (strlen(tok)>5))
427                                   {
428                                         strcat( lpResult, &tok[5]);
429                                   }
430                           }
431                         retval=33; /* FIXME - see above */
432                   }
433           }
434         }
435
436     TRACE(exec, "returning %s\n", lpResult);
437     return retval;
438 }
439
440 /*************************************************************************
441  *                              ShellExecute16          [SHELL.20]
442  */
443 HINSTANCE16 WINAPI ShellExecute16( HWND16 hWnd, LPCSTR lpOperation,
444                                    LPCSTR lpFile, LPCSTR lpParameters,
445                                    LPCSTR lpDirectory, INT16 iShowCmd )
446 {
447     HINSTANCE16 retval=31;
448     char old_dir[1024];
449     char cmd[256];
450
451     TRACE(exec, "(%04x,'%s','%s','%s','%s',%x)\n",
452                 hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
453                 lpParameters ? lpParameters : "<null>", 
454                 lpDirectory ? lpDirectory : "<null>", iShowCmd);
455
456     if (lpFile==NULL) return 0; /* should not happen */
457     if (lpOperation==NULL) /* default is open */
458       lpOperation="open";
459
460     if (lpDirectory)
461     {
462         GetCurrentDirectory32A( sizeof(old_dir), old_dir );
463         SetCurrentDirectory32A( lpDirectory );
464     }
465
466     retval = SHELL_FindExecutable( lpFile, lpOperation, cmd );
467
468     if (retval > 32)  /* Found */
469     {
470         if (lpParameters)
471         {
472             strcat(cmd," ");
473             strcat(cmd,lpParameters);
474         }
475
476         TRACE(exec,"starting %s\n",cmd);
477         retval = WinExec32( cmd, iShowCmd );
478     }
479     if (lpDirectory) SetCurrentDirectory32A( old_dir );
480     return retval;
481 }
482
483
484 /*************************************************************************
485  *             ShellExecute32A   (SHELL32.245)
486  */
487 HINSTANCE32 WINAPI ShellExecute32A( HWND32 hWnd, LPCSTR lpOperation,
488                                     LPCSTR lpFile, LPCSTR lpParameters,
489                                     LPCSTR lpDirectory, INT32 iShowCmd )
490 {
491     return ShellExecute16( hWnd, lpOperation, lpFile, lpParameters,
492                            lpDirectory, iShowCmd );
493 }
494
495
496 /*************************************************************************
497  *             FindExecutable16   (SHELL.21)
498  */
499 HINSTANCE16 WINAPI FindExecutable16( LPCSTR lpFile, LPCSTR lpDirectory,
500                                      LPSTR lpResult )
501 {
502     return (HINSTANCE16)FindExecutable32A( lpFile, lpDirectory, lpResult );
503 }
504
505 /*************************************************************************
506  *             FindExecutable32A   (SHELL32.184)
507  */
508 HINSTANCE32 WINAPI FindExecutable32A( LPCSTR lpFile, LPCSTR lpDirectory,
509                                       LPSTR lpResult )
510 {
511     HINSTANCE32 retval=31;    /* default - 'No association was found' */
512     char old_dir[1024];
513
514     TRACE(exec, "File %s, Dir %s\n", 
515                  (lpFile != NULL?lpFile:"-"), 
516                  (lpDirectory != NULL?lpDirectory:"-"));
517
518     lpResult[0]='\0'; /* Start off with an empty return string */
519
520     /* trap NULL parameters on entry */
521     if (( lpFile == NULL ) || ( lpResult == NULL ))
522     {
523         /* FIXME - should throw a warning, perhaps! */
524         return 2; /* File not found. Close enough, I guess. */
525     }
526
527     if (lpDirectory)
528     {
529         GetCurrentDirectory32A( sizeof(old_dir), old_dir );
530         SetCurrentDirectory32A( lpDirectory );
531     }
532
533     retval = SHELL_FindExecutable( lpFile, "open", lpResult );
534
535     TRACE(exec, "returning %s\n", lpResult);
536     if (lpDirectory) SetCurrentDirectory32A( old_dir );
537     return retval;
538 }
539
540 typedef struct
541 {
542     LPCSTR  szApp;
543     LPCSTR  szOtherStuff;
544     HICON32 hIcon;
545 } ABOUT_INFO;
546
547 #define         IDC_STATIC_TEXT         100
548 #define         IDC_LISTBOX             99
549 #define         IDC_WINE_TEXT           98
550
551 #define         DROP_FIELD_TOP          (-15)
552 #define         DROP_FIELD_HEIGHT       15
553
554 extern HICON32 hIconTitleFont;
555
556 static BOOL32 __get_dropline( HWND32 hWnd, LPRECT32 lprect )
557 {
558     HWND32 hWndCtl = GetDlgItem32(hWnd, IDC_WINE_TEXT);
559     if( hWndCtl )
560     {
561         GetWindowRect32( hWndCtl, lprect );
562         MapWindowPoints32( 0, hWnd, (LPPOINT32)lprect, 2 );
563         lprect->bottom = (lprect->top += DROP_FIELD_TOP);
564         return TRUE;
565     }
566     return FALSE;
567 }
568
569 /*************************************************************************
570  *             AboutDlgProc32  (not an exported API function)
571  */
572 LRESULT WINAPI AboutDlgProc32( HWND32 hWnd, UINT32 msg, WPARAM32 wParam,
573                                LPARAM lParam )
574 {
575     HWND32 hWndCtl;
576     char Template[512], AppTitle[512];
577
578     switch(msg)
579     {
580     case WM_INITDIALOG:
581         {
582             ABOUT_INFO *info = (ABOUT_INFO *)lParam;
583             if (info)
584             {
585                 const char* const *pstr = SHELL_People;
586                 SendDlgItemMessage32A(hWnd, stc1, STM_SETICON32,info->hIcon, 0);
587                 GetWindowText32A( hWnd, Template, sizeof(Template) );
588                 sprintf( AppTitle, Template, info->szApp );
589                 SetWindowText32A( hWnd, AppTitle );
590                 SetWindowText32A( GetDlgItem32(hWnd, IDC_STATIC_TEXT),
591                                   info->szOtherStuff );
592                 hWndCtl = GetDlgItem32(hWnd, IDC_LISTBOX);
593                 SendMessage32A( hWndCtl, WM_SETREDRAW, 0, 0 );
594                 SendMessage32A( hWndCtl, WM_SETFONT, hIconTitleFont, 0 );
595                 while (*pstr)
596                 {
597                     SendMessage32A( hWndCtl, LB_ADDSTRING32,
598                                     (WPARAM32)-1, (LPARAM)*pstr );
599                     pstr++;
600                 }
601                 SendMessage32A( hWndCtl, WM_SETREDRAW, 1, 0 );
602             }
603         }
604         return 1;
605
606     case WM_PAINT:
607         {
608             RECT32 rect;
609             PAINTSTRUCT32 ps;
610             HDC32 hDC = BeginPaint32( hWnd, &ps );
611
612             if( __get_dropline( hWnd, &rect ) )
613                 GRAPH_DrawLines( hDC, (LPPOINT32)&rect, 1, GetStockObject32( BLACK_PEN ) );
614             EndPaint32( hWnd, &ps );
615         }
616         break;
617
618     case WM_LBTRACKPOINT:
619
620         hWndCtl = GetDlgItem32(hWnd, IDC_LISTBOX);
621         if( (INT16)GetKeyState16( VK_CONTROL ) < 0 )
622         {
623             if( DragDetect32( hWndCtl, *((LPPOINT32)&lParam) ) )
624             {
625                 INT32 idx = SendMessage32A( hWndCtl, LB_GETCURSEL32, 0, 0 );
626                 if( idx != -1 )
627                 {
628                     INT32 length = SendMessage32A( hWndCtl, LB_GETTEXTLEN32, (WPARAM32)idx, 0 );
629                     HGLOBAL16 hMemObj = GlobalAlloc16( GMEM_MOVEABLE, length + 1 );
630                     char* pstr = (char*)GlobalLock16( hMemObj );
631
632                     if( pstr )
633                     {
634                         HCURSOR16 hCursor = LoadCursor16( 0, MAKEINTRESOURCE16(OCR_DRAGOBJECT) );
635                         SendMessage32A( hWndCtl, LB_GETTEXT32, (WPARAM32)idx, (LPARAM)pstr );
636                         SendMessage32A( hWndCtl, LB_DELETESTRING32, (WPARAM32)idx, 0 );
637                         UpdateWindow32( hWndCtl );
638                         if( !DragObject16((HWND16)hWnd, (HWND16)hWnd, DRAGOBJ_DATA, 0, (WORD)hMemObj, hCursor) )
639                             SendMessage32A( hWndCtl, LB_ADDSTRING32, (WPARAM32)-1, (LPARAM)pstr );
640                     }
641                     if( hMemObj ) GlobalFree16( hMemObj );
642                 }
643             }
644         }
645         break;
646
647     case WM_QUERYDROPOBJECT:
648         if( wParam == 0 )
649         {
650             LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
651             if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA )
652             {
653                 RECT32 rect;
654                 if( __get_dropline( hWnd, &rect ) )
655                 {
656                     POINT32 pt = { lpDragInfo->pt.x, lpDragInfo->pt.y };
657                     rect.bottom += DROP_FIELD_HEIGHT;
658                     if( PtInRect32( &rect, pt ) )
659                     {
660                         SetWindowLong32A( hWnd, DWL_MSGRESULT, 1 );
661                         return TRUE;
662                     }
663                 }
664             }
665         }
666         break;
667
668     case WM_DROPOBJECT:
669         if( wParam == hWnd )
670         {
671             LPDRAGINFO lpDragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN((SEGPTR)lParam);
672             if( lpDragInfo && lpDragInfo->wFlags == DRAGOBJ_DATA && lpDragInfo->hList )
673             {
674                 char* pstr = (char*)GlobalLock16( (HGLOBAL16)(lpDragInfo->hList) );
675                 if( pstr )
676                 {
677                     static char __appendix_str[] = " with";
678
679                     hWndCtl = GetDlgItem32( hWnd, IDC_WINE_TEXT );
680                     SendMessage32A( hWndCtl, WM_GETTEXT, 512, (LPARAM)Template );
681                     if( !lstrncmp32A( Template, "WINE", 4 ) )
682                         SetWindowText32A( GetDlgItem32(hWnd, IDC_STATIC_TEXT), Template );
683                     else
684                     {
685                         char* pch = Template + strlen(Template) - strlen(__appendix_str);
686                         *pch = '\0';
687                         SendMessage32A( GetDlgItem32(hWnd, IDC_LISTBOX), LB_ADDSTRING32, 
688                                         (WPARAM32)-1, (LPARAM)Template );
689                     }
690
691                     lstrcpy32A( Template, pstr );
692                     lstrcat32A( Template, __appendix_str );
693                     SetWindowText32A( hWndCtl, Template );
694
695                     SetWindowLong32A( hWnd, DWL_MSGRESULT, 1 );
696                     return TRUE;
697                 }
698             }
699         }
700         break;
701
702     case WM_COMMAND:
703         if (wParam == IDOK)
704         {
705             EndDialog32(hWnd, TRUE);
706             return TRUE;
707         }
708         break;
709     }
710     return 0;
711 }
712
713
714 /*************************************************************************
715  *             AboutDlgProc16   (SHELL.33)
716  */
717 LRESULT WINAPI AboutDlgProc16( HWND16 hWnd, UINT16 msg, WPARAM16 wParam,
718                                LPARAM lParam )
719 {
720     return AboutDlgProc32( hWnd, msg, wParam, lParam );
721 }
722
723
724 /*************************************************************************
725  *             ShellAbout16   (SHELL.22)
726  */
727 BOOL16 WINAPI ShellAbout16( HWND16 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
728                             HICON16 hIcon )
729 {
730     return ShellAbout32A( hWnd, szApp, szOtherStuff, hIcon );
731 }
732
733 /*************************************************************************
734  *             ShellAbout32A   (SHELL32.243)
735  */
736 BOOL32 WINAPI ShellAbout32A( HWND32 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
737                              HICON32 hIcon )
738 {
739     ABOUT_INFO info;
740     info.szApp        = szApp;
741     info.szOtherStuff = szOtherStuff;
742     info.hIcon        = hIcon;
743     if (!hIcon) info.hIcon = LoadIcon16( 0, MAKEINTRESOURCE16(OIC_WINEICON) );
744     return DialogBoxIndirectParam32A( WIN_GetWindowInstance( hWnd ),
745                          SYSRES_GetResPtr( SYSRES_DIALOG_SHELL_ABOUT_MSGBOX ),
746                                       hWnd, AboutDlgProc32, (LPARAM)&info );
747 }
748
749
750 /*************************************************************************
751  *             ShellAbout32W   (SHELL32.244)
752  */
753 BOOL32 WINAPI ShellAbout32W( HWND32 hWnd, LPCWSTR szApp, LPCWSTR szOtherStuff,
754                              HICON32 hIcon )
755 {
756     BOOL32 ret;
757     ABOUT_INFO info;
758
759     info.szApp        = HEAP_strdupWtoA( GetProcessHeap(), 0, szApp );
760     info.szOtherStuff = HEAP_strdupWtoA( GetProcessHeap(), 0, szOtherStuff );
761     info.hIcon        = hIcon;
762     if (!hIcon) info.hIcon = LoadIcon16( 0, MAKEINTRESOURCE16(OIC_WINEICON) );
763     ret = DialogBoxIndirectParam32A( WIN_GetWindowInstance( hWnd ),
764                          SYSRES_GetResPtr( SYSRES_DIALOG_SHELL_ABOUT_MSGBOX ),
765                                       hWnd, AboutDlgProc32, (LPARAM)&info );
766     HeapFree( GetProcessHeap(), 0, (LPSTR)info.szApp );
767     HeapFree( GetProcessHeap(), 0, (LPSTR)info.szOtherStuff );
768     return ret;
769 }
770
771 /*************************************************************************
772  *                              Shell_NotifyIcon        [SHELL32.249]
773  *      FIXME
774  *      This function is supposed to deal with the systray.
775  *      Any ideas on how this is to be implimented?
776  */
777 BOOL32 WINAPI Shell_NotifyIcon( DWORD dwMessage,
778                                 PNOTIFYICONDATA pnid )
779 {
780     return FALSE;
781 }
782
783 /*************************************************************************
784  *                              Shell_NotifyIcon        [SHELL32.240]
785  *      FIXME
786  *      This function is supposed to deal with the systray.
787  *      Any ideas on how this is to be implimented?
788  */
789 BOOL32 WINAPI Shell_NotifyIconA(DWORD dwMessage,
790                                 PNOTIFYICONDATA pnid )
791 {
792     return FALSE;
793 }
794
795 /*************************************************************************
796  *                              SHELL_GetResourceTable
797  */
798 static DWORD SHELL_GetResourceTable(HFILE32 hFile,LPBYTE *retptr)
799 {
800   IMAGE_DOS_HEADER      mz_header;
801   char                  magic[4];
802   int                   size;
803   
804   *retptr = NULL;
805   _llseek32( hFile, 0, SEEK_SET );
806   if (  (_lread32(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
807         (mz_header.e_magic != IMAGE_DOS_SIGNATURE)
808   ) { /* .ICO file ? */
809         if (mz_header.e_cblp == 1) { /* ICONHEADER.idType, must be 1 */
810             *retptr = (LPBYTE)-1;
811             return 1;
812         }
813         else
814             return 0; /* failed */
815   }
816   _llseek32( hFile, mz_header.e_lfanew, SEEK_SET );
817   if (_lread32( hFile, magic, sizeof(magic) ) != sizeof(magic))
818         return 0;
819   _llseek32( hFile, mz_header.e_lfanew, SEEK_SET);
820
821   if (*(DWORD*)magic  == IMAGE_NT_SIGNATURE)
822         return IMAGE_NT_SIGNATURE;
823   if (*(WORD*)magic == IMAGE_OS2_SIGNATURE) {
824         IMAGE_OS2_HEADER        ne_header;
825         LPBYTE                  pTypeInfo = (LPBYTE)-1;
826
827         if (_lread32(hFile,&ne_header,sizeof(ne_header))!=sizeof(ne_header))
828                 return 0;
829
830         if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return 0;
831         size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
832         if( size > sizeof(NE_TYPEINFO) )
833         {
834             pTypeInfo = (BYTE*)HeapAlloc( GetProcessHeap(), 0, size);
835             if( pTypeInfo ) {
836                 _llseek32(hFile, mz_header.e_lfanew+ne_header.resource_tab_offset, SEEK_SET);
837                 if( _lread32( hFile, (char*)pTypeInfo, size) != size ) { 
838                     HeapFree( GetProcessHeap(), 0, pTypeInfo); 
839                     pTypeInfo = NULL;
840                 }
841             }
842         }
843         *retptr = pTypeInfo;
844         return IMAGE_OS2_SIGNATURE;
845   } else
846         return 0; /* failed */
847 }
848
849 /*************************************************************************
850  *                      SHELL_LoadResource
851  */
852 static HGLOBAL16 SHELL_LoadResource(HINSTANCE16 hInst, HFILE32 hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
853 {
854  BYTE*  ptr;
855  HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
856
857  if( (ptr = (BYTE*)GlobalLock16( handle )) )
858    {
859     _llseek32( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
860      _lread32( hFile, (char*)ptr, pNInfo->length << sizeShift);
861      return handle;
862    }
863  return 0;
864 }
865
866 /*************************************************************************
867  *                      ICO_LoadIcon
868  */
869 static HGLOBAL16 ICO_LoadIcon(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIRENTRY lpiIDE)
870 {
871  BYTE*  ptr;
872  HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, lpiIDE->dwBytesInRes);
873
874  if( (ptr = (BYTE*)GlobalLock16( handle )) )
875    {
876     _llseek32( hFile, lpiIDE->dwImageOffset, SEEK_SET);
877      _lread32( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
878      return handle;
879    }
880  return 0;
881 }
882
883 /*************************************************************************
884  *                      ICO_GetIconDirectory
885  *
886  *  Read .ico file and build phony ICONDIR struct for GetIconID
887  */
888 static HGLOBAL16 ICO_GetIconDirectory(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIR* lplpiID ) 
889 {
890   WORD          id[3];  /* idReserved, idType, idCount */
891   LPicoICONDIR  lpiID;
892   int           i;
893  
894   _llseek32( hFile, 0, SEEK_SET );
895   if( _lread32(hFile,(char*)id,sizeof(id)) != sizeof(id) ) return 0;
896
897   /* check .ICO header 
898    *
899    * - see http://www.microsoft.com/win32dev/ui/icons.htm
900    */
901
902   if( id[0] || id[1] != 1 || !id[2] ) return 0;
903
904   i = id[2]*sizeof(icoICONDIRENTRY) + sizeof(id);
905
906   lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i);
907
908   if( _lread32(hFile,(char*)lpiID->idEntries,i) == i )
909   {  
910      HGLOBAL16 handle = DirectResAlloc( hInst, 0x10,
911                                      id[2]*sizeof(ICONDIRENTRY) + sizeof(id) );
912      if( handle ) 
913      {
914        CURSORICONDIR*     lpID = (CURSORICONDIR*)GlobalLock16( handle );
915        lpID->idReserved = lpiID->idReserved = id[0];
916        lpID->idType = lpiID->idType = id[1];
917        lpID->idCount = lpiID->idCount = id[2];
918        for( i=0; i < lpiID->idCount; i++ )
919          {
920             memcpy((void*)(lpID->idEntries + i), 
921                    (void*)(lpiID->idEntries + i), sizeof(ICONDIRENTRY) - 2);
922             lpID->idEntries[i].icon.wResId = i;
923          }
924       *lplpiID = lpiID;
925        return handle;
926      }
927   }
928   /* fail */
929
930   HeapFree( GetProcessHeap(), 0, lpiID);
931   return 0;
932 }
933
934 /*************************************************************************
935  *                      InternalExtractIcon             [SHELL.39]
936  *
937  * This abortion is called directly by Progman
938  */
939 HGLOBAL16 WINAPI InternalExtractIcon(HINSTANCE16 hInstance,
940                                      LPCSTR lpszExeFileName, UINT16 nIconIndex,
941                                      WORD n )
942 {
943   HGLOBAL16     hRet = 0;
944   HGLOBAL16*    RetPtr = NULL;
945   LPBYTE        pData;
946   OFSTRUCT      ofs;
947   DWORD         sig;
948   HFILE32       hFile = OpenFile32( lpszExeFileName, &ofs, OF_READ );
949   UINT16        iconDirCount = 0,iconCount = 0;
950   
951   TRACE(reg,"(%04x,file %s,start %d,extract %d\n", 
952                        hInstance, lpszExeFileName, nIconIndex, n);
953
954   if( hFile == HFILE_ERROR32 || !n ) return 0;
955
956   hRet = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
957   RetPtr = (HICON16*)GlobalLock16(hRet);
958
959   *RetPtr = (n == 0xFFFF)? 0: 1;        /* error return values */
960
961   sig = SHELL_GetResourceTable(hFile,&pData);
962
963   if((sig == IMAGE_OS2_SIGNATURE)
964   || (sig == 1)) /* .ICO file */
965   {
966     HICON16      hIcon = 0;
967     NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
968     NE_NAMEINFO* pIconStorage = NULL;
969     NE_NAMEINFO* pIconDir = NULL;
970     LPicoICONDIR lpiID = NULL;
971  
972     if( pData == (BYTE*)-1 )
973     {
974         /* check for .ICO file */
975
976         hIcon = ICO_GetIconDirectory(hInstance, hFile, &lpiID);
977         if( hIcon ) { iconDirCount = 1; iconCount = lpiID->idCount; }
978     }
979     else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
980     {
981         /* find icon directory and icon repository */
982
983         if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) 
984           {
985              iconDirCount = pTInfo->count;
986              pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
987              TRACE(reg,"\tfound directory - %i icon families\n", iconDirCount);
988           }
989         if( pTInfo->type_id == NE_RSCTYPE_ICON ) 
990           { 
991              iconCount = pTInfo->count;
992              pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
993              TRACE(reg,"\ttotal icons - %i\n", iconCount);
994           }
995         pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
996     }
997
998     /* load resources and create icons */
999
1000     if( (pIconStorage && pIconDir) || lpiID )
1001       if( nIconIndex == (UINT16)-1 ) RetPtr[0] = iconDirCount;
1002       else if( nIconIndex < iconDirCount )
1003       {
1004           UINT16   i, icon;
1005
1006           if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
1007
1008           for( i = nIconIndex; i < nIconIndex + n; i++ ) 
1009           {
1010               /* .ICO files have only one icon directory */
1011
1012               if( lpiID == NULL )
1013                    hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i, 
1014                                                               *(WORD*)pData );
1015               RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
1016               GlobalFree16(hIcon); 
1017           }
1018
1019           for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
1020           {
1021               hIcon = 0;
1022               if( lpiID )
1023                    hIcon = ICO_LoadIcon( hInstance, hFile, 
1024                                          lpiID->idEntries + RetPtr[icon-nIconIndex]);
1025               else
1026                  for( i = 0; i < iconCount; i++ )
1027                    if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
1028                      hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,
1029                                                                     *(WORD*)pData );
1030               if( hIcon )
1031               {
1032                   RetPtr[icon-nIconIndex] = LoadIconHandler( hIcon, TRUE ); 
1033                   FarSetOwner( RetPtr[icon-nIconIndex], GetExePtr(hInstance) );
1034               }
1035               else
1036                   RetPtr[icon-nIconIndex] = 0;
1037           }
1038       }
1039     if( lpiID ) HeapFree( GetProcessHeap(), 0, lpiID);
1040     else HeapFree( GetProcessHeap(), 0, pData);
1041   } 
1042   if( sig == IMAGE_NT_SIGNATURE)
1043   {
1044         LPBYTE                  peimage,idata,igdata;
1045         LPIMAGE_DOS_HEADER      dheader;
1046         LPIMAGE_NT_HEADERS      pe_header;
1047         LPIMAGE_SECTION_HEADER  pe_sections;
1048         LPIMAGE_RESOURCE_DIRECTORY      rootresdir,iconresdir,icongroupresdir;
1049         LPIMAGE_RESOURCE_DATA_ENTRY     idataent,igdataent;
1050         HANDLE32                fmapping;
1051         int                     i,j;
1052         LPIMAGE_RESOURCE_DIRECTORY_ENTRY        xresent;
1053         CURSORICONDIR           **cids;
1054         
1055         fmapping = CreateFileMapping32A(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL);
1056         if (fmapping == 0) { /* FIXME, INVALID_HANDLE_VALUE? */
1057                 WARN(reg,"failed to create filemap.\n");
1058                 _lclose32( hFile);
1059                 return 0;
1060         }
1061         peimage = MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0);
1062         if (!peimage) {
1063                 WARN(reg,"failed to mmap filemap.\n");
1064                 CloseHandle(fmapping);
1065                 _lclose32( hFile);
1066                 return 0;
1067         }
1068         dheader = (LPIMAGE_DOS_HEADER)peimage;
1069         /* it is a pe header, SHELL_GetResourceTable checked that */
1070         pe_header = (LPIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew);
1071         /* probably makes problems with short PE headers... but I haven't seen 
1072          * one yet... 
1073          */
1074         pe_sections = (LPIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header));
1075         rootresdir = NULL;
1076         for (i=0;i<pe_header->FileHeader.NumberOfSections;i++) {
1077                 if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
1078                         continue;
1079                 /* FIXME: doesn't work when the resources are not in a seperate section */
1080                 if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
1081                         rootresdir = (LPIMAGE_RESOURCE_DIRECTORY)((char*)peimage+pe_sections[i].PointerToRawData);
1082                         break;
1083                 }
1084         }
1085
1086         if (!rootresdir) {
1087                 WARN(reg,"haven't found section for resource directory.\n");
1088                 UnmapViewOfFile(peimage);
1089                 CloseHandle(fmapping);
1090                 _lclose32( hFile);
1091                 return 0;
1092         }
1093         icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICON32W,
1094                                           (DWORD)rootresdir,FALSE);
1095         if (!icongroupresdir) {
1096                 WARN(reg,"No Icongroupresourcedirectory!\n");
1097                 UnmapViewOfFile(peimage);
1098                 CloseHandle(fmapping);
1099                 _lclose32( hFile);
1100                 return 0;
1101         }
1102
1103         iconDirCount = icongroupresdir->NumberOfNamedEntries+icongroupresdir->NumberOfIdEntries;
1104         if( nIconIndex == (UINT16)-1 ) {
1105                 RetPtr[0] = iconDirCount;
1106                 UnmapViewOfFile(peimage);
1107                 CloseHandle(fmapping);
1108                 _lclose32( hFile);
1109                 return hRet;
1110         }
1111
1112         if (nIconIndex >= iconDirCount) {
1113                 WARN(reg,"nIconIndex %d is larger than iconDirCount %d\n",
1114                             nIconIndex,iconDirCount);
1115                 UnmapViewOfFile(peimage);
1116                 CloseHandle(fmapping);
1117                 _lclose32( hFile);
1118                 GlobalFree16(hRet);
1119                 return 0;
1120         }
1121         cids = (CURSORICONDIR**)HeapAlloc(GetProcessHeap(),0,n*sizeof(CURSORICONDIR*));
1122                 
1123         /* caller just wanted the number of entries */
1124
1125         xresent = (LPIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);
1126         /* assure we don't get too much ... */
1127         if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
1128
1129         /* starting from specified index ... */
1130         xresent = xresent+nIconIndex;
1131
1132         for (i=0;i<n;i++,xresent++) {
1133                 CURSORICONDIR   *cid;
1134                 LPIMAGE_RESOURCE_DIRECTORY      resdir;
1135
1136                 /* go down this resource entry, name */
1137                 resdir = (LPIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s.OffsetToDirectory));
1138                 /* default language (0) */
1139                 resdir = GetResDirEntryW(resdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
1140                 igdataent = (LPIMAGE_RESOURCE_DATA_ENTRY)resdir;
1141
1142                 /* lookup address in mapped image for virtual address */
1143                 igdata = NULL;
1144                 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) {
1145                         if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
1146                                 continue;
1147                         if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
1148                                 continue;
1149                         igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
1150                 }
1151                 if (!igdata) {
1152                         WARN(reg,"no matching real address for icongroup!\n");
1153                         UnmapViewOfFile(peimage);
1154                         CloseHandle(fmapping);
1155                         _lclose32( hFile);
1156                         return 0;
1157                 }
1158                 /* found */
1159                 cid = (CURSORICONDIR*)igdata;
1160                 cids[i] = cid;
1161                 RetPtr[i] = LookupIconIdFromDirectoryEx32(igdata,TRUE,SYSMETRICS_CXICON,SYSMETRICS_CYICON,0);
1162         }
1163         iconresdir=GetResDirEntryW(rootresdir,RT_ICON32W,
1164                                    (DWORD)rootresdir,FALSE);
1165         if (!iconresdir) {
1166             WARN(reg,"No Iconresourcedirectory!\n");
1167             UnmapViewOfFile(peimage);
1168             CloseHandle(fmapping);
1169             _lclose32( hFile);
1170             return 0;
1171         }
1172         for (i=0;i<n;i++) {
1173             LPIMAGE_RESOURCE_DIRECTORY  xresdir;
1174
1175             xresdir = GetResDirEntryW(iconresdir,(LPWSTR)RetPtr[i],(DWORD)rootresdir,FALSE);
1176             xresdir = GetResDirEntryW(xresdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
1177
1178             idataent = (LPIMAGE_RESOURCE_DATA_ENTRY)xresdir;
1179
1180             idata = NULL;
1181             /* map virtual to address in image */
1182             for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) {
1183                 if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
1184                     continue;
1185                 if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
1186                     continue;
1187                 idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
1188             }
1189             if (!idata) {
1190                 WARN(reg,"no matching real address found for icondata!\n");
1191                 RetPtr[i]=0;
1192                 continue;
1193             }
1194             RetPtr[i] = CreateIconFromResourceEx32(idata,idataent->Size,TRUE,0x00030000,SYSMETRICS_CXICON,SYSMETRICS_CYICON,0);
1195         }
1196         UnmapViewOfFile(peimage);
1197         CloseHandle(fmapping);
1198         _lclose32( hFile);
1199         return hRet;
1200   }
1201   _lclose32( hFile );
1202   /* return array with icon handles */
1203   return hRet;
1204
1205 }
1206
1207 /*************************************************************************
1208  *             ExtractIcon16   (SHELL.34)
1209  */
1210 HICON16 WINAPI ExtractIcon16( HINSTANCE16 hInstance, LPCSTR lpszExeFileName,
1211         UINT16 nIconIndex )
1212 {
1213     return ExtractIcon32A( hInstance, lpszExeFileName, nIconIndex );
1214 }
1215
1216
1217 /*************************************************************************
1218  *             ExtractIcon32A   (SHELL32.133)
1219  */
1220 HICON32 WINAPI ExtractIcon32A( HINSTANCE32 hInstance, LPCSTR lpszExeFileName,
1221         UINT32 nIconIndex )
1222 {
1223     HGLOBAL16 handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
1224
1225     if( handle )
1226     {
1227         HICON16* ptr = (HICON16*)GlobalLock16(handle);
1228         HICON16  hIcon = *ptr;
1229
1230         GlobalFree16(handle);
1231         return hIcon;
1232     }
1233     return 0;
1234 }
1235
1236 /*************************************************************************
1237  *             ExtractIcon32W   (SHELL32.180)
1238  */
1239 HICON32 WINAPI ExtractIcon32W( HINSTANCE32 hInstance, LPCWSTR lpszExeFileName,
1240         UINT32 nIconIndex )
1241 {
1242         LPSTR   exefn = HEAP_strdupWtoA(GetProcessHeap(),0,lpszExeFileName);
1243         HICON32 ret = ExtractIcon32A(hInstance,exefn,nIconIndex);
1244
1245         HeapFree(GetProcessHeap(),0,exefn);
1246         return ret;
1247 }
1248
1249
1250 /*************************************************************************
1251  *                              ExtractAssociatedIcon   [SHELL.36]
1252  * 
1253  * Return icon for given file (either from file itself or from associated
1254  * executable) and patch parameters if needed.
1255  */
1256 HICON32 WINAPI ExtractAssociatedIcon32A(HINSTANCE32 hInst,LPSTR lpIconPath,
1257         LPWORD lpiIcon)
1258 {
1259         return ExtractAssociatedIcon16(hInst,lpIconPath,lpiIcon);
1260 }
1261
1262 HICON16 WINAPI ExtractAssociatedIcon16(HINSTANCE16 hInst,LPSTR lpIconPath,
1263         LPWORD lpiIcon)
1264 {
1265     HICON16 hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
1266
1267     if( hIcon < 2 )
1268     {
1269
1270         if( hIcon == 1 ) /* no icons found in given file */
1271         {
1272             char  tempPath[0x80];
1273             UINT16  uRet = FindExecutable16(lpIconPath,NULL,tempPath);
1274
1275             if( uRet > 32 && tempPath[0] )
1276             {
1277                 strcpy(lpIconPath,tempPath);
1278                 hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
1279
1280                 if( hIcon > 2 ) return hIcon;
1281             }
1282             else hIcon = 0;
1283         }
1284
1285         if( hIcon == 1 ) 
1286             *lpiIcon = 2;   /* MSDOS icon - we found .exe but no icons in it */
1287         else
1288             *lpiIcon = 6;   /* generic icon - found nothing */
1289
1290         GetModuleFileName16(hInst, lpIconPath, 0x80);
1291         hIcon = LoadIcon16( hInst, MAKEINTRESOURCE16(*lpiIcon));
1292     }
1293
1294     return hIcon;
1295 }
1296
1297 /*************************************************************************
1298  *                              FindEnvironmentString   [SHELL.38]
1299  *
1300  * Returns a pointer into the DOS environment... Ugh.
1301  */
1302 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
1303 {
1304     UINT16      l = strlen(entry); 
1305     for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
1306     {
1307         if( lstrncmpi32A(lpEnv, entry, l) ) continue;
1308
1309         if( !*(lpEnv+l) )
1310             return (lpEnv + l);                 /* empty entry */
1311         else if ( *(lpEnv+l)== '=' )
1312             return (lpEnv + l + 1);
1313     }
1314     return NULL;
1315 }
1316
1317 SEGPTR WINAPI FindEnvironmentString(LPSTR str)
1318 {
1319     SEGPTR  spEnv = GetDOSEnvironment();
1320     LPSTR  lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
1321
1322     LPSTR  lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL; 
1323
1324     if( lpString )              /*  offset should be small enough */
1325         return spEnv + (lpString - lpEnv);
1326
1327     return (SEGPTR)NULL;
1328 }
1329
1330 /*************************************************************************
1331  *                              DoEnvironmentSubst      [SHELL.37]
1332  *
1333  * Replace %KEYWORD% in the str with the value of variable KEYWORD
1334  * from "DOS" environment.
1335  */
1336 DWORD WINAPI DoEnvironmentSubst(LPSTR str,WORD length)
1337 {
1338   LPSTR   lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
1339   LPSTR   lpBuffer = (LPSTR)HeapAlloc( GetProcessHeap(), 0, length);
1340   LPSTR   lpstr = str;
1341   LPSTR   lpbstr = lpBuffer;
1342
1343   CharToOem32A(str,str);
1344
1345   TRACE(reg,"accept %s\n", str);
1346
1347   while( *lpstr && lpbstr - lpBuffer < length )
1348    {
1349      LPSTR lpend = lpstr;
1350
1351      if( *lpstr == '%' )
1352        {
1353           do { lpend++; } while( *lpend && *lpend != '%' );
1354           if( *lpend == '%' && lpend - lpstr > 1 )      /* found key */
1355             {
1356                LPSTR lpKey;
1357               *lpend = '\0';  
1358                lpKey = SHELL_FindString(lpEnv, lpstr+1);
1359                if( lpKey )                              /* found key value */
1360                  {
1361                    int l = strlen(lpKey);
1362
1363                    if( l > length - (lpbstr - lpBuffer) - 1 )
1364                      {
1365                        WARN(reg,"Env subst aborted - string too short\n");
1366                       *lpend = '%';
1367                        break;
1368                      }
1369                    strcpy(lpbstr, lpKey);
1370                    lpbstr += l;
1371                  }
1372                else break;
1373               *lpend = '%';
1374                lpstr = lpend + 1;
1375             }
1376           else break;                                   /* back off and whine */
1377
1378           continue;
1379        } 
1380
1381      *lpbstr++ = *lpstr++;
1382    }
1383
1384  *lpbstr = '\0';
1385   if( lpstr - str == strlen(str) )
1386     {
1387       strncpy(str, lpBuffer, length);
1388       length = 1;
1389     }
1390   else
1391       length = 0;
1392
1393   TRACE(reg,"    return %s\n", str);
1394
1395   OemToChar32A(str,str);
1396   HeapFree( GetProcessHeap(), 0, lpBuffer);
1397
1398   /*  Return str length in the LOWORD
1399    *  and 1 in HIWORD if subst was successful.
1400    */
1401  return (DWORD)MAKELONG(strlen(str), length);
1402 }
1403
1404 /*************************************************************************
1405  *                              ShellHookProc           [SHELL.103]
1406  * System-wide WH_SHELL hook.
1407  */
1408 LRESULT WINAPI ShellHookProc(INT16 code, WPARAM16 wParam, LPARAM lParam)
1409 {
1410     TRACE(reg,"%i, %04x, %08x\n", code, wParam, 
1411                                                       (unsigned)lParam );
1412     if( SHELL_hHook && SHELL_hWnd )
1413     {
1414         UINT16  uMsg = 0;
1415         switch( code )
1416         {
1417             case HSHELL_WINDOWCREATED:          uMsg = uMsgWndCreated;   break;
1418             case HSHELL_WINDOWDESTROYED:        uMsg = uMsgWndDestroyed; break;
1419             case HSHELL_ACTIVATESHELLWINDOW:    uMsg = uMsgShellActivate;
1420         }
1421         PostMessage16( SHELL_hWnd, uMsg, wParam, 0 );
1422     }
1423     return CallNextHookEx16( WH_SHELL, code, wParam, lParam );
1424 }
1425
1426 /*************************************************************************
1427  *                              RegisterShellHook       [SHELL.102]
1428  */
1429 BOOL32 WINAPI RegisterShellHook(HWND16 hWnd, UINT16 uAction)
1430 {
1431     TRACE(reg,"%04x [%u]\n", hWnd, uAction );
1432
1433     switch( uAction )
1434     {
1435         case 2: /* register hWnd as a shell window */
1436
1437              if( !SHELL_hHook )
1438              {
1439                 HMODULE16 hShell = GetModuleHandle16( "SHELL" );
1440
1441                 SHELL_hHook = SetWindowsHookEx16( WH_SHELL, ShellHookProc,
1442                                                   hShell, 0 );
1443                 if( SHELL_hHook )
1444                 {
1445                     uMsgWndCreated = RegisterWindowMessage32A( lpstrMsgWndCreated );
1446                     uMsgWndDestroyed = RegisterWindowMessage32A( lpstrMsgWndDestroyed );
1447                     uMsgShellActivate = RegisterWindowMessage32A( lpstrMsgShellActivate );
1448                 } 
1449                 else WARN(reg, "unable to install ShellHookProc()!\n");
1450              }
1451
1452              if( SHELL_hHook ) return ((SHELL_hWnd = hWnd) != 0);
1453              break;
1454
1455         default:
1456
1457              WARN(reg, "unknown code %i\n", uAction );
1458
1459              /* just in case */
1460
1461              SHELL_hWnd = 0;
1462     }
1463     return FALSE;
1464 }
1465
1466
1467 /*************************************************************************
1468  *                              SHGetFileInfoA          [SHELL32.218]
1469  */
1470 DWORD WINAPI SHGetFileInfo32A(LPCSTR path,DWORD dwFileAttributes,
1471                               SHFILEINFO32A *psfi, UINT32 sizeofpsfi,
1472                               UINT32 flags )
1473 {
1474         FIXME(shell,"(%s,0x%08lx,%p,%d,0x%08x): stub\n",
1475               path,dwFileAttributes,psfi,sizeofpsfi,flags);
1476         return TRUE;
1477 }
1478
1479 /*************************************************************************
1480  *                              SHAppBarMessage32       [SHELL32.207]
1481  */
1482 UINT32 WINAPI SHAppBarMessage32(DWORD msg, PAPPBARDATA data)
1483 {
1484     FIXME(shell,"(0x%08lx,%p): stub\n", msg, data);
1485 #if 0
1486     switch (msg) {
1487         case ABM_ACTIVATE:
1488         case ABM_GETAUTOHIDEBAR:
1489         case ABM_GETSTATE:
1490         case ABM_GETTASKBARPOS:
1491         case ABM_NEW:
1492         case ABM_QUERYPOS:
1493         case ABM_REMOVE:
1494         case ABM_SETAUTOHIDEBAR:
1495         case ABM_SETPOS:
1496         case ABM_WINDOWPOSCHANGED:
1497             ;
1498     }
1499 #endif
1500     return 0;
1501 }
1502
1503 /*************************************************************************
1504  *                              CommandLineToArgvW      [SHELL32.7]
1505  */
1506 LPWSTR* WINAPI CommandLineToArgvW(LPWSTR cmdline,LPDWORD numargs)
1507 {
1508         LPWSTR  *argv,s,t;
1509         int     i;
1510
1511         /* to get writeable copy */
1512         cmdline = HEAP_strdupW( GetProcessHeap(), 0, cmdline);
1513         s=cmdline;i=0;
1514         while (*s) {
1515                 /* space */
1516                 if (*s==0x0020) {
1517                         i++;
1518                         s++;
1519                         while (*s && *s==0x0020)
1520                                 s++;
1521                         continue;
1522                 }
1523                 s++;
1524         }
1525         argv=(LPWSTR*)HeapAlloc( GetProcessHeap(), 0, sizeof(LPWSTR)*(i+1) );
1526         s=t=cmdline;
1527         i=0;
1528         while (*s) {
1529                 if (*s==0x0020) {
1530                         *s=0;
1531                         argv[i++]=HEAP_strdupW( GetProcessHeap(), 0, t );
1532                         *s=0x0020;
1533                         while (*s && *s==0x0020)
1534                                 s++;
1535                         if (*s)
1536                                 t=s+1;
1537                         else
1538                                 t=s;
1539                         continue;
1540                 }
1541                 s++;
1542         }
1543         if (*t)
1544                 argv[i++]=(LPWSTR)HEAP_strdupW( GetProcessHeap(), 0, t );
1545         HeapFree( GetProcessHeap(), 0, cmdline );
1546         argv[i]=NULL;
1547         *numargs=i;
1548         return argv;
1549 }
1550
1551 /*************************************************************************
1552  *                              Control_RunDLL          [SHELL32.12]
1553  *
1554  * Wild speculation in the following!
1555  *
1556  * http://premium.microsoft.com/msdn/library/techart/msdn193.htm
1557  */
1558
1559 void WINAPI Control_RunDLL (HWND32 hwnd, LPCVOID code, LPCSTR cmd, DWORD arg4)
1560 {
1561   TRACE(exec, "(%08x, %p, \"%s\", %08lx)\n",
1562         hwnd, code ? code : "(null)", cmd ? cmd : "(null)", arg4);
1563 }
1564
1565 /*************************************************************************
1566  */
1567
1568 void WINAPI FreeIconList( DWORD dw )
1569 {
1570     FIXME(reg, "empty stub\n" );
1571 }
1572
1573 /*************************************************************************
1574  *                       SHELL32_DllGetClassObject   [SHELL32.14]
1575  *
1576  * http://premium.microsoft.com/msdn/library/sdkdoc/api2_48fo.htm
1577  */
1578 DWORD WINAPI SHELL32_DllGetClassObject(REFCLSID rclsid,REFIID iid,LPVOID *ppv)
1579 {
1580     char        xclsid[50],xiid[50];
1581     HRESULT     hres = E_OUTOFMEMORY;
1582
1583
1584     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1585     WINE_StringFromCLSID((LPCLSID)iid,xiid);
1586     TRACE(shell,"(%s,%s,%p)\n",xclsid,xiid,ppv);
1587
1588     *ppv = NULL;
1589 /* SDK example code looks like this:
1590  *
1591     HRESULT     hres = E_OUTOFMEMORY;
1592
1593     *ppv = NULL;
1594     CClassFactory *pClassFactory = new CClassFactory(rclsid);
1595     
1596     if (pClassFactory) {
1597         hRes = pClassFactory->QueryInterface(riid,ppv);
1598         pClassFactory->Release();
1599     }
1600     return hRes;
1601  *
1602  * The magic of the whole stuff is still unclear to me, so just hack together 
1603  * something.
1604  */
1605   
1606     if (!memcmp(rclsid,&CLSID_ShellDesktop,sizeof(CLSID_ShellDesktop))) {
1607         TRACE(shell,"   requested CLSID_ShellDesktop, creating it.\n");
1608         *ppv = IShellFolder_Constructor();
1609         FIXME(shell,"Initialize this folder to be the shell desktop folder\n");
1610         return 0;
1611     }
1612
1613     FIXME(shell, "   -> clsid not found. returning E_OUTOFMEMORY.\n");
1614     return hres;
1615 }
1616
1617 /*************************************************************************
1618  *                       SHGetDesktopFolder             [SHELL32.216]
1619  * returns the interface to the shell desktop folder.
1620  *
1621  * [SDK header win95/shlobj.h: This is equivalent to call CoCreateInstance with
1622  *  CLSID_ShellDesktop.
1623  *
1624  *  CoCreateInstance(CLSID_Desktop, NULL,
1625  *                   CLSCTX_INPROC, IID_IShellFolder, &pshf);
1626  * ]
1627  * So what we are doing is currently wrong....
1628  */
1629 DWORD WINAPI SHGetDesktopFolder(LPSHELLFOLDER *shellfolder) {
1630         *shellfolder = IShellFolder_Constructor();
1631         return NOERROR;
1632 }
1633
1634 /*************************************************************************
1635  *                       SHGetMalloc                    [SHELL32.220]
1636  * returns the interface to shell malloc.
1637  *
1638  * [SDK header win95/shlobj.h:
1639  * equivalent to:  #define SHGetMalloc(ppmem)   CoGetMalloc(MEMCTX_TASK, ppmem)
1640  * ]
1641  * What we are currently doing is not very wrong, since we always use the same
1642  * heap (ProcessHeap).
1643  */
1644 DWORD WINAPI SHGetMalloc(LPMALLOC32 *lpmal) {
1645         TRACE(shell,"(%p)\n", lpmal);
1646         return CoGetMalloc32(0,lpmal);
1647 }
1648
1649 /*************************************************************************
1650  *                       SHGetSpecialFolderLocation     [SHELL32.223]
1651  * returns the PIDL of a special folder
1652  *
1653  * nFolder is a CSIDL_xxxxx.
1654  */
1655 HRESULT WINAPI SHGetSpecialFolderLocation(HWND32 hwndOwner, INT32 nFolder, LPITEMIDLIST * ppidl) {
1656         FIXME(shell,"(%04x,%d,%p),stub!\n", hwndOwner,nFolder,ppidl);
1657         *ppidl = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,2*sizeof(ITEMIDLIST));
1658         FIXME(shell, "we return only the empty ITEMIDLIST currently.\n");
1659         (*ppidl)->mkid.cb = 0;
1660         return NOERROR;
1661 }
1662
1663 /*************************************************************************
1664  *                       SHGetPathFromIDList            [SHELL32.221]
1665  * returns the path from a passed PIDL.
1666  */
1667 BOOL32 WINAPI SHGetPathFromIDList(LPCITEMIDLIST pidl,LPSTR pszPath) {
1668         FIXME(shell,"(%p,%p),stub!\n",pidl,pszPath);
1669         lstrcpy32A(pszPath,"E:\\"); /* FIXME */
1670         return NOERROR;
1671 }