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