Fix focus handling when deleting items, or changing modes.
[wine] / dlls / shell32 / shell.c
1 /*
2  *                              Shell Library Functions
3  *
4  * Copyright 1998 Marcus Meissner
5  * Copyright 2002 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <ctype.h>
31
32 #include "windef.h"
33 #include "winerror.h"
34 #include "winreg.h"
35 #include "dlgs.h"
36 #include "shellapi.h"
37 #include "shlobj.h"
38 #include "shlwapi.h"
39 #include "ddeml.h"
40
41 #include "wine/winbase16.h"
42 #include "wine/winuser16.h"
43 #include "shell32_main.h"
44
45 #include "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(shell);
48 WINE_DECLARE_DEBUG_CHANNEL(exec);
49
50
51 typedef struct {     /* structure for dropped files */
52  WORD     wSize;
53  POINT16  ptMousePos;
54  BOOL16   fInNonClientArea;
55  /* memory block with filenames follows */
56 } DROPFILESTRUCT16, *LPDROPFILESTRUCT16;
57
58 static const char*      lpstrMsgWndCreated = "OTHERWINDOWCREATED";
59 static const char*      lpstrMsgWndDestroyed = "OTHERWINDOWDESTROYED";
60 static const char*      lpstrMsgShellActivate = "ACTIVATESHELLWINDOW";
61
62 static HWND16   SHELL_hWnd = 0;
63 static HHOOK    SHELL_hHook = 0;
64 static UINT16   uMsgWndCreated = 0;
65 static UINT16   uMsgWndDestroyed = 0;
66 static UINT16   uMsgShellActivate = 0;
67 HINSTANCE16     SHELL_hInstance = 0;
68 HINSTANCE SHELL_hInstance32;
69 static int SHELL_Attach = 0;
70
71 /***********************************************************************
72  * DllEntryPoint [SHELL.101]
73  *
74  * Initialization code for shell.dll. Automatically loads the
75  * 32-bit shell32.dll to allow thunking up to 32-bit code.
76  *
77  * RETURNS:
78  */
79 BOOL WINAPI SHELL_DllEntryPoint(DWORD Reason, HINSTANCE16 hInst,
80                                 WORD ds, WORD HeapSize, DWORD res1, WORD res2)
81 {
82     TRACE("(%08lx, %04x, %04x, %04x, %08lx, %04x)\n",
83           Reason, hInst, ds, HeapSize, res1, res2);
84
85     switch(Reason)
86     {
87     case DLL_PROCESS_ATTACH:
88         if (SHELL_Attach++) break;
89         SHELL_hInstance = hInst;
90         if(!SHELL_hInstance32)
91         {
92             if(!(SHELL_hInstance32 = LoadLibraryA("shell32.dll")))
93             {
94                 ERR("Could not load sibling shell32.dll\n");
95                 return FALSE;
96             }
97         }
98         break;
99
100     case DLL_PROCESS_DETACH:
101         if(!--SHELL_Attach)
102         {
103             SHELL_hInstance = 0;
104             if(SHELL_hInstance32)
105                 FreeLibrary(SHELL_hInstance32);
106         }
107         break;
108     }
109     return TRUE;
110 }
111
112 /*************************************************************************
113  *                              DragAcceptFiles         [SHELL.9]
114  */
115 void WINAPI DragAcceptFiles16(HWND16 hWnd, BOOL16 b)
116 {
117   DragAcceptFiles(HWND_32(hWnd), b);
118 }
119
120 /*************************************************************************
121  *                              DragQueryFile           [SHELL.11]
122  */
123 UINT16 WINAPI DragQueryFile16(
124         HDROP16 hDrop,
125         WORD wFile,
126         LPSTR lpszFile,
127         WORD wLength)
128 {
129         LPSTR lpDrop;
130         UINT i = 0;
131         LPDROPFILESTRUCT16 lpDropFileStruct = (LPDROPFILESTRUCT16) GlobalLock16(hDrop);
132
133         TRACE("(%04x, %x, %p, %u)\n", hDrop,wFile,lpszFile,wLength);
134
135         if(!lpDropFileStruct) goto end;
136
137         lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
138         wFile = (wFile==0xffff) ? 0xffffffff : wFile;
139
140         while (i++ < wFile)
141         {
142           while (*lpDrop++); /* skip filename */
143           if (!*lpDrop)
144           {
145             i = (wFile == 0xFFFFFFFF) ? i : 0;
146             goto end;
147           }
148         }
149
150         i = strlen(lpDrop);
151         i++;
152         if (!lpszFile ) goto end;   /* needed buffer size */
153         i = (wLength > i) ? i : wLength;
154         lstrcpynA (lpszFile,  lpDrop,  i);
155 end:
156         GlobalUnlock16(hDrop);
157         return i;
158 }
159
160 /*************************************************************************
161  *                              DragFinish              [SHELL.12]
162  */
163 void WINAPI DragFinish16(HDROP16 h)
164 {
165     TRACE("\n");
166     GlobalFree16((HGLOBAL16)h);
167 }
168
169
170 /*************************************************************************
171  *                              DragQueryPoint          [SHELL.13]
172  */
173 BOOL16 WINAPI DragQueryPoint16(HDROP16 hDrop, POINT16 *p)
174 {
175   LPDROPFILESTRUCT16 lpDropFileStruct;
176   BOOL16           bRet;
177   TRACE("\n");
178   lpDropFileStruct = (LPDROPFILESTRUCT16) GlobalLock16(hDrop);
179
180   memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT16));
181   bRet = lpDropFileStruct->fInNonClientArea;
182
183   GlobalUnlock16(hDrop);
184   return bRet;
185 }
186
187 /*************************************************************************
188  *             FindExecutable   (SHELL.21)
189  */
190 HINSTANCE16 WINAPI FindExecutable16( LPCSTR lpFile, LPCSTR lpDirectory,
191                                      LPSTR lpResult )
192 { return (HINSTANCE16)FindExecutableA( lpFile, lpDirectory, lpResult );
193 }
194
195
196 /*************************************************************************
197  *             AboutDlgProc   (SHELL.33)
198  */
199 BOOL16 WINAPI AboutDlgProc16( HWND16 hWnd, UINT16 msg, WPARAM16 wParam,
200                                LPARAM lParam )
201 { return AboutDlgProc( HWND_32(hWnd), msg, wParam, lParam );
202 }
203
204
205 /*************************************************************************
206  *             ShellAbout   (SHELL.22)
207  */
208 BOOL16 WINAPI ShellAbout16( HWND16 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
209                             HICON16 hIcon )
210 { return ShellAboutA( HWND_32(hWnd), szApp, szOtherStuff, hIcon );
211 }
212
213 /*************************************************************************
214  *                      InternalExtractIcon             [SHELL.39]
215  *
216  * This abortion is called directly by Progman
217  */
218 HGLOBAL16 WINAPI InternalExtractIcon16(HINSTANCE16 hInstance,
219                                      LPCSTR lpszExeFileName, UINT16 nIconIndex, WORD n )
220 {
221     HGLOBAL16 hRet = 0;
222     HICON16 *RetPtr = NULL;
223     OFSTRUCT ofs;
224     HFILE hFile;
225
226         TRACE("(%04x,file %s,start %d,extract %d\n",
227                        hInstance, lpszExeFileName, nIconIndex, n);
228
229         if( !n )
230           return 0;
231
232         hFile = OpenFile( lpszExeFileName, &ofs, OF_READ|OF_EXIST );
233
234         hRet = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
235         RetPtr = (HICON16*)GlobalLock16(hRet);
236
237         if (hFile == HFILE_ERROR)
238         { /* not found - load from builtin module if available */
239           HINSTANCE hInst = (HINSTANCE)LoadLibrary16(lpszExeFileName);
240
241           if (hInst < 32) /* hmm, no Win16 module - try Win32 :-) */
242             hInst = LoadLibraryA(lpszExeFileName);
243           if (hInst)
244           {
245             int i;
246             for (i=nIconIndex; i < nIconIndex + n; i++)
247               RetPtr[i-nIconIndex] =
248                       (HICON16)LoadIconA(hInst, (LPCSTR)(DWORD)i);
249             FreeLibrary(hInst);
250             return hRet;
251           }
252           GlobalFree16( hRet );
253           return 0;
254         }
255
256         if (nIconIndex == (UINT16)-1)  /* get number of icons */
257         {
258             RetPtr[0] = PrivateExtractIconsA( ofs.szPathName, -1, 0, 0, NULL, 0, 0, 0 );
259         }
260         else
261         {
262             HRESULT res;
263             HICON *icons;
264             icons = HeapAlloc( GetProcessHeap(), 0, n * sizeof(*icons) );
265             res = PrivateExtractIconsA( ofs.szPathName, nIconIndex,
266                                         GetSystemMetrics(SM_CXICON),
267                                         GetSystemMetrics(SM_CYICON),
268                                         icons, 0, n, 0 );
269             if (!res)
270             {
271                 int i;
272                 for (i = 0; i < n; i++) RetPtr[i] = (HICON16)icons[i];
273             }
274             else
275             {
276                 GlobalFree16( hRet );
277                 hRet = 0;
278             }
279             HeapFree( GetProcessHeap(), 0, icons );
280         }
281         return hRet;
282 }
283
284 /*************************************************************************
285  *             ExtractIcon   (SHELL.34)
286  */
287 HICON16 WINAPI ExtractIcon16( HINSTANCE16 hInstance, LPCSTR lpszExeFileName,
288         UINT16 nIconIndex )
289 {   TRACE("\n");
290     return ExtractIconA( hInstance, lpszExeFileName, nIconIndex );
291 }
292
293 /*************************************************************************
294  *             ExtractIconEx   (SHELL.40)
295  */
296 HICON16 WINAPI ExtractIconEx16(
297         LPCSTR lpszFile, INT16 nIconIndex, HICON16 *phiconLarge,
298         HICON16 *phiconSmall, UINT16 nIcons
299 ) {
300     HICON       *ilarge,*ismall;
301     UINT16      ret;
302     int         i;
303
304     if (phiconLarge)
305         ilarge = (HICON*)HeapAlloc(GetProcessHeap(),0,nIcons*sizeof(HICON));
306     else
307         ilarge = NULL;
308     if (phiconSmall)
309         ismall = (HICON*)HeapAlloc(GetProcessHeap(),0,nIcons*sizeof(HICON));
310     else
311         ismall = NULL;
312     ret = ExtractIconExA(lpszFile,nIconIndex,ilarge,ismall,nIcons);
313     if (ilarge) {
314         for (i=0;i<nIcons;i++)
315             phiconLarge[i]=ilarge[i];
316         HeapFree(GetProcessHeap(),0,ilarge);
317     }
318     if (ismall) {
319         for (i=0;i<nIcons;i++)
320             phiconSmall[i]=ismall[i];
321         HeapFree(GetProcessHeap(),0,ismall);
322     }
323     return ret;
324 }
325
326 /*************************************************************************
327  *                              ExtractAssociatedIcon   [SHELL.36]
328  *
329  * Return icon for given file (either from file itself or from associated
330  * executable) and patch parameters if needed.
331  */
332 HICON16 WINAPI ExtractAssociatedIcon16(HINSTANCE16 hInst, LPSTR lpIconPath, LPWORD lpiIcon)
333 {       HICON16 hIcon;
334         WORD wDummyIcon = 0;
335
336         TRACE("\n");
337
338         if(lpiIcon == NULL)
339             lpiIcon = &wDummyIcon;
340
341         hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
342
343         if( hIcon < 2 )
344         { if( hIcon == 1 ) /* no icons found in given file */
345           { char  tempPath[0x80];
346             UINT16  uRet = FindExecutable16(lpIconPath,NULL,tempPath);
347
348             if( uRet > 32 && tempPath[0] )
349             { strcpy(lpIconPath,tempPath);
350               hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
351               if( hIcon > 2 )
352                 return hIcon;
353             }
354             else hIcon = 0;
355           }
356
357           if( hIcon == 1 )
358             *lpiIcon = 2;   /* MSDOS icon - we found .exe but no icons in it */
359           else
360             *lpiIcon = 6;   /* generic icon - found nothing */
361
362           GetModuleFileName16(hInst, lpIconPath, 0x80);
363           hIcon = LoadIconA( hInst, MAKEINTRESOURCEA(*lpiIcon));
364         }
365         return hIcon;
366 }
367
368 /*************************************************************************
369  *                              FindEnvironmentString   [SHELL.38]
370  *
371  * Returns a pointer into the DOS environment... Ugh.
372  */
373 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
374 { UINT16 l;
375
376   TRACE("\n");
377
378   l = strlen(entry);
379   for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
380   { if( strncasecmp(lpEnv, entry, l) )
381       continue;
382         if( !*(lpEnv+l) )
383             return (lpEnv + l);                 /* empty entry */
384         else if ( *(lpEnv+l)== '=' )
385             return (lpEnv + l + 1);
386     }
387     return NULL;
388 }
389
390 /**********************************************************************/
391
392 SEGPTR WINAPI FindEnvironmentString16(LPSTR str)
393 { SEGPTR  spEnv;
394   LPSTR lpEnv,lpString;
395   TRACE("\n");
396
397   spEnv = GetDOSEnvironment16();
398
399   lpEnv = MapSL(spEnv);
400   lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL;
401
402     if( lpString )              /*  offset should be small enough */
403         return spEnv + (lpString - lpEnv);
404     return (SEGPTR)NULL;
405 }
406
407 /*************************************************************************
408  *                              DoEnvironmentSubst      [SHELL.37]
409  *
410  * Replace %KEYWORD% in the str with the value of variable KEYWORD
411  * from "DOS" environment.
412  */
413 DWORD WINAPI DoEnvironmentSubst16(LPSTR str,WORD length)
414 {
415   LPSTR   lpEnv = MapSL(GetDOSEnvironment16());
416   LPSTR   lpBuffer = (LPSTR)HeapAlloc( GetProcessHeap(), 0, length);
417   LPSTR   lpstr = str;
418   LPSTR   lpbstr = lpBuffer;
419
420   CharToOemA(str,str);
421
422   TRACE("accept %s\n", str);
423
424   while( *lpstr && lpbstr - lpBuffer < length )
425    {
426      LPSTR lpend = lpstr;
427
428      if( *lpstr == '%' )
429        {
430           do { lpend++; } while( *lpend && *lpend != '%' );
431           if( *lpend == '%' && lpend - lpstr > 1 )      /* found key */
432             {
433                LPSTR lpKey;
434               *lpend = '\0';
435                lpKey = SHELL_FindString(lpEnv, lpstr+1);
436                if( lpKey )                              /* found key value */
437                  {
438                    int l = strlen(lpKey);
439
440                    if( l > length - (lpbstr - lpBuffer) - 1 )
441                      {
442            WARN("-- Env subst aborted - string too short\n");
443                       *lpend = '%';
444                        break;
445                      }
446                    strcpy(lpbstr, lpKey);
447                    lpbstr += l;
448                  }
449                else break;
450               *lpend = '%';
451                lpstr = lpend + 1;
452             }
453           else break;                                   /* back off and whine */
454
455           continue;
456        }
457
458      *lpbstr++ = *lpstr++;
459    }
460
461  *lpbstr = '\0';
462   if( lpstr - str == strlen(str) )
463     {
464       strncpy(str, lpBuffer, length);
465       length = 1;
466     }
467   else
468       length = 0;
469
470   TRACE("-- return %s\n", str);
471
472   OemToCharA(str,str);
473   HeapFree( GetProcessHeap(), 0, lpBuffer);
474
475   /*  Return str length in the LOWORD
476    *  and 1 in HIWORD if subst was successful.
477    */
478  return (DWORD)MAKELONG(strlen(str), length);
479 }
480
481 /*************************************************************************
482  *                              ShellHookProc           [SHELL.103]
483  * System-wide WH_SHELL hook.
484  */
485 LRESULT WINAPI ShellHookProc16(INT16 code, WPARAM16 wParam, LPARAM lParam)
486 {
487     TRACE("%i, %04x, %08x\n", code, wParam,
488                                                       (unsigned)lParam );
489     if( SHELL_hHook && SHELL_hWnd )
490     {
491         UINT16  uMsg = 0;
492         switch( code )
493         {
494             case HSHELL_WINDOWCREATED:          uMsg = uMsgWndCreated;   break;
495             case HSHELL_WINDOWDESTROYED:        uMsg = uMsgWndDestroyed; break;
496             case HSHELL_ACTIVATESHELLWINDOW:    uMsg = uMsgShellActivate;
497         }
498         PostMessageA( HWND_32(SHELL_hWnd), uMsg, wParam, 0 );
499     }
500     return CallNextHookEx16( SHELL_hHook, code, wParam, lParam );
501 }
502
503 /*************************************************************************
504  *                              RegisterShellHook       [SHELL.102]
505  */
506 BOOL WINAPI RegisterShellHook16(HWND16 hWnd, UINT16 uAction)
507 {
508     TRACE("%04x [%u]\n", hWnd, uAction );
509
510     switch( uAction )
511     {
512     case 2:  /* register hWnd as a shell window */
513         if( !SHELL_hHook )
514         {
515             HMODULE16 hShell = GetModuleHandle16( "SHELL" );
516             HOOKPROC16 hookProc = (HOOKPROC16)GetProcAddress16( hShell, (LPCSTR)103 );
517             SHELL_hHook = SetWindowsHookEx16( WH_SHELL, hookProc, hShell, 0 );
518             if ( SHELL_hHook )
519             {
520                 uMsgWndCreated = RegisterWindowMessageA( lpstrMsgWndCreated );
521                 uMsgWndDestroyed = RegisterWindowMessageA( lpstrMsgWndDestroyed );
522                 uMsgShellActivate = RegisterWindowMessageA( lpstrMsgShellActivate );
523             }
524             else
525                 WARN("-- unable to install ShellHookProc()!\n");
526         }
527
528         if ( SHELL_hHook )
529             return ((SHELL_hWnd = hWnd) != 0);
530         break;
531
532     default:
533         WARN("-- unknown code %i\n", uAction );
534         SHELL_hWnd = 0; /* just in case */
535     }
536     return FALSE;
537 }
538
539
540 /***********************************************************************
541  *           DriveType   (SHELL.262)
542  */
543 UINT16 WINAPI DriveType16( UINT16 drive )
544 {
545     UINT ret;
546     char path[] = "A:\\";
547     path[0] += drive;
548     ret = GetDriveTypeA(path);
549     switch(ret)  /* some values are not supported in Win16 */
550     {
551     case DRIVE_CDROM:
552         ret = DRIVE_REMOTE;
553         break;
554     case DRIVE_NO_ROOT_DIR:
555         ret = DRIVE_UNKNOWN;
556         break;
557     }
558     return ret;
559 }