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