Added support for #pragma code_page.
[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  *                              FindEnvironmentString   [SHELL.38]
367  *
368  * Returns a pointer into the DOS environment... Ugh.
369  */
370 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
371 { UINT16 l;
372
373   TRACE("\n");
374
375   l = strlen(entry);
376   for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
377   { if( strncasecmp(lpEnv, entry, l) )
378       continue;
379         if( !*(lpEnv+l) )
380             return (lpEnv + l);                 /* empty entry */
381         else if ( *(lpEnv+l)== '=' )
382             return (lpEnv + l + 1);
383     }
384     return NULL;
385 }
386
387 /**********************************************************************/
388
389 SEGPTR WINAPI FindEnvironmentString16(LPSTR str)
390 { SEGPTR  spEnv;
391   LPSTR lpEnv,lpString;
392   TRACE("\n");
393
394   spEnv = GetDOSEnvironment16();
395
396   lpEnv = MapSL(spEnv);
397   lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL;
398
399     if( lpString )              /*  offset should be small enough */
400         return spEnv + (lpString - lpEnv);
401     return (SEGPTR)NULL;
402 }
403
404 /*************************************************************************
405  *                              DoEnvironmentSubst      [SHELL.37]
406  *
407  * Replace %KEYWORD% in the str with the value of variable KEYWORD
408  * from "DOS" environment.
409  */
410 DWORD WINAPI DoEnvironmentSubst16(LPSTR str,WORD length)
411 {
412   LPSTR   lpEnv = MapSL(GetDOSEnvironment16());
413   LPSTR   lpBuffer = (LPSTR)HeapAlloc( GetProcessHeap(), 0, length);
414   LPSTR   lpstr = str;
415   LPSTR   lpbstr = lpBuffer;
416
417   CharToOemA(str,str);
418
419   TRACE("accept %s\n", str);
420
421   while( *lpstr && lpbstr - lpBuffer < length )
422    {
423      LPSTR lpend = lpstr;
424
425      if( *lpstr == '%' )
426        {
427           do { lpend++; } while( *lpend && *lpend != '%' );
428           if( *lpend == '%' && lpend - lpstr > 1 )      /* found key */
429             {
430                LPSTR lpKey;
431               *lpend = '\0';
432                lpKey = SHELL_FindString(lpEnv, lpstr+1);
433                if( lpKey )                              /* found key value */
434                  {
435                    int l = strlen(lpKey);
436
437                    if( l > length - (lpbstr - lpBuffer) - 1 )
438                      {
439            WARN("-- Env subst aborted - string too short\n");
440                       *lpend = '%';
441                        break;
442                      }
443                    strcpy(lpbstr, lpKey);
444                    lpbstr += l;
445                  }
446                else break;
447               *lpend = '%';
448                lpstr = lpend + 1;
449             }
450           else break;                                   /* back off and whine */
451
452           continue;
453        }
454
455      *lpbstr++ = *lpstr++;
456    }
457
458  *lpbstr = '\0';
459   if( lpstr - str == strlen(str) )
460     {
461       strncpy(str, lpBuffer, length);
462       length = 1;
463     }
464   else
465       length = 0;
466
467   TRACE("-- return %s\n", str);
468
469   OemToCharA(str,str);
470   HeapFree( GetProcessHeap(), 0, lpBuffer);
471
472   /*  Return str length in the LOWORD
473    *  and 1 in HIWORD if subst was successful.
474    */
475  return (DWORD)MAKELONG(strlen(str), length);
476 }
477
478 /*************************************************************************
479  *                              ShellHookProc           [SHELL.103]
480  * System-wide WH_SHELL hook.
481  */
482 LRESULT WINAPI ShellHookProc16(INT16 code, WPARAM16 wParam, LPARAM lParam)
483 {
484     TRACE("%i, %04x, %08x\n", code, wParam,
485                                                       (unsigned)lParam );
486     if( SHELL_hHook && SHELL_hWnd )
487     {
488         UINT16  uMsg = 0;
489         switch( code )
490         {
491             case HSHELL_WINDOWCREATED:          uMsg = uMsgWndCreated;   break;
492             case HSHELL_WINDOWDESTROYED:        uMsg = uMsgWndDestroyed; break;
493             case HSHELL_ACTIVATESHELLWINDOW:    uMsg = uMsgShellActivate;
494         }
495         PostMessageA( SHELL_hWnd, uMsg, wParam, 0 );
496     }
497     return CallNextHookEx16( SHELL_hHook, code, wParam, lParam );
498 }
499
500 /*************************************************************************
501  *                              RegisterShellHook       [SHELL.102]
502  */
503 BOOL WINAPI RegisterShellHook16(HWND16 hWnd, UINT16 uAction)
504 {
505     TRACE("%04x [%u]\n", hWnd, uAction );
506
507     switch( uAction )
508     {
509     case 2:  /* register hWnd as a shell window */
510         if( !SHELL_hHook )
511         {
512             HMODULE16 hShell = GetModuleHandle16( "SHELL" );
513             HOOKPROC16 hookProc = (HOOKPROC16)GetProcAddress16( hShell, (LPCSTR)103 );
514             SHELL_hHook = SetWindowsHookEx16( WH_SHELL, hookProc, hShell, 0 );
515             if ( SHELL_hHook )
516             {
517                 uMsgWndCreated = RegisterWindowMessageA( lpstrMsgWndCreated );
518                 uMsgWndDestroyed = RegisterWindowMessageA( lpstrMsgWndDestroyed );
519                 uMsgShellActivate = RegisterWindowMessageA( lpstrMsgShellActivate );
520             }
521             else
522                 WARN("-- unable to install ShellHookProc()!\n");
523         }
524
525         if ( SHELL_hHook )
526             return ((SHELL_hWnd = hWnd) != 0);
527         break;
528
529     default:
530         WARN("-- unknown code %i\n", uAction );
531         SHELL_hWnd = 0; /* just in case */
532     }
533     return FALSE;
534 }
535
536
537 /***********************************************************************
538  *           DriveType   (SHELL.262)
539  */
540 UINT16 WINAPI DriveType16( UINT16 drive )
541 {
542     UINT ret;
543     char path[] = "A:\\";
544     path[0] += drive;
545     ret = GetDriveTypeA(path);
546     switch(ret)  /* some values are not supported in Win16 */
547     {
548     case DRIVE_CDROM:
549         ret = DRIVE_REMOTE;
550         break;
551     case DRIVE_NO_ROOT_DIR:
552         ret = DRIVE_UNKNOWN;
553         break;
554     }
555     return ret;
556 }