Release 960506
[wine/multimedia.git] / misc / shell.c
blobdd2d591eeba1bc7f9d4ace963f95fd1ffa241b33
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"
21 extern HANDLE CURSORICON_LoadHandler( HANDLE, HINSTANCE, BOOL);
22 extern WORD GetIconID( HANDLE hResource, DWORD resType );
24 /*************************************************************************
25 * DragAcceptFiles [SHELL.9]
27 void DragAcceptFiles(HWND hWnd, BOOL b)
29 WND* wnd = WIN_FindWndPtr(hWnd);
31 if( wnd )
32 wnd->dwExStyle = b? wnd->dwExStyle | WS_EX_ACCEPTFILES
33 : wnd->dwExStyle & ~WS_EX_ACCEPTFILES;
37 /*************************************************************************
38 * DragQueryFile [SHELL.11]
40 UINT DragQueryFile(HDROP hDrop, WORD wFile, LPSTR lpszFile, WORD wLength)
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 */
46 LPDROPFILESTRUCT lpDropFileStruct;
47 LPSTR lpCurrent;
48 WORD i;
50 dprintf_reg(stddeb,"DragQueryFile(%04x, %i, %p, %u)\n",
51 hDrop,wFile,lpszFile,wLength);
53 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
54 if(!lpDropFileStruct)
56 dprintf_reg(stddeb,"DragQueryFile: unable to lock handle!\n");
57 return 0;
59 lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
61 i = 0;
62 while (i++ < wFile)
64 while (*lpCurrent++); /* skip filename */
65 if (!*lpCurrent)
66 return (wFile == 0xFFFF) ? i : 0;
69 i = strlen(lpCurrent);
70 if (!lpszFile) return i+1; /* needed buffer size */
72 i = (wLength > i) ? i : wLength-1;
73 strncpy(lpszFile, lpCurrent, i);
74 lpszFile[i] = '\0';
76 GlobalUnlock16(hDrop);
77 return i;
81 /*************************************************************************
82 * DragFinish [SHELL.12]
84 void DragFinish(HDROP h)
86 GlobalFree16((HGLOBAL16)h);
90 /*************************************************************************
91 * DragQueryPoint [SHELL.13]
93 BOOL DragQueryPoint(HDROP hDrop, POINT *p)
95 LPDROPFILESTRUCT lpDropFileStruct;
96 BOOL bRet;
98 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
100 memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT));
101 bRet = lpDropFileStruct->fInNonClientArea;
103 GlobalUnlock16(hDrop);
104 return bRet;
108 /*************************************************************************
109 * ShellExecute [SHELL.20]
111 HINSTANCE ShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
113 char cmd[400];
114 char *p,*x;
115 long len;
116 char subclass[200];
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.
123 * FIXME: Should also look up WIN.INI [Extensions] section?
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);
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++;}
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);
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);
175 /* does this use %x magic too? */
176 if (lpParameters) {
177 strcat(cmd," ");
178 strcat(cmd,lpParameters);
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 */
184 } else {
185 fprintf(stddeb,"ShellExecute: No operation found for \"%s\" suffix.\n",p);
186 return (HINSTANCE)31; /* file not found */
189 dprintf_exec(stddeb,"ShellExecute:starting %s\n",cmd);
190 return WinExec(cmd,iShowCmd);
194 /*************************************************************************
195 * FindExecutable [SHELL.21]
197 HINSTANCE FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
199 fprintf(stdnimp, "FindExecutable: someone has to fix me and this is YOUR turn! :-)\n");
201 lpResult[0]='\0';
202 return 31; /* no association */
205 static char AppName[128], AppMisc[1536];
207 /*************************************************************************
208 * AboutDlgProc [SHELL.33]
210 LRESULT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
212 char Template[512], AppTitle[512];
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;
227 case WM_COMMAND:
228 switch (wParam) {
229 case IDOK:
230 EndDialog(hWnd, TRUE);
231 return TRUE;
233 break;
235 return FALSE;
238 /*************************************************************************
239 * ShellAbout [SHELL.22]
241 INT ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon)
243 HANDLE handle;
244 BOOL bRet;
246 if (szApp) strncpy(AppName, szApp, sizeof(AppName));
247 else *AppName = 0;
248 AppName[sizeof(AppName)-1]=0;
250 if (szOtherStuff) strncpy(AppMisc, szOtherStuff, sizeof(AppMisc));
251 else *AppMisc = 0;
252 AppMisc[sizeof(AppMisc)-1]=0;
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;
265 /*************************************************************************
266 * SHELL_GetResourceTable
268 * FIXME: Implement GetPEResourceTable in w32sys.c and call it here.
270 BYTE* SHELL_GetResourceTable(HFILE hFile)
272 struct mz_header_s mz_header;
273 struct ne_header_s ne_header;
274 int size;
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;
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;
284 if (ne_header.ne_magic == PE_SIGNATURE)
285 { fprintf(stdnimp,"Win32 FIXME: file %s line %i\n", __FILE__, __LINE__ );
286 return NULL; }
288 if (ne_header.ne_magic != NE_SIGNATURE) return NULL;
290 size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
292 if( size > sizeof(NE_TYPEINFO) )
294 BYTE* pTypeInfo = (BYTE*)xmalloc(size);
296 if( !pTypeInfo ) return NULL;
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;
303 /* no resources */
305 return NULL;
308 /*************************************************************************
309 * SHELL_LoadResource
311 HANDLE SHELL_LoadResource(HINSTANCE hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
313 BYTE* ptr;
314 HANDLE handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
316 if( (ptr = (BYTE*)GlobalLock16( handle )) )
318 _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
319 FILE_Read( hFile, (char*)ptr, pNInfo->length << sizeShift);
320 return handle;
322 return (HANDLE)0;
325 /*************************************************************************
326 * InternalExtractIcon [SHELL.39]
328 * This abortion is called directly by Progman
330 HICON InternalExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, UINT nIconIndex, WORD n )
332 HANDLE hRet = 0;
333 HICON* RetPtr = NULL;
334 BYTE* pData;
335 OFSTRUCT ofs;
336 HFILE hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
338 dprintf_reg(stddeb, "InternalExtractIcon(%04x, file '%s', start from %d, extract %d\n",
339 hInstance, lpszExeFileName, nIconIndex, n);
341 if( hFile == HFILE_ERROR || !n ) return 0;
343 hRet = GlobalAlloc16( GMEM_FIXED, sizeof(HICON)*n);
344 RetPtr = (HICON*)GlobalLock16(hRet);
346 *RetPtr = (n == 0xFFFF)? 0: 1; /* error return values */
348 pData = SHELL_GetResourceTable(hFile);
349 if( pData )
350 if( pData == (BYTE*)-1 )
352 /* FIXME: possible .ICO file */
354 fprintf(stddeb,"InternalExtractIcon: cannot handle file %s\n", lpszExeFileName);
356 else /* got resource table */
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;
364 /* find icon directory and icon repository */
366 while( pTInfo->type_id && !(pIconStorage && pIconDir) )
368 if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON )
370 iconDirCount = pTInfo->count;
371 pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
372 dprintf_reg(stddeb,"\tfound directory - %i icon families\n", iconDirCount);
374 if( pTInfo->type_id == NE_RSCTYPE_ICON )
376 iconCount = pTInfo->count;
377 pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
378 dprintf_reg(stddeb,"\ttotal icons - %i\n", iconCount);
380 pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
383 /* load resources and create icons */
385 if( pIconStorage && pIconDir )
387 if( nIconIndex == (UINT)-1 ) RetPtr[0] = iconDirCount;
388 else if( nIconIndex < iconDirCount )
390 HANDLE hIcon;
391 UINT i, icon;
393 if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
395 for( i = nIconIndex; i < nIconIndex + n; i++ )
397 hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + (i - nIconIndex),
398 *(WORD*)pData );
399 RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
400 GlobalFree16(hIcon);
403 for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
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;
413 free(pData);
416 _lclose( hFile );
418 /* return array with icon handles */
420 return hRet;
423 /*************************************************************************
424 * ExtractIcon [SHELL.34]
426 HICON ExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, WORD nIconIndex)
428 HANDLE handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
430 if( handle )
432 HICON* ptr = (HICON*)GlobalLock16(handle);
433 HICON hIcon = *ptr;
435 GlobalFree16(handle);
436 return hIcon;
438 return 0;
441 /*************************************************************************
442 * ExtractAssociatedIcon [SHELL.36]
444 HICON ExtractAssociatedIcon(HINSTANCE hInst,LPSTR lpIconPath, LPWORD lpiIcon)
446 HICON hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
448 /* MAKEINTRESOURCE(2) seems to be "default" icon according to Progman
450 * For data files it probably should call FindExecutable and load
451 * icon from there. As of now FindExecutable is empty stub.
454 if( hIcon < 2 ) hIcon = LoadIcon( hInst, MAKEINTRESOURCE(2));
456 return hIcon;
459 /*************************************************************************
460 * FindEnvironmentString [SHELL.38]
462 * Returns a pointer into the DOS environment... Ugh.
464 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
466 UINT l = strlen(entry);
467 for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
469 if( strncasecmp(lpEnv, entry, l) ) continue;
471 if( !*(lpEnv+l) )
472 return (lpEnv + l); /* empty entry */
473 else if ( *(lpEnv+l)== '=' )
474 return (lpEnv + l + 1);
476 return NULL;
479 SEGPTR FindEnvironmentString(LPSTR str)
481 SEGPTR spEnv = GetDOSEnvironment();
482 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
484 LPSTR lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL;
486 if( lpString ) /* offset should be small enough */
487 return spEnv + (lpString - lpEnv);
489 return (SEGPTR)NULL;
492 /*************************************************************************
493 * DoEnvironmentSubst [SHELL.37]
495 * Replace %KEYWORD% in the str with the value of variable KEYWORD
496 * from "DOS" environment.
498 DWORD DoEnvironmentSubst(LPSTR str,WORD length)
500 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
501 LPSTR lpBuffer = (LPSTR)xmalloc(length);
502 LPSTR lpstr = str;
503 LPSTR lpbstr = lpBuffer;
505 AnsiToOem(str,str);
507 dprintf_reg(stddeb,"DoEnvSubst: accept %s", str);
509 while( *lpstr && lpbstr - lpBuffer < length )
511 LPSTR lpend = lpstr;
513 if( *lpstr == '%' )
515 do { lpend++; } while( *lpend && *lpend != '%' );
516 if( *lpend == '%' && lpend - lpstr > 1 ) /* found key */
518 LPSTR lpKey;
519 *lpend = '\0';
520 lpKey = SHELL_FindString(lpEnv, lpstr+1);
521 if( lpKey ) /* found key value */
523 int l = strlen(lpKey);
525 if( l > length - (lpbstr - lpBuffer) - 1 )
527 fprintf(stdnimp,"File %s, line %i: Env subst aborted - string too short\n",
528 __FILE__, __LINE__);
529 *lpend = '%';
530 break;
532 strcpy(lpbstr, lpKey);
533 lpbstr += l;
535 else break;
536 *lpend = '%';
537 lpstr = lpend + 1;
539 else break; /* back off and whine */
541 continue;
544 *lpbstr++ = *lpstr++;
547 *lpbstr = '\0';
548 if( lpstr - str == strlen(str) )
550 strncpy(str, lpBuffer, length);
551 length = 1;
553 else
554 length = 0;
556 dprintf_reg(stddeb," return %s\n", str);
558 OemToAnsi(str,str);
559 free(lpBuffer);
561 /* Return str length in the LOWORD
562 * and 1 in HIWORD if subst was successful.
564 return (DWORD)MAKELONG(strlen(str), length);
567 /*************************************************************************
568 * RegisterShellHook [SHELL.102]
570 int RegisterShellHook(void *ptr)
572 dprintf_reg(stdnimp, "RegisterShellHook : Empty Stub !!!\n");
573 return 0;
577 /*************************************************************************
578 * ShellHookProc [SHELL.103]
580 int ShellHookProc(void)
582 dprintf_reg(stdnimp, "ShellHookProc : Empty Stub !!!\n");
583 return 0;