2 * Shell Library Functions
11 #include "wine/winuser16.h"
12 #include "wine/winbase16.h"
13 #include "wine/shell16.h"
21 #include "cursoricon.h"
22 #include "sysmetrics.h"
27 #include "imagelist.h"
29 /* .ICO file ICONDIR definitions */
35 BYTE bWidth
; /* Width, in pixels, of the image */
36 BYTE bHeight
; /* Height, in pixels, of the image */
37 BYTE bColorCount
; /* Number of colors in image (0 if >=8bpp) */
38 BYTE bReserved
; /* Reserved ( must be 0) */
39 WORD wPlanes
; /* Color Planes */
40 WORD wBitCount
; /* Bits per pixel */
41 DWORD dwBytesInRes
; /* How many bytes in this resource? */
42 DWORD dwImageOffset
; /* Where in the file is this image? */
43 } icoICONDIRENTRY
, *LPicoICONDIRENTRY
;
47 WORD idReserved
; /* Reserved (must be 0) */
48 WORD idType
; /* Resource Type (1 for icons) */
49 WORD idCount
; /* How many images? */
50 icoICONDIRENTRY idEntries
[1]; /* An entry for each image (idCount of 'em) */
51 } icoICONDIR
, *LPicoICONDIR
;
55 static const char* lpstrMsgWndCreated
= "OTHERWINDOWCREATED";
56 static const char* lpstrMsgWndDestroyed
= "OTHERWINDOWDESTROYED";
57 static const char* lpstrMsgShellActivate
= "ACTIVATESHELLWINDOW";
59 static HWND16 SHELL_hWnd
= 0;
60 static HHOOK SHELL_hHook
= 0;
61 static UINT16 uMsgWndCreated
= 0;
62 static UINT16 uMsgWndDestroyed
= 0;
63 static UINT16 uMsgShellActivate
= 0;
65 /*************************************************************************
66 * DragAcceptFiles32 [SHELL32.54]
68 void WINAPI
DragAcceptFiles32(HWND32 hWnd
, BOOL32 b
)
70 WND
* wnd
= WIN_FindWndPtr(hWnd
);
73 wnd
->dwExStyle
= b
? wnd
->dwExStyle
| WS_EX_ACCEPTFILES
74 : wnd
->dwExStyle
& ~WS_EX_ACCEPTFILES
;
77 /*************************************************************************
78 * DragAcceptFiles16 [SHELL.9]
80 void WINAPI
DragAcceptFiles16(HWND16 hWnd
, BOOL16 b
)
82 DragAcceptFiles32(hWnd
, b
);
85 /*************************************************************************
86 * SHELL_DragQueryFile [internal]
89 static UINT32
SHELL_DragQueryFile(LPSTR lpDrop
, LPWSTR lpwDrop
, UINT32 lFile
,
90 LPSTR lpszFile
, LPWSTR lpszwFile
, UINT32 lLength
)
97 while (*lpDrop
++); /* skip filename */
99 return (lFile
== 0xFFFFFFFF) ? i
: 0;
103 while (i
++ < lFile
) {
104 while (*lpwDrop
++); /* skip filename */
106 return (lFile
== 0xFFFFFFFF) ? i
: 0;
110 if (lpDrop
) i
= lstrlen32A(lpDrop
);
111 if (lpwDrop
) i
= lstrlen32W(lpwDrop
);
113 if (!lpszFile
&& !lpszwFile
) {
114 return i
; /* needed buffer size */
116 i
= (lLength
> i
) ? i
: lLength
;
118 if (lpDrop
) lstrcpyn32A (lpszFile
, lpDrop
, i
);
119 else lstrcpynWtoA(lpszFile
, lpwDrop
, i
);
121 if (lpDrop
) lstrcpynAtoW(lpszwFile
, lpDrop
, i
);
122 else lstrcpyn32W (lpszwFile
, lpwDrop
, i
);
127 /*************************************************************************
128 * DragQueryFile32A [SHELL32.81] [shell32.82]
130 UINT32 WINAPI
DragQueryFile32A(HDROP32 hDrop
, UINT32 lFile
, LPSTR lpszFile
,
132 { /* hDrop is a global memory block allocated with GMEM_SHARE
133 * with DROPFILESTRUCT as a header and filenames following
134 * it, zero length filename is in the end */
136 LPDROPFILESTRUCT32 lpDropFileStruct
;
140 TRACE(shell
,"(%08x, %x, %p, %u)\n", hDrop
,lFile
,lpszFile
,lLength
);
142 lpDropFileStruct
= (LPDROPFILESTRUCT32
) GlobalLock32(hDrop
);
143 if(!lpDropFileStruct
)
146 lpCurrent
= (LPSTR
) lpDropFileStruct
+ lpDropFileStruct
->lSize
;
147 i
= SHELL_DragQueryFile(lpCurrent
, NULL
, lFile
, lpszFile
, NULL
, lLength
);
148 GlobalUnlock32(hDrop
);
152 /*************************************************************************
153 * DragQueryFile32W [shell32.133]
155 UINT32 WINAPI
DragQueryFile32W(HDROP32 hDrop
, UINT32 lFile
, LPWSTR lpszwFile
,
158 LPDROPFILESTRUCT32 lpDropFileStruct
;
162 TRACE(shell
,"(%08x, %x, %p, %u)\n", hDrop
,lFile
,lpszwFile
,lLength
);
164 lpDropFileStruct
= (LPDROPFILESTRUCT32
) GlobalLock32(hDrop
);
165 if(!lpDropFileStruct
)
168 lpwCurrent
= (LPWSTR
) lpDropFileStruct
+ lpDropFileStruct
->lSize
;
169 i
= SHELL_DragQueryFile(NULL
, lpwCurrent
, lFile
, NULL
, lpszwFile
,lLength
);
170 GlobalUnlock32(hDrop
);
173 /*************************************************************************
174 * DragQueryFile16 [SHELL.11]
176 UINT16 WINAPI
DragQueryFile16(HDROP16 hDrop
, WORD wFile
, LPSTR lpszFile
,
178 { /* hDrop is a global memory block allocated with GMEM_SHARE
179 * with DROPFILESTRUCT as a header and filenames following
180 * it, zero length filename is in the end */
182 LPDROPFILESTRUCT16 lpDropFileStruct
;
186 TRACE(shell
,"(%04x, %x, %p, %u)\n", hDrop
,wFile
,lpszFile
,wLength
);
188 lpDropFileStruct
= (LPDROPFILESTRUCT16
) GlobalLock16(hDrop
);
189 if(!lpDropFileStruct
)
192 lpCurrent
= (LPSTR
) lpDropFileStruct
+ lpDropFileStruct
->wSize
;
194 i
= (WORD
)SHELL_DragQueryFile(lpCurrent
, NULL
, wFile
==0xffff?0xffffffff:wFile
,
195 lpszFile
, NULL
, wLength
);
196 GlobalUnlock16(hDrop
);
202 /*************************************************************************
203 * DragFinish32 [SHELL32.80]
205 void WINAPI
DragFinish32(HDROP32 h
)
207 GlobalFree32((HGLOBAL32
)h
);
210 /*************************************************************************
211 * DragFinish16 [SHELL.12]
213 void WINAPI
DragFinish16(HDROP16 h
)
215 GlobalFree16((HGLOBAL16
)h
);
219 /*************************************************************************
220 * DragQueryPoint32 [SHELL32.135]
222 BOOL32 WINAPI
DragQueryPoint32(HDROP32 hDrop
, POINT32
*p
)
224 LPDROPFILESTRUCT32 lpDropFileStruct
;
227 lpDropFileStruct
= (LPDROPFILESTRUCT32
) GlobalLock32(hDrop
);
229 memcpy(p
,&lpDropFileStruct
->ptMousePos
,sizeof(POINT32
));
230 bRet
= lpDropFileStruct
->fInNonClientArea
;
232 GlobalUnlock32(hDrop
);
236 /*************************************************************************
237 * DragQueryPoint16 [SHELL.13]
239 BOOL16 WINAPI
DragQueryPoint16(HDROP16 hDrop
, POINT16
*p
)
241 LPDROPFILESTRUCT16 lpDropFileStruct
;
244 lpDropFileStruct
= (LPDROPFILESTRUCT16
) GlobalLock16(hDrop
);
246 memcpy(p
,&lpDropFileStruct
->ptMousePos
,sizeof(POINT16
));
247 bRet
= lpDropFileStruct
->fInNonClientArea
;
249 GlobalUnlock16(hDrop
);
253 /*************************************************************************
254 * SHELL_FindExecutable [Internal]
256 * Utility for code sharing between FindExecutable and ShellExecute
258 HINSTANCE32
SHELL_FindExecutable( LPCSTR lpFile
,
261 { char *extension
= NULL
; /* pointer to file extension */
262 char tmpext
[5]; /* local copy to mung as we please */
263 char filetype
[256]; /* registry name for this filetype */
264 LONG filetypelen
=256; /* length of above */
265 char command
[256]; /* command from registry */
266 LONG commandlen
=256; /* This is the most DOS can handle :) */
267 char buffer
[256]; /* Used to GetProfileString */
268 HINSTANCE32 retval
=31; /* default - 'No association was found' */
269 char *tok
; /* token pointer */
270 int i
; /* random counter */
271 char xlpFile
[256]; /* result of SearchPath */
273 TRACE(shell
, "%s\n", (lpFile
!= NULL
?lpFile
:"-") );
275 lpResult
[0]='\0'; /* Start off with an empty return string */
277 /* trap NULL parameters on entry */
278 if (( lpFile
== NULL
) || ( lpResult
== NULL
) || ( lpOperation
== NULL
))
279 { WARN(exec
, "(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
280 lpFile
, lpOperation
, lpResult
);
281 return 2; /* File not found. Close enough, I guess. */
284 if (SearchPath32A( NULL
, lpFile
,".exe",sizeof(xlpFile
),xlpFile
,NULL
))
285 { TRACE(shell
, "SearchPath32A returned non-zero\n");
289 /* First thing we need is the file's extension */
290 extension
= strrchr( xlpFile
, '.' ); /* Assume last "." is the one; */
291 /* File->Run in progman uses */
293 TRACE(shell
, "xlpFile=%s,extension=%s\n", xlpFile
, extension
);
295 if ((extension
== NULL
) || (extension
== &xlpFile
[strlen(xlpFile
)]))
296 { WARN(shell
, "Returning 31 - No association\n");
297 return 31; /* no association */
300 /* Make local copy & lowercase it for reg & 'programs=' lookup */
301 lstrcpyn32A( tmpext
, extension
, 5 );
302 CharLower32A( tmpext
);
303 TRACE(shell
, "%s file\n", tmpext
);
305 /* Three places to check: */
306 /* 1. win.ini, [windows], programs (NB no leading '.') */
307 /* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
308 /* 3. win.ini, [extensions], extension (NB no leading '.' */
309 /* All I know of the order is that registry is checked before */
310 /* extensions; however, it'd make sense to check the programs */
311 /* section first, so that's what happens here. */
313 /* See if it's a program - if GetProfileString fails, we skip this
314 * section. Actually, if GetProfileString fails, we've probably
315 * got a lot more to worry about than running a program... */
316 if ( GetProfileString32A("windows", "programs", "exe pif bat com",
317 buffer
, sizeof(buffer
)) > 0 )
318 { for (i
=0;i
<strlen(buffer
); i
++) buffer
[i
]=tolower(buffer
[i
]);
320 tok
= strtok(buffer
, " \t"); /* ? */
323 if (strcmp(tok
, &tmpext
[1])==0) /* have to skip the leading "." */
325 strcpy(lpResult
, xlpFile
);
326 /* Need to perhaps check that the file has a path
328 TRACE(shell
, "found %s\n", lpResult
);
331 /* Greater than 32 to indicate success FIXME According to the
332 * docs, I should be returning a handle for the
333 * executable. Does this mean I'm supposed to open the
334 * executable file or something? More RTFM, I guess... */
336 tok
=strtok(NULL
, " \t");
341 if (RegQueryValue16( HKEY_CLASSES_ROOT
, tmpext
, filetype
,
342 &filetypelen
) == ERROR_SUCCESS
)
344 filetype
[filetypelen
]='\0';
345 TRACE(shell
, "File type: %s\n", filetype
);
347 /* Looking for ...buffer\shell\lpOperation\command */
348 strcat( filetype
, "\\shell\\" );
349 strcat( filetype
, lpOperation
);
350 strcat( filetype
, "\\command" );
352 if (RegQueryValue16( HKEY_CLASSES_ROOT
, filetype
, command
,
353 &commandlen
) == ERROR_SUCCESS
)
355 /* Is there a replace() function anywhere? */
356 command
[commandlen
]='\0';
357 strcpy( lpResult
, command
);
358 tok
=strstr( lpResult
, "%1" );
361 tok
[0]='\0'; /* truncate string at the percent */
362 strcat( lpResult
, xlpFile
); /* what if no dir in xlpFile? */
363 tok
=strstr( command
, "%1" );
364 if ((tok
!=NULL
) && (strlen(tok
)>2))
366 strcat( lpResult
, &tok
[2] );
369 retval
=33; /* FIXME see above */
372 else /* Check win.ini */
374 /* Toss the leading dot */
376 if ( GetProfileString32A( "extensions", extension
, "", command
,
377 sizeof(command
)) > 0)
379 if (strlen(command
)!=0)
381 strcpy( lpResult
, command
);
382 tok
=strstr( lpResult
, "^" ); /* should be ^.extension? */
386 strcat( lpResult
, xlpFile
); /* what if no dir in xlpFile? */
387 tok
=strstr( command
, "^" ); /* see above */
388 if ((tok
!= NULL
) && (strlen(tok
)>5))
390 strcat( lpResult
, &tok
[5]);
393 retval
=33; /* FIXME - see above */
398 TRACE(shell
, "returning %s\n", lpResult
);
402 /*************************************************************************
403 * ShellExecute16 [SHELL.20]
405 HINSTANCE16 WINAPI
ShellExecute16( HWND16 hWnd
, LPCSTR lpOperation
,
406 LPCSTR lpFile
, LPCSTR lpParameters
,
407 LPCSTR lpDirectory
, INT16 iShowCmd
)
408 { HINSTANCE16 retval
=31;
412 TRACE(shell
, "(%04x,'%s','%s','%s','%s',%x)\n",
413 hWnd
, lpOperation
? lpOperation
:"<null>", lpFile
? lpFile
:"<null>",
414 lpParameters
? lpParameters
: "<null>",
415 lpDirectory
? lpDirectory
: "<null>", iShowCmd
);
417 if (lpFile
==NULL
) return 0; /* should not happen */
418 if (lpOperation
==NULL
) /* default is open */
422 { GetCurrentDirectory32A( sizeof(old_dir
), old_dir
);
423 SetCurrentDirectory32A( lpDirectory
);
426 retval
= SHELL_FindExecutable( lpFile
, lpOperation
, cmd
);
428 if (retval
> 32) /* Found */
431 strcat(cmd
,lpParameters
);
434 TRACE(shell
,"starting %s\n",cmd
);
435 retval
= WinExec32( cmd
, iShowCmd
);
438 SetCurrentDirectory32A( old_dir
);
442 /*************************************************************************
443 * FindExecutable16 (SHELL.21)
445 HINSTANCE16 WINAPI
FindExecutable16( LPCSTR lpFile
, LPCSTR lpDirectory
,
447 { return (HINSTANCE16
)FindExecutable32A( lpFile
, lpDirectory
, lpResult
);
451 /*************************************************************************
452 * AboutDlgProc16 (SHELL.33)
454 BOOL16 WINAPI
AboutDlgProc16( HWND16 hWnd
, UINT16 msg
, WPARAM16 wParam
,
456 { return AboutDlgProc32( hWnd
, msg
, wParam
, lParam
);
460 /*************************************************************************
461 * ShellAbout16 (SHELL.22)
463 BOOL16 WINAPI
ShellAbout16( HWND16 hWnd
, LPCSTR szApp
, LPCSTR szOtherStuff
,
465 { return ShellAbout32A( hWnd
, szApp
, szOtherStuff
, hIcon
);
468 /*************************************************************************
469 * SHELL_GetResourceTable
471 static DWORD
SHELL_GetResourceTable(HFILE32 hFile
,LPBYTE
*retptr
)
472 { IMAGE_DOS_HEADER mz_header
;
479 _llseek32( hFile
, 0, SEEK_SET
);
480 if ((_lread32(hFile
,&mz_header
,sizeof(mz_header
)) != sizeof(mz_header
)) || (mz_header
.e_magic
!= IMAGE_DOS_SIGNATURE
))
482 if (mz_header
.e_cblp
== 1)
483 { /* ICONHEADER.idType, must be 1 */
484 *retptr
= (LPBYTE
)-1;
488 return 0; /* failed */
490 _llseek32( hFile
, mz_header
.e_lfanew
, SEEK_SET
);
492 if (_lread32( hFile
, magic
, sizeof(magic
) ) != sizeof(magic
))
495 _llseek32( hFile
, mz_header
.e_lfanew
, SEEK_SET
);
497 if (*(DWORD
*)magic
== IMAGE_NT_SIGNATURE
)
498 return IMAGE_NT_SIGNATURE
;
500 if (*(WORD
*)magic
== IMAGE_OS2_SIGNATURE
)
501 { IMAGE_OS2_HEADER ne_header
;
502 LPBYTE pTypeInfo
= (LPBYTE
)-1;
504 if (_lread32(hFile
,&ne_header
,sizeof(ne_header
))!=sizeof(ne_header
))
507 if (ne_header
.ne_magic
!= IMAGE_OS2_SIGNATURE
)
510 size
= ne_header
.rname_tab_offset
- ne_header
.resource_tab_offset
;
512 if( size
> sizeof(NE_TYPEINFO
) )
513 { pTypeInfo
= (BYTE
*)HeapAlloc( GetProcessHeap(), 0, size
);
515 { _llseek32(hFile
, mz_header
.e_lfanew
+ne_header
.resource_tab_offset
, SEEK_SET
);
516 if( _lread32( hFile
, (char*)pTypeInfo
, size
) != size
)
517 { HeapFree( GetProcessHeap(), 0, pTypeInfo
);
523 return IMAGE_OS2_SIGNATURE
;
525 return 0; /* failed */
528 /*************************************************************************
531 static HGLOBAL16
SHELL_LoadResource(HINSTANCE16 hInst
, HFILE32 hFile
, NE_NAMEINFO
* pNInfo
, WORD sizeShift
)
533 HGLOBAL16 handle
= DirectResAlloc( hInst
, 0x10, (DWORD
)pNInfo
->length
<< sizeShift
);
537 if( (ptr
= (BYTE
*)GlobalLock16( handle
)) )
538 { _llseek32( hFile
, (DWORD
)pNInfo
->offset
<< sizeShift
, SEEK_SET
);
539 _lread32( hFile
, (char*)ptr
, pNInfo
->length
<< sizeShift
);
545 /*************************************************************************
548 static HGLOBAL16
ICO_LoadIcon(HINSTANCE16 hInst
, HFILE32 hFile
, LPicoICONDIRENTRY lpiIDE
)
550 HGLOBAL16 handle
= DirectResAlloc( hInst
, 0x10, lpiIDE
->dwBytesInRes
);
552 if( (ptr
= (BYTE
*)GlobalLock16( handle
)) )
553 { _llseek32( hFile
, lpiIDE
->dwImageOffset
, SEEK_SET
);
554 _lread32( hFile
, (char*)ptr
, lpiIDE
->dwBytesInRes
);
560 /*************************************************************************
561 * ICO_GetIconDirectory
563 * Read .ico file and build phony ICONDIR struct for GetIconID
565 static HGLOBAL16
ICO_GetIconDirectory(HINSTANCE16 hInst
, HFILE32 hFile
, LPicoICONDIR
* lplpiID
)
566 { WORD id
[3]; /* idReserved, idType, idCount */
571 _llseek32( hFile
, 0, SEEK_SET
);
572 if( _lread32(hFile
,(char*)id
,sizeof(id
)) != sizeof(id
) ) return 0;
576 * - see http://www.microsoft.com/win32dev/ui/icons.htm
579 if( id
[0] || id
[1] != 1 || !id
[2] ) return 0;
581 i
= id
[2]*sizeof(icoICONDIRENTRY
) + sizeof(id
);
583 lpiID
= (LPicoICONDIR
)HeapAlloc( GetProcessHeap(), 0, i
);
585 if( _lread32(hFile
,(char*)lpiID
->idEntries
,i
) == i
)
586 { HGLOBAL16 handle
= DirectResAlloc( hInst
, 0x10,
587 id
[2]*sizeof(ICONDIRENTRY
) + sizeof(id
) );
589 { CURSORICONDIR
* lpID
= (CURSORICONDIR
*)GlobalLock16( handle
);
590 lpID
->idReserved
= lpiID
->idReserved
= id
[0];
591 lpID
->idType
= lpiID
->idType
= id
[1];
592 lpID
->idCount
= lpiID
->idCount
= id
[2];
593 for( i
=0; i
< lpiID
->idCount
; i
++ )
594 { memcpy((void*)(lpID
->idEntries
+ i
),
595 (void*)(lpiID
->idEntries
+ i
), sizeof(ICONDIRENTRY
) - 2);
596 lpID
->idEntries
[i
].icon
.wResId
= i
;
604 HeapFree( GetProcessHeap(), 0, lpiID
);
608 /*************************************************************************
609 * InternalExtractIcon [SHELL.39]
611 * This abortion is called directly by Progman
613 HGLOBAL16 WINAPI
InternalExtractIcon(HINSTANCE16 hInstance
,
614 LPCSTR lpszExeFileName
, UINT16 nIconIndex
, WORD n
)
615 { HGLOBAL16 hRet
= 0;
616 HGLOBAL16
* RetPtr
= NULL
;
620 HFILE32 hFile
= OpenFile32( lpszExeFileName
, &ofs
, OF_READ
);
621 UINT16 iconDirCount
= 0,iconCount
= 0;
625 TRACE(shell
,"(%04x,file %s,start %d,extract %d\n",
626 hInstance
, lpszExeFileName
, nIconIndex
, n
);
628 if( hFile
== HFILE_ERROR32
|| !n
)
631 hRet
= GlobalAlloc16( GMEM_FIXED
| GMEM_ZEROINIT
, sizeof(HICON16
)*n
);
632 RetPtr
= (HICON16
*)GlobalLock16(hRet
);
634 *RetPtr
= (n
== 0xFFFF)? 0: 1; /* error return values */
636 sig
= SHELL_GetResourceTable(hFile
,&pData
);
638 if( sig
==IMAGE_OS2_SIGNATURE
|| sig
==1 ) /* .ICO file */
640 NE_TYPEINFO
* pTInfo
= (NE_TYPEINFO
*)(pData
+ 2);
641 NE_NAMEINFO
* pIconStorage
= NULL
;
642 NE_NAMEINFO
* pIconDir
= NULL
;
643 LPicoICONDIR lpiID
= NULL
;
645 if( pData
== (BYTE
*)-1 )
646 { hIcon
= ICO_GetIconDirectory(hInstance
, hFile
, &lpiID
); /* check for .ICO file */
648 { iconDirCount
= 1; iconCount
= lpiID
->idCount
;
651 else while( pTInfo
->type_id
&& !(pIconStorage
&& pIconDir
) )
652 { if( pTInfo
->type_id
== NE_RSCTYPE_GROUP_ICON
) /* find icon directory and icon repository */
653 { iconDirCount
= pTInfo
->count
;
654 pIconDir
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
655 TRACE(shell
,"\tfound directory - %i icon families\n", iconDirCount
);
657 if( pTInfo
->type_id
== NE_RSCTYPE_ICON
)
658 { iconCount
= pTInfo
->count
;
659 pIconStorage
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
660 TRACE(shell
,"\ttotal icons - %i\n", iconCount
);
662 pTInfo
= (NE_TYPEINFO
*)((char*)(pTInfo
+1)+pTInfo
->count
*sizeof(NE_NAMEINFO
));
665 /* load resources and create icons */
667 if( (pIconStorage
&& pIconDir
) || lpiID
)
668 { if( nIconIndex
== (UINT16
)-1 )
669 { RetPtr
[0] = iconDirCount
;
671 else if( nIconIndex
< iconDirCount
)
673 if( n
> iconDirCount
- nIconIndex
)
674 n
= iconDirCount
- nIconIndex
;
676 for( i
= nIconIndex
; i
< nIconIndex
+ n
; i
++ )
677 { /* .ICO files have only one icon directory */
680 hIcon
= SHELL_LoadResource( hInstance
, hFile
, pIconDir
+ i
, *(WORD
*)pData
);
681 RetPtr
[i
-nIconIndex
] = GetIconID( hIcon
, 3 );
685 for( icon
= nIconIndex
; icon
< nIconIndex
+ n
; icon
++ )
688 { hIcon
= ICO_LoadIcon( hInstance
, hFile
, lpiID
->idEntries
+ RetPtr
[icon
-nIconIndex
]);
691 { for( i
= 0; i
< iconCount
; i
++ )
692 { if( pIconStorage
[i
].id
== (RetPtr
[icon
-nIconIndex
] | 0x8000) )
693 { hIcon
= SHELL_LoadResource( hInstance
, hFile
, pIconStorage
+ i
,*(WORD
*)pData
);
698 { RetPtr
[icon
-nIconIndex
] = LoadIconHandler( hIcon
, TRUE
);
699 FarSetOwner( RetPtr
[icon
-nIconIndex
], GetExePtr(hInstance
) );
702 { RetPtr
[icon
-nIconIndex
] = 0;
708 HeapFree( GetProcessHeap(), 0, lpiID
);
710 HeapFree( GetProcessHeap(), 0, pData
);
713 if( sig
== IMAGE_NT_SIGNATURE
)
714 { LPBYTE idata
,igdata
;
715 PIMAGE_DOS_HEADER dheader
;
716 PIMAGE_NT_HEADERS pe_header
;
717 PIMAGE_SECTION_HEADER pe_sections
;
718 PIMAGE_RESOURCE_DIRECTORY rootresdir
,iconresdir
,icongroupresdir
;
719 PIMAGE_RESOURCE_DATA_ENTRY idataent
,igdataent
;
721 PIMAGE_RESOURCE_DIRECTORY_ENTRY xresent
;
722 CURSORICONDIR
**cids
;
724 fmapping
= CreateFileMapping32A(hFile
,NULL
,PAGE_READONLY
|SEC_COMMIT
,0,0,NULL
);
726 { /* FIXME, INVALID_HANDLE_VALUE? */
727 WARN(shell
,"failed to create filemap.\n");
729 goto end_2
; /* failure */
731 peimage
= MapViewOfFile(fmapping
,FILE_MAP_READ
,0,0,0);
733 { WARN(shell
,"failed to mmap filemap.\n");
735 goto end_2
; /* failure */
737 dheader
= (PIMAGE_DOS_HEADER
)peimage
;
739 /* it is a pe header, SHELL_GetResourceTable checked that */
740 pe_header
= (PIMAGE_NT_HEADERS
)(peimage
+dheader
->e_lfanew
);
742 /* probably makes problems with short PE headers... but I haven't seen
745 pe_sections
= (PIMAGE_SECTION_HEADER
)(((char*)pe_header
)+sizeof(*pe_header
));
748 for (i
=0;i
<pe_header
->FileHeader
.NumberOfSections
;i
++)
749 { if (pe_sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
751 /* FIXME: doesn't work when the resources are not in a seperate section */
752 if (pe_sections
[i
].VirtualAddress
== pe_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
)
753 { rootresdir
= (PIMAGE_RESOURCE_DIRECTORY
)((char*)peimage
+pe_sections
[i
].PointerToRawData
);
759 { WARN(shell
,"haven't found section for resource directory.\n");
760 goto end_4
; /* failure */
763 icongroupresdir
= GetResDirEntryW(rootresdir
,RT_GROUP_ICON32W
, (DWORD
)rootresdir
,FALSE
);
765 if (!icongroupresdir
)
766 { WARN(shell
,"No Icongroupresourcedirectory!\n");
767 goto end_4
; /* failure */
770 iconDirCount
= icongroupresdir
->NumberOfNamedEntries
+icongroupresdir
->NumberOfIdEntries
;
772 if( nIconIndex
== (UINT16
)-1 )
773 { RetPtr
[0] = iconDirCount
;
774 goto end_3
; /* success */
777 if (nIconIndex
>= iconDirCount
)
778 { WARN(shell
,"nIconIndex %d is larger than iconDirCount %d\n",nIconIndex
,iconDirCount
);
780 goto end_4
; /* failure */
783 cids
= (CURSORICONDIR
**)HeapAlloc(GetProcessHeap(),0,n
*sizeof(CURSORICONDIR
*));
785 /* caller just wanted the number of entries */
786 xresent
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(icongroupresdir
+1);
788 /* assure we don't get too much ... */
789 if( n
> iconDirCount
- nIconIndex
)
790 { n
= iconDirCount
- nIconIndex
;
793 /* starting from specified index ... */
794 xresent
= xresent
+nIconIndex
;
796 for (i
=0;i
<n
;i
++,xresent
++)
797 { CURSORICONDIR
*cid
;
798 PIMAGE_RESOURCE_DIRECTORY resdir
;
800 /* go down this resource entry, name */
801 resdir
= (PIMAGE_RESOURCE_DIRECTORY
)((DWORD
)rootresdir
+(xresent
->u2
.s
.OffsetToDirectory
));
803 /* default language (0) */
804 resdir
= GetResDirEntryW(resdir
,(LPWSTR
)0,(DWORD
)rootresdir
,TRUE
);
805 igdataent
= (PIMAGE_RESOURCE_DATA_ENTRY
)resdir
;
807 /* lookup address in mapped image for virtual address */
810 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
811 { if (igdataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
813 if (igdataent
->OffsetToData
+igdataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
815 igdata
= peimage
+(igdataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
819 { WARN(shell
,"no matching real address for icongroup!\n");
820 goto end_4
; /* failure */
823 cid
= (CURSORICONDIR
*)igdata
;
825 RetPtr
[i
] = LookupIconIdFromDirectoryEx32(igdata
,TRUE
,SYSMETRICS_CXICON
,SYSMETRICS_CYICON
,0);
828 iconresdir
=GetResDirEntryW(rootresdir
,RT_ICON32W
,(DWORD
)rootresdir
,FALSE
);
831 { WARN(shell
,"No Iconresourcedirectory!\n");
832 goto end_4
; /* failure */
836 { PIMAGE_RESOURCE_DIRECTORY xresdir
;
837 xresdir
= GetResDirEntryW(iconresdir
,(LPWSTR
)(DWORD
)RetPtr
[i
],(DWORD
)rootresdir
,FALSE
);
838 xresdir
= GetResDirEntryW(xresdir
,(LPWSTR
)0,(DWORD
)rootresdir
,TRUE
);
839 idataent
= (PIMAGE_RESOURCE_DATA_ENTRY
)xresdir
;
842 /* map virtual to address in image */
843 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
844 { if (idataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
846 if (idataent
->OffsetToData
+idataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
848 idata
= peimage
+(idataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
851 { WARN(shell
,"no matching real address found for icondata!\n");
855 RetPtr
[i
] = CreateIconFromResourceEx32(idata
,idataent
->Size
,TRUE
,0x00030000,SYSMETRICS_CXICON
,SYSMETRICS_CYICON
,0);
857 goto end_3
; /* sucess */
859 goto end_1
; /* return array with icon handles */
861 /* cleaning up (try & catch would be nicer) */
862 end_4
: hRet
= 0; /* failure */
863 end_3
: UnmapViewOfFile(peimage
); /* success */
864 end_2
: CloseHandle(fmapping
);
865 end_1
: _lclose32( hFile
);
869 /*************************************************************************
870 * ExtractIcon16 (SHELL.34)
872 HICON16 WINAPI
ExtractIcon16( HINSTANCE16 hInstance
, LPCSTR lpszExeFileName
,
875 return ExtractIcon32A( hInstance
, lpszExeFileName
, nIconIndex
);
878 /*************************************************************************
879 * ExtractIconEx16 (SHELL.40)
881 HICON16 WINAPI
ExtractIconEx16(
882 LPCSTR lpszFile
, INT16 nIconIndex
, HICON16
*phiconLarge
,
883 HICON16
*phiconSmall
, UINT16 nIcons
885 HICON32
*ilarge
,*ismall
;
890 ilarge
= (HICON32
*)HeapAlloc(GetProcessHeap(),0,nIcons
*sizeof(HICON32
));
894 ismall
= (HICON32
*)HeapAlloc(GetProcessHeap(),0,nIcons
*sizeof(HICON32
));
897 ret
= ExtractIconEx32A(lpszFile
,nIconIndex
,ilarge
,ismall
,nIcons
);
899 for (i
=0;i
<nIcons
;i
++)
900 phiconLarge
[i
]=ilarge
[i
];
901 HeapFree(GetProcessHeap(),0,ilarge
);
904 for (i
=0;i
<nIcons
;i
++)
905 phiconSmall
[i
]=ismall
[i
];
906 HeapFree(GetProcessHeap(),0,ismall
);
911 /*************************************************************************
912 * ExtractAssociatedIcon [SHELL.36]
914 * Return icon for given file (either from file itself or from associated
915 * executable) and patch parameters if needed.
917 HICON32 WINAPI
ExtractAssociatedIcon32A(HINSTANCE32 hInst
, LPSTR lpIconPath
, LPWORD lpiIcon
)
919 return ExtractAssociatedIcon16(hInst
,lpIconPath
,lpiIcon
);
922 HICON16 WINAPI
ExtractAssociatedIcon16(HINSTANCE16 hInst
, LPSTR lpIconPath
, LPWORD lpiIcon
)
927 hIcon
= ExtractIcon16(hInst
, lpIconPath
, *lpiIcon
);
930 { if( hIcon
== 1 ) /* no icons found in given file */
931 { char tempPath
[0x80];
932 UINT16 uRet
= FindExecutable16(lpIconPath
,NULL
,tempPath
);
934 if( uRet
> 32 && tempPath
[0] )
935 { strcpy(lpIconPath
,tempPath
);
936 hIcon
= ExtractIcon16(hInst
, lpIconPath
, *lpiIcon
);
944 *lpiIcon
= 2; /* MSDOS icon - we found .exe but no icons in it */
946 *lpiIcon
= 6; /* generic icon - found nothing */
948 GetModuleFileName16(hInst
, lpIconPath
, 0x80);
949 hIcon
= LoadIcon16( hInst
, MAKEINTRESOURCE16(*lpiIcon
));
954 /*************************************************************************
955 * FindEnvironmentString [SHELL.38]
957 * Returns a pointer into the DOS environment... Ugh.
959 LPSTR
SHELL_FindString(LPSTR lpEnv
, LPCSTR entry
)
965 for( ; *lpEnv
; lpEnv
+=strlen(lpEnv
)+1 )
966 { if( lstrncmpi32A(lpEnv
, entry
, l
) )
969 return (lpEnv
+ l
); /* empty entry */
970 else if ( *(lpEnv
+l
)== '=' )
971 return (lpEnv
+ l
+ 1);
976 SEGPTR WINAPI
FindEnvironmentString(LPSTR str
)
978 LPSTR lpEnv
,lpString
;
981 spEnv
= GetDOSEnvironment();
983 lpEnv
= (LPSTR
)PTR_SEG_TO_LIN(spEnv
);
984 lpString
= (spEnv
)?SHELL_FindString(lpEnv
, str
):NULL
;
986 if( lpString
) /* offset should be small enough */
987 return spEnv
+ (lpString
- lpEnv
);
991 /*************************************************************************
992 * DoEnvironmentSubst [SHELL.37]
994 * Replace %KEYWORD% in the str with the value of variable KEYWORD
995 * from "DOS" environment.
997 DWORD WINAPI
DoEnvironmentSubst(LPSTR str
,WORD length
)
999 LPSTR lpEnv
= (LPSTR
)PTR_SEG_TO_LIN(GetDOSEnvironment());
1000 LPSTR lpBuffer
= (LPSTR
)HeapAlloc( GetProcessHeap(), 0, length
);
1002 LPSTR lpbstr
= lpBuffer
;
1004 CharToOem32A(str
,str
);
1006 TRACE(shell
,"accept %s\n", str
);
1008 while( *lpstr
&& lpbstr
- lpBuffer
< length
)
1010 LPSTR lpend
= lpstr
;
1014 do { lpend
++; } while( *lpend
&& *lpend
!= '%' );
1015 if( *lpend
== '%' && lpend
- lpstr
> 1 ) /* found key */
1019 lpKey
= SHELL_FindString(lpEnv
, lpstr
+1);
1020 if( lpKey
) /* found key value */
1022 int l
= strlen(lpKey
);
1024 if( l
> length
- (lpbstr
- lpBuffer
) - 1 )
1026 WARN(shell
,"-- Env subst aborted - string too short\n");
1030 strcpy(lpbstr
, lpKey
);
1037 else break; /* back off and whine */
1042 *lpbstr
++ = *lpstr
++;
1046 if( lpstr
- str
== strlen(str
) )
1048 strncpy(str
, lpBuffer
, length
);
1054 TRACE(shell
,"-- return %s\n", str
);
1056 OemToChar32A(str
,str
);
1057 HeapFree( GetProcessHeap(), 0, lpBuffer
);
1059 /* Return str length in the LOWORD
1060 * and 1 in HIWORD if subst was successful.
1062 return (DWORD
)MAKELONG(strlen(str
), length
);
1065 /*************************************************************************
1066 * ShellHookProc [SHELL.103]
1067 * System-wide WH_SHELL hook.
1069 LRESULT WINAPI
ShellHookProc(INT16 code
, WPARAM16 wParam
, LPARAM lParam
)
1071 TRACE(shell
,"%i, %04x, %08x\n", code
, wParam
,
1073 if( SHELL_hHook
&& SHELL_hWnd
)
1078 case HSHELL_WINDOWCREATED
: uMsg
= uMsgWndCreated
; break;
1079 case HSHELL_WINDOWDESTROYED
: uMsg
= uMsgWndDestroyed
; break;
1080 case HSHELL_ACTIVATESHELLWINDOW
: uMsg
= uMsgShellActivate
;
1082 PostMessage16( SHELL_hWnd
, uMsg
, wParam
, 0 );
1084 return CallNextHookEx16( WH_SHELL
, code
, wParam
, lParam
);
1087 /*************************************************************************
1088 * RegisterShellHook [SHELL.102]
1090 BOOL32 WINAPI
RegisterShellHook(HWND16 hWnd
, UINT16 uAction
)
1091 { TRACE(shell
,"%04x [%u]\n", hWnd
, uAction
);
1094 { case 2: /* register hWnd as a shell window */
1096 { HMODULE16 hShell
= GetModuleHandle16( "SHELL" );
1097 SHELL_hHook
= SetWindowsHookEx16( WH_SHELL
, ShellHookProc
, hShell
, 0 );
1099 { uMsgWndCreated
= RegisterWindowMessage32A( lpstrMsgWndCreated
);
1100 uMsgWndDestroyed
= RegisterWindowMessage32A( lpstrMsgWndDestroyed
);
1101 uMsgShellActivate
= RegisterWindowMessage32A( lpstrMsgShellActivate
);
1104 WARN(shell
,"-- unable to install ShellHookProc()!\n");
1108 return ((SHELL_hWnd
= hWnd
) != 0);
1112 WARN(shell
, "-- unknown code %i\n", uAction
);