Newer
Older
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "windef.h"
#include "wingdi.h"
#include "wine/winbase16.h"
#include "wine/shell16.h"
#include "shellapi.h"
#include "debugtools.h"
#include "syslevel.h"
DEFAULT_DEBUG_CHANNEL(shell)
DECLARE_DEBUG_CHANNEL(exec)
typedef struct
{
BYTE bWidth; /* Width, in pixels, of the image */
BYTE bHeight; /* Height, in pixels, of the image */
BYTE bColorCount; /* Number of colors in image (0 if >=8bpp) */
BYTE bReserved; /* Reserved ( must be 0) */
WORD wPlanes; /* Color Planes */
WORD wBitCount; /* Bits per pixel */
DWORD dwBytesInRes; /* How many bytes in this resource? */
DWORD dwImageOffset; /* Where in the file is this image? */
} icoICONDIRENTRY, *LPicoICONDIRENTRY;
typedef struct
{
WORD idReserved; /* Reserved (must be 0) */
WORD idType; /* Resource Type (1 for icons) */
WORD idCount; /* How many images? */
icoICONDIRENTRY idEntries[1]; /* An entry for each image (idCount of 'em) */
} icoICONDIR, *LPicoICONDIR;
static const char* lpstrMsgWndCreated = "OTHERWINDOWCREATED";
static const char* lpstrMsgWndDestroyed = "OTHERWINDOWDESTROYED";
static const char* lpstrMsgShellActivate = "ACTIVATESHELLWINDOW";
static HWND16 SHELL_hWnd = 0;
static HHOOK SHELL_hHook = 0;
static UINT16 uMsgWndCreated = 0;
static UINT16 uMsgWndDestroyed = 0;
static UINT16 uMsgShellActivate = 0;
HINSTANCE16 SHELL_hInstance = 0;
HINSTANCE SHELL_hInstance32;
static int SHELL_Attach = 0;
/***********************************************************************
* SHELL_DllEntryPoint [SHELL.entry]
*
* Initialization code for shell.dll. Automatically loads the
* 32-bit shell32.dll to allow thunking up to 32-bit code.
*
* RETURNS:
*/
BOOL WINAPI SHELL_DllEntryPoint(DWORD Reason, HINSTANCE16 hInst,
WORD ds, WORD HeapSize, DWORD res1, WORD res2)
{
TRACE("(%08lx, %04x, %04x, %04x, %08lx, %04x)\n",
Reason, hInst, ds, HeapSize, res1, res2);
switch(Reason)
{
case DLL_PROCESS_ATTACH:
SHELL_Attach++;
if (SHELL_hInstance)
{
ERR("shell.dll instantiated twice!\n");
/*
* We should return FALSE here, but that will break
* most apps that use CreateProcess because we do
* not yet support seperate address-spaces.
*/
return TRUE;
}
SHELL_hInstance = hInst;
if(!SHELL_hInstance32)
{
if(!(SHELL_hInstance32 = LoadLibraryA("shell32.dll")))
{
ERR("Could not load sibling shell32.dll\n");
return FALSE;
}
}
break;
case DLL_PROCESS_DETACH:
if(!--SHELL_Attach)
{
SHELL_hInstance = 0;
if(SHELL_hInstance32)
FreeLibrary(SHELL_hInstance32);
}
break;
}
return TRUE;
}
/*************************************************************************
* DragAcceptFiles16 [SHELL.9]
*/
void WINAPI DragAcceptFiles16(HWND16 hWnd, BOOL16 b)
{
DragAcceptFiles(hWnd, b);
/*************************************************************************
* DragQueryFile16 [SHELL.11]
UINT16 WINAPI DragQueryFile16(
HDROP16 hDrop,
WORD wFile,
LPSTR lpszFile,
WORD wLength)
LPSTR lpDrop;
UINT i = 0;
LPDROPFILESTRUCT16 lpDropFileStruct = (LPDROPFILESTRUCT16) GlobalLock16(hDrop);
TRACE("(%04x, %x, %p, %u)\n", hDrop,wFile,lpszFile,wLength);
if(!lpDropFileStruct) goto end;
lpDrop = (LPSTR) lpDropFileStruct + lpDropFileStruct->wSize;
wFile = (wFile==0xffff) ? 0xffffffff : wFile;
while (i++ < wFile)
{
while (*lpDrop++); /* skip filename */
if (!*lpDrop)
{
i = (wFile == 0xFFFFFFFF) ? i : 0;
goto end;
}
}
i = lstrlenA(lpDrop);
i++;
if (!lpszFile ) goto end; /* needed buffer size */
i = (wLength > i) ? i : wLength;
lstrcpynA (lpszFile, lpDrop, i);
end:
GlobalUnlock16(hDrop);
return i;
}
/*************************************************************************
* DragFinish16 [SHELL.12]
*/
void WINAPI DragFinish16(HDROP16 h)
{
TRACE("\n");
/*************************************************************************
* DragQueryPoint16 [SHELL.13]
*/
BOOL16 WINAPI DragQueryPoint16(HDROP16 hDrop, POINT16 *p)
{
LPDROPFILESTRUCT16 lpDropFileStruct;
BOOL16 bRet;
TRACE("\n");
lpDropFileStruct = (LPDROPFILESTRUCT16) GlobalLock16(hDrop);
memcpy(p,&lpDropFileStruct->ptMousePos,sizeof(POINT16));
bRet = lpDropFileStruct->fInNonClientArea;
GlobalUnlock16(hDrop);
return bRet;
/*************************************************************************
* Utility for code sharing between FindExecutable and ShellExecute
HINSTANCE SHELL_FindExecutable( LPCSTR lpFile,
{ char *extension = NULL; /* pointer to file extension */
char tmpext[5]; /* local copy to mung as we please */
char filetype[256]; /* registry name for this filetype */
LONG filetypelen=256; /* length of above */
char command[256]; /* command from registry */
LONG commandlen=256; /* This is the most DOS can handle :) */
char buffer[256]; /* Used to GetProfileString */
HINSTANCE retval=31; /* default - 'No association was found' */
char *tok; /* token pointer */
int i; /* random counter */
char xlpFile[256] = ""; /* result of SearchPath */
TRACE("%s\n", (lpFile != NULL?lpFile:"-") );
lpResult[0]='\0'; /* Start off with an empty return string */
/* trap NULL parameters on entry */
if (( lpFile == NULL ) || ( lpResult == NULL ) || ( lpOperation == NULL ))
{ WARN_(exec)("(lpFile=%s,lpResult=%s,lpOperation=%s): NULL parameter\n",
lpFile, lpOperation, lpResult);
return 2; /* File not found. Close enough, I guess. */
if (SearchPathA( NULL, lpFile,".exe",sizeof(xlpFile),xlpFile,NULL))
{ TRACE("SearchPathA returned non-zero\n");
/* First thing we need is the file's extension */
extension = strrchr( xlpFile, '.' ); /* Assume last "." is the one; */
/* File->Run in progman uses */
/* .\FILE.EXE :( */
TRACE("xlpFile=%s,extension=%s\n", xlpFile, extension);
if ((extension == NULL) || (extension == &xlpFile[strlen(xlpFile)]))
{ WARN("Returning 31 - No association\n");
}
/* Make local copy & lowercase it for reg & 'programs=' lookup */
lstrcpynA( tmpext, extension, 5 );
CharLowerA( tmpext );
TRACE("%s file\n", tmpext);
/* Three places to check: */
/* 1. win.ini, [windows], programs (NB no leading '.') */
/* 2. Registry, HKEY_CLASS_ROOT\<filetype>\shell\open\command */
/* 3. win.ini, [extensions], extension (NB no leading '.' */
/* All I know of the order is that registry is checked before */
/* extensions; however, it'd make sense to check the programs */
/* section first, so that's what happens here. */
/* See if it's a program - if GetProfileString fails, we skip this
* section. Actually, if GetProfileString fails, we've probably
* got a lot more to worry about than running a program... */
if ( GetProfileStringA("windows", "programs", "exe pif bat com",
{ for (i=0;i<strlen(buffer); i++) buffer[i]=tolower(buffer[i]);
tok = strtok(buffer, " \t"); /* ? */
while( tok!= NULL)
{
if (strcmp(tok, &tmpext[1])==0) /* have to skip the leading "." */
{
strcpy(lpResult, xlpFile);
/* Need to perhaps check that the file has a path
* attached */
TRACE("found %s\n", lpResult);
return 33;
/* Greater than 32 to indicate success FIXME According to the
* docs, I should be returning a handle for the
* executable. Does this mean I'm supposed to open the
* executable file or something? More RTFM, I guess... */
}
tok=strtok(NULL, " \t");
}
}
if (RegQueryValue16( HKEY_CLASSES_ROOT, tmpext, filetype,
&filetypelen ) == ERROR_SUCCESS )
/* Looking for ...buffer\shell\lpOperation\command */
strcat( filetype, "\\shell\\" );
strcat( filetype, lpOperation );
strcat( filetype, "\\command" );
if (RegQueryValue16( HKEY_CLASSES_ROOT, filetype, command,
&commandlen ) == ERROR_SUCCESS )
LPSTR tmp;
char param[256];
LONG paramlen = 256;
/* Get the parameters needed by the application
from the associated ddeexec key */
tmp = strstr(filetype,"command");
tmp[0] = '\0';
strcat(filetype,"ddeexec");
if(RegQueryValue16( HKEY_CLASSES_ROOT, filetype, param,¶mlen ) == ERROR_SUCCESS)
{
strcat(command," ");
strcat(command,param);
commandlen += paramlen;
}
/* Is there a replace() function anywhere? */
command[commandlen]='\0';
strcpy( lpResult, command );
tok=strstr( lpResult, "%1" );
if (tok != NULL)
{
tok[0]='\0'; /* truncate string at the percent */
strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
tok=strstr( command, "%1" );
if ((tok!=NULL) && (strlen(tok)>2))
{
strcat( lpResult, &tok[2] );
}
}
}
}
else /* Check win.ini */
{
/* Toss the leading dot */
extension++;
if ( GetProfileStringA( "extensions", extension, "", command,
sizeof(command)) > 0)
{
if (strlen(command)!=0)
{
strcpy( lpResult, command );
tok=strstr( lpResult, "^" ); /* should be ^.extension? */
if (tok != NULL)
{
tok[0]='\0';
strcat( lpResult, xlpFile ); /* what if no dir in xlpFile? */
tok=strstr( command, "^" ); /* see above */
if ((tok != NULL) && (strlen(tok)>5))
{
strcat( lpResult, &tok[5]);
}
}
retval=33; /* FIXME - see above */
}
}
TRACE("returning %s\n", lpResult);
return retval;
}
/*************************************************************************
HINSTANCE16 WINAPI ShellExecute16( HWND16 hWnd, LPCSTR lpOperation,
LPCSTR lpFile, LPCSTR lpParameters,
LPCSTR lpDirectory, INT16 iShowCmd )
TRACE("(%04x,'%s','%s','%s','%s',%x)\n",
hWnd, lpOperation ? lpOperation:"<null>", lpFile ? lpFile:"<null>",
lpParameters ? lpParameters : "<null>",
lpDirectory ? lpDirectory : "<null>", iShowCmd);
if (lpFile==NULL) return 0; /* should not happen */
if (lpOperation==NULL) /* default is open */
lpOperation="open";
{ GetCurrentDirectoryA( sizeof(old_dir), old_dir );
SetCurrentDirectoryA( lpDirectory );
/* First try to execute lpFile with lpParameters directly */
strcpy(cmd,lpFile);
strcat(cmd,lpParameters ? lpParameters : "");
SYSLEVEL_ReleaseWin16Lock();
retval = WinExec( cmd, iShowCmd );
SYSLEVEL_RestoreWin16Lock();
/* Unable to execute lpFile directly
Check if we can match an application to lpFile */
if(retval < 31)
{
cmd[0] = '\0';
retval = SHELL_FindExecutable( lpFile, lpOperation, cmd );
if (retval > 32) /* Found */
{
if (lpParameters)
{
strcat(cmd," ");
SYSLEVEL_ReleaseWin16Lock();
retval = WinExec( cmd, iShowCmd );
SYSLEVEL_RestoreWin16Lock();
}
else if(PathIsURLA((LPSTR)lpFile)) /* File not found, check for URL */
{
char lpstrProtocol[256];
LONG cmdlen = 512;
LPSTR lpstrRes;
INT iSize;
lpstrRes = strchr(lpFile,':');
iSize = lpstrRes - lpFile;
/* Looking for ...protocol\shell\lpOperation\command */
strncpy(lpstrProtocol,lpFile,iSize);
lpstrProtocol[iSize]='\0';
strcat( lpstrProtocol, "\\shell\\" );
strcat( lpstrProtocol, lpOperation );
strcat( lpstrProtocol, "\\command" );
/* Remove File Protocol from lpFile */
/* In the case file://path/file */
if(!strncasecmp(lpFile,"file",iSize))
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
{
lpFile += iSize;
while(*lpFile == ':') lpFile++;
}
/* Get the application for the protocol and execute it */
if (RegQueryValue16( HKEY_CLASSES_ROOT, lpstrProtocol, cmd,
&cmdlen ) == ERROR_SUCCESS )
{
LPSTR tok;
LPSTR tmp;
char param[256] = "";
LONG paramlen = 256;
/* Get the parameters needed by the application
from the associated ddeexec key */
tmp = strstr(lpstrProtocol,"command");
tmp[0] = '\0';
strcat(lpstrProtocol,"ddeexec");
if(RegQueryValue16( HKEY_CLASSES_ROOT, lpstrProtocol, param,¶mlen ) == ERROR_SUCCESS)
{
strcat(cmd," ");
strcat(cmd,param);
cmdlen += paramlen;
}
/* Is there a replace() function anywhere? */
cmd[cmdlen]='\0';
tok=strstr( cmd, "%1" );
if (tok != NULL)
{
tok[0]='\0'; /* truncate string at the percent */
strcat( cmd, lpFile ); /* what if no dir in xlpFile? */
tok=strstr( cmd, "%1" );
if ((tok!=NULL) && (strlen(tok)>2))
{
strcat( cmd, &tok[2] );
}
}
SYSLEVEL_ReleaseWin16Lock();
retval = WinExec( cmd, iShowCmd );
SYSLEVEL_RestoreWin16Lock();
}
}
/* Check if file specified is in the form www.??????.*** */
else if(!strncasecmp(lpFile,"www",3))
{
/* if so, append lpFile http:// and call ShellExecute */
char lpstrTmpFile[256] = "http://" ;
strcat(lpstrTmpFile,lpFile);
retval = ShellExecuteA(hWnd,lpOperation,lpstrTmpFile,NULL,NULL,0);
}
SetCurrentDirectoryA( old_dir );
}
/*************************************************************************
HINSTANCE16 WINAPI FindExecutable16( LPCSTR lpFile, LPCSTR lpDirectory,
LPSTR lpResult )
{ return (HINSTANCE16)FindExecutableA( lpFile, lpDirectory, lpResult );
/*************************************************************************
BOOL16 WINAPI AboutDlgProc16( HWND16 hWnd, UINT16 msg, WPARAM16 wParam,
{ return AboutDlgProc( hWnd, msg, wParam, lParam );
/*************************************************************************
BOOL16 WINAPI ShellAbout16( HWND16 hWnd, LPCSTR szApp, LPCSTR szOtherStuff,
HICON16 hIcon )
{ return ShellAboutA( hWnd, szApp, szOtherStuff, hIcon );
/*************************************************************************
static DWORD SHELL_GetResourceTable(HFILE hFile,LPBYTE *retptr)
{ IMAGE_DOS_HEADER mz_header;
char magic[4];
int size;
TRACE("\n");
_llseek( hFile, 0, SEEK_SET );
if ((_lread(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) || (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
{ /* .ICO file ? */
if (mz_header.e_cblp == 1)
{ /* ICONHEADER.idType, must be 1 */
_llseek( hFile, mz_header.e_lfanew, SEEK_SET );
if (_lread( hFile, magic, sizeof(magic) ) != sizeof(magic))
_llseek( hFile, mz_header.e_lfanew, SEEK_SET);
if (*(DWORD*)magic == IMAGE_NT_SIGNATURE)
return IMAGE_NT_SIGNATURE;
if (*(WORD*)magic == IMAGE_OS2_SIGNATURE)
{ IMAGE_OS2_HEADER ne_header;
LPBYTE pTypeInfo = (LPBYTE)-1;
if (_lread(hFile,&ne_header,sizeof(ne_header))!=sizeof(ne_header))
return 0;
if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE)
return 0;
size = ne_header.ne_restab - ne_header.ne_rsrctab;
if( size > sizeof(NE_TYPEINFO) )
{ pTypeInfo = (BYTE*)HeapAlloc( GetProcessHeap(), 0, size);
if( pTypeInfo )
{ _llseek(hFile, mz_header.e_lfanew+ne_header.ne_rsrctab, SEEK_SET);
if( _lread( hFile, (char*)pTypeInfo, size) != size )
{ HeapFree( GetProcessHeap(), 0, pTypeInfo);
pTypeInfo = NULL;
}
}
*retptr = pTypeInfo;
return IMAGE_OS2_SIGNATURE;
}
/*************************************************************************
* SHELL_LoadResource
*/
static HGLOBAL16 SHELL_LoadResource(HINSTANCE16 hInst, HFILE hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
HGLOBAL16 handle = DirectResAlloc16( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
TRACE("\n");
if( (ptr = (BYTE*)GlobalLock16( handle )) )
{ _llseek( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
_lread( hFile, (char*)ptr, pNInfo->length << sizeShift);
return handle;
}
return 0;
/*************************************************************************
* ICO_LoadIcon
*/
static HGLOBAL16 ICO_LoadIcon(HINSTANCE16 hInst, HFILE hFile, LPicoICONDIRENTRY lpiIDE)
HGLOBAL16 handle = DirectResAlloc16( hInst, 0x10, lpiIDE->dwBytesInRes);
TRACE("\n");
if( (ptr = (BYTE*)GlobalLock16( handle )) )
{ _llseek( hFile, lpiIDE->dwImageOffset, SEEK_SET);
_lread( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
return handle;
}
return 0;
}
/*************************************************************************
* ICO_GetIconDirectory
*
* Read .ico file and build phony ICONDIR struct for GetIconID
*/
static HGLOBAL16 ICO_GetIconDirectory(HINSTANCE16 hInst, HFILE hFile, LPicoICONDIR* lplpiID )
TRACE("\n");
_llseek( hFile, 0, SEEK_SET );
if( _lread(hFile,(char*)id,sizeof(id)) != sizeof(id) ) return 0;
/* check .ICO header
*
* - see http://www.microsoft.com/win32dev/ui/icons.htm
*/
if( id[0] || id[1] != 1 || !id[2] ) return 0;
lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i + sizeof(id));
if( _lread(hFile,(char*)lpiID->idEntries,i) == i )
{ HGLOBAL16 handle = DirectResAlloc16( hInst, 0x10,
id[2]*sizeof(CURSORICONDIRENTRY) + sizeof(id) );
{ CURSORICONDIR* lpID = (CURSORICONDIR*)GlobalLock16( handle );
lpID->idReserved = lpiID->idReserved = id[0];
lpID->idType = lpiID->idType = id[1];
lpID->idCount = lpiID->idCount = id[2];
for( i=0; i < lpiID->idCount; i++ )
(void*)(lpiID->idEntries + i), sizeof(CURSORICONDIRENTRY) - 2);
lpID->idEntries[i].wResId = i;
}
*lplpiID = lpiID;
return handle;
}
}
/* fail */
/*************************************************************************
* InternalExtractIcon [SHELL.39]
*
* This abortion is called directly by Progman
*/
HGLOBAL16 WINAPI InternalExtractIcon16(HINSTANCE16 hInstance,
LPCSTR lpszExeFileName, UINT16 nIconIndex, WORD n )
{ HGLOBAL16 hRet = 0;
HGLOBAL16* RetPtr = NULL;
LPBYTE pData;
OFSTRUCT ofs;
DWORD sig;
HFILE hFile = OpenFile( lpszExeFileName, &ofs, OF_READ );
UINT16 iconDirCount = 0,iconCount = 0;
LPBYTE peimage;
HANDLE fmapping;
TRACE("(%04x,file %s,start %d,extract %d\n",
if( hFile == HFILE_ERROR || !n )
hRet = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON16)*n);
RetPtr = (HICON16*)GlobalLock16(hRet);
*RetPtr = (n == 0xFFFF)? 0: 1; /* error return values */
sig = SHELL_GetResourceTable(hFile,&pData);
if( sig==IMAGE_OS2_SIGNATURE || sig==1 ) /* .ICO file */
{ HICON16 hIcon = 0;
NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(pData + 2);
NE_NAMEINFO* pIconStorage = NULL;
NE_NAMEINFO* pIconDir = NULL;
LPicoICONDIR lpiID = NULL;
if( pData == (BYTE*)-1 )
{ hIcon = ICO_GetIconDirectory(hInstance, hFile, &lpiID); /* check for .ICO file */
if( hIcon )
{ iconDirCount = 1; iconCount = lpiID->idCount;
}
}
else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
{ if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) /* find icon directory and icon repository */
{ iconDirCount = pTInfo->count;
pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
TRACE("\tfound directory - %i icon families\n", iconDirCount);
}
if( pTInfo->type_id == NE_RSCTYPE_ICON )
{ iconCount = pTInfo->count;
pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
TRACE("\ttotal icons - %i\n", iconCount);
}
pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
}
/* load resources and create icons */
if( (pIconStorage && pIconDir) || lpiID )
{ if( nIconIndex == (UINT16)-1 )
{ RetPtr[0] = iconDirCount;
}
else if( nIconIndex < iconDirCount )
{ UINT16 i, icon;
if( n > iconDirCount - nIconIndex )
n = iconDirCount - nIconIndex;
for( i = nIconIndex; i < nIconIndex + n; i++ )
{ /* .ICO files have only one icon directory */
if( lpiID == NULL )
hIcon = SHELL_LoadResource( hInstance, hFile, pIconDir + i, *(WORD*)pData );
RetPtr[i-nIconIndex] = GetIconID16( hIcon, 3 );
GlobalFree16(hIcon);
}
for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
{ hIcon = 0;
if( lpiID )
{ hIcon = ICO_LoadIcon( hInstance, hFile, lpiID->idEntries + RetPtr[icon-nIconIndex]);
}
else
{ for( i = 0; i < iconCount; i++ )
{ if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
{ hIcon = SHELL_LoadResource( hInstance, hFile, pIconStorage + i,*(WORD*)pData );
}
}
}
if( hIcon )
{ RetPtr[icon-nIconIndex] = LoadIconHandler16( hIcon, TRUE );
FarSetOwner16( RetPtr[icon-nIconIndex], GetExePtr(hInstance) );
}
else
{ RetPtr[icon-nIconIndex] = 0;
}
}
}
if( lpiID )
HeapFree( GetProcessHeap(), 0, lpiID);
else
HeapFree( GetProcessHeap(), 0, pData);
}
if( sig == IMAGE_NT_SIGNATURE)
{ LPBYTE idata,igdata;
PIMAGE_DOS_HEADER dheader;
PIMAGE_NT_HEADERS pe_header;
PIMAGE_SECTION_HEADER pe_sections;
PIMAGE_RESOURCE_DIRECTORY rootresdir,iconresdir,icongroupresdir;
PIMAGE_RESOURCE_DATA_ENTRY idataent,igdataent;
int i,j;
PIMAGE_RESOURCE_DIRECTORY_ENTRY xresent;
CURSORICONDIR **cids;
fmapping = CreateFileMappingA(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL);
if (fmapping == 0)
{ /* FIXME, INVALID_HANDLE_VALUE? */
WARN("failed to create filemap.\n");
hRet = 0;
goto end_2; /* failure */
}
peimage = MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0);
if (!peimage)
{ WARN("failed to mmap filemap.\n");
hRet = 0;
goto end_2; /* failure */
}
dheader = (PIMAGE_DOS_HEADER)peimage;
/* it is a pe header, SHELL_GetResourceTable checked that */
pe_header = (PIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew);
/* probably makes problems with short PE headers... but I haven't seen
* one yet...
*/
pe_sections = (PIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header));
rootresdir = NULL;
for (i=0;i<pe_header->FileHeader.NumberOfSections;i++)
{ if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
continue;
/* FIXME: doesn't work when the resources are not in a seperate section */
if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
{ rootresdir = (PIMAGE_RESOURCE_DIRECTORY)((char*)peimage+pe_sections[i].PointerToRawData);
break;
}
{ WARN("haven't found section for resource directory.\n");
goto end_4; /* failure */
}
icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICONW, (DWORD)rootresdir,FALSE);
{ WARN("No Icongroupresourcedirectory!\n");
goto end_4; /* failure */
}
iconDirCount = icongroupresdir->NumberOfNamedEntries+icongroupresdir->NumberOfIdEntries;
if( nIconIndex == (UINT16)-1 )
{ RetPtr[0] = iconDirCount;
goto end_3; /* success */
}
if (nIconIndex >= iconDirCount)
{ WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount);
GlobalFree16(hRet);
goto end_4; /* failure */
cids = (CURSORICONDIR**)HeapAlloc(GetProcessHeap(),0,n*sizeof(CURSORICONDIR*));
/* caller just wanted the number of entries */
xresent = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);
/* assure we don't get too much ... */
if( n > iconDirCount - nIconIndex )
{ n = iconDirCount - nIconIndex;
}
/* starting from specified index ... */
xresent = xresent+nIconIndex;
for (i=0;i<n;i++,xresent++)
{ CURSORICONDIR *cid;
PIMAGE_RESOURCE_DIRECTORY resdir;
/* go down this resource entry, name */
resdir = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s.OffsetToDirectory));
/* default language (0) */
resdir = GetResDirEntryW(resdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
igdataent = (PIMAGE_RESOURCE_DATA_ENTRY)resdir;
/* lookup address in mapped image for virtual address */
igdata = NULL;
for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
{ if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
continue;
if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
continue;
igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
}
if (!igdata)
{ WARN("no matching real address for icongroup!\n");
goto end_4; /* failure */
}
/* found */
cid = (CURSORICONDIR*)igdata;
cids[i] = cid;
RetPtr[i] = LookupIconIdFromDirectoryEx(igdata,TRUE,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0);
iconresdir=GetResDirEntryW(rootresdir,RT_ICONW,(DWORD)rootresdir,FALSE);
{ WARN("No Iconresourcedirectory!\n");
goto end_4; /* failure */
}
for (i=0;i<n;i++)
{ PIMAGE_RESOURCE_DIRECTORY xresdir;
xresdir = GetResDirEntryW(iconresdir,(LPWSTR)(DWORD)RetPtr[i],(DWORD)rootresdir,FALSE);
xresdir = GetResDirEntryW(xresdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
idataent = (PIMAGE_RESOURCE_DATA_ENTRY)xresdir;
for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
{ if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
continue;
if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
continue;
idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
{ WARN("no matching real address found for icondata!\n");
RetPtr[i] = CreateIconFromResourceEx(idata,idataent->Size,TRUE,0x00030000,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0);
goto end_1; /* return array with icon handles */
/* cleaning up (try & catch would be nicer) */
end_4: hRet = 0; /* failure */
end_3: UnmapViewOfFile(peimage); /* success */
end_2: CloseHandle(fmapping);
end_1: _lclose( hFile);
/*************************************************************************
HICON16 WINAPI ExtractIcon16( HINSTANCE16 hInstance, LPCSTR lpszExeFileName,
{ TRACE("\n");
return ExtractIconA( hInstance, lpszExeFileName, nIconIndex );
/*************************************************************************
* ExtractIconEx16 (SHELL.40)
*/
HICON16 WINAPI ExtractIconEx16(
LPCSTR lpszFile, INT16 nIconIndex, HICON16 *phiconLarge,
HICON16 *phiconSmall, UINT16 nIcons
) {
HICON *ilarge,*ismall;
UINT16 ret;
int i;
if (phiconLarge)
ilarge = (HICON*)HeapAlloc(GetProcessHeap(),0,nIcons*sizeof(HICON));
else
ilarge = NULL;
if (phiconSmall)
ismall = (HICON*)HeapAlloc(GetProcessHeap(),0,nIcons*sizeof(HICON));
else
ismall = NULL;
ret = ExtractIconExA(lpszFile,nIconIndex,ilarge,ismall,nIcons);
if (ilarge) {
for (i=0;i<nIcons;i++)
phiconLarge[i]=ilarge[i];
HeapFree(GetProcessHeap(),0,ilarge);
}
if (ismall) {
for (i=0;i<nIcons;i++)
phiconSmall[i]=ismall[i];
HeapFree(GetProcessHeap(),0,ismall);
}
return ret;
}
/*************************************************************************
*
* Return icon for given file (either from file itself or from associated
* executable) and patch parameters if needed.
HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
{ TRACE("\n");
return ExtractAssociatedIcon16(hInst,lpIconPath,lpiIcon);
}
/*************************************************************************
* ExtractAssociatedIcon [SHELL.36]
*
* Return icon for given file (either from file itself or from associated
* executable) and patch parameters if needed.
*/
HICON16 WINAPI ExtractAssociatedIcon16(HINSTANCE16 hInst, LPSTR lpIconPath, LPWORD lpiIcon)
{ HICON16 hIcon;
TRACE("\n");
hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
if( hIcon < 2 )
{ if( hIcon == 1 ) /* no icons found in given file */
{ char tempPath[0x80];
UINT16 uRet = FindExecutable16(lpIconPath,NULL,tempPath);
{ strcpy(lpIconPath,tempPath);
hIcon = ExtractIcon16(hInst, lpIconPath, *lpiIcon);
if( hIcon > 2 )