2 * Shell Library Functions
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);
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;
51 dprintf_reg(stddeb,"DragQueryFile(%04x, %i, %p, %u)\n",
52 hDrop,wFile,lpszFile,wLength);
54 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
57 dprintf_reg(stddeb,"DragQueryFile: unable to lock handle!\n");
60 lpCurrent = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
65 while (*lpCurrent++); /* skip filename */
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);
77 GlobalUnlock16(hDrop);
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;
99 lpDropFileStruct = (LPDROPFILESTRUCT) GlobalLock16(hDrop);
101 memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT16));
102 bRet = lpDropFileStruct->fInNonClientArea;
104 GlobalUnlock16(hDrop);
109 /*************************************************************************
110 * ShellExecute [SHELL.20]
112 HINSTANCE ShellExecute(HWND hWnd, LPCSTR lpOperation, LPCSTR lpFile, LPSTR lpParameters, LPCSTR lpDirectory, INT iShowCmd)
119 /* OK. We are supposed to lookup the program associated with lpFile,
120 * then to execute it using that program. If lpFile is a program,
121 * we have to pass the parameters. If an instance is already running,
122 * we might have to send DDE commands.
124 * FIXME: Should also look up WIN.INI [Extensions] section?
127 dprintf_exec(stddeb, "ShellExecute(%04x,'%s','%s','%s','%s',%x)\n",
128 hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
129 lpParameters ? lpParameters : "<null>",
130 lpDirectory ? lpDirectory : "<null>", iShowCmd);
132 if (lpFile==NULL) return 0; /* should not happen */
133 if (lpOperation==NULL) /* default is open */
135 p=strrchr(lpFile,'.');
137 x=p; /* the suffixes in the register database are lowercased */
138 while (*x) {*x=tolower(*x);x++;}
140 if (p==NULL || !strcmp(p,".exe")) {
143 sprintf(cmd,"%s %s",lpFile,lpParameters);
149 if (RegQueryValue16((HKEY)HKEY_CLASSES_ROOT,p,subclass,&len)==SHELL_ERROR_SUCCESS) {
151 fprintf(stddeb,"ShellExecute:subclass with len %ld? (%s), please report.\n",len,subclass);
153 strcat(subclass,"\\shell\\");
154 strcat(subclass,lpOperation);
155 strcat(subclass,"\\command");
156 dprintf_exec(stddeb,"ShellExecute:looking for %s.\n",subclass);
158 if (RegQueryValue16((HKEY)HKEY_CLASSES_ROOT,subclass,cmd,&len)==SHELL_ERROR_SUCCESS) {
160 dprintf_exec(stddeb,"ShellExecute:...got %s\n",cmd);
168 s=xmalloc(len+strlen(lpFile)+10);
169 strncpy(s,cmd,t-cmd);
176 /* does this use %x magic too? */
179 strcat(cmd,lpParameters);
182 fprintf(stddeb,"ShellExecute: No %s\\shell\\%s\\command found for \"%s\" suffix.\n",subclass,lpOperation,p);
183 return (HINSTANCE)31; /* unknown type */
186 fprintf(stddeb,"ShellExecute: No operation found for \"%s\" suffix.\n",p);
187 return (HINSTANCE)31; /* file not found */
190 dprintf_exec(stddeb,"ShellExecute:starting %s\n",cmd);
191 return WinExec(cmd,iShowCmd);
195 /*************************************************************************
196 * FindExecutable [SHELL.21]
198 HINSTANCE FindExecutable(LPCSTR lpFile, LPCSTR lpDirectory, LPSTR lpResult)
200 char *extension = NULL; /* pointer to file extension */
201 char tmpext[5]; /* local copy to mung as we please */
202 char filetype[256]; /* registry name for this filetype */
203 LONG filetypelen=256; /* length of above */
204 char command[256]; /* command from registry */
205 LONG commandlen=256; /* This is the most DOS can handle :) */
206 char buffer[256]; /* Used to GetProfileString */
207 HINSTANCE retval=31; /* default - 'No association was found' */
208 char *tok; /* token pointer */
209 int i; /* random counter */
211 dprintf_exec(stddeb, "FindExecutable: File %s, Dir %s\n",
212 (lpFile != NULL?lpFile:"-"),
213 (lpDirectory != NULL?lpDirectory:"-"));
215 lpResult[0]='\0'; /* Start off with an empty return string */
217 /* trap NULL parameters on entry */
218 if (( lpFile == NULL ) || ( lpDirectory == NULL ) ||
219 ( lpResult == NULL ))
221 /* FIXME - should throw a warning, perhaps! */
222 return 2; /* File not found. Close enough, I guess. */
225 /* First thing we need is the file's extension */
226 extension = strchr( lpFile, '.' ); /* Assumes first "." is the one... */
227 if ((extension == NULL) || (extension == &lpFile[strlen(lpFile)]))
229 return 31; /* no association */
232 /* Make local copy & lowercase it for reg & 'programs=' lookup */
233 strncpy( tmpext, extension, 5 );
234 if (strlen(extension)<=4)
235 tmpext[strlen(extension)]='\0';
238 for (i=0;i<strlen(tmpext);i++) tmpext[i]=tolower(tmpext[i]);
239 dprintf_exec(stddeb, "FindExecutable: %s file\n", tmpext);
241 /* Three places to check: */
242 /* 1. win.ini, [windows], programs (NB no leading '.') */
243 /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
244 /* 3. win.ini, [extensions], extension (NB no leading '.' */
245 /* All I know of the order is that registry is checked before */
246 /* extensions; however, it'd make sense to check the programs */
247 /* section first, so that's what happens here. */
249 /* See if it's a program */
250 GetProfileString("windows", "programs", "exe pif bat com",
251 buffer, sizeof(buffer)); /* FIXME check return code! */
253 for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
255 tok = strtok(buffer, " \t"); /* ? */
258 if (strcmp(tok, &tmpext[1])==0) /* have to skip the leading "." */
260 strcpy(lpResult, lpFile); /* Need to perhaps check that */
261 /* the file has a path attached */
262 dprintf_exec(stddeb, "FindExecutable: found %s\n", lpResult);
263 return 33; /* Greater than 32 to indicate success FIXME */
264 /* what are the correct values here? */
266 tok=strtok(NULL, " \t");
270 if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, tmpext, filetype,
271 &filetypelen ) == SHELL_ERROR_SUCCESS )
273 filetype[filetypelen]='\0';
274 dprintf_exec(stddeb, "File type: %s\n", filetype);
276 /* Looking for ...buffer\shell\open\command */
277 strcat( filetype, "\\shell\\open\\command" );
279 if (RegQueryValue16( (HKEY)HKEY_CLASSES_ROOT, filetype, command,
280 &commandlen ) == SHELL_ERROR_SUCCESS )
282 /* Is there a replace() function anywhere? */
283 command[commandlen]='\0';
284 strcpy( lpResult, command );
285 tok=strstr( lpResult, "%1" );
288 tok[0]='\0'; /* truncate string at the percent */
289 strcat( lpResult, lpFile ); /* what if no dir in lpFile? */
290 tok=strstr( command, "%1" );
291 if ((tok!=NULL) && (strlen(tok)>2))
293 strcat( lpResult, &tok[2] );
299 else /* Check win.ini */
301 /* Toss the leading dot */
303 GetProfileString( "extensions", extension, "", command,
305 if (strlen(command)!=0)
307 strcpy( lpResult, command );
308 tok=strstr( lpResult, "^" ); /* should be ^.extension? */
312 strcat( lpResult, lpFile ); /* what if no dir in lpFile? */
313 tok=strstr( command, "^" ); /* see above */
314 if ((tok != NULL) && (strlen(tok)>5))
316 strcat( lpResult, &tok[5]);
323 dprintf_exec(stddeb, "FindExecutable: returning %s\n", lpResult);
327 static char AppName[128], AppMisc[1536];
329 /*************************************************************************
330 * AboutDlgProc [SHELL.33]
332 LRESULT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
334 char Template[512], AppTitle[512];
339 SendDlgItemMessage32A(hWnd,stc1,STM_SETICON,lParam,0);
341 SendDlgItemMessage16(hWnd,stc1,STM_SETICON,LOWORD(lParam),0);
343 GetWindowText32A(hWnd, Template, sizeof(Template));
344 sprintf(AppTitle, Template, AppName);
345 SetWindowText32A(hWnd, AppTitle);
346 SetWindowText32A(GetDlgItem(hWnd,100), AppMisc);
352 EndDialog(hWnd, TRUE);
360 /*************************************************************************
361 * ShellAbout [SHELL.22]
363 INT ShellAbout(HWND hWnd, LPCSTR szApp, LPCSTR szOtherStuff, HICON hIcon)
368 if (szApp) strncpy(AppName, szApp, sizeof(AppName));
370 AppName[sizeof(AppName)-1]=0;
372 if (szOtherStuff) strncpy(AppMisc, szOtherStuff, sizeof(AppMisc));
374 AppMisc[sizeof(AppMisc)-1]=0;
376 if (!hIcon) hIcon = LoadIcon(0,MAKEINTRESOURCE(OIC_WINEICON));
377 handle = SYSRES_LoadResource( SYSRES_DIALOG_SHELL_ABOUT_MSGBOX );
378 if (!handle) return FALSE;
379 bRet = DialogBoxIndirectParam( WIN_GetWindowInstance( hWnd ),
381 MODULE_GetWndProcEntry16("AboutDlgProc"),
383 SYSRES_FreeResource( handle );
387 /*************************************************************************
388 * SHELL_GetResourceTable
390 * FIXME: Implement GetPEResourceTable in w32sys.c and call it here.
392 BYTE* SHELL_GetResourceTable(HFILE hFile)
394 struct mz_header_s mz_header;
395 struct ne_header_s ne_header;
398 _llseek( hFile, 0, SEEK_SET );
399 if ((FILE_Read(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) ||
400 (mz_header.mz_magic != MZ_SIGNATURE)) return (BYTE*)-1;
402 _llseek( hFile, mz_header.ne_offset, SEEK_SET );
403 if (FILE_Read( hFile, &ne_header, sizeof(ne_header) ) != sizeof(ne_header))
406 if (ne_header.ne_magic == PE_SIGNATURE)
407 { fprintf(stdnimp,"Win32 FIXME: file %s line %i\n", __FILE__, __LINE__ );
410 if (ne_header.ne_magic != NE_SIGNATURE) return NULL;
412 size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
414 if( size > sizeof(NE_TYPEINFO) )
416 BYTE* pTypeInfo = (BYTE*)xmalloc(size);
418 if( !pTypeInfo ) return NULL;
420 _llseek(hFile, mz_header.ne_offset+ne_header.resource_tab_offset, SEEK_SET);
421 if( FILE_Read( hFile, (char*)pTypeInfo, size) != size )
422 { free(pTypeInfo); return NULL; }
430 /*************************************************************************
433 HANDLE SHELL_LoadResource(HINSTANCE hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
436 HANDLE handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
438 if( (ptr = (BYTE*)GlobalLock16( handle )) )
440 _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
441 FILE_Read( hFile, (char*)ptr, pNInfo->length << sizeShift);
447 /*************************************************************************
448 * InternalExtractIcon [SHELL.39]
450 * This abortion is called directly by Progman
452 HICON InternalExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, UINT nIconIndex, WORD n )
455 HICON* RetPtr = NULL;
458 HFILE hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
460 dprintf_reg(stddeb, "InternalExtractIcon(%04x, file '%s', start from %d, extract %d\n",
461 hInstance, lpszExeFileName, nIconIndex, n);
463 if( hFile == HFILE_ERROR || !n ) return 0;
465 hRet = GlobalAlloc16( GMEM_FIXED, sizeof(HICON)*n);
466 RetPtr = (HICON*)GlobalLock16(hRet);
468 *RetPtr = (n == 0xFFFF)? 0: 1; /* error return values */
470 pData = SHELL_GetResourceTable(hFile);
472 if( pData == (BYTE*)-1 )
474 /* FIXME: possible .ICO file */
476 fprintf(stddeb,"InternalExtractIcon: cannot handle file %s\n", lpszExeFileName);
478 else /* got resource table */
480 UINT iconDirCount = 0;
482 NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
483 NE_NAMEINFO* pIconStorage = NULL;
484 NE_NAMEINFO* pIconDir = NULL;
486 /* find icon directory and icon repository */
488 while( pTInfo->type_id && !(pIconStorage && pIconDir) )
490 if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON )
492 iconDirCount = pTInfo->count;
493 pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
494 dprintf_reg(stddeb,"\tfound directory - %i icon families\n", iconDirCount);
496 if( pTInfo->type_id == NE_RSCTYPE_ICON )
498 iconCount = pTInfo->count;
499 pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
500 dprintf_reg(stddeb,"\ttotal icons - %i\n", iconCount);
502 pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
505 /* load resources and create icons */
507 if( pIconStorage && pIconDir )
509 if( nIconIndex == (UINT)-1 ) RetPtr[0] = iconDirCount;
510 else if( nIconIndex < iconDirCount )
515 if( n > iconDirCount - nIconIndex ) n = iconDirCount - nIconIndex;
517 for( i = nIconIndex; i < nIconIndex + n; i++ )
519 hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + (i - nIconIndex),
521 RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
525 for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
528 for( i = 0; i < iconCount; i++ )
529 if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
530 hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,
532 RetPtr[icon-nIconIndex] = (hIcon)?CURSORICON_LoadHandler( hIcon, hInstance, FALSE ):0;
540 /* return array with icon handles */
545 /*************************************************************************
546 * ExtractIcon [SHELL.34]
548 HICON ExtractIcon(HINSTANCE hInstance, LPCSTR lpszExeFileName, WORD nIconIndex)
550 HANDLE handle = InternalExtractIcon(hInstance,lpszExeFileName,nIconIndex, 1);
554 HICON* ptr = (HICON*)GlobalLock16(handle);
557 GlobalFree16(handle);
563 /*************************************************************************
564 * ExtractAssociatedIcon [SHELL.36]
566 HICON ExtractAssociatedIcon(HINSTANCE hInst,LPSTR lpIconPath, LPWORD lpiIcon)
568 HICON hIcon = ExtractIcon(hInst, lpIconPath, *lpiIcon);
570 /* MAKEINTRESOURCE(2) seems to be "default" icon according to Progman
572 * For data files it probably should call FindExecutable and load
573 * icon from there. As of now FindExecutable is empty stub.
576 if( hIcon < 2 ) hIcon = LoadIcon( hInst, MAKEINTRESOURCE(2));
581 /*************************************************************************
582 * FindEnvironmentString [SHELL.38]
584 * Returns a pointer into the DOS environment... Ugh.
586 LPSTR SHELL_FindString(LPSTR lpEnv, LPCSTR entry)
588 UINT l = strlen(entry);
589 for( ; *lpEnv ; lpEnv+=strlen(lpEnv)+1 )
591 if( lstrncmpi(lpEnv, entry, l) ) continue;
594 return (lpEnv + l); /* empty entry */
595 else if ( *(lpEnv+l)== '=' )
596 return (lpEnv + l + 1);
601 SEGPTR FindEnvironmentString(LPSTR str)
603 SEGPTR spEnv = GetDOSEnvironment();
604 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(spEnv);
606 LPSTR lpString = (spEnv)?SHELL_FindString(lpEnv, str):NULL;
608 if( lpString ) /* offset should be small enough */
609 return spEnv + (lpString - lpEnv);
614 /*************************************************************************
615 * DoEnvironmentSubst [SHELL.37]
617 * Replace %KEYWORD% in the str with the value of variable KEYWORD
618 * from "DOS" environment.
620 DWORD DoEnvironmentSubst(LPSTR str,WORD length)
622 LPSTR lpEnv = (LPSTR)PTR_SEG_TO_LIN(GetDOSEnvironment());
623 LPSTR lpBuffer = (LPSTR)xmalloc(length);
625 LPSTR lpbstr = lpBuffer;
629 dprintf_reg(stddeb,"DoEnvSubst: accept %s", str);
631 while( *lpstr && lpbstr - lpBuffer < length )
637 do { lpend++; } while( *lpend && *lpend != '%' );
638 if( *lpend == '%' && lpend - lpstr > 1 ) /* found key */
642 lpKey = SHELL_FindString(lpEnv, lpstr+1);
643 if( lpKey ) /* found key value */
645 int l = strlen(lpKey);
647 if( l > length - (lpbstr - lpBuffer) - 1 )
649 fprintf(stdnimp,"File %s, line %i: Env subst aborted - string too short\n",
654 strcpy(lpbstr, lpKey);
661 else break; /* back off and whine */
666 *lpbstr++ = *lpstr++;
670 if( lpstr - str == strlen(str) )
672 strncpy(str, lpBuffer, length);
678 dprintf_reg(stddeb," return %s\n", str);
683 /* Return str length in the LOWORD
684 * and 1 in HIWORD if subst was successful.
686 return (DWORD)MAKELONG(strlen(str), length);
689 /*************************************************************************
690 * RegisterShellHook [SHELL.102]
692 int RegisterShellHook(void *ptr)
694 dprintf_reg(stdnimp, "RegisterShellHook : Empty Stub !!!\n");
699 /*************************************************************************
700 * ShellHookProc [SHELL.103]
702 int ShellHookProc(void)
704 dprintf_reg(stdnimp, "ShellHookProc : Empty Stub !!!\n");