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