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