Release 960506
[wine] / misc / shell.c
1 /*
2  *                              Shell Library Functions
3  */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <ctype.h>
9 #include "windows.h"
10 #include "file.h"
11 #include "shell.h"
12 #include "module.h"
13 #include "neexe.h"
14 #include "resource.h"
15 #include "dlgs.h"
16 #include "win.h"
17 #include "stddebug.h"
18 #include "debug.h"
19 #include "xmalloc.h"
20
21 extern HANDLE   CURSORICON_LoadHandler( HANDLE, HINSTANCE, BOOL);
22 extern WORD     GetIconID( HANDLE hResource, DWORD resType );
23
24 /*************************************************************************
25  *                              DragAcceptFiles         [SHELL.9]
26  */
27 void DragAcceptFiles(HWND hWnd, BOOL b)
28 {
29     WND* wnd = WIN_FindWndPtr(hWnd);
30
31     if( wnd )
32         wnd->dwExStyle = b? wnd->dwExStyle | WS_EX_ACCEPTFILES
33                           : wnd->dwExStyle & ~WS_EX_ACCEPTFILES;
34 }
35
36
37 /*************************************************************************
38  *                              DragQueryFile           [SHELL.11]
39  */
40 UINT DragQueryFile(HDROP hDrop, WORD wFile, LPSTR lpszFile, WORD wLength)
41 {
42     /* hDrop is a global memory block allocated with GMEM_SHARE 
43      * with DROPFILESTRUCT as a header and filenames following
44      * it, zero length filename is in the end */       
45     
46     LPDROPFILESTRUCT lpDropFileStruct;
47     LPSTR lpCurrent;
48     WORD  i;
49     
50     dprintf_reg(stddeb,"DragQueryFile(%04x, %i, %p, %u)\n",
51                 hDrop,wFile,lpszFile,wLength);
52     
53     lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop); 
54     if(!lpDropFileStruct)
55     {
56         dprintf_reg(stddeb,"DragQueryFile: unable to lock handle!\n");
57         return 0;
58     } 
59     lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
60     
61     i = 0;
62     while (i++ < wFile)
63     {
64         while (*lpCurrent++);  /* skip filename */
65         if (!*lpCurrent) 
66             return (wFile == 0xFFFF) ? i : 0;  
67     }
68     
69     i = strlen(lpCurrent); 
70     if (!lpszFile) return i+1;   /* needed buffer size */
71     
72     i = (wLength > i) ? i : wLength-1;
73     strncpy(lpszFile, lpCurrent, i);
74     lpszFile[i] = '\0';
75     
76     GlobalUnlock16(hDrop);
77     return i;
78 }
79
80
81 /*************************************************************************
82  *                              DragFinish              [SHELL.12]
83  */
84 void DragFinish(HDROP h)
85 {
86     GlobalFree16((HGLOBAL16)h);
87 }
88
89
90 /*************************************************************************
91  *                              DragQueryPoint          [SHELL.13]
92  */
93 BOOL DragQueryPoint(HDROP hDrop, POINT *p)
94 {
95     LPDROPFILESTRUCT lpDropFileStruct;  
96     BOOL             bRet;
97
98     lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
99
100     memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT));
101     bRet = lpDropFileStruct->fInNonClientArea;
102
103     GlobalUnlock16(hDrop);
104     return bRet;
105 }
106
107
108 /*************************************************************************
109  *                              ShellExecute            [SHELL.20]
110  */
111 HINSTANCE ShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
112 {
113     char cmd[400];
114     char *p,*x;
115     long len;
116     char subclass[200];
117
118     /* OK. We are supposed to lookup the program associated with lpFile,
119      * then to execute it using that program. If lpFile is a program,
120      * we have to pass the parameters. If an instance is already running,
121      * we might have to send DDE commands.
122      *
123      * FIXME: Should also look up WIN.INI [Extensions] section?
124      */
125
126     dprintf_exec(stddeb, "ShellExecute(%04x,'%s','%s','%s','%s',%x)\n",
127                 hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
128                 lpParameters ? lpParameters : "<null>", 
129                 lpDirectory ? lpDirectory : "<null>", iShowCmd);
130
131     if (lpFile==NULL) return 0; /* should not happen */
132     if (lpOperation==NULL) /* default is open */
133       lpOperation="open";
134     p=strrchr(lpFile,'.');
135     if (p!=NULL) {
136       x=p; /* the suffixes in the register database are lowercased */
137       while (*x) {*x=tolower(*x);x++;}
138     }
139     if (p==NULL || !strcmp(p,".exe")) {
140       p=".exe";
141       if (lpParameters) {
142         sprintf(cmd,"%s %s",lpFile,lpParameters);
143       } else {
144         strcpy(cmd,lpFile);
145       }
146     } else {
147       len=200;
148       if (RegQueryValue((HKEY)HKEY_CLASSES_ROOT,p,subclass,&len)==SHELL_ERROR_SUCCESS) {
149         if (len>20)
150           fprintf(stddeb,"ShellExecute:subclass with len %ld? (%s), please report.\n",len,subclass);
151         subclass[len]='\0';
152         strcat(subclass,"\\shell\\");
153         strcat(subclass,lpOperation);
154         strcat(subclass,"\\command");
155         dprintf_exec(stddeb,"ShellExecute:looking for %s.\n",subclass);
156         len=400;
157         if (RegQueryValue((HKEY)HKEY_CLASSES_ROOT,subclass,cmd,&len)==SHELL_ERROR_SUCCESS) {
158           char *t;
159           dprintf_exec(stddeb,"ShellExecute:...got %s\n",cmd);
160           cmd[len]='\0';
161           t=strstr(cmd,"%1");
162           if (t==NULL) {
163             strcat(cmd," ");
164             strcat(cmd,lpFile);
165           } else {
166             char *s;
167             s=xmalloc(len+strlen(lpFile)+10);
168             strncpy(s,cmd,t-cmd);
169             s[t-cmd]='\0';
170             strcat(s,lpFile);
171             strcat(s,t+2);
172             strcpy(cmd,s);
173             free(s);
174           }
175           /* does this use %x magic too? */
176           if (lpParameters) {
177             strcat(cmd," ");
178             strcat(cmd,lpParameters);
179           }
180         } else {
181           fprintf(stddeb,"ShellExecute: No %s\\shell\\%s\\command found for \"%s\" suffix.\n",subclass,lpOperation,p);
182           return (HINSTANCE)31; /* unknown type */
183         }
184       } else {
185         fprintf(stddeb,"ShellExecute: No operation found for \"%s\" suffix.\n",p);
186         return (HINSTANCE)31; /* file not found */
187       }
188     }
189     dprintf_exec(stddeb,"ShellExecute:starting %s\n",cmd);
190     return WinExec(cmd,iShowCmd);
191 }
192
193
194 /*************************************************************************
195  *                              FindExecutable          [SHELL.21]
196  */
197 HINSTANCE FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
198 {
199         fprintf(stdnimp, "FindExecutable: someone has to fix me and this is YOUR turn! :-)\n");
200
201         lpResult[0]='\0';
202         return 31;              /* no association */
203 }
204
205 static char AppName[128], AppMisc[1536];
206
207 /*************************************************************************
208  *                              AboutDlgProc            [SHELL.33]
209  */
210 LRESULT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
211 {
212   char Template[512], AppTitle[512];
213  
214   switch(msg) {
215    case WM_INITDIALOG:
216 #ifdef WINELIB32
217     SendDlgItemMessage(hWnd,stc1,STM_SETICON,lParam,0);
218 #else
219     SendDlgItemMessage(hWnd,stc1,STM_SETICON,LOWORD(lParam),0);
220 #endif
221     GetWindowText(hWnd, Template, 511);
222     sprintf(AppTitle, Template, AppName);
223     SetWindowText(hWnd, AppTitle);
224     SetWindowText(GetDlgItem(hWnd,100), AppMisc);
225     return 1;
226     
227    case WM_COMMAND:
228     switch (wParam) {
229      case IDOK:
230       EndDialog(hWnd, TRUE);
231       return TRUE;
232     }
233     break;
234   }
235   return FALSE;
236 }
237
238 /*************************************************************************
239  *                              ShellAbout              [SHELL.22]
240  */
241 INT ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon)
242 {
243     HANDLE handle;
244     BOOL bRet;
245
246     if (szApp) strncpy(AppName, szApp, sizeof(AppName));
247     else *AppName = 0;
248     AppName[sizeof(AppName)-1]=0;
249
250     if (szOtherStuff) strncpy(AppMisc, szOtherStuff, sizeof(AppMisc));
251     else *AppMisc = 0;
252     AppMisc[sizeof(AppMisc)-1]=0;
253
254     if (!hIcon) hIcon = LoadIcon(0,MAKEINTRESOURCE(OIC_WINEICON));
255     handle = SYSRES_LoadResource( SYSRES_DIALOG_SHELL_ABOUT_MSGBOX );
256     if (!handle) return FALSE;
257     bRet = DialogBoxIndirectParam( WIN_GetWindowInstance( hWnd ),
258                                    handle, hWnd,
259                                    MODULE_GetWndProcEntry16("AboutDlgProc"), 
260                                    (LONG)hIcon );
261     SYSRES_FreeResource( handle );
262     return bRet;
263 }
264
265 /*************************************************************************
266  *                              SHELL_GetResourceTable
267  *
268  * FIXME: Implement GetPEResourceTable in w32sys.c and call it here.
269  */
270 BYTE* SHELL_GetResourceTable(HFILE hFile)
271 {
272   struct mz_header_s mz_header;
273   struct ne_header_s ne_header;
274   int           size;
275   
276   _llseek( hFile, 0, SEEK_SET );
277   if ((FILE_Read(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
278       (mz_header.mz_magic != MZ_SIGNATURE)) return (BYTE*)-1;
279
280   _llseek( hFile, mz_header.ne_offset, SEEK_SET );
281   if (FILE_Read( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
282       return NULL;
283
284   if (ne_header.ne_magic == PE_SIGNATURE) 
285      { fprintf(stdnimp,"Win32 FIXME: file %s line %i\n", __FILE__, __LINE__ );
286        return NULL; }
287
288   if (ne_header.ne_magic != NE_SIGNATURE) return NULL;
289
290   size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
291
292   if( size > sizeof(NE_TYPEINFO) )
293     {
294       BYTE* pTypeInfo = (BYTE*)xmalloc(size);
295
296       if( !pTypeInfo ) return NULL;
297
298       _llseek(hFile, mz_header.ne_offset+ne_header.resource_tab_offset, SEEK_SET);
299       if( FILE_Read( hFile, (char*)pTypeInfo, size) != size )
300         { free(pTypeInfo); return NULL; }
301       return pTypeInfo;
302     }
303   /* no resources */
304
305   return NULL;
306 }
307
308 /*************************************************************************
309  *                      SHELL_LoadResource
310  */
311 HANDLE  SHELL_LoadResource(HINSTANCE hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
312 {
313  BYTE*  ptr;
314  HANDLE handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
315
316  if( (ptr = (BYTE*)GlobalLock16( handle )) )
317    {
318     _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
319      FILE_Read( hFile, (char*)ptr, pNInfo->length << sizeShift);
320      return handle;
321    }
322  return (HANDLE)0;
323 }
324
325 /*************************************************************************
326  *                      InternalExtractIcon             [SHELL.39]
327  *
328  * This abortion is called directly by Progman
329  */
330 HICON InternalExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, UINT nIconIndex, WORD n )
331 {
332   HANDLE        hRet = 0;
333   HICON*        RetPtr = NULL;
334   BYTE*         pData;
335   OFSTRUCT      ofs;
336   HFILE         hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
337   
338   dprintf_reg(stddeb, "InternalExtractIcon(%04x, file '%s', start from %d, extract %d\n", 
339                        hInstance, lpszExeFileName, nIconIndex, n);
340
341   if( hFile == HFILE_ERROR || !n ) return 0;
342
343   hRet = GlobalAlloc16( GMEM_FIXED, sizeof(HICON)*n);
344   RetPtr = (HICON*)GlobalLock16(hRet);
345
346  *RetPtr = (n == 0xFFFF)? 0: 1;                         /* error return values */
347
348   pData = SHELL_GetResourceTable(hFile);
349   if( pData ) 
350     if( pData == (BYTE*)-1 )
351       {
352         /* FIXME: possible .ICO file */
353
354         fprintf(stddeb,"InternalExtractIcon: cannot handle file %s\n", lpszExeFileName);
355       }
356     else                                                /* got resource table */
357       {
358         UINT         iconDirCount = 0;
359         UINT         iconCount = 0;
360         NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
361         NE_NAMEINFO* pIconStorage = NULL;
362         NE_NAMEINFO* pIconDir = NULL;
363
364         /* find icon directory and icon repository */
365
366         while( pTInfo->type_id && !(pIconStorage && pIconDir) )
367           {
368            if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) 
369                {
370                  iconDirCount = pTInfo->count;
371                  pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
372                  dprintf_reg(stddeb,"\tfound directory - %i icon families\n", iconDirCount);
373                }
374            if( pTInfo->type_id == NE_RSCTYPE_ICON ) 
375                { 
376                  iconCount = pTInfo->count;
377                  pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
378                  dprintf_reg(stddeb,"\ttotal icons - %i\n", iconCount);
379                }
380            pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
381           }
382
383         /* load resources and create icons */
384
385         if( pIconStorage && pIconDir )
386
387             if( nIconIndex == (UINT)-1 ) RetPtr[0] = iconDirCount;
388             else if( nIconIndex < iconDirCount )
389               {
390                   HANDLE hIcon;
391                   UINT   i, icon;
392
393                   if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
394
395                   for( i = nIconIndex; i < nIconIndex + n; i++ ) 
396                      {
397                        hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + (i - nIconIndex), 
398                                                                                  *(WORD*)pData );
399                        RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
400                        GlobalFree16(hIcon); 
401                      }
402
403                   for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
404                      {
405                        hIcon = 0;
406                        for( i = 0; i < iconCount; i++ )
407                           if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
408                               hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,
409                                                                              *(WORD*)pData );
410                        RetPtr[icon-nIconIndex] = (hIcon)?CURSORICON_LoadHandler( hIcon, hInstance, FALSE ):0;
411                      }
412               }
413         free(pData);
414       }
415
416  _lclose( hFile );
417  
418   /* return array with icon handles */
419
420   return hRet;
421 }
422
423 /*************************************************************************
424  *                              ExtractIcon             [SHELL.34]
425  */
426 HICON ExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, WORD nIconIndex)
427 {
428   HANDLE handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
429
430   if( handle )
431     {
432       HICON* ptr = (HICON*)GlobalLock16(handle);
433       HICON  hIcon = *ptr;
434
435       GlobalFree16(handle);
436       return hIcon;
437     }
438   return 0;
439 }
440
441 /*************************************************************************
442  *                              ExtractAssociatedIcon   [SHELL.36]
443  */
444 HICON ExtractAssociatedIcon(HINSTANCE hInst,LPSTR lpIconPath, LPWORD lpiIcon)
445 {
446     HICON hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
447
448     /* MAKEINTRESOURCE(2) seems to be "default" icon according to Progman 
449      *
450      * For data files it probably should call FindExecutable and load
451      * icon from there. As of now FindExecutable is empty stub.
452      */
453
454     if( hIcon < 2 ) hIcon = LoadIcon( hInst, MAKEINTRESOURCE(2));
455
456     return hIcon;
457 }
458
459 /*************************************************************************
460  *                              FindEnvironmentString   [SHELL.38]
461  *
462  * Returns a pointer into the DOS environment... Ugh.
463  */
464 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
465 {
466   UINT  l = strlen(entry); 
467   for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
468      {
469        if( strncasecmp(lpEnv, entry, l) ) continue;
470        
471        if( !*(lpEnv+l) )
472          return (lpEnv + l);            /* empty entry */
473        else if ( *(lpEnv+l)== '=' )
474          return (lpEnv + l + 1);
475      }
476   return NULL;
477 }
478
479 SEGPTR FindEnvironmentString(LPSTR str)
480 {
481  SEGPTR  spEnv = GetDOSEnvironment();
482  LPSTR  lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
483  
484  LPSTR  lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL; 
485
486  if( lpString )         /*  offset should be small enough */
487      return spEnv + (lpString - lpEnv);
488
489  return (SEGPTR)NULL;
490 }
491
492 /*************************************************************************
493  *                              DoEnvironmentSubst      [SHELL.37]
494  *
495  * Replace %KEYWORD% in the str with the value of variable KEYWORD
496  * from "DOS" environment.
497  */
498 DWORD DoEnvironmentSubst(LPSTR str,WORD length)
499 {
500   LPSTR   lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
501   LPSTR   lpBuffer = (LPSTR)xmalloc(length);
502   LPSTR   lpstr = str;
503   LPSTR   lpbstr = lpBuffer;
504
505   AnsiToOem(str,str);
506
507   dprintf_reg(stddeb,"DoEnvSubst: accept %s", str);
508
509   while( *lpstr && lpbstr - lpBuffer < length )
510    {
511      LPSTR lpend = lpstr;
512
513      if( *lpstr == '%' )
514        {
515           do { lpend++; } while( *lpend && *lpend != '%' );
516           if( *lpend == '%' && lpend - lpstr > 1 )      /* found key */
517             {
518                LPSTR lpKey;
519               *lpend = '\0';  
520                lpKey = SHELL_FindString(lpEnv, lpstr+1);
521                if( lpKey )                              /* found key value */
522                  {
523                    int l = strlen(lpKey);
524
525                    if( l > length - (lpbstr - lpBuffer) - 1 )
526                      {
527                        fprintf(stdnimp,"File %s, line %i: Env subst aborted - string too short\n", 
528                                         __FILE__, __LINE__);
529                       *lpend = '%';
530                        break;
531                      }
532                    strcpy(lpbstr, lpKey);
533                    lpbstr += l;
534                  }
535                else break;
536               *lpend = '%';
537                lpstr = lpend + 1;
538             }
539           else break;                                   /* back off and whine */
540
541           continue;
542        } 
543
544      *lpbstr++ = *lpstr++;
545    }
546
547  *lpbstr = '\0';
548   if( lpstr - str == strlen(str) )
549     {
550       strncpy(str, lpBuffer, length);
551       length = 1;
552     }
553   else
554       length = 0;
555
556   dprintf_reg(stddeb," return %s\n", str);
557
558   OemToAnsi(str,str);
559   free(lpBuffer);
560
561   /*  Return str length in the LOWORD
562    *  and 1 in HIWORD if subst was successful.
563    */
564  return (DWORD)MAKELONG(strlen(str), length);
565 }
566
567 /*************************************************************************
568  *                              RegisterShellHook       [SHELL.102]
569  */
570 int RegisterShellHook(void *ptr) 
571 {
572         dprintf_reg(stdnimp, "RegisterShellHook : Empty Stub !!!\n");
573         return 0;
574 }
575
576
577 /*************************************************************************
578  *                              ShellHookProc           [SHELL.103]
579  */
580 int ShellHookProc(void) 
581 {
582         dprintf_reg(stdnimp, "ShellHookProc : Empty Stub !!!\n");
583         return 0;
584 }