Release 960717
[wine/multimedia.git] / misc / shell.c
blobe9dbbcb8dd59a6291141390094f353989507c6ed
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 #include "winreg.h"
22 extern HANDLE CURSORICON_LoadHandler( HANDLE, HINSTANCE, BOOL);
23 extern WORD GetIconID( HANDLE hResource, DWORD resType );
25 /*************************************************************************
26 * DragAcceptFiles [SHELL.9]
28 void DragAcceptFiles(HWND hWnd, BOOL b)
30 WND* wnd = WIN_FindWndPtr(hWnd);
32 if( wnd )
33 wnd->dwExStyle = b? wnd->dwExStyle | WS_EX_ACCEPTFILES
34 : wnd->dwExStyle & ~WS_EX_ACCEPTFILES;
38 /*************************************************************************
39 * DragQueryFile [SHELL.11]
41 UINT DragQueryFile(HDROP16 hDrop, WORD wFile, LPSTR lpszFile, WORD wLength)
43 /* hDrop is a global memory block allocated with GMEM_SHARE
44 * with DROPFILESTRUCT as a header and filenames following
45 * it, zero length filename is in the end */
47 LPDROPFILESTRUCT lpDropFileStruct;
48 LPSTR lpCurrent;
49 WORD i;
51 dprintf_reg(stddeb,"DragQueryFile(%04x, %i, %p, %u)\n",
52 hDrop,wFile,lpszFile,wLength);
54 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
55 if(!lpDropFileStruct)
57 dprintf_reg(stddeb,"DragQueryFile: unable to lock handle!\n");
58 return 0;
60 lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
62 i = 0;
63 while (i++ < wFile)
65 while (*lpCurrent++); /* skip filename */
66 if (!*lpCurrent)
67 return (wFile == 0xFFFF) ? i : 0;
70 i = strlen(lpCurrent);
71 if (!lpszFile) return i+1; /* needed buffer size */
73 i = (wLength > i) ? i : wLength-1;
74 strncpy(lpszFile, lpCurrent, i);
75 lpszFile[i] = '\0';
77 GlobalUnlock16(hDrop);
78 return i;
82 /*************************************************************************
83 * DragFinish [SHELL.12]
85 void DragFinish(HDROP16 h)
87 GlobalFree16((HGLOBAL16)h);
91 /*************************************************************************
92 * DragQueryPoint [SHELL.13]
94 BOOL DragQueryPoint(HDROP16 hDrop, POINT16 *p)
96 LPDROPFILESTRUCT lpDropFileStruct;
97 BOOL bRet;
99 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
101 memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT16));
102 bRet = lpDropFileStruct->fInNonClientArea;
104 GlobalUnlock16(hDrop);
105 return bRet;
108 /*************************************************************************
109 * SHELL_FindExecutable
110 * Utility for code sharing between FindExecutable and ShellExecute
112 static HINSTANCE SHELL_FindExecutable( LPCSTR lpFile,
113 LPCSTR lpDirectory,
114 LPCSTR lpOperation,
115 LPSTR lpResult)
117 char *extension = NULL; /* pointer to file extension */
118 char tmpext[5]; /* local copy to mung as we please */
119 char filetype[256]; /* registry name for this filetype */
120 LONG filetypelen=256; /* length of above */
121 char command[256]; /* command from registry */
122 LONG commandlen=256; /* This is the most DOS can handle :) */
123 char buffer[256]; /* Used to GetProfileString */
124 HINSTANCE retval=31; /* default - 'No association was found' */
125 char *tok; /* token pointer */
126 int i; /* random counter */
128 dprintf_exec(stddeb, "SHELL_FindExecutable: File %s, Dir %s\n",
129 (lpFile != NULL?lpFile:"-"),
130 (lpDirectory != NULL?lpDirectory:"-"));
132 lpResult[0]='\0'; /* Start off with an empty return string */
134 /* trap NULL parameters on entry */
135 if (( lpFile == NULL ) || ( lpDirectory == NULL ) ||
136 ( lpResult == NULL ) || ( lpOperation == NULL ))
138 /* FIXME - should throw a warning, perhaps! */
139 return 2; /* File not found. Close enough, I guess. */
142 /* First thing we need is the file's extension */
143 extension = strrchr( lpFile, '.' ); /* Assume last "." is the one; */
144 /* File->Run in progman uses */
145 /* .\FILE.EXE :( */
146 if ((extension == NULL) || (extension == &lpFile[strlen(lpFile)]))
148 return 31; /* no association */
151 /* Make local copy & lowercase it for reg & 'programs=' lookup */
152 strncpy( tmpext, extension, 5 );
153 if (strlen(extension)<=4)
154 tmpext[strlen(extension)]='\0';
155 else
156 tmpext[4]='\0';
157 for (i=0;i<strlen(tmpext);i++) tmpext[i]=tolower(tmpext[i]);
158 dprintf_exec(stddeb, "SHELL_FindExecutable: %s file\n", tmpext);
160 /* Three places to check: */
161 /* 1. win.ini, [windows], programs (NB no leading '.') */
162 /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
163 /* 3. win.ini, [extensions], extension (NB no leading '.' */
164 /* All I know of the order is that registry is checked before */
165 /* extensions; however, it'd make sense to check the programs */
166 /* section first, so that's what happens here. */
168 /* See if it's a program */
169 GetProfileString("windows", "programs", "exe pif bat com",
170 buffer, sizeof(buffer)); /* FIXME check return code! */
172 for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
174 tok = strtok(buffer, " \t"); /* ? */
175 while( tok!= NULL)
177 if (strcmp(tok, &tmpext[1])==0) /* have to skip the leading "." */
179 strcpy(lpResult, lpFile); /* Need to perhaps check that */
180 /* the file has a path attached */
181 dprintf_exec(stddeb, "SHELL_FindExecutable: found %s\n",
182 lpResult);
183 return 33; /* Greater than 32 to indicate success FIXME */
184 /* According to the docs, I should be returning */
185 /* a handle for the executable. Does this mean */
186 /* I'm supposed to open the executable file or */
187 /* something? More RTFM, I guess... */
189 tok=strtok(NULL, " \t");
192 /* Check registry */
193 if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, tmpext, filetype,
194 &filetypelen ) == SHELL_ERROR_SUCCESS )
196 filetype[filetypelen]='\0';
197 dprintf_exec(stddeb, "SHELL_FindExecutable: File type: %s\n",
198 filetype);
200 /* Looking for ...buffer\shell\lpOperation\command */
201 strcat( filetype, "\\shell\\" );
202 strcat( filetype, lpOperation );
203 strcat( filetype, "\\command" );
205 if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, filetype, command,
206 &commandlen ) == SHELL_ERROR_SUCCESS )
208 /* Is there a replace() function anywhere? */
209 command[commandlen]='\0';
210 strcpy( lpResult, command );
211 tok=strstr( lpResult, "%1" );
212 if (tok != NULL)
214 tok[0]='\0'; /* truncate string at the percent */
215 strcat( lpResult, lpFile ); /* what if no dir in lpFile? */
216 tok=strstr( command, "%1" );
217 if ((tok!=NULL) && (strlen(tok)>2))
219 strcat( lpResult, &tok[2] );
222 retval=33;
225 else /* Check win.ini */
227 /* Toss the leading dot */
228 extension++;
229 GetProfileString( "extensions", extension, "", command,
230 sizeof(command));
231 if (strlen(command)!=0)
233 strcpy( lpResult, command );
234 tok=strstr( lpResult, "^" ); /* should be ^.extension? */
235 if (tok != NULL)
237 tok[0]='\0';
238 strcat( lpResult, lpFile ); /* what if no dir in lpFile? */
239 tok=strstr( command, "^" ); /* see above */
240 if ((tok != NULL) && (strlen(tok)>5))
242 strcat( lpResult, &tok[5]);
245 retval=33;
249 dprintf_exec(stddeb, "SHELL_FindExecutable: returning %s\n", lpResult);
250 return retval;
253 /*************************************************************************
254 * ShellExecute [SHELL.20]
256 HINSTANCE ShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile,
257 LPSTR lpParameters, LPCSTR lpDirectory,
258 INT iShowCmd)
260 HINSTANCE retval=31;
261 char cmd[256];
263 dprintf_exec(stddeb, "ShellExecute(%04x,'%s','%s','%s','%s',%x)\n",
264 hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
265 lpParameters ? lpParameters : "<null>",
266 lpDirectory ? lpDirectory : "<null>", iShowCmd);
268 if (lpFile==NULL) return 0; /* should not happen */
269 if (lpOperation==NULL) /* default is open */
270 lpOperation="open";
272 retval = SHELL_FindExecutable( lpFile, lpDirectory, lpOperation, cmd );
274 if ( retval <= 32 )
276 return retval;
279 if (lpParameters)
281 strcat(cmd," ");
282 strcat(cmd,lpParameters);
285 dprintf_exec(stddeb,"ShellExecute:starting %s\n",cmd);
286 return WinExec(cmd,iShowCmd);
289 /*************************************************************************
290 * FindExecutable [SHELL.21]
292 HINSTANCE FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
294 HINSTANCE retval=31; /* default - 'No association was found' */
296 dprintf_exec(stddeb, "FindExecutable: File %s, Dir %s\n",
297 (lpFile != NULL?lpFile:"-"),
298 (lpDirectory != NULL?lpDirectory:"-"));
300 lpResult[0]='\0'; /* Start off with an empty return string */
302 /* trap NULL parameters on entry */
303 if (( lpFile == NULL ) || ( lpDirectory == NULL ) ||
304 ( lpResult == NULL ))
306 /* FIXME - should throw a warning, perhaps! */
307 return 2; /* File not found. Close enough, I guess. */
310 retval = SHELL_FindExecutable( lpFile, lpDirectory, "open",
311 lpResult );
313 dprintf_exec(stddeb, "FindExecutable: returning %s\n", lpResult);
314 return retval;
317 static char AppName[128], AppMisc[1536];
319 /*************************************************************************
320 * AboutDlgProc [SHELL.33]
322 LRESULT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
324 char Template[512], AppTitle[512];
326 switch(msg) {
327 case WM_INITDIALOG:
328 SendDlgItemMessage32A(hWnd,stc1,STM_SETICON,lParam,0);
329 GetWindowText32A(hWnd, Template, sizeof(Template));
330 sprintf(AppTitle, Template, AppName);
331 SetWindowText32A(hWnd, AppTitle);
332 SetWindowText32A(GetDlgItem(hWnd,100), AppMisc);
333 return 1;
335 case WM_COMMAND:
336 switch (wParam) {
337 case IDOK:
338 EndDialog(hWnd, TRUE);
339 return TRUE;
341 break;
343 return FALSE;
346 /*************************************************************************
347 * ShellAbout [SHELL.22]
349 INT ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon)
351 HANDLE handle;
352 BOOL bRet;
354 if (szApp) strncpy(AppName, szApp, sizeof(AppName));
355 else *AppName = 0;
356 AppName[sizeof(AppName)-1]=0;
358 if (szOtherStuff) strncpy(AppMisc, szOtherStuff, sizeof(AppMisc));
359 else *AppMisc = 0;
360 AppMisc[sizeof(AppMisc)-1]=0;
362 if (!hIcon) hIcon = LoadIcon16(0,MAKEINTRESOURCE(OIC_WINEICON));
363 handle = SYSRES_LoadResource( SYSRES_DIALOG_SHELL_ABOUT_MSGBOX );
364 if (!handle) return FALSE;
365 bRet = DialogBoxIndirectParam16( WIN_GetWindowInstance( hWnd ),
366 handle, hWnd,
367 MODULE_GetWndProcEntry16("AboutDlgProc"),
368 (LONG)hIcon );
369 SYSRES_FreeResource( handle );
370 return bRet;
373 /*************************************************************************
374 * SHELL_GetResourceTable
376 * FIXME: Implement GetPEResourceTable in w32sys.c and call it here.
378 BYTE* SHELL_GetResourceTable(HFILE hFile)
380 struct mz_header_s mz_header;
381 struct ne_header_s ne_header;
382 int size;
384 _llseek( hFile, 0, SEEK_SET );
385 if ((FILE_Read(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
386 (mz_header.mz_magic != MZ_SIGNATURE)) return (BYTE*)-1;
388 _llseek( hFile, mz_header.ne_offset, SEEK_SET );
389 if (FILE_Read( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
390 return NULL;
392 if (ne_header.ne_magic == PE_SIGNATURE)
393 { fprintf(stdnimp,"Win32 FIXME: file %s line %i\n", __FILE__, __LINE__ );
394 return NULL; }
396 if (ne_header.ne_magic != NE_SIGNATURE) return NULL;
398 size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
400 if( size > sizeof(NE_TYPEINFO) )
402 BYTE* pTypeInfo = (BYTE*)xmalloc(size);
404 if( !pTypeInfo ) return NULL;
406 _llseek(hFile, mz_header.ne_offset+ne_header.resource_tab_offset, SEEK_SET);
407 if( FILE_Read( hFile, (char*)pTypeInfo, size) != size )
408 { free(pTypeInfo); return NULL; }
409 return pTypeInfo;
411 /* no resources */
413 return NULL;
416 /*************************************************************************
417 * SHELL_LoadResource
419 HANDLE SHELL_LoadResource(HINSTANCE hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
421 BYTE* ptr;
422 HANDLE handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
424 if( (ptr = (BYTE*)GlobalLock16( handle )) )
426 _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
427 FILE_Read( hFile, (char*)ptr, pNInfo->length << sizeShift);
428 return handle;
430 return (HANDLE)0;
433 /*************************************************************************
434 * InternalExtractIcon [SHELL.39]
436 * This abortion is called directly by Progman
438 HICON InternalExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, UINT nIconIndex, WORD n )
440 HANDLE hRet = 0;
441 HICON* RetPtr = NULL;
442 BYTE* pData;
443 OFSTRUCT ofs;
444 HFILE hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
446 dprintf_reg(stddeb, "InternalExtractIcon(%04x, file '%s', start from %d, extract %d\n",
447 hInstance, lpszExeFileName, nIconIndex, n);
449 if( hFile == HFILE_ERROR || !n ) return 0;
451 hRet = GlobalAlloc16( GMEM_FIXED, sizeof(HICON)*n);
452 RetPtr = (HICON*)GlobalLock16(hRet);
454 *RetPtr = (n == 0xFFFF)? 0: 1; /* error return values */
456 pData = SHELL_GetResourceTable(hFile);
457 if( pData )
458 if( pData == (BYTE*)-1 )
460 /* FIXME: possible .ICO file */
462 fprintf(stddeb,"InternalExtractIcon: cannot handle file %s\n", lpszExeFileName);
464 else /* got resource table */
466 UINT iconDirCount = 0;
467 UINT iconCount = 0;
468 NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
469 NE_NAMEINFO* pIconStorage = NULL;
470 NE_NAMEINFO* pIconDir = NULL;
472 /* find icon directory and icon repository */
474 while( pTInfo->type_id && !(pIconStorage && pIconDir) )
476 if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON )
478 iconDirCount = pTInfo->count;
479 pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
480 dprintf_reg(stddeb,"\tfound directory - %i icon families\n", iconDirCount);
482 if( pTInfo->type_id == NE_RSCTYPE_ICON )
484 iconCount = pTInfo->count;
485 pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
486 dprintf_reg(stddeb,"\ttotal icons - %i\n", iconCount);
488 pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
491 /* load resources and create icons */
493 if( pIconStorage && pIconDir )
495 if( nIconIndex == (UINT)-1 ) RetPtr[0] = iconDirCount;
496 else if( nIconIndex < iconDirCount )
498 HANDLE hIcon;
499 UINT i, icon;
501 if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
503 for( i = nIconIndex; i < nIconIndex + n; i++ )
505 hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i,
506 *(WORD*)pData );
507 RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
508 GlobalFree16(hIcon);
511 for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
513 hIcon = 0;
514 for( i = 0; i < iconCount; i++ )
515 if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
516 hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,
517 *(WORD*)pData );
518 RetPtr[icon-nIconIndex] = (hIcon)?CURSORICON_LoadHandler( hIcon, hInstance, FALSE ):0;
521 free(pData);
524 _lclose( hFile );
526 /* return array with icon handles */
528 return hRet;
531 /*************************************************************************
532 * ExtractIcon [SHELL.34]
534 HICON ExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, WORD nIconIndex)
536 HANDLE handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
538 if( handle )
540 HICON* ptr = (HICON*)GlobalLock16(handle);
541 HICON hIcon = *ptr;
543 GlobalFree16(handle);
544 return hIcon;
546 return 0;
549 /*************************************************************************
550 * ExtractAssociatedIcon [SHELL.36]
552 * Return icon for given file (either from file itself or from associated
553 * executable) and patch parameters if needed.
555 HICON16 ExtractAssociatedIcon(HINSTANCE16 hInst,LPSTR lpIconPath,LPWORD lpiIcon)
557 HICON16 hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
559 if( hIcon < 2 )
562 if( hIcon == 1 ) /* no icons found in given file */
564 char tempPath[0x80];
565 UINT uRet = FindExecutable(lpIconPath,NULL,tempPath);
567 if( uRet > 32 && tempPath[0] )
569 strcpy(lpIconPath,tempPath);
570 hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
572 if( hIcon > 2 ) return hIcon;
574 else hIcon = 0;
577 if( hIcon == 1 )
578 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
579 else
580 *lpiIcon = 6; /* generic icon - found nothing */
582 GetModuleFileName(hInst, lpIconPath, 0x80);
583 hIcon = LoadIcon16( hInst, MAKEINTRESOURCE(*lpiIcon));
586 return hIcon;
589 /*************************************************************************
590 * FindEnvironmentString [SHELL.38]
592 * Returns a pointer into the DOS environment... Ugh.
594 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
596 UINT l = strlen(entry);
597 for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
599 if( lstrncmpi32A(lpEnv, entry, l) ) continue;
601 if( !*(lpEnv+l) )
602 return (lpEnv + l); /* empty entry */
603 else if ( *(lpEnv+l)== '=' )
604 return (lpEnv + l + 1);
606 return NULL;
609 SEGPTR FindEnvironmentString(LPSTR str)
611 SEGPTR spEnv = GetDOSEnvironment();
612 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
614 LPSTR lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL;
616 if( lpString ) /* offset should be small enough */
617 return spEnv + (lpString - lpEnv);
619 return (SEGPTR)NULL;
622 /*************************************************************************
623 * DoEnvironmentSubst [SHELL.37]
625 * Replace %KEYWORD% in the str with the value of variable KEYWORD
626 * from "DOS" environment.
628 DWORD DoEnvironmentSubst(LPSTR str,WORD length)
630 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
631 LPSTR lpBuffer = (LPSTR)xmalloc(length);
632 LPSTR lpstr = str;
633 LPSTR lpbstr = lpBuffer;
635 AnsiToOem(str,str);
637 dprintf_reg(stddeb,"DoEnvSubst: accept %s", str);
639 while( *lpstr && lpbstr - lpBuffer < length )
641 LPSTR lpend = lpstr;
643 if( *lpstr == '%' )
645 do { lpend++; } while( *lpend && *lpend != '%' );
646 if( *lpend == '%' && lpend - lpstr > 1 ) /* found key */
648 LPSTR lpKey;
649 *lpend = '\0';
650 lpKey = SHELL_FindString(lpEnv, lpstr+1);
651 if( lpKey ) /* found key value */
653 int l = strlen(lpKey);
655 if( l > length - (lpbstr - lpBuffer) - 1 )
657 fprintf(stdnimp,"File %s, line %i: Env subst aborted - string too short\n",
658 __FILE__, __LINE__);
659 *lpend = '%';
660 break;
662 strcpy(lpbstr, lpKey);
663 lpbstr += l;
665 else break;
666 *lpend = '%';
667 lpstr = lpend + 1;
669 else break; /* back off and whine */
671 continue;
674 *lpbstr++ = *lpstr++;
677 *lpbstr = '\0';
678 if( lpstr - str == strlen(str) )
680 strncpy(str, lpBuffer, length);
681 length = 1;
683 else
684 length = 0;
686 dprintf_reg(stddeb," return %s\n", str);
688 OemToAnsi(str,str);
689 free(lpBuffer);
691 /* Return str length in the LOWORD
692 * and 1 in HIWORD if subst was successful.
694 return (DWORD)MAKELONG(strlen(str), length);
697 /*************************************************************************
698 * RegisterShellHook [SHELL.102]
700 int RegisterShellHook(void *ptr)
702 dprintf_reg(stdnimp, "RegisterShellHook : Empty Stub !!!\n");
703 return 0;
707 /*************************************************************************
708 * ShellHookProc [SHELL.103]
710 int ShellHookProc(void)
712 dprintf_reg(stdnimp, "ShellHookProc : Empty Stub !!!\n");
713 return 0;