Release 980517
[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   ) { /* .ICO file ? */
798         if (mz_header.e_cblp == 1) { /* ICONHEADER.idType, must be 1 */
799             *retptr = (LPBYTE)-1;
800             return 1;
801         }
802         else
803             return 0; /* failed */
804   }
805   _llseek32( hFile, mz_header.e_lfanew, SEEK_SET );
806   if (_lread32( hFile, magic, sizeof(magic) ) != sizeof(magic))
807         return 0;
808   _llseek32( hFile, mz_header.e_lfanew, SEEK_SET);
809
810   if (*(DWORD*)magic  == IMAGE_NT_SIGNATURE)
811         return IMAGE_NT_SIGNATURE;
812   if (*(WORD*)magic == IMAGE_OS2_SIGNATURE) {
813         IMAGE_OS2_HEADER        ne_header;
814         LPBYTE                  pTypeInfo = (LPBYTE)-1;
815
816         if (_lread32(hFile,&ne_header,sizeof(ne_header))!=sizeof(ne_header))
817                 return 0;
818
819         if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE) return 0;
820         size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
821         if( size > sizeof(NE_TYPEINFO) )
822         {
823             pTypeInfo = (BYTE*)HeapAlloc( GetProcessHeap(), 0, size);
824             if( pTypeInfo ) {
825                 _llseek32(hFile, mz_header.e_lfanew+ne_header.resource_tab_offset, SEEK_SET);
826                 if( _lread32( hFile, (char*)pTypeInfo, size) != size ) { 
827                     HeapFree( GetProcessHeap(), 0, pTypeInfo); 
828                     pTypeInfo = NULL;
829                 }
830             }
831         }
832         *retptr = pTypeInfo;
833         return IMAGE_OS2_SIGNATURE;
834   } else
835         return 0; /* failed */
836 }
837
838 /*************************************************************************
839  *                      SHELL_LoadResource
840  */
841 static HGLOBAL16 SHELL_LoadResource(HINSTANCE16 hInst, HFILE32 hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
842 {
843  BYTE*  ptr;
844  HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
845
846  if( (ptr = (BYTE*)GlobalLock16( handle )) )
847    {
848     _llseek32( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
849      _lread32( hFile, (char*)ptr, pNInfo->length << sizeShift);
850      return handle;
851    }
852  return 0;
853 }
854
855 /*************************************************************************
856  *                      ICO_LoadIcon
857  */
858 static HGLOBAL16 ICO_LoadIcon(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIRENTRY lpiIDE)
859 {
860  BYTE*  ptr;
861  HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, lpiIDE->dwBytesInRes);
862
863  if( (ptr = (BYTE*)GlobalLock16( handle )) )
864    {
865     _llseek32( hFile, lpiIDE->dwImageOffset, SEEK_SET);
866      _lread32( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
867      return handle;
868    }
869  return 0;
870 }
871
872 /*************************************************************************
873  *                      ICO_GetIconDirectory
874  *
875  *  Read .ico file and build phony ICONDIR struct for GetIconID
876  */
877 static HGLOBAL16 ICO_GetIconDirectory(HINSTANCE16 hInst, HFILE32 hFile, LPicoICONDIR* lplpiID ) 
878 {
879   WORD          id[3];  /* idReserved, idType, idCount */
880   LPicoICONDIR  lpiID;
881   int           i;
882  
883   _llseek32( hFile, 0, SEEK_SET );
884   if( _lread32(hFile,(char*)id,sizeof(id)) != sizeof(id) ) return 0;
885
886   /* check .ICO header 
887    *
888    * - see http://www.microsoft.com/win32dev/ui/icons.htm
889    */
890
891   if( id[0] || id[1] != 1 || !id[2] ) return 0;
892
893   i = id[2]*sizeof(icoICONDIRENTRY) + sizeof(id);
894
895   lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i);
896
897   if( _lread32(hFile,(char*)lpiID->idEntries,i) == i )
898   {  
899      HGLOBAL16 handle = DirectResAlloc( hInst, 0x10,
900                                      id[2]*sizeof(ICONDIRENTRY) + sizeof(id) );
901      if( handle ) 
902      {
903        CURSORICONDIR*     lpID = (CURSORICONDIR*)GlobalLock16( handle );
904        lpID->idReserved = lpiID->idReserved = id[0];
905        lpID->idType = lpiID->idType = id[1];
906        lpID->idCount = lpiID->idCount = id[2];
907        for( i=0; i < lpiID->idCount; i++ )
908          {
909             memcpy((void*)(lpID->idEntries + i), 
910                    (void*)(lpiID->idEntries + i), sizeof(ICONDIRENTRY) - 2);
911             lpID->idEntries[i].icon.wResId = i;
912          }
913       *lplpiID = lpiID;
914        return handle;
915      }
916   }
917   /* fail */
918
919   HeapFree( GetProcessHeap(), 0, lpiID);
920   return 0;
921 }
922
923 /*************************************************************************
924  *                      InternalExtractIcon             [SHELL.39]
925  *
926  * This abortion is called directly by Progman
927  */
928 HGLOBAL16 WINAPI InternalExtractIcon(HINSTANCE16 hInstance,
929                                      LPCSTR lpszExeFileName, UINT16 nIconIndex,
930                                      WORD n )
931 {
932   HGLOBAL16     hRet = 0;
933   HGLOBAL16*    RetPtr = NULL;
934   LPBYTE        pData;
935   OFSTRUCT      ofs;
936   DWORD         sig;
937   HFILE32       hFile = OpenFile32( lpszExeFileName, &ofs, OF_READ );
938   UINT16        iconDirCount = 0,iconCount = 0;
939   
940   TRACE(reg,"(%04x,file %s,start %d,extract %d\n", 
941                        hInstance, lpszExeFileName, nIconIndex, n);
942
943   if( hFile == HFILE_ERROR32 || !n ) return 0;
944
945   hRet = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
946   RetPtr = (HICON16*)GlobalLock16(hRet);
947
948   *RetPtr = (n == 0xFFFF)? 0: 1;        /* error return values */
949
950   sig = SHELL_GetResourceTable(hFile,&pData);
951
952   if((sig == IMAGE_OS2_SIGNATURE)
953   || (sig == 1)) /* .ICO file */
954   {
955     HICON16      hIcon = 0;
956     NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
957     NE_NAMEINFO* pIconStorage = NULL;
958     NE_NAMEINFO* pIconDir = NULL;
959     LPicoICONDIR lpiID = NULL;
960  
961     if( pData == (BYTE*)-1 )
962     {
963         /* check for .ICO file */
964
965         hIcon = ICO_GetIconDirectory(hInstance, hFile, &lpiID);
966         if( hIcon ) { iconDirCount = 1; iconCount = lpiID->idCount; }
967     }
968     else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
969     {
970         /* find icon directory and icon repository */
971
972         if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) 
973           {
974              iconDirCount = pTInfo->count;
975              pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
976              TRACE(reg,"\tfound directory - %i icon families\n", iconDirCount);
977           }
978         if( pTInfo->type_id == NE_RSCTYPE_ICON ) 
979           { 
980              iconCount = pTInfo->count;
981              pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
982              TRACE(reg,"\ttotal icons - %i\n", iconCount);
983           }
984         pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
985     }
986
987     /* load resources and create icons */
988
989     if( (pIconStorage && pIconDir) || lpiID )
990       if( nIconIndex == (UINT16)-1 ) RetPtr[0] = iconDirCount;
991       else if( nIconIndex < iconDirCount )
992       {
993           UINT16   i, icon;
994
995           if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
996
997           for( i = nIconIndex; i < nIconIndex + n; i++ ) 
998           {
999               /* .ICO files have only one icon directory */
1000
1001               if( lpiID == NULL )
1002                    hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i, 
1003                                                               *(WORD*)pData );
1004               RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
1005               GlobalFree16(hIcon); 
1006           }
1007
1008           for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
1009           {
1010               hIcon = 0;
1011               if( lpiID )
1012                    hIcon = ICO_LoadIcon( hInstance, hFile, 
1013                                          lpiID->idEntries + RetPtr[icon-nIconIndex]);
1014               else
1015                  for( i = 0; i < iconCount; i++ )
1016                    if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
1017                      hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,
1018                                                                     *(WORD*)pData );
1019               if( hIcon )
1020               {
1021                   RetPtr[icon-nIconIndex] = LoadIconHandler( hIcon, TRUE ); 
1022                   FarSetOwner( RetPtr[icon-nIconIndex], GetExePtr(hInstance) );
1023               }
1024               else
1025                   RetPtr[icon-nIconIndex] = 0;
1026           }
1027       }
1028     if( lpiID ) HeapFree( GetProcessHeap(), 0, lpiID);
1029     else HeapFree( GetProcessHeap(), 0, pData);
1030   } 
1031   if( sig == IMAGE_NT_SIGNATURE)
1032   {
1033         LPBYTE                  peimage,idata,igdata;
1034         LPIMAGE_DOS_HEADER      dheader;
1035         LPIMAGE_NT_HEADERS      pe_header;
1036         LPIMAGE_SECTION_HEADER  pe_sections;
1037         LPIMAGE_RESOURCE_DIRECTORY      rootresdir,iconresdir,icongroupresdir;
1038         LPIMAGE_RESOURCE_DATA_ENTRY     idataent,igdataent;
1039         HANDLE32                fmapping;
1040         int                     i,j;
1041         LPIMAGE_RESOURCE_DIRECTORY_ENTRY        xresent;
1042         CURSORICONDIR           **cids;
1043         
1044         fmapping = CreateFileMapping32A(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL);
1045         if (fmapping == 0) { /* FIXME, INVALID_HANDLE_VALUE? */
1046                 WARN(reg,"failed to create filemap.\n");
1047                 _lclose32( hFile);
1048                 return 0;
1049         }
1050         peimage = MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0);
1051         if (!peimage) {
1052                 WARN(reg,"failed to mmap filemap.\n");
1053                 CloseHandle(fmapping);
1054                 _lclose32( hFile);
1055                 return 0;
1056         }
1057         dheader = (LPIMAGE_DOS_HEADER)peimage;
1058         /* it is a pe header, SHELL_GetResourceTable checked that */
1059         pe_header = (LPIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew);
1060         /* probably makes problems with short PE headers... but I haven't seen 
1061          * one yet... 
1062          */
1063         pe_sections = (LPIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header));
1064         rootresdir = NULL;
1065         for (i=0;i<pe_header->FileHeader.NumberOfSections;i++) {
1066                 if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
1067                         continue;
1068                 /* FIXME: doesn't work when the resources are not in a seperate section */
1069                 if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) {
1070                         rootresdir = (LPIMAGE_RESOURCE_DIRECTORY)((char*)peimage+pe_sections[i].PointerToRawData);
1071                         break;
1072                 }
1073         }
1074
1075         if (!rootresdir) {
1076                 WARN(reg,"haven't found section for resource directory.\n");
1077                 UnmapViewOfFile(peimage);
1078                 CloseHandle(fmapping);
1079                 _lclose32( hFile);
1080                 return 0;
1081         }
1082         icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICON32W,
1083                                           (DWORD)rootresdir,FALSE);
1084         if (!icongroupresdir) {
1085                 WARN(reg,"No Icongroupresourcedirectory!\n");
1086                 UnmapViewOfFile(peimage);
1087                 CloseHandle(fmapping);
1088                 _lclose32( hFile);
1089                 return 0;
1090         }
1091
1092         iconDirCount = icongroupresdir->NumberOfNamedEntries+icongroupresdir->NumberOfIdEntries;
1093         if( nIconIndex == (UINT16)-1 ) {
1094                 RetPtr[0] = iconDirCount;
1095                 UnmapViewOfFile(peimage);
1096                 CloseHandle(fmapping);
1097                 _lclose32( hFile);
1098                 return hRet;
1099         }
1100
1101         if (nIconIndex >= iconDirCount) {
1102                 WARN(reg,"nIconIndex %d is larger than iconDirCount %d\n",
1103                             nIconIndex,iconDirCount);
1104                 UnmapViewOfFile(peimage);
1105                 CloseHandle(fmapping);
1106                 _lclose32( hFile);
1107                 GlobalFree16(hRet);
1108                 return 0;
1109         }
1110         cids = (CURSORICONDIR**)HeapAlloc(GetProcessHeap(),0,n*sizeof(CURSORICONDIR*));
1111                 
1112         /* caller just wanted the number of entries */
1113
1114         xresent = (LPIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);
1115         /* assure we don't get too much ... */
1116         if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
1117
1118         /* starting from specified index ... */
1119         xresent = xresent+nIconIndex;
1120
1121         for (i=0;i<n;i++,xresent++) {
1122                 CURSORICONDIR   *cid;
1123                 LPIMAGE_RESOURCE_DIRECTORY      resdir;
1124
1125                 /* go down this resource entry, name */
1126                 resdir = (LPIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s.OffsetToDirectory));
1127                 /* default language (0) */
1128                 resdir = GetResDirEntryW(resdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
1129                 igdataent = (LPIMAGE_RESOURCE_DATA_ENTRY)resdir;
1130
1131                 /* lookup address in mapped image for virtual address */
1132                 igdata = NULL;
1133                 for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) {
1134                         if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
1135                                 continue;
1136                         if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
1137                                 continue;
1138                         igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
1139                 }
1140                 if (!igdata) {
1141                         WARN(reg,"no matching real address for icongroup!\n");
1142                         UnmapViewOfFile(peimage);
1143                         CloseHandle(fmapping);
1144                         _lclose32( hFile);
1145                         return 0;
1146                 }
1147                 /* found */
1148                 cid = (CURSORICONDIR*)igdata;
1149                 cids[i] = cid;
1150                 RetPtr[i] = LookupIconIdFromDirectoryEx32(igdata,TRUE,SYSMETRICS_CXICON,SYSMETRICS_CYICON,0);
1151         }
1152         iconresdir=GetResDirEntryW(rootresdir,RT_ICON32W,
1153                                    (DWORD)rootresdir,FALSE);
1154         if (!iconresdir) {
1155             WARN(reg,"No Iconresourcedirectory!\n");
1156             UnmapViewOfFile(peimage);
1157             CloseHandle(fmapping);
1158             _lclose32( hFile);
1159             return 0;
1160         }
1161         for (i=0;i<n;i++) {
1162             LPIMAGE_RESOURCE_DIRECTORY  xresdir;
1163
1164             xresdir = GetResDirEntryW(iconresdir,(LPWSTR)RetPtr[i],(DWORD)rootresdir,FALSE);
1165             xresdir = GetResDirEntryW(xresdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
1166
1167             idataent = (LPIMAGE_RESOURCE_DATA_ENTRY)xresdir;
1168
1169             idata = NULL;
1170             /* map virtual to address in image */
1171             for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) {
1172                 if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
1173                     continue;
1174                 if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
1175                     continue;
1176                 idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
1177             }
1178             if (!idata) {
1179                 WARN(reg,"no matching real address found for icondata!\n");
1180                 RetPtr[i]=0;
1181                 continue;
1182             }
1183             RetPtr[i] = CreateIconFromResourceEx32(idata,idataent->Size,TRUE,0x00030000,SYSMETRICS_CXICON,SYSMETRICS_CYICON,0);
1184         }
1185         UnmapViewOfFile(peimage);
1186         CloseHandle(fmapping);
1187         _lclose32( hFile);
1188         return hRet;
1189   }
1190   _lclose32( hFile );
1191   /* return array with icon handles */
1192   return hRet;
1193
1194 }
1195
1196 /*************************************************************************
1197  *             ExtractIcon16   (SHELL.34)
1198  */
1199 HICON16 WINAPI ExtractIcon16( HINSTANCE16 hInstance, LPCSTR lpszExeFileName,
1200         UINT16 nIconIndex )
1201 {
1202     return ExtractIcon32A( hInstance, lpszExeFileName, nIconIndex );
1203 }
1204
1205
1206 /*************************************************************************
1207  *             ExtractIcon32A   (SHELL32.133)
1208  */
1209 HICON32 WINAPI ExtractIcon32A( HINSTANCE32 hInstance, LPCSTR lpszExeFileName,
1210         UINT32 nIconIndex )
1211 {
1212     HGLOBAL16 handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
1213
1214     if( handle )
1215     {
1216         HICON16* ptr = (HICON16*)GlobalLock16(handle);
1217         HICON16  hIcon = *ptr;
1218
1219         GlobalFree16(handle);
1220         return hIcon;
1221     }
1222     return 0;
1223 }
1224
1225 /*************************************************************************
1226  *             ExtractIcon32W   (SHELL32.180)
1227  */
1228 HICON32 WINAPI ExtractIcon32W( HINSTANCE32 hInstance, LPCWSTR lpszExeFileName,
1229         UINT32 nIconIndex )
1230 {
1231         LPSTR   exefn = HEAP_strdupWtoA(GetProcessHeap(),0,lpszExeFileName);
1232         HICON32 ret = ExtractIcon32A(hInstance,exefn,nIconIndex);
1233
1234         HeapFree(GetProcessHeap(),0,exefn);
1235         return ret;
1236 }
1237
1238
1239 /*************************************************************************
1240  *                              ExtractAssociatedIcon   [SHELL.36]
1241  * 
1242  * Return icon for given file (either from file itself or from associated
1243  * executable) and patch parameters if needed.
1244  */
1245 HICON32 WINAPI ExtractAssociatedIcon32A(HINSTANCE32 hInst,LPSTR lpIconPath,
1246         LPWORD lpiIcon)
1247 {
1248         return ExtractAssociatedIcon16(hInst,lpIconPath,lpiIcon);
1249 }
1250
1251 HICON16 WINAPI ExtractAssociatedIcon16(HINSTANCE16 hInst,LPSTR lpIconPath,
1252         LPWORD lpiIcon)
1253 {
1254     HICON16 hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
1255
1256     if( hIcon < 2 )
1257     {
1258
1259         if( hIcon == 1 ) /* no icons found in given file */
1260         {
1261             char  tempPath[0x80];
1262             UINT16  uRet = FindExecutable16(lpIconPath,NULL,tempPath);
1263
1264             if( uRet > 32 && tempPath[0] )
1265             {
1266                 strcpy(lpIconPath,tempPath);
1267                 hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
1268
1269                 if( hIcon > 2 ) return hIcon;
1270             }
1271             else hIcon = 0;
1272         }
1273
1274         if( hIcon == 1 ) 
1275             *lpiIcon = 2;   /* MSDOS icon - we found .exe but no icons in it */
1276         else
1277             *lpiIcon = 6;   /* generic icon - found nothing */
1278
1279         GetModuleFileName16(hInst, lpIconPath, 0x80);
1280         hIcon = LoadIcon16( hInst, MAKEINTRESOURCE16(*lpiIcon));
1281     }
1282
1283     return hIcon;
1284 }
1285
1286 /*************************************************************************
1287  *                              FindEnvironmentString   [SHELL.38]
1288  *
1289  * Returns a pointer into the DOS environment... Ugh.
1290  */
1291 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
1292 {
1293     UINT16      l = strlen(entry); 
1294     for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
1295     {
1296         if( lstrncmpi32A(lpEnv, entry, l) ) continue;
1297
1298         if( !*(lpEnv+l) )
1299             return (lpEnv + l);                 /* empty entry */
1300         else if ( *(lpEnv+l)== '=' )
1301             return (lpEnv + l + 1);
1302     }
1303     return NULL;
1304 }
1305
1306 SEGPTR WINAPI FindEnvironmentString(LPSTR str)
1307 {
1308     SEGPTR  spEnv = GetDOSEnvironment();
1309     LPSTR  lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
1310
1311     LPSTR  lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL; 
1312
1313     if( lpString )              /*  offset should be small enough */
1314         return spEnv + (lpString - lpEnv);
1315
1316     return (SEGPTR)NULL;
1317 }
1318
1319 /*************************************************************************
1320  *                              DoEnvironmentSubst      [SHELL.37]
1321  *
1322  * Replace %KEYWORD% in the str with the value of variable KEYWORD
1323  * from "DOS" environment.
1324  */
1325 DWORD WINAPI DoEnvironmentSubst(LPSTR str,WORD length)
1326 {
1327   LPSTR   lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
1328   LPSTR   lpBuffer = (LPSTR)HeapAlloc( GetProcessHeap(), 0, length);
1329   LPSTR   lpstr = str;
1330   LPSTR   lpbstr = lpBuffer;
1331
1332   CharToOem32A(str,str);
1333
1334   TRACE(reg,"accept %s\n", str);
1335
1336   while( *lpstr && lpbstr - lpBuffer < length )
1337    {
1338      LPSTR lpend = lpstr;
1339
1340      if( *lpstr == '%' )
1341        {
1342           do { lpend++; } while( *lpend && *lpend != '%' );
1343           if( *lpend == '%' && lpend - lpstr > 1 )      /* found key */
1344             {
1345                LPSTR lpKey;
1346               *lpend = '\0';  
1347                lpKey = SHELL_FindString(lpEnv, lpstr+1);
1348                if( lpKey )                              /* found key value */
1349                  {
1350                    int l = strlen(lpKey);
1351
1352                    if( l > length - (lpbstr - lpBuffer) - 1 )
1353                      {
1354                        WARN(reg,"Env subst aborted - string too short\n");
1355                       *lpend = '%';
1356                        break;
1357                      }
1358                    strcpy(lpbstr, lpKey);
1359                    lpbstr += l;
1360                  }
1361                else break;
1362               *lpend = '%';
1363                lpstr = lpend + 1;
1364             }
1365           else break;                                   /* back off and whine */
1366
1367           continue;
1368        } 
1369
1370      *lpbstr++ = *lpstr++;
1371    }
1372
1373  *lpbstr = '\0';
1374   if( lpstr - str == strlen(str) )
1375     {
1376       strncpy(str, lpBuffer, length);
1377       length = 1;
1378     }
1379   else
1380       length = 0;
1381
1382   TRACE(reg,"    return %s\n", str);
1383
1384   OemToChar32A(str,str);
1385   HeapFree( GetProcessHeap(), 0, lpBuffer);
1386
1387   /*  Return str length in the LOWORD
1388    *  and 1 in HIWORD if subst was successful.
1389    */
1390  return (DWORD)MAKELONG(strlen(str), length);
1391 }
1392
1393 /*************************************************************************
1394  *                              ShellHookProc           [SHELL.103]
1395  * System-wide WH_SHELL hook.
1396  */
1397 LRESULT WINAPI ShellHookProc(INT16 code, WPARAM16 wParam, LPARAM lParam)
1398 {
1399     TRACE(reg,"%i, %04x, %08x\n", code, wParam, 
1400                                                       (unsigned)lParam );
1401     if( SHELL_hHook && SHELL_hWnd )
1402     {
1403         UINT16  uMsg = 0;
1404         switch( code )
1405         {
1406             case HSHELL_WINDOWCREATED:          uMsg = uMsgWndCreated;   break;
1407             case HSHELL_WINDOWDESTROYED:        uMsg = uMsgWndDestroyed; break;
1408             case HSHELL_ACTIVATESHELLWINDOW:    uMsg = uMsgShellActivate;
1409         }
1410         PostMessage16( SHELL_hWnd, uMsg, wParam, 0 );
1411     }
1412     return CallNextHookEx16( WH_SHELL, code, wParam, lParam );
1413 }
1414
1415 /*************************************************************************
1416  *                              RegisterShellHook       [SHELL.102]
1417  */
1418 BOOL32 WINAPI RegisterShellHook(HWND16 hWnd, UINT16 uAction)
1419 {
1420     TRACE(reg,"%04x [%u]\n", hWnd, uAction );
1421
1422     switch( uAction )
1423     {
1424         case 2: /* register hWnd as a shell window */
1425
1426              if( !SHELL_hHook )
1427              {
1428                 HMODULE16 hShell = GetModuleHandle16( "SHELL" );
1429
1430                 SHELL_hHook = SetWindowsHookEx16( WH_SHELL, ShellHookProc,
1431                                                   hShell, 0 );
1432                 if( SHELL_hHook )
1433                 {
1434                     uMsgWndCreated = RegisterWindowMessage32A( lpstrMsgWndCreated );
1435                     uMsgWndDestroyed = RegisterWindowMessage32A( lpstrMsgWndDestroyed );
1436                     uMsgShellActivate = RegisterWindowMessage32A( lpstrMsgShellActivate );
1437                 } 
1438                 else WARN(reg, "unable to install ShellHookProc()!\n");
1439              }
1440
1441              if( SHELL_hHook ) return ((SHELL_hWnd = hWnd) != 0);
1442              break;
1443
1444         default:
1445
1446              WARN(reg, "unknown code %i\n", uAction );
1447
1448              /* just in case */
1449
1450              SHELL_hWnd = 0;
1451     }
1452     return FALSE;
1453 }
1454
1455
1456 /*************************************************************************
1457  *                              SHGetFileInfoA          [SHELL32.218]
1458  */
1459 DWORD WINAPI SHGetFileInfo32A(LPCSTR path,DWORD dwFileAttributes,
1460                               SHFILEINFO32A *psfi, UINT32 sizeofpsfi,
1461                               UINT32 flags )
1462 {
1463         FIXME(shell,"(%s,0x%08lx,%p,%d,0x%08x): stub\n",
1464               path,dwFileAttributes,psfi,sizeofpsfi,flags);
1465         return TRUE;
1466 }
1467
1468 /*************************************************************************
1469  *                              SHAppBarMessage32       [SHELL32.207]
1470  */
1471 UINT32 WINAPI SHAppBarMessage32(DWORD msg, PAPPBARDATA data)
1472 {
1473     FIXME(shell,"(0x%08lx,%p): stub\n", msg, data);
1474 #if 0
1475     switch (msg) {
1476         case ABM_ACTIVATE:
1477         case ABM_GETAUTOHIDEBAR:
1478         case ABM_GETSTATE:
1479         case ABM_GETTASKBARPOS:
1480         case ABM_NEW:
1481         case ABM_QUERYPOS:
1482         case ABM_REMOVE:
1483         case ABM_SETAUTOHIDEBAR:
1484         case ABM_SETPOS:
1485         case ABM_WINDOWPOSCHANGED:
1486             ;
1487     }
1488 #endif
1489     return 0;
1490 }
1491
1492 /*************************************************************************
1493  *                              CommandLineToArgvW      [SHELL32.7]
1494  */
1495 LPWSTR* WINAPI CommandLineToArgvW(LPWSTR cmdline,LPDWORD numargs)
1496 {
1497         LPWSTR  *argv,s,t;
1498         int     i;
1499
1500         /* to get writeable copy */
1501         cmdline = HEAP_strdupW( GetProcessHeap(), 0, cmdline);
1502         s=cmdline;i=0;
1503         while (*s) {
1504                 /* space */
1505                 if (*s==0x0020) {
1506                         i++;
1507                         s++;
1508                         while (*s && *s==0x0020)
1509                                 s++;
1510                         continue;
1511                 }
1512                 s++;
1513         }
1514         argv=(LPWSTR*)HeapAlloc( GetProcessHeap(), 0, sizeof(LPWSTR)*(i+1) );
1515         s=t=cmdline;
1516         i=0;
1517         while (*s) {
1518                 if (*s==0x0020) {
1519                         *s=0;
1520                         argv[i++]=HEAP_strdupW( GetProcessHeap(), 0, t );
1521                         *s=0x0020;
1522                         while (*s && *s==0x0020)
1523                                 s++;
1524                         if (*s)
1525                                 t=s+1;
1526                         else
1527                                 t=s;
1528                         continue;
1529                 }
1530                 s++;
1531         }
1532         if (*t)
1533                 argv[i++]=(LPWSTR)HEAP_strdupW( GetProcessHeap(), 0, t );
1534         HeapFree( GetProcessHeap(), 0, cmdline );
1535         argv[i]=NULL;
1536         *numargs=i;
1537         return argv;
1538 }
1539
1540 /*************************************************************************
1541  *                              Control_RunDLL          [SHELL32.12]
1542  *
1543  * Wild speculation in the following!
1544  *
1545  * http://premium.microsoft.com/msdn/library/techart/msdn193.htm
1546  */
1547
1548 void WINAPI Control_RunDLL (HWND32 hwnd, LPCVOID code, LPCSTR cmd, DWORD arg4)
1549 {
1550   TRACE(exec, "(%08x, %p, \"%s\", %08lx)\n",
1551         hwnd, code ? code : "(null)", cmd ? cmd : "(null)", arg4);
1552 }
1553
1554 /*************************************************************************
1555  */
1556
1557 void WINAPI FreeIconList( DWORD dw )
1558 {
1559     FIXME(reg, "empty stub\n" );
1560 }
1561
1562 /*************************************************************************
1563  *                       SHELL32_DllGetClassObject   [SHELL32.14]
1564  *
1565  * http://premium.microsoft.com/msdn/library/sdkdoc/api2_48fo.htm
1566  */
1567 DWORD WINAPI SHELL32_DllGetClassObject(REFCLSID rclsid,REFIID iid,LPVOID *ppv)
1568 {
1569     char        xclsid[50],xiid[50];
1570     HRESULT     hres = E_OUTOFMEMORY;
1571
1572
1573     WINE_StringFromCLSID((LPCLSID)rclsid,xclsid);
1574     WINE_StringFromCLSID((LPCLSID)iid,xiid);
1575     TRACE(shell,"(%s,%s,%p)\n",xclsid,xiid,ppv);
1576
1577     *ppv = NULL;
1578 /* SDK example code looks like this:
1579  *
1580     HRESULT     hres = E_OUTOFMEMORY;
1581
1582     *ppv = NULL;
1583     CClassFactory *pClassFactory = new CClassFactory(rclsid);
1584     
1585     if (pClassFactory) {
1586         hRes = pClassFactory->QueryInterface(riid,ppv);
1587         pClassFactory->Release();
1588     }
1589     return hRes;
1590  *
1591  * The magic of the whole stuff is still unclear to me, so just hack together 
1592  * something.
1593  */
1594   
1595     if (!memcmp(rclsid,&CLSID_ShellDesktop,sizeof(CLSID_ShellDesktop))) {
1596         TRACE(shell,"   requested CLSID_ShellDesktop, creating it.\n");
1597         *ppv = IShellFolder_Constructor();
1598         FIXME(shell,"Initialize this folder to be the shell desktop folder\n");
1599         return 0;
1600     }
1601
1602     FIXME(shell, "   -> clsid not found. returning E_OUTOFMEMORY.\n");
1603     return hres;
1604 }
1605
1606 /*************************************************************************
1607  *                       SHGetDesktopFolder             [SHELL32.216]
1608  * returns the interface to the shell desktop folder.
1609  *
1610  * [SDK header win95/shlobj.h: This is equivalent to call CoCreateInstance with
1611  *  CLSID_ShellDesktop.
1612  *
1613  *  CoCreateInstance(CLSID_Desktop, NULL,
1614  *                   CLSCTX_INPROC, IID_IShellFolder, &pshf);
1615  * ]
1616  * So what we are doing is currently wrong....
1617  */
1618 DWORD WINAPI SHGetDesktopFolder(LPSHELLFOLDER *shellfolder) {
1619         *shellfolder = IShellFolder_Constructor();
1620         return NOERROR;
1621 }
1622
1623 /*************************************************************************
1624  *                       SHGetMalloc                    [SHELL32.220]
1625  * returns the interface to shell malloc.
1626  *
1627  * [SDK header win95/shlobj.h:
1628  * equivalent to:  #define SHGetMalloc(ppmem)   CoGetMalloc(MEMCTX_TASK, ppmem)
1629  * ]
1630  * What we are currently doing is not very wrong, since we always use the same
1631  * heap (ProcessHeap).
1632  */
1633 DWORD WINAPI SHGetMalloc(LPMALLOC32 *lpmal) {
1634         TRACE(shell,"(%p)\n", lpmal);
1635         return CoGetMalloc32(0,lpmal);
1636 }
1637
1638 /*************************************************************************
1639  *                       SHGetSpecialFolderLocation     [SHELL32.223]
1640  * returns the PIDL of a special folder
1641  *
1642  * nFolder is a CSIDL_xxxxx.
1643  */
1644 HRESULT WINAPI SHGetSpecialFolderLocation(HWND32 hwndOwner, INT32 nFolder, LPITEMIDLIST * ppidl) {
1645         FIXME(shell,"(%04x,%d,%p),stub!\n", hwndOwner,nFolder,ppidl);
1646         *ppidl = (LPITEMIDLIST)HeapAlloc(GetProcessHeap(),0,2*sizeof(ITEMIDLIST));
1647         FIXME(shell, "we return only the empty ITEMIDLIST currently.\n");
1648         (*ppidl)->mkid.cb = 0;
1649         return NOERROR;
1650 }
1651
1652 /*************************************************************************
1653  *                       SHGetPathFromIDList            [SHELL32.221]
1654  * returns the path from a passed PIDL.
1655  */
1656 BOOL32 WINAPI SHGetPathFromIDList(LPCITEMIDLIST pidl,LPSTR pszPath) {
1657         FIXME(shell,"(%p,%p),stub!\n",pidl,pszPath);
1658         lstrcpy32A(pszPath,"E:\\"); /* FIXME */
1659         return NOERROR;
1660 }
1661
1662
1663
1664
1665