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