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