2 * Shell Library Functions
11 #include "wine/winuser16.h"
21 #include "cursoricon.h"
22 #include "interfaces.h"
23 #include "sysmetrics.h"
27 #include "imagelist.h"
30 /* .ICO file ICONDIR definitions */
36 BYTE bWidth
; /* Width, in pixels, of the image */
37 BYTE bHeight
; /* Height, in pixels, of the image */
38 BYTE bColorCount
; /* Number of colors in image (0 if >=8bpp) */
39 BYTE bReserved
; /* Reserved ( must be 0) */
40 WORD wPlanes
; /* Color Planes */
41 WORD wBitCount
; /* Bits per pixel */
42 DWORD dwBytesInRes
; /* How many bytes in this resource? */
43 DWORD dwImageOffset
; /* Where in the file is this image? */
44 } icoICONDIRENTRY
, *LPicoICONDIRENTRY
;
48 WORD idReserved
; /* Reserved (must be 0) */
49 WORD idType
; /* Resource Type (1 for icons) */
50 WORD idCount
; /* How many images? */
51 icoICONDIRENTRY idEntries
[1]; /* An entry for each image (idCount of 'em) */
52 } icoICONDIR
, *LPicoICONDIR
;
56 static const char* lpstrMsgWndCreated
= "OTHERWINDOWCREATED";
57 static const char* lpstrMsgWndDestroyed
= "OTHERWINDOWDESTROYED";
58 static const char* lpstrMsgShellActivate
= "ACTIVATESHELLWINDOW";
60 static HWND16 SHELL_hWnd
= 0;
61 static HHOOK SHELL_hHook
= 0;
62 static UINT16 uMsgWndCreated
= 0;
63 static UINT16 uMsgWndDestroyed
= 0;
64 static UINT16 uMsgShellActivate
= 0;
66 /*************************************************************************
67 * DragAcceptFiles32 [SHELL32.54]
69 void WINAPI
DragAcceptFiles32(HWND32 hWnd
, BOOL32 b
)
71 WND
* wnd
= WIN_FindWndPtr(hWnd
);
74 wnd
->dwExStyle
= b
? wnd
->dwExStyle
| WS_EX_ACCEPTFILES
75 : wnd
->dwExStyle
& ~WS_EX_ACCEPTFILES
;
78 /*************************************************************************
79 * DragAcceptFiles16 [SHELL.9]
81 void WINAPI
DragAcceptFiles16(HWND16 hWnd
, BOOL16 b
)
83 DragAcceptFiles32(hWnd
, b
);
86 /*************************************************************************
87 * SHELL_DragQueryFile [internal]
90 static UINT32
SHELL_DragQueryFile(LPSTR lpDrop
, LPWSTR lpwDrop
, UINT32 lFile
,
91 LPSTR lpszFile
, LPWSTR lpszwFile
, UINT32 lLength
)
98 while (*lpDrop
++); /* skip filename */
100 return (lFile
== 0xFFFFFFFF) ? i
: 0;
104 while (i
++ < lFile
) {
105 while (*lpwDrop
++); /* skip filename */
107 return (lFile
== 0xFFFFFFFF) ? i
: 0;
111 if (lpDrop
) i
= lstrlen32A(lpDrop
);
112 if (lpwDrop
) i
= lstrlen32W(lpwDrop
);
114 if (!lpszFile
&& !lpszwFile
) {
115 return i
; /* needed buffer size */
117 i
= (lLength
> i
) ? i
: lLength
;
119 if (lpDrop
) lstrcpyn32A (lpszFile
, lpDrop
, i
);
120 else lstrcpynWtoA(lpszFile
, lpwDrop
, i
);
122 if (lpDrop
) lstrcpynAtoW(lpszwFile
, lpDrop
, i
);
123 else lstrcpyn32W (lpszwFile
, lpwDrop
, i
);
128 /*************************************************************************
129 * DragQueryFile32A [SHELL32.81] [shell32.82]
131 UINT32 WINAPI
DragQueryFile32A(HDROP32 hDrop
, UINT32 lFile
, LPSTR lpszFile
,
133 { /* hDrop is a global memory block allocated with GMEM_SHARE
134 * with DROPFILESTRUCT as a header and filenames following
135 * it, zero length filename is in the end */
137 LPDROPFILESTRUCT32 lpDropFileStruct
;
141 TRACE(shell
,"(%08x, %x, %p, %u)\n", hDrop
,lFile
,lpszFile
,lLength
);
143 lpDropFileStruct
= (LPDROPFILESTRUCT32
) GlobalLock32(hDrop
);
144 if(!lpDropFileStruct
)
147 lpCurrent
= (LPSTR
) lpDropFileStruct
+ lpDropFileStruct
->lSize
;
148 i
= SHELL_DragQueryFile(lpCurrent
, NULL
, lFile
, lpszFile
, NULL
, lLength
);
149 GlobalUnlock32(hDrop
);
153 /*************************************************************************
154 * DragQueryFile32W [shell32.133]
156 UINT32 WINAPI
DragQueryFile32W(HDROP32 hDrop
, UINT32 lFile
, LPWSTR lpszwFile
,
159 LPDROPFILESTRUCT32 lpDropFileStruct
;
163 TRACE(shell
,"(%08x, %x, %p, %u)\n", hDrop
,lFile
,lpszwFile
,lLength
);
165 lpDropFileStruct
= (LPDROPFILESTRUCT32
) GlobalLock32(hDrop
);
166 if(!lpDropFileStruct
)
169 lpwCurrent
= (LPWSTR
) lpDropFileStruct
+ lpDropFileStruct
->lSize
;
170 i
= SHELL_DragQueryFile(NULL
, lpwCurrent
, lFile
, NULL
, lpszwFile
,lLength
);
171 GlobalUnlock32(hDrop
);
174 /*************************************************************************
175 * DragQueryFile16 [SHELL.11]
177 UINT16 WINAPI
DragQueryFile16(HDROP16 hDrop
, WORD wFile
, LPSTR lpszFile
,
179 { /* hDrop is a global memory block allocated with GMEM_SHARE
180 * with DROPFILESTRUCT as a header and filenames following
181 * it, zero length filename is in the end */
183 LPDROPFILESTRUCT16 lpDropFileStruct
;
187 TRACE(shell
,"(%04x, %x, %p, %u)\n", hDrop
,wFile
,lpszFile
,wLength
);
189 lpDropFileStruct
= (LPDROPFILESTRUCT16
) GlobalLock16(hDrop
);
190 if(!lpDropFileStruct
)
193 lpCurrent
= (LPSTR
) lpDropFileStruct
+ lpDropFileStruct
->wSize
;
195 i
= (WORD
)SHELL_DragQueryFile(lpCurrent
, NULL
, wFile
==0xffff?0xffffffff:wFile
,
196 lpszFile
, NULL
, wLength
);
197 GlobalUnlock16(hDrop
);
203 /*************************************************************************
204 * DragFinish32 [SHELL32.80]
206 void WINAPI
DragFinish32(HDROP32 h
)
208 GlobalFree32((HGLOBAL32
)h
);
211 /*************************************************************************
212 * DragFinish16 [SHELL.12]
214 void WINAPI
DragFinish16(HDROP16 h
)
216 GlobalFree16((HGLOBAL16
)h
);
220 /*************************************************************************
221 * DragQueryPoint32 [SHELL32.135]
223 BOOL32 WINAPI
DragQueryPoint32(HDROP32 hDrop
, POINT32
*p
)
225 LPDROPFILESTRUCT32 lpDropFileStruct
;
228 lpDropFileStruct
= (LPDROPFILESTRUCT32
) GlobalLock32(hDrop
);
230 memcpy(p
,&lpDropFileStruct
->ptMousePos
,sizeof(POINT32
));
231 bRet
= lpDropFileStruct
->fInNonClientArea
;
233 GlobalUnlock32(hDrop
);
237 /*************************************************************************
238 * DragQueryPoint16 [SHELL.13]
240 BOOL16 WINAPI
DragQueryPoint16(HDROP16 hDrop
, POINT16
*p
)
242 LPDROPFILESTRUCT16 lpDropFileStruct
;
245 lpDropFileStruct
= (LPDROPFILESTRUCT16
) GlobalLock16(hDrop
);
247 memcpy(p
,&lpDropFileStruct
->ptMousePos
,sizeof(POINT16
));
248 bRet
= lpDropFileStruct
->fInNonClientArea
;
250 GlobalUnlock16(hDrop
);
254 /*************************************************************************
255 * SHELL_FindExecutable [Internal]
257 * Utility for code sharing between FindExecutable and ShellExecute
259 HINSTANCE32
SHELL_FindExecutable( LPCSTR lpFile
,
262 { char *extension
= NULL
; /* pointer to file extension */
263 char tmpext
[5]; /* local copy to mung as we please */
264 char filetype
[256]; /* registry name for this filetype */
265 LONG filetypelen
=256; /* length of above */
266 char command
[256]; /* command from registry */
267 LONG commandlen
=256; /* This is the most DOS can handle :) */
268 char buffer
[256]; /* Used to GetProfileString */
269 HINSTANCE32 retval
=31; /* default - 'No association was found' */
270 char *tok
; /* token pointer */
271 int i
; /* random counter */
272 char xlpFile
[256]; /* result of SearchPath */
274 TRACE(shell
, "%s\n", (lpFile
!= NULL
?lpFile
:"-") );
276 lpResult
[0]='\0'; /* Start off with an empty return string */
278 /* trap NULL parameters on entry */
279 if (( lpFile
== NULL
) || ( lpResult
== NULL
) || ( lpOperation
== NULL
))
280 { WARN(exec
, "(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
281 lpFile
, lpOperation
, lpResult
);
282 return 2; /* File not found. Close enough, I guess. */
285 if (SearchPath32A( NULL
, lpFile
,".exe",sizeof(xlpFile
),xlpFile
,NULL
))
286 { TRACE(shell
, "SearchPath32A returned non-zero\n");
290 /* First thing we need is the file's extension */
291 extension
= strrchr( xlpFile
, '.' ); /* Assume last "." is the one; */
292 /* File->Run in progman uses */
294 TRACE(shell
, "xlpFile=%s,extension=%s\n", xlpFile
, extension
);
296 if ((extension
== NULL
) || (extension
== &xlpFile
[strlen(xlpFile
)]))
297 { WARN(shell
, "Returning 31 - No association\n");
298 return 31; /* no association */
301 /* Make local copy & lowercase it for reg & 'programs=' lookup */
302 lstrcpyn32A( tmpext
, extension
, 5 );
303 CharLower32A( tmpext
);
304 TRACE(shell
, "%s file\n", tmpext
);
306 /* Three places to check: */
307 /* 1. win.ini, [windows], programs (NB no leading '.') */
308 /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
309 /* 3. win.ini, [extensions], extension (NB no leading '.' */
310 /* All I know of the order is that registry is checked before */
311 /* extensions; however, it'd make sense to check the programs */
312 /* section first, so that's what happens here. */
314 /* See if it's a program - if GetProfileString fails, we skip this
315 * section. Actually, if GetProfileString fails, we've probably
316 * got a lot more to worry about than running a program... */
317 if ( GetProfileString32A("windows", "programs", "exe pif bat com",
318 buffer
, sizeof(buffer
)) > 0 )
319 { for (i
=0;i
<strlen(buffer
); i
++) buffer
[i
]=tolower(buffer
[i
]);
321 tok
= strtok(buffer
, " \t"); /* ? */
324 if (strcmp(tok
, &tmpext
[1])==0) /* have to skip the leading "." */
326 strcpy(lpResult
, xlpFile
);
327 /* Need to perhaps check that the file has a path
329 TRACE(shell
, "found %s\n", lpResult
);
332 /* Greater than 32 to indicate success FIXME According to the
333 * docs, I should be returning a handle for the
334 * executable. Does this mean I'm supposed to open the
335 * executable file or something? More RTFM, I guess... */
337 tok
=strtok(NULL
, " \t");
342 if (RegQueryValue16( HKEY_CLASSES_ROOT
, tmpext
, filetype
,
343 &filetypelen
) == ERROR_SUCCESS
)
345 filetype
[filetypelen
]='\0';
346 TRACE(shell
, "File type: %s\n", filetype
);
348 /* Looking for ...buffer\shell\lpOperation\command */
349 strcat( filetype
, "\\shell\\" );
350 strcat( filetype
, lpOperation
);
351 strcat( filetype
, "\\command" );
353 if (RegQueryValue16( HKEY_CLASSES_ROOT
, filetype
, command
,
354 &commandlen
) == ERROR_SUCCESS
)
356 /* Is there a replace() function anywhere? */
357 command
[commandlen
]='\0';
358 strcpy( lpResult
, command
);
359 tok
=strstr( lpResult
, "%1" );
362 tok
[0]='\0'; /* truncate string at the percent */
363 strcat( lpResult
, xlpFile
); /* what if no dir in xlpFile? */
364 tok
=strstr( command
, "%1" );
365 if ((tok
!=NULL
) && (strlen(tok
)>2))
367 strcat( lpResult
, &tok
[2] );
370 retval
=33; /* FIXME see above */
373 else /* Check win.ini */
375 /* Toss the leading dot */
377 if ( GetProfileString32A( "extensions", extension
, "", command
,
378 sizeof(command
)) > 0)
380 if (strlen(command
)!=0)
382 strcpy( lpResult
, command
);
383 tok
=strstr( lpResult
, "^" ); /* should be ^.extension? */
387 strcat( lpResult
, xlpFile
); /* what if no dir in xlpFile? */
388 tok
=strstr( command
, "^" ); /* see above */
389 if ((tok
!= NULL
) && (strlen(tok
)>5))
391 strcat( lpResult
, &tok
[5]);
394 retval
=33; /* FIXME - see above */
399 TRACE(shell
, "returning %s\n", lpResult
);
403 /*************************************************************************
404 * ShellExecute16 [SHELL.20]
406 HINSTANCE16 WINAPI
ShellExecute16( HWND16 hWnd
, LPCSTR lpOperation
,
407 LPCSTR lpFile
, LPCSTR lpParameters
,
408 LPCSTR lpDirectory
, INT16 iShowCmd
)
409 { HINSTANCE16 retval
=31;
413 TRACE(shell
, "(%04x,'%s','%s','%s','%s',%x)\n",
414 hWnd
, lpOperation
? lpOperation
:"<null>", lpFile
? lpFile
:"<null>",
415 lpParameters
? lpParameters
: "<null>",
416 lpDirectory
? lpDirectory
: "<null>", iShowCmd
);
418 if (lpFile
==NULL
) return 0; /* should not happen */
419 if (lpOperation
==NULL
) /* default is open */
423 { GetCurrentDirectory32A( sizeof(old_dir
), old_dir
);
424 SetCurrentDirectory32A( lpDirectory
);
427 retval
= SHELL_FindExecutable( lpFile
, lpOperation
, cmd
);
429 if (retval
> 32) /* Found */
432 strcat(cmd
,lpParameters
);
435 TRACE(shell
,"starting %s\n",cmd
);
436 retval
= WinExec32( cmd
, iShowCmd
);
439 SetCurrentDirectory32A( old_dir
);
443 /*************************************************************************
444 * FindExecutable16 (SHELL.21)
446 HINSTANCE16 WINAPI
FindExecutable16( LPCSTR lpFile
, LPCSTR lpDirectory
,
448 { return (HINSTANCE16
)FindExecutable32A( lpFile
, lpDirectory
, lpResult
);
452 /*************************************************************************
453 * AboutDlgProc16 (SHELL.33)
455 LRESULT WINAPI
AboutDlgProc16( HWND16 hWnd
, UINT16 msg
, WPARAM16 wParam
,
457 { return AboutDlgProc32( hWnd
, msg
, wParam
, lParam
);
461 /*************************************************************************
462 * ShellAbout16 (SHELL.22)
464 BOOL16 WINAPI
ShellAbout16( HWND16 hWnd
, LPCSTR szApp
, LPCSTR szOtherStuff
,
466 { return ShellAbout32A( hWnd
, szApp
, szOtherStuff
, hIcon
);
469 /*************************************************************************
470 * SHELL_GetResourceTable
472 static DWORD
SHELL_GetResourceTable(HFILE32 hFile
,LPBYTE
*retptr
)
473 { IMAGE_DOS_HEADER mz_header
;
480 _llseek32( hFile
, 0, SEEK_SET
);
481 if ((_lread32(hFile
,&mz_header
,sizeof(mz_header
)) != sizeof(mz_header
)) || (mz_header
.e_magic
!= IMAGE_DOS_SIGNATURE
))
483 if (mz_header
.e_cblp
== 1)
484 { /* ICONHEADER.idType, must be 1 */
485 *retptr
= (LPBYTE
)-1;
489 return 0; /* failed */
491 _llseek32( hFile
, mz_header
.e_lfanew
, SEEK_SET
);
493 if (_lread32( hFile
, magic
, sizeof(magic
) ) != sizeof(magic
))
496 _llseek32( hFile
, mz_header
.e_lfanew
, SEEK_SET
);
498 if (*(DWORD
*)magic
== IMAGE_NT_SIGNATURE
)
499 return IMAGE_NT_SIGNATURE
;
501 if (*(WORD
*)magic
== IMAGE_OS2_SIGNATURE
)
502 { IMAGE_OS2_HEADER ne_header
;
503 LPBYTE pTypeInfo
= (LPBYTE
)-1;
505 if (_lread32(hFile
,&ne_header
,sizeof(ne_header
))!=sizeof(ne_header
))
508 if (ne_header
.ne_magic
!= IMAGE_OS2_SIGNATURE
)
511 size
= ne_header
.rname_tab_offset
- ne_header
.resource_tab_offset
;
513 if( size
> sizeof(NE_TYPEINFO
) )
514 { pTypeInfo
= (BYTE
*)HeapAlloc( GetProcessHeap(), 0, size
);
516 { _llseek32(hFile
, mz_header
.e_lfanew
+ne_header
.resource_tab_offset
, SEEK_SET
);
517 if( _lread32( hFile
, (char*)pTypeInfo
, size
) != size
)
518 { HeapFree( GetProcessHeap(), 0, pTypeInfo
);
524 return IMAGE_OS2_SIGNATURE
;
526 return 0; /* failed */
529 /*************************************************************************
532 static HGLOBAL16
SHELL_LoadResource(HINSTANCE16 hInst
, HFILE32 hFile
, NE_NAMEINFO
* pNInfo
, WORD sizeShift
)
534 HGLOBAL16 handle
= DirectResAlloc( hInst
, 0x10, (DWORD
)pNInfo
->length
<< sizeShift
);
538 if( (ptr
= (BYTE
*)GlobalLock16( handle
)) )
539 { _llseek32( hFile
, (DWORD
)pNInfo
->offset
<< sizeShift
, SEEK_SET
);
540 _lread32( hFile
, (char*)ptr
, pNInfo
->length
<< sizeShift
);
546 /*************************************************************************
549 static HGLOBAL16
ICO_LoadIcon(HINSTANCE16 hInst
, HFILE32 hFile
, LPicoICONDIRENTRY lpiIDE
)
551 HGLOBAL16 handle
= DirectResAlloc( hInst
, 0x10, lpiIDE
->dwBytesInRes
);
553 if( (ptr
= (BYTE
*)GlobalLock16( handle
)) )
554 { _llseek32( hFile
, lpiIDE
->dwImageOffset
, SEEK_SET
);
555 _lread32( hFile
, (char*)ptr
, lpiIDE
->dwBytesInRes
);
561 /*************************************************************************
562 * ICO_GetIconDirectory
564 * Read .ico file and build phony ICONDIR struct for GetIconID
566 static HGLOBAL16
ICO_GetIconDirectory(HINSTANCE16 hInst
, HFILE32 hFile
, LPicoICONDIR
* lplpiID
)
567 { WORD id
[3]; /* idReserved, idType, idCount */
572 _llseek32( hFile
, 0, SEEK_SET
);
573 if( _lread32(hFile
,(char*)id
,sizeof(id
)) != sizeof(id
) ) return 0;
577 * - see http://www.microsoft.com/win32dev/ui/icons.htm
580 if( id
[0] || id
[1] != 1 || !id
[2] ) return 0;
582 i
= id
[2]*sizeof(icoICONDIRENTRY
) + sizeof(id
);
584 lpiID
= (LPicoICONDIR
)HeapAlloc( GetProcessHeap(), 0, i
);
586 if( _lread32(hFile
,(char*)lpiID
->idEntries
,i
) == i
)
587 { HGLOBAL16 handle
= DirectResAlloc( hInst
, 0x10,
588 id
[2]*sizeof(ICONDIRENTRY
) + sizeof(id
) );
590 { CURSORICONDIR
* lpID
= (CURSORICONDIR
*)GlobalLock16( handle
);
591 lpID
->idReserved
= lpiID
->idReserved
= id
[0];
592 lpID
->idType
= lpiID
->idType
= id
[1];
593 lpID
->idCount
= lpiID
->idCount
= id
[2];
594 for( i
=0; i
< lpiID
->idCount
; i
++ )
595 { memcpy((void*)(lpID
->idEntries
+ i
),
596 (void*)(lpiID
->idEntries
+ i
), sizeof(ICONDIRENTRY
) - 2);
597 lpID
->idEntries
[i
].icon
.wResId
= i
;
605 HeapFree( GetProcessHeap(), 0, lpiID
);
609 /*************************************************************************
610 * InternalExtractIcon [SHELL.39]
612 * This abortion is called directly by Progman
614 HGLOBAL16 WINAPI
InternalExtractIcon(HINSTANCE16 hInstance
,
615 LPCSTR lpszExeFileName
, UINT16 nIconIndex
, WORD n
)
616 { HGLOBAL16 hRet
= 0;
617 HGLOBAL16
* RetPtr
= NULL
;
621 HFILE32 hFile
= OpenFile32( lpszExeFileName
, &ofs
, OF_READ
);
622 UINT16 iconDirCount
= 0,iconCount
= 0;
626 TRACE(shell
,"(%04x,file %s,start %d,extract %d\n",
627 hInstance
, lpszExeFileName
, nIconIndex
, n
);
629 if( hFile
== HFILE_ERROR32
|| !n
)
632 hRet
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, sizeof(HICON16
)*n
);
633 RetPtr
= (HICON16
*)GlobalLock16(hRet
);
635 *RetPtr
= (n
== 0xFFFF)? 0: 1; /* error return values */
637 sig
= SHELL_GetResourceTable(hFile
,&pData
);
639 if( sig
==IMAGE_OS2_SIGNATURE
|| sig
==1 ) /* .ICO file */
641 NE_TYPEINFO
* pTInfo
= (NE_TYPEINFO
*)(pData
+ 2);
642 NE_NAMEINFO
* pIconStorage
= NULL
;
643 NE_NAMEINFO
* pIconDir
= NULL
;
644 LPicoICONDIR lpiID
= NULL
;
646 if( pData
== (BYTE
*)-1 )
647 { hIcon
= ICO_GetIconDirectory(hInstance
, hFile
, &lpiID
); /* check for .ICO file */
649 { iconDirCount
= 1; iconCount
= lpiID
->idCount
;
652 else while( pTInfo
->type_id
&& !(pIconStorage
&& pIconDir
) )
653 { if( pTInfo
->type_id
== NE_RSCTYPE_GROUP_ICON
) /* find icon directory and icon repository */
654 { iconDirCount
= pTInfo
->count
;
655 pIconDir
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
656 TRACE(shell
,"\tfound directory - %i icon families\n", iconDirCount
);
658 if( pTInfo
->type_id
== NE_RSCTYPE_ICON
)
659 { iconCount
= pTInfo
->count
;
660 pIconStorage
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
661 TRACE(shell
,"\ttotal icons - %i\n", iconCount
);
663 pTInfo
= (NE_TYPEINFO
*)((char*)(pTInfo
+1)+pTInfo
->count
*sizeof(NE_NAMEINFO
));
666 /* load resources and create icons */
668 if( (pIconStorage
&& pIconDir
) || lpiID
)
669 { if( nIconIndex
== (UINT16
)-1 )
670 { RetPtr
[0] = iconDirCount
;
672 else if( nIconIndex
< iconDirCount
)
674 if( n
> iconDirCount
- nIconIndex
)
675 n
= iconDirCount
- nIconIndex
;
677 for( i
= nIconIndex
; i
< nIconIndex
+ n
; i
++ )
678 { /* .ICO files have only one icon directory */
681 hIcon
= SHELL_LoadResource( hInstance
, hFile
, pIconDir
+ i
, *(WORD
*)pData
);
682 RetPtr
[i
-nIconIndex
] = GetIconID( hIcon
, 3 );
686 for( icon
= nIconIndex
; icon
< nIconIndex
+ n
; icon
++ )
689 { hIcon
= ICO_LoadIcon( hInstance
, hFile
, lpiID
->idEntries
+ RetPtr
[icon
-nIconIndex
]);
692 { for( i
= 0; i
< iconCount
; i
++ )
693 { if( pIconStorage
[i
].id
== (RetPtr
[icon
-nIconIndex
] | 0x8000) )
694 { hIcon
= SHELL_LoadResource( hInstance
, hFile
, pIconStorage
+ i
,*(WORD
*)pData
);
699 { RetPtr
[icon
-nIconIndex
] = LoadIconHandler( hIcon
, TRUE
);
700 FarSetOwner( RetPtr
[icon
-nIconIndex
], GetExePtr(hInstance
) );
703 { RetPtr
[icon
-nIconIndex
] = 0;
709 HeapFree( GetProcessHeap(), 0, lpiID
);
711 HeapFree( GetProcessHeap(), 0, pData
);
714 if( sig
== IMAGE_NT_SIGNATURE
)
715 { LPBYTE idata
,igdata
;
716 PIMAGE_DOS_HEADER dheader
;
717 PIMAGE_NT_HEADERS pe_header
;
718 PIMAGE_SECTION_HEADER pe_sections
;
719 PIMAGE_RESOURCE_DIRECTORY rootresdir
,iconresdir
,icongroupresdir
;
720 PIMAGE_RESOURCE_DATA_ENTRY idataent
,igdataent
;
722 PIMAGE_RESOURCE_DIRECTORY_ENTRY xresent
;
723 CURSORICONDIR
**cids
;
725 fmapping
= CreateFileMapping32A(hFile
,NULL
,PAGE_READONLY
|SEC_COMMIT
,0,0,NULL
);
727 { /* FIXME, INVALID_HANDLE_VALUE? */
728 WARN(shell
,"failed to create filemap.\n");
730 goto end_2
; /* failure */
732 peimage
= MapViewOfFile(fmapping
,FILE_MAP_READ
,0,0,0);
734 { WARN(shell
,"failed to mmap filemap.\n");
736 goto end_2
; /* failure */
738 dheader
= (PIMAGE_DOS_HEADER
)peimage
;
740 /* it is a pe header, SHELL_GetResourceTable checked that */
741 pe_header
= (PIMAGE_NT_HEADERS
)(peimage
+dheader
->e_lfanew
);
743 /* probably makes problems with short PE headers... but I haven't seen
746 pe_sections
= (PIMAGE_SECTION_HEADER
)(((char*)pe_header
)+sizeof(*pe_header
));
749 for (i
=0;i
<pe_header
->FileHeader
.NumberOfSections
;i
++)
750 { if (pe_sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
752 /* FIXME: doesn't work when the resources are not in a seperate section */
753 if (pe_sections
[i
].VirtualAddress
== pe_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
)
754 { rootresdir
= (PIMAGE_RESOURCE_DIRECTORY
)((char*)peimage
+pe_sections
[i
].PointerToRawData
);
760 { WARN(shell
,"haven't found section for resource directory.\n");
761 goto end_4
; /* failure */
764 icongroupresdir
= GetResDirEntryW(rootresdir
,RT_GROUP_ICON32W
, (DWORD
)rootresdir
,FALSE
);
766 if (!icongroupresdir
)
767 { WARN(shell
,"No Icongroupresourcedirectory!\n");
768 goto end_4
; /* failure */
771 iconDirCount
= icongroupresdir
->NumberOfNamedEntries
+icongroupresdir
->NumberOfIdEntries
;
773 if( nIconIndex
== (UINT16
)-1 )
774 { RetPtr
[0] = iconDirCount
;
775 goto end_3
; /* success */
778 if (nIconIndex
>= iconDirCount
)
779 { WARN(shell
,"nIconIndex %d is larger than iconDirCount %d\n",nIconIndex
,iconDirCount
);
781 goto end_4
; /* failure */
784 cids
= (CURSORICONDIR
**)HeapAlloc(GetProcessHeap(),0,n
*sizeof(CURSORICONDIR
*));
786 /* caller just wanted the number of entries */
787 xresent
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(icongroupresdir
+1);
789 /* assure we don't get too much ... */
790 if( n
> iconDirCount
- nIconIndex
)
791 { n
= iconDirCount
- nIconIndex
;
794 /* starting from specified index ... */
795 xresent
= xresent
+nIconIndex
;
797 for (i
=0;i
<n
;i
++,xresent
++)
798 { CURSORICONDIR
*cid
;
799 PIMAGE_RESOURCE_DIRECTORY resdir
;
801 /* go down this resource entry, name */
802 resdir
= (PIMAGE_RESOURCE_DIRECTORY
)((DWORD
)rootresdir
+(xresent
->u2
.s
.OffsetToDirectory
));
804 /* default language (0) */
805 resdir
= GetResDirEntryW(resdir
,(LPWSTR
)0,(DWORD
)rootresdir
,TRUE
);
806 igdataent
= (PIMAGE_RESOURCE_DATA_ENTRY
)resdir
;
808 /* lookup address in mapped image for virtual address */
811 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
812 { if (igdataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
814 if (igdataent
->OffsetToData
+igdataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
816 igdata
= peimage
+(igdataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
820 { WARN(shell
,"no matching real address for icongroup!\n");
821 goto end_4
; /* failure */
824 cid
= (CURSORICONDIR
*)igdata
;
826 RetPtr
[i
] = LookupIconIdFromDirectoryEx32(igdata
,TRUE
,SYSMETRICS_CXICON
,SYSMETRICS_CYICON
,0);
829 iconresdir
=GetResDirEntryW(rootresdir
,RT_ICON32W
,(DWORD
)rootresdir
,FALSE
);
832 { WARN(shell
,"No Iconresourcedirectory!\n");
833 goto end_4
; /* failure */
837 { PIMAGE_RESOURCE_DIRECTORY xresdir
;
838 xresdir
= GetResDirEntryW(iconresdir
,(LPWSTR
)(DWORD
)RetPtr
[i
],(DWORD
)rootresdir
,FALSE
);
839 xresdir
= GetResDirEntryW(xresdir
,(LPWSTR
)0,(DWORD
)rootresdir
,TRUE
);
840 idataent
= (PIMAGE_RESOURCE_DATA_ENTRY
)xresdir
;
843 /* map virtual to address in image */
844 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
845 { if (idataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
847 if (idataent
->OffsetToData
+idataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
849 idata
= peimage
+(idataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
852 { WARN(shell
,"no matching real address found for icondata!\n");
856 RetPtr
[i
] = CreateIconFromResourceEx32(idata
,idataent
->Size
,TRUE
,0x00030000,SYSMETRICS_CXICON
,SYSMETRICS_CYICON
,0);
858 goto end_3
; /* sucess */
860 goto end_1
; /* return array with icon handles */
862 /* cleaning up (try & catch would be nicer) */
863 end_4
: hRet
= 0; /* failure */
864 end_3
: UnmapViewOfFile(peimage
); /* success */
865 end_2
: CloseHandle(fmapping
);
866 end_1
: _lclose32( hFile
);
870 /*************************************************************************
871 * ExtractIcon16 (SHELL.34)
873 HICON16 WINAPI
ExtractIcon16( HINSTANCE16 hInstance
, LPCSTR lpszExeFileName
,
876 return ExtractIcon32A( hInstance
, lpszExeFileName
, nIconIndex
);
881 /*************************************************************************
882 * ExtractAssociatedIcon [SHELL.36]
884 * Return icon for given file (either from file itself or from associated
885 * executable) and patch parameters if needed.
887 HICON32 WINAPI
ExtractAssociatedIcon32A(HINSTANCE32 hInst
, LPSTR lpIconPath
, LPWORD lpiIcon
)
889 return ExtractAssociatedIcon16(hInst
,lpIconPath
,lpiIcon
);
892 HICON16 WINAPI
ExtractAssociatedIcon16(HINSTANCE16 hInst
, LPSTR lpIconPath
, LPWORD lpiIcon
)
897 hIcon
= ExtractIcon16(hInst
, lpIconPath
, *lpiIcon
);
900 { if( hIcon
== 1 ) /* no icons found in given file */
901 { char tempPath
[0x80];
902 UINT16 uRet
= FindExecutable16(lpIconPath
,NULL
,tempPath
);
904 if( uRet
> 32 && tempPath
[0] )
905 { strcpy(lpIconPath
,tempPath
);
906 hIcon
= ExtractIcon16(hInst
, lpIconPath
, *lpiIcon
);
914 *lpiIcon
= 2; /* MSDOS icon - we found .exe but no icons in it */
916 *lpiIcon
= 6; /* generic icon - found nothing */
918 GetModuleFileName16(hInst
, lpIconPath
, 0x80);
919 hIcon
= LoadIcon16( hInst
, MAKEINTRESOURCE16(*lpiIcon
));
924 /*************************************************************************
925 * FindEnvironmentString [SHELL.38]
927 * Returns a pointer into the DOS environment... Ugh.
929 LPSTR
SHELL_FindString(LPSTR lpEnv
, LPCSTR entry
)
935 for( ; *lpEnv
; lpEnv
+=strlen(lpEnv
)+1 )
936 { if( lstrncmpi32A(lpEnv
, entry
, l
) )
939 return (lpEnv
+ l
); /* empty entry */
940 else if ( *(lpEnv
+l
)== '=' )
941 return (lpEnv
+ l
+ 1);
946 SEGPTR WINAPI
FindEnvironmentString(LPSTR str
)
948 LPSTR lpEnv
,lpString
;
951 spEnv
= GetDOSEnvironment();
953 lpEnv
= (LPSTR
)PTR_SEG_TO_LIN(spEnv
);
954 lpString
= (spEnv
)?SHELL_FindString(lpEnv
, str
):NULL
;
956 if( lpString
) /* offset should be small enough */
957 return spEnv
+ (lpString
- lpEnv
);
961 /*************************************************************************
962 * DoEnvironmentSubst [SHELL.37]
964 * Replace %KEYWORD% in the str with the value of variable KEYWORD
965 * from "DOS" environment.
967 DWORD WINAPI
DoEnvironmentSubst(LPSTR str
,WORD length
)
969 LPSTR lpEnv
= (LPSTR
)PTR_SEG_TO_LIN(GetDOSEnvironment());
970 LPSTR lpBuffer
= (LPSTR
)HeapAlloc( GetProcessHeap(), 0, length
);
972 LPSTR lpbstr
= lpBuffer
;
974 CharToOem32A(str
,str
);
976 TRACE(shell
,"accept %s\n", str
);
978 while( *lpstr
&& lpbstr
- lpBuffer
< length
)
984 do { lpend
++; } while( *lpend
&& *lpend
!= '%' );
985 if( *lpend
== '%' && lpend
- lpstr
> 1 ) /* found key */
989 lpKey
= SHELL_FindString(lpEnv
, lpstr
+1);
990 if( lpKey
) /* found key value */
992 int l
= strlen(lpKey
);
994 if( l
> length
- (lpbstr
- lpBuffer
) - 1 )
996 WARN(shell
,"-- Env subst aborted - string too short\n");
1000 strcpy(lpbstr
, lpKey
);
1007 else break; /* back off and whine */
1012 *lpbstr
++ = *lpstr
++;
1016 if( lpstr
- str
== strlen(str
) )
1018 strncpy(str
, lpBuffer
, length
);
1024 TRACE(shell
,"-- return %s\n", str
);
1026 OemToChar32A(str
,str
);
1027 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1029 /* Return str length in the LOWORD
1030 * and 1 in HIWORD if subst was successful.
1032 return (DWORD
)MAKELONG(strlen(str
), length
);
1035 /*************************************************************************
1036 * ShellHookProc [SHELL.103]
1037 * System-wide WH_SHELL hook.
1039 LRESULT WINAPI
ShellHookProc(INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
1041 TRACE(shell
,"%i, %04x, %08x\n", code
, wParam
,
1043 if( SHELL_hHook
&& SHELL_hWnd
)
1048 case HSHELL_WINDOWCREATED
: uMsg
= uMsgWndCreated
; break;
1049 case HSHELL_WINDOWDESTROYED
: uMsg
= uMsgWndDestroyed
; break;
1050 case HSHELL_ACTIVATESHELLWINDOW
: uMsg
= uMsgShellActivate
;
1052 PostMessage16( SHELL_hWnd
, uMsg
, wParam
, 0 );
1054 return CallNextHookEx16( WH_SHELL
, code
, wParam
, lParam
);
1057 /*************************************************************************
1058 * RegisterShellHook [SHELL.102]
1060 BOOL32 WINAPI
RegisterShellHook(HWND16 hWnd
, UINT16 uAction
)
1061 { TRACE(shell
,"%04x [%u]\n", hWnd
, uAction
);
1064 { case 2: /* register hWnd as a shell window */
1066 { HMODULE16 hShell
= GetModuleHandle16( "SHELL" );
1067 SHELL_hHook
= SetWindowsHookEx16( WH_SHELL
, ShellHookProc
, hShell
, 0 );
1069 { uMsgWndCreated
= RegisterWindowMessage32A( lpstrMsgWndCreated
);
1070 uMsgWndDestroyed
= RegisterWindowMessage32A( lpstrMsgWndDestroyed
);
1071 uMsgShellActivate
= RegisterWindowMessage32A( lpstrMsgShellActivate
);
1074 WARN(shell
,"-- unable to install ShellHookProc()!\n");
1078 return ((SHELL_hWnd
= hWnd
) != 0);
1082 WARN(shell
, "-- unknown code %i\n", uAction
);