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