Category : Windows 3.X Files
Archive   : ICONEX.ZIP
Filename : ICONEX02.C
* WINDOWS ICON EXTRACTION UTILITY - FILE READING FUNCTIONS
*
* LANGUAGE : Microsoft C 6.0
* TOOLKIT : Windows 3.0 SDK
* MODEL : Medium
* STATUS : Operational
*
* Copyright (C) 1991 - All Rights Reserved
*
* Eikon Systems, Inc.
* 989 East Hillsdale Blvd, Suite 260
* Foster City, California 94404
*
* 07/08/91 - James N. Hancock - initial creation.
*
*/
#include
#include
#include "iconex.h"
/* local defines */
#define SEEK_SET 0
#define SEEK_CUR 1
#define SEEK_END 2
#define OF_ERROR -1
#define BITSPERBYTE 8
#define ICONHEADER_RESERVED 0
#define ICONHEADER_RESOURCETYPE 1
#define ICONTYPE_UNKNOWN 0
#define ICONTYPE_CGA 1
#define ICONTYPE_MONO 2
#define ICONTYPE_EGA 3
#define ICONTYPE_VGA 4
#define ICONTYPE_HIRES 5
#define MONO_PLANES 1
#define MONO_BITS 1
#define OS2EXE 1
#define WINDOWSEXE 2
#define OLDEXESIGNATURE 0x5A4D
#define NEWEXESIGNATURE 0x454E
#define ORDINALFLAG 0x8000
#define ICONRESTYPE 0x0003
#define GROUPICONRESTYPE 0x000E
/* local typedefs */
typedef struct { /* DOS 1, 2, 3, 4 .EXE header */
USHORT ehSignature; /* signature bytes */
USHORT ehcbLP; /* bytes on last page of file */
USHORT ehcp; /* pages in file */
USHORT ehcRelocation; /* count of relocation table entries*/
USHORT ehcParagraphHdr; /* size of header in paragraphs */
USHORT ehMinAlloc; /* minimum extra paragraphs needed */
USHORT ehMaxAlloc; /* maximum extra paragraphs needed */
USHORT ehSS; /* initial (relative) SS value */
USHORT ehSP; /* initial SP value */
USHORT ehChecksum; /* checksum */
USHORT ehIP; /* initial IP value */
USHORT ehCS; /* initial (relative) CS value */
USHORT ehlpRelocation; /* file address of relocation table */
USHORT ehOverlayNo; /* overlay number */
USHORT ehReserved[16]; /* reserved words */
LONG ehPosNewHdr; /* file address of new exe header */
} EXEHDR; /* eh */
typedef struct { /* new .EXE header */
WORD nhSignature; /* signature bytes */
CHAR nhVer; /* LINK version number */
CHAR nhRev; /* LINK revision number */
WORD nhoffEntryTable; /* offset of Entry Table */
WORD nhcbEntryTable; /* number of bytes in Entry Table */
LONG nhCRC; /* checksum of whole file */
WORD nhFlags; /* flag word */
WORD nhAutoData; /* automatic data segment number */
WORD nhHeap; /* initial heap allocation */
WORD nhStack; /* initial stack allocation */
LONG nhCSIP; /* initial CS:IP setting */
LONG nhSSSP; /* initial SS:SP setting */
WORD nhcSeg; /* count of file segments */
WORD nhcMod; /* entries in Module Reference Table*/
WORD nhcbNonResNameTable; /* size of non-resident name table */
WORD nhoffSegTable; /* offset of Segment Table */
WORD nhoffResourceTable; /* offset of Resource Table */
WORD nhoffResNameTable; /* offset of Resident Name Table */
WORD nhoffModRefTable; /* offset of Module Reference Table */
WORD nhoffImpNameTable; /* offset of Imported Names Table */
LONG nhoffNonResNameTable;/* offset of Non-resident Names Tab */
WORD nhcMovableEntries; /* count of movable entries */
WORD nhcAlign; /* segment alignment shift count */
WORD nhCRes; /* count of resource segments */
BYTE nhExeType; /* target OS (OS/2=1, Windows=2) */
BYTE nhFlagsOther; /* additional exe flags */
WORD nhGangStart; /* offset to gangload area */
WORD nhGangLength; /* length of gangload area */
WORD nhSwapArea; /* minimum code swap area size*/
WORD nhExpVer; /* expected Windows version number */
} NEWHDR; /* nh */
typedef struct { /* resource information block */
WORD rtType; /* resource type (icon = 3) */
WORD rtCount; /* number of resources of this type */
LONG rtProc; /* reserved for runtime use */
} RESTYPEINFO; /* rt */
typedef struct { /* Resource name information block */
USHORT rnOffset; /* file offset to resource data */
USHORT rnLength; /* length of resource data */
USHORT rnFlags; /* resource flags */
USHORT rnID; /* resource name id */
USHORT rnHandle; /* reserved for runtime use */
USHORT rnUsage; /* reserved for runtime use */
} RESNAMEINFO; /* rn */
typedef RESNAMEINFO FAR * LPRESNAMEINFO;
typedef struct {
RESTYPEINFO rt;
RESNAMEINFO rn[1];
} RESTABLE;
typedef RESTABLE FAR * LPRESTABLE;
/* The rnOffset and rnLength fields above must be shifted to compute their
* actual values. This allows resources to be larger than 64k, but they
* do not need to be aligned on 512 byte boundaries the way segments are.
*/
typedef struct {
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
WORD wNameOrdinal;
} RESDIRECTORY;
typedef struct {
BYTE fTypeFlag;
WORD wTypeOrdinal;
BYTE fNameFlag;
WORD wNameOrdinal;
WORD wMemoryFlags;
ULONG lSize;
} RESOURCEHEADER;
/* local prototypes */
static WORD GetIconType( BITMAPINFOHEADER* );
static HBITMAP GetANDBitmap( HDC, BYTE, BYTE, LPBYTE, LPBITMAPINFO, LONG );
static WORD GetBitmaps( HFILE, LPHANDLE, WORD, WORD, BYTE, BYTE, WORD,
WORD, LONG );
static BOOL GetXORDIBits( HDC, HBITMAP, LPBYTE, LPBITMAPINFO, LONG );
static HBITMAP GetXORBitmap( HDC, BYTE, BYTE, LPBYTE, LPBITMAPINFO, LONG );
static WORD ReadExeOldHeader( HFILE, LONG, PLONG );
static WORD ReadExeNewHeader( HFILE, LONG, LONG, PLONG );
static WORD ReadExeResTable( HFILE, LONG, PHANDLE );
static WORD ReadExeIcons( HFILE, LONG, HANDLE, WORD, LPWORD, LPHANDLE );
static HBITMAP CreateCFBITMAPData( ICON );
static HANDLE CreateCFSDKPAINTData( HBITMAP );
/*
*
* IconFree( hIconData ) : WORD;
*
* hIconData handle to aggregate icon data to free
*
* This function performs the cleanup for the icon extraction program. It
* frees the bitmaps of any icons that were read in from disk and frees
* the dynamic memory that was allocated for storing the ICON data
* structures.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD FAR PASCAL IconFree(
HANDLE hIconData )
{
WORD wResult;
/* initialize */
wResult = IDERR_SUCCESS;
/* lock handle to icon data */
if (hIconData)
{
LPICONDATA lpIconData;
lpIconData = (LPICONDATA)GlobalLock( hIconData );
if (lpIconData)
{
WORD wArraySize;
WORD wIndex;
LPICON lpIconArray;
wArraySize = lpIconData->wArraySize;
lpIconArray = &(lpIconData->icIconArray[0]);
/* delete bitmaps that were created for icons */
for (wIndex = 0; wIndex < wArraySize; wIndex++)
{
if (lpIconArray[wIndex].hbmANDbits)
DeleteObject( lpIconArray[wIndex].hbmANDbits );
if (lpIconArray[wIndex].hbmXORbits)
DeleteObject( lpIconArray[wIndex].hbmXORbits );
}
/* free globally allocated memory */
if (GlobalUnlock( hIconData ) == 0)
GlobalFree( hIconData );
else
wResult = IDERR_LOCKFAIL;
} else
wResult = IDERR_LOCKFAIL;
} else
wResult = IDERR_INVALIDPARAM;
return wResult;
}
/*
*
* IconCreateIcon( hWnd, hIconData, wIndex, lphIcon ) : WORD;
*
* hWnd window handle of the window that is creating the icon
* hIconData handle to aggregate data structure
* wIndex index to the array element that is to be used
* lphIcon pointer to icon handle
*
* This function uses the information in an ICON data structure to create a
* Windows 3.0 icon through the CreateIcon function. It expects to receive a
* handle to an array of ICON data structures, plus an index to the element
* that is to be used to create the icon.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
#define BITSPERBYTE 8
WORD FAR PASCAL IconCreateIcon(
HWND hWnd,
HANDLE hIconData,
WORD wIndex,
LPHANDLE lphIcon )
{
WORD wResult;
HANDLE hXORbits;
HANDLE hANDbits;
LPBYTE lpbXORbits;
LPBYTE lpbANDbits;
HBITMAP hbmDestXORMask;
HBITMAP hbmDestANDMask;
WORD cbXORmaskSize;
WORD cbANDmaskSize;
WORD wIconWidth;
WORD wIconHeight;
ICON icIcon;
/* initialize */
wResult = IDERR_SUCCESS;
hXORbits = NULL;
hANDbits = NULL;
lpbXORbits = NULL;
lpbANDbits = NULL;
/* check parameters */
if (IsWindow( hWnd ) && hIconData)
{
LPICONDATA lpIconData;
lpIconData = (LPICONDATA)GlobalLock( hIconData );
if (lpIconData)
{
if (wIndex < lpIconData->wArraySize)
/* get icon creation data */
icIcon = lpIconData->icIconArray[wIndex];
else
wResult = IDERR_INVALIDPARAM;
GlobalUnlock( hIconData );
} else
wResult = IDERR_LOCKFAIL;
} else
wResult = IDERR_INVALIDPARAM;
/* create device dependent bitmaps for an icon on this system */
if (wResult == IDERR_SUCCESS)
{
HDC hdc;
HDC hdcSource;
HDC hdcDest;
hdc = GetDC( NULL );
if (hdc)
{
/* create device-dependent bitmaps for XOR mask and AND mask */
/* then use StretchBlt() to copy bits from ICON struct's bitmaps */
hdcSource = hdc ? CreateCompatibleDC( hdc ) : NULL;
hdcDest = hdc ? CreateCompatibleDC( hdc ) : NULL;
if (hdcSource && hdcDest)
{
/* get dimensions of an icon on this system */
wIconWidth = GetSystemMetrics( SM_CXICON );
wIconHeight = GetSystemMetrics( SM_CYICON );
/* create device-dependent bitmap for XOR mask */
hbmDestXORMask = CreateCompatibleBitmap( hdc,
wIconWidth,
wIconHeight
);
/* create device-dependent bitmap for monochrome AND mask */
hbmDestANDMask = CreateBitmap(
wIconWidth,
wIconHeight,
MONO_PLANES,
MONO_BITS,
NULL
);
if (hbmDestXORMask && hbmDestANDMask)
{
/* copy bits for XOR mask */
SelectObject( hdcSource, icIcon.hbmXORbits );
SelectObject( hdcDest, hbmDestXORMask );
SetStretchBltMode( hdcDest, COLORONCOLOR );
StretchBlt( hdcDest,
0, 0,
wIconWidth,
wIconHeight,
hdcSource,
0, 0,
icIcon.wWidth,
icIcon.wHeight,
SRCCOPY
);
/* copy bits for AND mask */
SelectObject( hdcSource, icIcon.hbmANDbits );
SelectObject( hdcDest, hbmDestANDMask );
SetStretchBltMode( hdcDest, BLACKONWHITE );
StretchBlt( hdcDest,
0, 0,
wIconWidth,
wIconHeight,
hdcSource,
0, 0,
icIcon.wWidth,
icIcon.wHeight,
SRCCOPY
);
} else {
wResult = IDERR_ALLOCFAIL;
}
DeleteDC( hdcSource );
DeleteDC( hdcDest );
} else {
wResult = IDERR_ALLOCFAIL;
}
ReleaseDC( NULL, hdc );
} else {
wResult = IDERR_ALLOCFAIL;
}
}
/* allocate memory where we can store device dependent XOR bits */
if (wResult == IDERR_SUCCESS)
{
BITMAP bm;
if (sizeof(BITMAP) == GetObject(
hbmDestXORMask,
sizeof(BITMAP),
(LPSTR)&bm ))
{
cbXORmaskSize = (bm.bmWidth * bm.bmHeight) *
(bm.bmPlanes * bm.bmBitsPixel) / BITSPERBYTE;
hXORbits = GlobalAlloc( GMEM_MOVEABLE, cbXORmaskSize );
if (hXORbits == NULL)
wResult = IDERR_ALLOCFAIL;
else if ((lpbXORbits = (LPBYTE)GlobalLock( hXORbits )) == NULL)
wResult = IDERR_LOCKFAIL;
else if (!GetBitmapBits( hbmDestXORMask,cbXORmaskSize,lpbXORbits))
wResult = IDERR_WINFUNCFAIL;
} else
wResult = IDERR_WINFUNCFAIL;
}
/* allocate memory where we can store AND bits */
if (wResult == IDERR_SUCCESS)
{
BITMAP bm;
if (sizeof(BITMAP) == GetObject(
hbmDestANDMask,
sizeof(BITMAP),
(LPSTR)&bm ))
{
cbANDmaskSize = (bm.bmWidth * bm.bmHeight) / BITSPERBYTE;
hANDbits = GlobalAlloc( GMEM_MOVEABLE, cbANDmaskSize );
if (hANDbits == NULL)
wResult = IDERR_ALLOCFAIL;
else if ((lpbANDbits = (LPBYTE) GlobalLock( hANDbits )) == NULL)
wResult = IDERR_LOCKFAIL;
else if (!GetBitmapBits( hbmDestANDMask,cbANDmaskSize,lpbANDbits))
wResult = IDERR_WINFUNCFAIL;
} else
wResult = IDERR_WINFUNCFAIL;
}
/* create the icon */
if (wResult == IDERR_SUCCESS)
{
HANDLE hInst;
BITMAP bm;
if (sizeof(BITMAP) == GetObject(
hbmDestXORMask,
sizeof(BITMAP),
(LPSTR)&bm ))
{
hInst = GetWindowWord( hWnd, GWW_HINSTANCE );
*lphIcon = CreateIcon(
hInst,
bm.bmWidth,
bm.bmHeight,
bm.bmPlanes,
bm.bmBitsPixel,
lpbANDbits,
lpbXORbits
);
}
if (*lphIcon == NULL)
wResult = IDERR_WINFUNCFAIL;
}
/* cleanup */
if (hXORbits)
{
if (lpbXORbits)
GlobalUnlock( hXORbits );
GlobalFree( hXORbits );
}
if (hANDbits)
{
if (lpbANDbits)
GlobalUnlock( hANDbits );
GlobalFree( hANDbits );
}
if (hbmDestXORMask)
DeleteObject(hbmDestXORMask);
if (hbmDestANDMask)
DeleteObject(hbmDestANDMask);
return wResult;
}
/*
*
* IconGetIconDescrip( hIconData, wIndex, lpszBuffer ) : WORD;
*
* hIconData handle to aggregate data structure
* wIndex index to the array element that is to be described
* lpszBuffer buffer for description
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD FAR PASCAL IconGetIconDescrip(
HANDLE hIconData,
WORD wIndex,
LPSZ lpszBuffer )
{
WORD wResult;
WORD wIconType;
LPICONDATA lpIconData;
LPSZ lpszDescrip;
/* initialize */
wResult = IDERR_SUCCESS;
lpIconData = NULL;
if (hIconData && lpszBuffer)
{
lpIconData = (LPICONDATA)GlobalLock( hIconData );
if (lpIconData)
{
if (wIndex < lpIconData->wArraySize)
{
/* determine icon type */
wIconType = lpIconData->icIconArray[wIndex].wIconType;
switch (wIconType)
{
case ICONTYPE_CGA:
lpszDescrip = "CGA Icon \r\n32x16, 2 Color";
break;
case ICONTYPE_MONO:
lpszDescrip = "MONO Icon \r\n32x32, 2 Color";
break;
case ICONTYPE_EGA:
case ICONTYPE_VGA:
lpszDescrip = "VGA / EGA Icon \r\n32x32, 16 Color";
break;
case ICONTYPE_HIRES:
lpszDescrip = "HI-RES Icon \r\n64x64, 16 Color";
break;
default:
lpszDescrip = "UNKNOWN ICON";
break;
}
lstrcpy( lpszBuffer, lpszDescrip );
} else
wResult = IDERR_INVALIDPARAM;
GlobalUnlock( hIconData );
} else
wResult = IDERR_LOCKFAIL;
} else
wResult = IDERR_INVALIDPARAM;
return wResult;
}
/*
* IconCopyToClipboard( hWnd, hIconData, wIndex, wPrivateFormat ) : WORD;
*
* hWnd window handle of the window that is making the copy
* hIconData handle to aggregate data structure
* wIndex index to the array element that is to be copied
* wPrivateFormat id of a private clipboard format to be used
*
* This function copies an icon to the clipboard using the SDKPAINT
* clipboard format.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD FAR PASCAL IconCopyToClipboard(
HWND hWnd,
HANDLE hIconData,
WORD wIndex,
WORD wPrivateFormat )
{
WORD wResult;
LPICONDATA lpIconData;
ICON icIcon;
/* initialize */
wResult = IDERR_SUCCESS;
lpIconData = NULL;
if (IsWindow( hWnd ) && hIconData)
{
/* get the data for the icon to be copied */
lpIconData = (LPICONDATA)GlobalLock( hIconData );
if (lpIconData)
{
if (wIndex < lpIconData->wArraySize)
{
HBITMAP hbmCFBITMAP;
HANDLE hmemCFSDKPAINT;
icIcon = lpIconData->icIconArray[wIndex];
if (OpenClipboard( hWnd ))
{
hbmCFBITMAP = CreateCFBITMAPData( icIcon );
if (hbmCFBITMAP)
{
if ( EmptyClipboard() )
{
SetClipboardData( CF_BITMAP, hbmCFBITMAP );
hmemCFSDKPAINT=CreateCFSDKPAINTData(icIcon.hbmANDbits);
if (wPrivateFormat && hmemCFSDKPAINT)
SetClipboardData( wPrivateFormat, hmemCFSDKPAINT );
}
} else
wResult = IDERR_ALLOCFAIL;
if (! CloseClipboard())
wResult = IDERR_WINFUNCFAIL;
} else
wResult = IDERR_WINFUNCFAIL;
} else
wResult = IDERR_INVALIDPARAM;
GlobalUnlock( hIconData );
} else
wResult = IDERR_LOCKFAIL;
} else
wResult = IDERR_INVALIDPARAM;
return wResult;
}
/*
* CreateCFBITMAPData( icIcon ) : HBITMAP;
*
* icIcon structure containing icon dimensions and bitmap handles
*
* This function combines an icon's AND mask and XOR mask to create a bitmap
* that can be placed on the clipboard with the CF_BITMAP format.
*
* This function returns a bitmap handle if successful or NULL
* if unsuccessful.
*
*/
HBITMAP CreateCFBITMAPData(
ICON icIcon )
{
HBITMAP hbmResult;
HDC hdc;
/* init */
hbmResult = NULL;
/* get handle to device context */
hdc = GetDC( NULL );
if (hdc)
{
HDC hdcTarget;
HDC hdcSource;
HBRUSH hbrScreen;
hdcSource = CreateCompatibleDC( hdc );
if (hdcSource)
{
hdcTarget = CreateCompatibleDC( hdc );
if (hdcTarget)
{
hbrScreen = CreateSolidBrush( GetSysColor( COLOR_WINDOW ) );
if (hbrScreen)
{
/* create bitmap */
hbmResult = CreateCompatibleBitmap(
hdc,
icIcon.wWidth,
icIcon.wHeight
);
if (hbmResult)
{
/* STEP I : Fill rectangle with screen color */
SelectObject( hdcTarget, hbrScreen );
SelectObject( hdcTarget, hbmResult );
PatBlt(
hdcTarget,
0,
0,
icIcon.wWidth,
icIcon.wHeight,
PATCOPY
);
/* STEP II : Apply the AND mask */
SelectObject( hdcSource, icIcon.hbmANDbits );
BitBlt(
hdcTarget,
0, 0,
icIcon.wWidth,
icIcon.wHeight,
hdcSource,
0, 0,
SRCAND
);
/* STEP III : Copy the XOR mask */
SelectObject( hdcSource, icIcon.hbmXORbits );
BitBlt(
hdcTarget,
0, 0,
icIcon.wWidth,
icIcon.wHeight,
hdcSource,
0, 0,
SRCINVERT
);
}
DeleteObject( hbrScreen );
}
DeleteDC( hdcTarget );
}
DeleteDC( hdcSource );
}
ReleaseDC( NULL, hdc );
}
return hbmResult;
}
/*
* CreateCFSDKAPAINTData( hbmANDbits ) : HANDLE;
*
* hbmANDbits handle to bitmap for icon's AND mask
*
* This function allocates memory space and generates the SDK Paint private
* clipboard format. The SDKPAINT format must be registered with string
* "SDKPAINT" before use. The private SDKPAINT format data consists of:
*
* 1. a DWORD indicating the screen viewing color at the time image was
* sent to the clipboard followed by ...
* 2. the bits of the monochrome AND image in device dependent form.
*
* This function returns the memory handle if successful or NULL if not.
*
*/
HANDLE CreateCFSDKPAINTData(
HBITMAP hbmANDbits )
{
HANDLE hmemResult;
LONG lMemSize;
LONG lBMPSize;
LPDWORD lpdw;
BOOL fSuccess;
BITMAP bm;
/* initialize */
hmemResult = NULL;
fSuccess = TRUE;
if (GetObject( hbmANDbits, sizeof(BITMAP), (LPSTR)&bm )==sizeof(BITMAP))
{
/* compute memory size to allow for alignment on 16 byte boundary */
lBMPSize = ((((bm.bmHeight * bm.bmWidth) / 8) + 15) / 16) * 16;
lMemSize = sizeof( DWORD ) + lBMPSize;
/* allocate memory */
hmemResult = GlobalAlloc( GHND, lMemSize );
lpdw = hmemResult ? (LPDWORD) GlobalLock( hmemResult ) : NULL;
if (lpdw)
{
/* get current screen color */
*lpdw = GetSysColor( COLOR_WINDOW );
if (!GetBitmapBits(hbmANDbits,lBMPSize,(LPSTR)lpdw+sizeof(DWORD)))
fSuccess = FALSE;
}
else
fSuccess = FALSE;
}
else
fSuccess = FALSE;
/* unlock memory */
if (lpdw)
GlobalUnlock( hmemResult );
/* clean up if unsuccessful */
if (!fSuccess && hmemResult)
{
GlobalFree( hmemResult );
hmemResult = NULL;
}
return hmemResult;
}
/*
*
* IconExtract( lpszFileName, lphIconData, lpwIconCount ) : WORD;
*
* lpszFileName pointer to file name string
* lphIconData pointer to handle to aggregate icon data
* lpwCount pointer to variable in which to return icon count
*
* This function performs the following operations:
* - opens an .exe file
* - finds any component icons in the file
* - dynamically allocates an array of ICON data structures
* - fills the array of ICON data structures with all component icons
* - closes the file
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
* Notes: Icons in an .exe file are organized into groups. This function
* ignores the icon groups and simply reads the individual component icons
* from the file.
*
* References: MS-DOS Encyclopedia, pp. 119-124, pp. 1487-1491.
* Microsoft Windows Development Notes.
* Microsoft Windows 3.0 Internal Resource Formats (11/12/90)
*
*/
WORD FAR PASCAL IconExtract(
LPSZ lpszFileName,
LPHANDLE lphIconData,
LPWORD lpwIconCount )
{
HFILE hFile;
HANDLE haoff;
PWORD paoff;
WORD wResult;
WORD wShiftCount;
LONG lPos;
LONG lPosNewHdr;
LONG lPosResourceTable;
LONG lFileLen;
OFSTRUCT ofFile;
/* initialize */
wResult = IDERR_SUCCESS;
hFile = OF_ERROR;
haoff = NULL;
paoff = NULL;
*lpwIconCount = NULL;
*lphIconData = NULL;
/* open file for reading */
if ((hFile = OpenFile( lpszFileName, &ofFile, OF_READ)) == OF_ERROR)
wResult = IDERR_OPENFAIL;
/* get file length */
if (wResult == IDERR_SUCCESS)
if ((lFileLen = _llseek( hFile, 0L, SEEK_END )) == -1)
wResult = IDERR_READFAIL;
/* read old header, verify contents, and get positon of new header */
if (wResult == IDERR_SUCCESS)
wResult = ReadExeOldHeader( hFile, lFileLen, &lPosNewHdr );
/* read new header, verify contents, & get position of resource table */
if (wResult == IDERR_SUCCESS)
wResult = ReadExeNewHeader(
hFile,
lFileLen,
lPosNewHdr,
&lPosResourceTable
);
/* read shift count for file offsets of resources */
if (wResult == IDERR_SUCCESS)
{
USHORT cb;
/* initialize */
cb = 0;
lPos = _llseek( hFile, lPosResourceTable, SEEK_SET );
if (lPos == -1 || lPos > lFileLen || lPos != lPosResourceTable)
wResult = IDERR_READFAIL;
if (wResult == IDERR_SUCCESS)
cb = _lread( hFile, (LPSTR)&wShiftCount, sizeof(wShiftCount));
if (cb != sizeof(wShiftCount))
wResult = IDERR_READFAIL;
else if (wShiftCount > 16)
wResult = IDERR_RESTABLEBAD;
}
/* read resource table entries and save icon offsets */
if (wResult == IDERR_SUCCESS)
wResult = ReadExeResTable( hFile, lFileLen, &haoff );
/* read component icons from file */
if (wResult == IDERR_SUCCESS)
wResult = ReadExeIcons(
hFile,
lFileLen,
haoff,
wShiftCount,
lpwIconCount,
lphIconData
);
/* clean up */
if (haoff)
LocalFree( haoff );
if (hFile != OF_ERROR)
_lclose( hFile );
return wResult;
}
/*
*
* ReadExeOldHeader( hFile, lFileLen, plPosNewHdr ) : WORD;
*
* hFile file handle of .exe file being read
* lFileLen length of file
* plPosNewHdr pointer to file position of new header
*
* This function reads the old header from an executable file, checks to be
* sure that it is a valid header, and saves the position of the file's
* new header.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD ReadExeOldHeader(
HFILE hFile,
LONG lFileLen,
PLONG plPosNewHdr )
{
LONG lPos;
USHORT cb;
EXEHDR ehOldHeader;
WORD wResult;
/* initialize */
wResult = IDERR_SUCCESS;
lPos = _llseek( hFile, 0L, SEEK_SET );
if (lPos == -1 || lPos != 0L)
wResult = IDERR_READFAIL;
if (wResult == IDERR_SUCCESS)
{
cb = _lread( hFile, (LPSTR)&ehOldHeader, sizeof(ehOldHeader) );
if (cb != sizeof(ehOldHeader))
wResult = IDERR_READFAIL;
else if (ehOldHeader.ehSignature != OLDEXESIGNATURE)
wResult = IDERR_FILETYPEBAD;
else if (ehOldHeader.ehPosNewHdr < sizeof(EXEHDR))
wResult = IDERR_EXETYPEBAD;
else if (ehOldHeader.ehPosNewHdr > lFileLen - sizeof(NEWHDR))
wResult = IDERR_EXETYPEBAD;
else
*plPosNewHdr = ehOldHeader.ehPosNewHdr;
}
return wResult;
}
/*
*
* ReadExeNewHeader( hFile, lFileLen, lPosNewHdr, plPosResourceTable ) : WORD;
*
* hFile file handle of .exe file being read
* lFileLen length of file
* lPosNewHdr file position of new header
* plPosResourceTable pointer to file position of resource table
*
* This function reads the new header from an executable file, checks to be
* sure that it is a valid header, and saves the position of the file's
* resource table.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD ReadExeNewHeader(
HFILE hFile,
LONG lFileLen,
LONG lPosNewHdr,
PLONG plPosResourceTable )
{
WORD wResult;
USHORT cb;
LONG lPos;
NEWHDR nhNewHeader;
/* initialize */
wResult = IDERR_SUCCESS;
lPos = _llseek( hFile, lPosNewHdr, SEEK_SET );
if (lPos == -1 || lPos > lFileLen || lPos != lPosNewHdr)
wResult = IDERR_READFAIL;
else
{
WORD wVersion;
wVersion = (GetVersion() >> 8) | (GetVersion() << 8);
cb = _lread( hFile, (LPSTR)&nhNewHeader, sizeof(nhNewHeader) );
if (cb != sizeof(nhNewHeader))
wResult = IDERR_READFAIL;
else if (nhNewHeader.nhSignature != NEWEXESIGNATURE)
wResult = IDERR_FILETYPEBAD;
else if (nhNewHeader.nhExeType != WINDOWSEXE)
wResult = IDERR_EXETYPEBAD;
else if (nhNewHeader.nhExpVer < 0x0300)
wResult = IDERR_WINVERSIONBAD;
else if (nhNewHeader.nhExpVer > wVersion)
wResult = IDERR_WINVERSIONBAD;
else if (nhNewHeader.nhoffResourceTable == 0)
wResult = IDERR_RESTABLEBAD;
else
*plPosResourceTable = lPosNewHdr + nhNewHeader.nhoffResourceTable;
}
return wResult;
}
/*
*
* ReadExeResTable( hFile, lFileLen, phaoff ) : WORD;
*
* hFile file handle of .exe file being read
* lFileLen length of file
* phaoff address of variable to hold memory handle
*
* This function reads through the entries in an .exe file's resource table,
* identifies any icons in that table, and saves the file offsets of the data
* for those icons. This function expects the initial file position to point
* to the first entry in the resource table.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD ReadExeResTable(
HFILE hFile,
LONG lFileLen,
PHANDLE phaoff )
{
HANDLE haoff;
BOOL fLoop;
WORD wResult;
WORD wLocalSize;
LONG lPosNextEntry;
USHORT iIcon;
/* initialize */
wResult = IDERR_SUCCESS;
fLoop = TRUE;
haoff = NULL;
iIcon = 0;
wLocalSize = 1;
lPosNextEntry = _llseek( hFile, 0L, SEEK_CUR );
/* loop through entries in resource table */
while (fLoop == TRUE)
{
USHORT cb;
USHORT iFile;
LONG lPos;
RESTYPEINFO rt;
PWORD paoff;
/* read RESTYPEINFO */
cb = _lread( hFile, (LPSTR)&rt, sizeof(rt) );
if (cb != sizeof(rt))
wResult = IDERR_READFAIL;
else if (rt.rtType != 0)
{
if (rt.rtType == (ORDINALFLAG | ICONRESTYPE))
{
wLocalSize += sizeof(WORD) * rt.rtCount;
haoff = (haoff == NULL) ?
LocalAlloc( LMEM_FIXED, wLocalSize ) :
LocalReAlloc( haoff, wLocalSize, LMEM_MOVEABLE );
if (haoff == NULL)
wResult = IDERR_ALLOCFAIL;
else if ((paoff = (PWORD)LocalLock( haoff )) == NULL)
wResult = IDERR_LOCKFAIL;
if (wResult == IDERR_SUCCESS)
{
for (
iFile = 0;
iFile
{
RESNAMEINFO rn;
cb = _lread( hFile, (LPSTR)&rn, sizeof(rn) );
if (cb != sizeof(rn))
wResult = IDERR_READFAIL;
else
paoff[iIcon++] = rn.rnOffset;
}
/* mark end of list */
paoff[iIcon] = 0;
/* unlock memory */
LocalUnlock( haoff );
}
}
if (wResult == IDERR_SUCCESS)
{
lPosNextEntry += sizeof(rt) + rt.rtCount * sizeof(RESNAMEINFO);
lPos = _llseek( hFile, lPosNextEntry, SEEK_SET );
if (lPos == -1 || lPos > lFileLen || lPos != lPosNextEntry)
wResult = IDERR_READFAIL;
}
}
fLoop = (rt.rtType != 0) && (wResult == IDERR_SUCCESS);
}
if (wResult == IDERR_SUCCESS && iIcon == 0)
wResult = IDERR_NOICONS;
*phaoff = haoff;
/* return final result */
return wResult;
}
/*
*
* ReadExeIcons( hFile, lFileLen, haoff, wShiftCount, lpwIconCount,
* lphIconData ) : WORD;
*
* hFile file handle of .exe file being read
* lFileLen length of file
* haoff memory handle
* wShiftCount number of bits to shift file offsets
* lpwIconCount pointer to word containing the number of icons read
* lphIconData pointer to handle to aggregate icon data
*
* This function finds the icons in an .exe file, tests their DIB headers to
* determine if their type, and fills a data structure with their DDBs.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD ReadExeIcons(
HFILE hFile,
LONG lFileLen,
HANDLE haoff,
WORD wShiftCount,
LPWORD lpwIconCount,
LPHANDLE lphIconData )
{
USHORT ioff;
USHORT iIcon;
WORD wResult;
PWORD paoff;
/* initialize */
wResult = IDERR_SUCCESS;
iIcon = 0;
/* lock local memory */
paoff = haoff ? (PWORD)LocalLock( haoff ) : NULL;
if (!paoff)
wResult = IDERR_LOCKFAIL;
/* loop through component icons */
for (ioff = 0; (paoff[ioff] != 0) && (wResult == IDERR_SUCCESS); ioff++)
{
BITMAPINFOHEADER bi;
LONG lPos;
LONG lPosDIB;
lPosDIB = (LONG)paoff[ioff] << wShiftCount;
lPos = _llseek( hFile, lPosDIB, SEEK_SET );
if (lPos == -1 || lPos > lFileLen || lPos != lPosDIB)
wResult = IDERR_READFAIL;
/* read BITMAPINFOHEADER */
if (wResult == IDERR_SUCCESS)
if (_lread( hFile, (LPSTR)&bi, sizeof(bi) ) != sizeof(bi))
wResult = IDERR_READFAIL;
/* build XOR and AND bitmaps */
if (wResult == IDERR_SUCCESS)
{
WORD wIconType;
wIconType = GetIconType( &bi );
if (wIconType != ICONTYPE_UNKNOWN)
{
WORD wColorTableSize;
WORD wDIBHeaderSize;
WORD wImageSize;
WORD wDIBSize;
/* calculate combined size of XOR & AND masks */
wImageSize = (WORD)(bi.biWidth * (bi.biHeight / 2)) *
(WORD)(bi.biBitCount + 1) / BITSPERBYTE;
/* calculate size of entire DIB */
wColorTableSize = sizeof(RGBQUAD) * (0x0001 << bi.biBitCount);
wDIBHeaderSize = (WORD)bi.biSize + wColorTableSize;
wDIBSize = wDIBHeaderSize + wImageSize;
wResult = GetBitmaps(
hFile,
lphIconData,
iIcon,
wIconType,
(BYTE)bi.biWidth,
(BYTE)(bi.biHeight / 2),
wDIBHeaderSize,
wDIBSize,
lPosDIB
);
iIcon++;
}
}
}
/* set error code if no icons found, or free memory if error occurred */
if (wResult == IDERR_SUCCESS)
{
if (iIcon == 0)
wResult = IDERR_NOICONS;
}
else
{
if (iIcon > 0)
{
IconFree( *lphIconData );
iIcon = 0;
}
}
*lpwIconCount = iIcon;
/* unlock memory */
if (paoff)
LocalUnlock( haoff );
/* return final result */
return wResult;
}
/*
* GetBitmaps( hFile, lphIconData, iIcon, wIconType, bWidth, bHeight,
* wDIBHeaderSize, wDIBSize, lPosDIB ) : WORD;
*
* hFile file handle
* lphIconData pointer to handle to aggregate icon data
* iIcon index to ICON array
* wIconType icon type identifer
* bWidth icon width
* bHeight icon height
* wDIBHeaderSize size of DIB header including color table
* wDIBSize device independent bitmap size
* lPosDIB file offset of the DIB
*
* This function computes XOR and AND mask bitmaps and fills the ICON data
* structure.
*
* This function returns IDERR_SUCCESS if there are no errors, or a non-zero
* error code if there are.
*
*/
WORD GetBitmaps(
HFILE hFile,
LPHANDLE lphIconData,
WORD iIcon,
WORD wIconType,
BYTE bWidth,
BYTE bHeight,
WORD wDIBHeaderSize,
WORD wDIBSize,
LONG lPosDIB )
{
LPSTR lpDIB;
HANDLE hMemDIB;
WORD wResult;
/* initialization */
wResult = IDERR_SUCCESS;
hMemDIB = NULL;
lpDIB = NULL;
/* allocate memory for the DIB */
if ((hMemDIB = GlobalAlloc( GMEM_MOVEABLE, wDIBSize )) == NULL)
wResult = IDERR_ALLOCFAIL;
else if ((lpDIB = GlobalLock( hMemDIB )) == NULL)
wResult = IDERR_LOCKFAIL;
/* read in device independent bitmaps for both the AND and XOR masks */
/* the file position is set, so that the BITMAPINFOHEADER is reread */
if (wResult == IDERR_SUCCESS)
if ((_llseek( hFile, lPosDIB, SEEK_SET ) != lPosDIB)
|| (WORD)(_lread( hFile, lpDIB, wDIBSize ) != wDIBSize))
wResult = IDERR_READFAIL;
/* create device-dependent bitmaps and copy DIB bits to them from the */
/* bits that were read in from disk */
if (wResult == IDERR_SUCCESS)
{
LPBITMAPINFO lpbmiXORinfo;
HDC hdc;
USHORT cbXORmaskSize;
USHORT cbANDmaskSize;
LPBYTE lpbDIBANDbits;
LPBYTE lpbDIBXORbits;
HBITMAP hbmXORbits;
HBITMAP hbmANDbits;
/* point to BITMAPINFO structure at beginning of DIB */
lpbmiXORinfo = (LPBITMAPINFO)lpDIB;
/* calculate mask sizes */
cbXORmaskSize = ((bWidth * bHeight) *
lpbmiXORinfo->bmiHeader.biBitCount) / BITSPERBYTE;
cbANDmaskSize = (bWidth * bHeight) / BITSPERBYTE;
/* calculate offsets to bitmap bits */
lpbDIBXORbits = lpDIB + wDIBHeaderSize;
lpbDIBANDbits = lpbDIBXORbits + cbXORmaskSize;
hdc = GetDC( NULL );
if (hdc)
{
lpbmiXORinfo->bmiHeader.biHeight = bHeight;
hbmXORbits = GetXORBitmap(
hdc,
bWidth,
bHeight,
lpbDIBXORbits,
lpbmiXORinfo,
cbXORmaskSize
);
if (hbmXORbits)
{
hbmANDbits = GetANDBitmap(
hdc,
bWidth,
bHeight,
lpbDIBANDbits,
lpbmiXORinfo,
cbANDmaskSize
);
/* allocate memory and fill out the ICON data structure */
if (hbmANDbits)
{
BITMAP bm;
USHORT cb;
cb = GetObject( hbmXORbits, sizeof(BITMAP), (LPSTR)&bm );
if (cb == sizeof(BITMAP))
{
HANDLE hIconData;
/* initialize */
hIconData = *lphIconData;
if (hIconData)
hIconData = GlobalReAlloc(
hIconData,
sizeof(ICONDATA) + (iIcon * sizeof(ICON)),
GMEM_MOVEABLE
);
else
hIconData = GlobalAlloc(
GMEM_MOVEABLE,
sizeof(ICONDATA)
);
if (hIconData)
{
LPICONDATA lpIconData;
*lphIconData = hIconData;
lpIconData = (LPICONDATA)GlobalLock( hIconData );
if (lpIconData)
{
ICON icTemp;
icTemp.wIconType = wIconType;
icTemp.wWidth = bm.bmWidth;
icTemp.wHeight = bm.bmHeight;
icTemp.bPlanes = bm.bmPlanes;
icTemp.bBitsPixel = bm.bmBitsPixel;
icTemp.hbmANDbits = hbmANDbits;
icTemp.hbmXORbits = hbmXORbits;
icTemp.lFilePos = lPosDIB;
lpIconData->wArraySize = iIcon + 1;
lpIconData->icIconArray[iIcon] = icTemp;
GlobalUnlock( hIconData );
} else
wResult = IDERR_LOCKFAIL;
} else
wResult = IDERR_ALLOCFAIL;
}
}
}
ReleaseDC( NULL, hdc );
} else {
wResult = IDERR_ALLOCFAIL;
}
if (wResult != IDERR_SUCCESS)
{
if (hbmXORbits)
DeleteObject( hbmXORbits );
if (hbmANDbits)
DeleteObject( hbmANDbits );
}
} /* end if (wResult == IDERR_SUCCESS) */
/* clean up */
if (hMemDIB)
{
if (lpDIB)
GlobalUnlock( hMemDIB );
GlobalFree( hMemDIB );
}
/* return value */
return wResult;
}
/*
* GetIconType( lpbi ) : WORD;
*
* lpbi points to BITMAPINFOHEADER component of DIB header
*
* This function checks the height, width, and color count of the specified
* DIB to determine if they match known icon types.
*
* This function returns a code identifying the icon type. It returns the value
* ICONTYPE_UNKNOWN if the icon type could not be determined.
*
*/
WORD GetIconType(
BITMAPINFOHEADER* lpbi )
{
typedef const struct {
WORD wIconType;
WORD wWidth;
WORD wHeight;
WORD wBitCount;
} ICONPARAMS;
WORD wResult;
WORD wIndex;
BITMAPINFOHEADER biTemp;
ICONPARAMS ip[] = {
{ICONTYPE_CGA, 32, 16, 1},
{ICONTYPE_MONO, 32, 32, 1},
{ICONTYPE_EGA, 32, 32, 4},
{ICONTYPE_VGA, 32, 32, 4},
{ICONTYPE_HIRES, 64, 64, 4},
{ICONTYPE_UNKNOWN, 0, 0, 0} };
/* initialize */
wResult = ICONTYPE_UNKNOWN;
biTemp = *lpbi;
/* check to see if current icon matches a known type */
for (wIndex = 0; wIndex < (sizeof(ip) / sizeof(ICONPARAMS)); wIndex++)
if ((biTemp.biWidth == ip[wIndex].wWidth) &&
(biTemp.biHeight == ip[wIndex].wHeight * 2) &&
(biTemp.biBitCount == ip[wIndex].wBitCount))
{
wResult = ip[wIndex].wIconType;
break;
}
/* return value */
return wResult;
}
/*
* GetXORBitmap( hdc, bWidth, bHeight, lpbBits, lpbmpInfo, lSize )
* : HBITMAP;
*
* hdc device context handle
* bWidth icon width
* bHeight icon height
* lpbBits bitmap bits
* lpbmpInfo pointer to BITMAPINFO struct
* lSize bitmap size
*
* This function creates an XOR mask bitmap.
*
* This function returns the handle to the bitmap if it is successful, or NULL
* if it fails.
*
*/
HBITMAP GetXORBitmap(
HDC hdc,
BYTE bWidth,
BYTE bHeight,
LPBYTE lpbBits,
LPBITMAPINFO lpbmpInfo,
LONG lSize )
{
HBITMAP hbmp;
/* create device-dependent bitmap for XOR mask */
hbmp = CreateCompatibleBitmap( hdc, bWidth, bHeight );
if (hbmp)
{
USHORT usScanLineCount;
/* modify BITMAPINFOHEADER structure for color bitmap */
lpbmpInfo->bmiHeader.biSizeImage = lSize;
/* convert XOR mask from DIB to device-dependent bitmap */
usScanLineCount = SetDIBits(
hdc,
hbmp,
0,
bHeight,
lpbBits,
lpbmpInfo,
DIB_RGB_COLORS
);
if (usScanLineCount == 0)
{
DeleteObject( hbmp );
hbmp = NULL;
}
}
/* return value */
return hbmp;
}
/*
* GetANDBitmap( hdc, bWidth, bHeight, lpbBits, lpbmpInfo, lSize ) : HBITMAP;
*
* hdc device context handle
* bWidth icon width
* bHeight icon height
* lpbBits bitmap bits
* lpbmpInfo pointer to BITMAPINFO struct
* lSize bitmap size
*
* This function creates an AND mask bitmap.
*
* This function returns the handle to the bitmap if it is successful, or NULL
* if it fails.
*
*/
HBITMAP GetANDBitmap(
HDC hdc,
BYTE bWidth,
BYTE bHeight,
LPBYTE lpbBits,
LPBITMAPINFO lpbmpInfo,
LONG lSize )
{
HBITMAP hbmp;
/* create device-dependent bitmap for AND mask */
hbmp = CreateBitmap( bWidth, bHeight, MONO_PLANES, MONO_BITS, NULL );
if (hbmp)
{
const RGBQUAD rBlack = { 0x00, 0x00, 0x00, 0x00 };
const RGBQUAD rWhite = { 0xFF, 0xFF, 0xFF, 0x00 };
USHORT usScanLineCount;
/* modify BITMAPINFOHEADER structure for monochrome bitmap */
lpbmpInfo->bmiHeader.biHeight = bHeight;
lpbmpInfo->bmiHeader.biSizeImage = lSize;
lpbmpInfo->bmiHeader.biBitCount = 1;
lpbmpInfo->bmiColors[0] = rBlack;
lpbmpInfo->bmiColors[1] = rWhite;
/* convert AND mask from DIB to device-dependent bitmap */
usScanLineCount = SetDIBits(
hdc,
hbmp,
0,
bHeight,
lpbBits,
lpbmpInfo,
DIB_RGB_COLORS
);
if (usScanLineCount == 0)
{
DeleteObject( hbmp );
hbmp = NULL;
}
}
/* return value */
return hbmp;
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/