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