Category : C++ Source Code
Archive   : 256CAPP.ZIP
Filename : BSCRLAPP.CPP
#include
#include
#include
#include
#include
#include "bscrlapp.h"
#define BSA_NAME "BitmapScroll"
#define BSA_NAME_SIZE 12
/* TBitScrollApp, a TApplication descendant */
class TBitScrollApp : public TApplication {
public:
TBitScrollApp(LPSTR AName, HANDLE hInstance,
HANDLE hPrevInstance, LPSTR lpCmd,
int nCmdShow)
: TApplication(AName, hInstance,
hPrevInstance, lpCmd, nCmdShow) {};
virtual void InitMainWindow();
};
/* TBMPFileDialog, a TFileDialog descendant which uses .bmp as its
default extension. */
class TBMPFileDialog : public TFileDialog {
public:
TBMPFileDialog(PTWindowsObject AParent, int ResourceId,
LPSTR AFilePath, PTModule AModule = NULL)
: TFileDialog(AParent, ResourceId, AFilePath, AModule)
{ strcpy(Extension, ".bmp"); }
};
/* TBitScrollWindow, a TWindow descendant */
class TBitScrollWindow : public TWindow {
public:
char FileName[MAXPATH];
HBITMAP BitmapHandle;
HPALETTE hPal;
WORD PixelHeight , PixelWidth;
short Colors;
long Mode;
TBitScrollWindow(LPSTR);
virtual ~TBitScrollWindow();
virtual LPSTR GetClassName();
virtual void GetWindowClass(WNDCLASS&);
virtual void Paint(HDC, PAINTSTRUCT&);
virtual void CMFileOpen(TMessage&) = [CM_FIRST + CM_FILEOPEN];
virtual void CMRead1(TMessage&) = [CM_FIRST + CM_READ1];
virtual void CMRead2(TMessage&) = [CM_FIRST + CM_READ2];
virtual void CMCopy(TMessage&) = [CM_FIRST + CM_EDITCOPY];
virtual void CMPaste(TMessage&) = [CM_FIRST + CM_EDITPASTE];
virtual void WMSize(TMessage&) = [WM_FIRST + WM_SIZE];
virtual void WMSetFocus( TMessage&) = [WM_FIRST + WM_SETFOCUS];
virtual void WMInitMenuPopup( TMessage&) = [WM_FIRST + WM_INITMENUPOPUP];
void SetCaption( char *szName);
void AdjustScroller();
BOOL LoadBitmapFile(LPSTR);
BOOL LoadBitmapResource(LPSTR);
BOOL ReadWin3DIB(int TheFile, char * ErrorMsg);
BOOL ReadPM1DIB(int TheFile, char * ErrorMsg);
BOOL ReadDIB(int TheFile, char * ErrorMsg);
};
/* Construct the TBitScrollApp's MainWindow of type TBitScrollWindow */
void TBitScrollApp::InitMainWindow()
{
MainWindow = new TBitScrollWindow(BSA_NAME);
}
/* Constructor for a TBitScrollWindow, sets scroll styles and constructs
the Scroller object. Also sets the Mode based on whether the display
is monochrome (two-color) or polychrome. */
TBitScrollWindow::TBitScrollWindow(LPSTR ATitle)
:TWindow(NULL, ATitle)
{
HDC DCHandle;
Attr.Style |= WS_VSCROLL | WS_HSCROLL;
AssignMenu(BSA_NAME);
BitmapHandle = 0;
hPal = 0;
Scroller = new TScroller(this, 1, 1, 200, 200);
// Calling GetDC with a 0 window handle gets a device context for
// the entire screen. Since no clipping needs to be set up,
// this method is probably the fastest way to obtain a device
// context for getting display driver information....
DCHandle = GetDC( 0);
if ( GetDeviceCaps(DCHandle, NUMCOLORS) < 3 )
Mode = NOTSRCCOPY;
else
Mode = SRCCOPY;
ReleaseDC( 0, DCHandle);
}
/* Change the class name to the application name. */
LPSTR TBitScrollWindow::GetClassName()
{
return BSA_NAME;
}
/* Allow the iconic picture to be drawn from the client area. */
void TBitScrollWindow::GetWindowClass(WNDCLASS& WndClass)
{
TWindow::GetWindowClass(WndClass);
WndClass.hIcon = 0; /* Client area will be painted by the app. */
}
TBitScrollWindow::~TBitScrollWindow()
{
if ( BitmapHandle )
DeleteObject(BitmapHandle);
if ( hPal)
DeleteObject( hPal);
}
void TBitScrollWindow::SetCaption( char *szName)
{
char CaptionBuffer [MAXPATH + BSA_NAME_SIZE + 2 /*" "*/ + 1 /*'\0'*/ ];
strcpy(FileName, szName);
strcpy(CaptionBuffer, BSA_NAME);
strcat(CaptionBuffer, ": ");
lstrcat(CaptionBuffer, strlwr(FileName));
SetWindowText(HWindow, CaptionBuffer);
}
/* copy a logical palette to the clipboard */
void PaletteToClip( HPALETTE hPal)
{
HPALETTE hNewPal;
WORD nColors;
LOGPALETTE * pPal;
if ( hPal)
{
GetObject( hPal, sizeof( WORD), (LPSTR) &nColors);
if ( nColors)
{
pPal = (LOGPALETTE *) new
BYTE[ sizeof( LOGPALETTE) + ( nColors - 1) * sizeof( PALETTEENTRY)];
if ( pPal)
{
pPal->palVersion = 0x300;
pPal->palNumEntries = nColors;
GetPaletteEntries( hPal, 0, nColors, pPal->palPalEntry);
hNewPal = CreatePalette( pPal);
if ( hNewPal)
{
SetClipboardData( CF_PALETTE, hNewPal);
}
delete pPal;
}
}
}
}
/* duplicate a bitmap */
HBITMAP DupBitmap( HBITMAP hSrc)
{
HBITMAP hBit = 0;
if ( hSrc)
{
HDC hDC, hMem1, hMem2;
HBITMAP hOld1, hOld2;
BITMAP bm;
hMem1 = CreateCompatibleDC( 0);
if ( !hMem1)
return 0;
hMem2 = CreateCompatibleDC( 0);
if ( !hMem2)
{
DeleteDC( hMem1);
return 0;
}
GetObject( hSrc, sizeof( BITMAP), (LPSTR) &bm);
if
(
( bm.bmPlanes != 1) ||
( bm.bmBitsPixel != 1 )
)
{
// create a color bitmap
hDC = GetDC( 0);
if ( hDC)
{
hBit = CreateCompatibleBitmap( hDC, bm.bmWidth, bm.bmHeight);
ReleaseDC( 0, hDC);
}
}
else
{
// create a mono bitmap
hBit = CreateBitmap
(
bm.bmWidth,
bm.bmHeight,
1,
1,
NULL
);
}
if ( hBit)
{
hOld1 = SelectObject( hMem1, hSrc);
hOld2 = SelectObject( hMem2, hBit);
BitBlt
(
hMem2,
0,
0,
bm.bmWidth,
bm.bmHeight,
hMem1,
0,
0,
SRCCOPY
);
if ( hOld1)
SelectObject( hMem1, hOld1);
if ( hOld2)
SelectObject( hMem2, hOld2);
}
DeleteDC( hMem1);
DeleteDC( hMem2);
}
return hBit;
}
/* copy a device-dependent bitmap to the clipboard */
void BitmapToClip
(
HBITMAP hSrc
)
{
if ( hSrc)
{
HBITMAP hDst;
hDst = DupBitmap( hSrc);
if ( hDst)
{
SetClipboardData( CF_BITMAP, hDst);
}
}
}
void PASCAL DIBToClip( HBITMAP hSrc, HPALETTE hPal, short nColors)
{
if ( hSrc)
{
HANDLE hBits;
LPBITMAPINFOHEADER pBits;
BITMAPINFOHEADER bi;
LONG Length;
short nBits;
HDC hDC;
LPSTR lpNewBits;
HPALETTE hOldPal;
BITMAP bm;
HWND hFocus;
GetObject( hSrc, sizeof( BITMAP), (LPSTR) &bm);
if ( nColors <= 2)
nBits = 1;
else if ( nColors <= 16)
nBits = 4;
else if ( nColors <= 256)
nBits = 8;
else
nBits = 24;
hFocus = GetFocus();
bi.biSize = sizeof( BITMAPINFOHEADER);
bi.biWidth = bm.bmWidth;
bi.biHeight = bm.bmHeight;
bi.biBitCount = nBits;
bi.biPlanes = 1;
bi.biXPelsPerMeter =
bi.biYPelsPerMeter = 0;
bi.biClrUsed =
bi.biClrImportant = 0;
bi.biCompression = BI_RGB;
bi.biSizeImage =
( ( ( (bi.biWidth * bi.biBitCount) + 31)/32) * 4) *
bi.biHeight;
Length = bi.biSize + bi.biSizeImage;
if ( bi.biBitCount != 24)
{
if
(
( bi.biBitCount == 1) ||
( bi.biBitCount == 4) ||
( bi.biBitCount == 8)
)
{
Length += ( 1 << bi.biBitCount) * sizeof( RGBQUAD);
}
}
hBits = GlobalAlloc( GMEM_MOVEABLE, Length);
if ( hBits)
{
pBits = (LPBITMAPINFOHEADER) GlobalLock( hBits);
*pBits = bi;
hDC = GetDC( hFocus );
if ( hPal)
hOldPal = SelectPalette( hDC, hPal, FALSE);
else
hOldPal = NULL;
lpNewBits = (LPSTR) pBits + sizeof( BITMAPINFOHEADER);
lpNewBits += nColors * sizeof( RGBQUAD);
GetDIBits
(
hDC,
hSrc,
(WORD) 0,
(WORD) pBits->biHeight,
(LPSTR) lpNewBits,
(LPBITMAPINFO) pBits,
DIB_RGB_COLORS
);
if ( hOldPal)
SelectPalette( hDC, hOldPal, FALSE);
ReleaseDC( hFocus, hDC);
GlobalUnlock( hBits);
SetClipboardData( CF_DIB, hBits);
}
}
}
/* When a user selects edit.copy, copy the current
bitmap to the clipboard. Put 3 formats in:
1) CF_BITMAP
2) CF_DIB
3) CF_PALETTE
*/
void TBitScrollWindow::CMCopy(TMessage&)
{
if ( OpenClipboard( HWindow) )
{
if ( EmptyClipboard() )
{
PaletteToClip( hPal);
DIBToClip( BitmapHandle, hPal, Colors);
BitmapToClip( BitmapHandle);
}
CloseClipboard();
}
}
/* copy a logical palette to the clipboard */
HPALETTE PaletteFromClip( HPALETTE hPal)
{
HPALETTE hNewPal = 0;
WORD nColors;
LOGPALETTE * pPal;
if ( hPal)
{
GetObject( hPal, sizeof( WORD), (LPSTR) &nColors);
if ( nColors)
{
pPal = (LOGPALETTE *) new
BYTE[ sizeof( LOGPALETTE) + ( nColors - 1) * sizeof( PALETTEENTRY)];
if ( pPal)
{
pPal->palVersion = 0x300;
pPal->palNumEntries = nColors;
GetPaletteEntries( hPal, 0, nColors, pPal->palPalEntry);
hNewPal = CreatePalette( pPal);
delete pPal;
}
}
}
return hNewPal;
}
/* realize a metafile into a bitmap */
HBITMAP BitmapFromMeta
(
HANDLE hMeta,
HPALETTE hPal,
POINT * Size
)
{
HBITMAP hBit = 0;
if ( hMeta)
{
HDC hMem;
RECT Rect;
HBRUSH hBrush = GetStockObject( WHITE_BRUSH);
HBITMAP hOld;
HPALETTE hOldPal;
LPMETAFILEPICT pMeta;
short nColors;
pMeta = (LPMETAFILEPICT) GlobalLock( hMeta);
hMem = CreateCompatibleDC( 0);
if ( hMem)
{
if ( hPal)
{
GetObject( hPal, sizeof(short), (LPSTR) &nColors);
}
else
nColors = 16;
if ( nColors > 2)
{
HDC hDC = GetDC( NULL);
hBit = CreateCompatibleBitmap
(
hDC,
Size->x,
Size->y
);
ReleaseDC( NULL, hDC);
}
else
hBit = CreateBitmap
(
Size->x,
Size->y,
1,
1,
NULL
);
if ( hBit)
{
hOld = SelectObject( hMem, hBit);
SetRect
(
&Rect,
0,
0,
Size->x,
Size->y
);
FillRect
(
hMem,
&Rect,
hBrush
);
SetMapMode( hMem, pMeta->mm);
SetViewportExt
(
hMem,
Size->x,
Size->y
);
if ( hPal)
hOldPal = SelectPalette( hMem, hPal, FALSE);
else
hOldPal = 0;
PlayMetaFile( hMem, pMeta->hMF);
if ( hOld)
SelectObject( hMem, hOld);
if ( hOldPal)
SelectPalette( hMem, hOldPal, FALSE);
}
DeleteDC( hMem);
}
GlobalUnlock( hMeta);
}
return hBit;
}
/* This routine converts a bit count into a color count
It also verifies that the bit count is one that is
supported by windows, ie 1, 4, 8, and 24.
If the bit count is not supported, it returns -1
*/
short GetDInColors( WORD BitCount)
{
short nColors;
if
(
( BitCount == 1) ||
( BitCount == 4) ||
( BitCount == 8)
)
{
nColors = ( 1 << BitCount);
}
else if ( BitCount == 24)
nColors = 0;
else
nColors = -1;
return nColors;
}
/* This routine accepts a pointer to a BITMAPINFO structure
and creates a GDI logical palette from the color table which
follows it, for 2, 16 and 256 color bitmaps.
It returns 0 for all others, including 24-bit DIB's
*/
HPALETTE PaletteFromW3DIB( LPBITMAPINFO pBI)
{
LPLOGPALETTE lpDstPal;
HPALETTE hRet = 0;
short nColors, n;
RGBQUAD FAR *pRgb;
pRgb = pBI->bmiColors;
// if the ClrUsed field of the header is non-zero,
// it means that we could have have a short color table.
if ( pBI->bmiHeader.biClrUsed)
nColors = pBI->bmiHeader.biClrUsed;
else
nColors = GetDInColors( pBI->bmiHeader.biBitCount);
if ( nColors)
{
lpDstPal = (LPLOGPALETTE) GlobalLock( GlobalAlloc(
GHND, sizeof(LOGPALETTE) + ( (nColors - 1) * sizeof(PALETTEENTRY) )));
lpDstPal->palNumEntries = nColors;
lpDstPal->palVersion = 0x300; // Windows 3.0 version
for (n = 0; n < nColors; n++)
{
lpDstPal->palPalEntry[n].peRed = pRgb[n].rgbRed;
lpDstPal->palPalEntry[n].peGreen = pRgb[n].rgbGreen;
lpDstPal->palPalEntry[n].peBlue = pRgb[n].rgbBlue;
lpDstPal->palPalEntry[n].peFlags = 0;
}
hRet = CreatePalette(lpDstPal);
GlobalFree( (HANDLE) GlobalHandle( HIWORD( lpDstPal) ) );
}
return hRet;
}
/* BitmapFromhDIB -- convert a handle to a packed DIB into a
bitmap
*/
HBITMAP BitmapFromhDIB
(
HBITMAP hData,
HPALETTE * pPal
)
{
HBITMAP hBit = 0;
if ( hData)
{
HDC hDC = GetDC( GetFocus() );
LPBITMAPINFOHEADER lpBI = (LPBITMAPINFOHEADER) GlobalLock( hData);
short nColors;
HPALETTE hOldPal;
if ( lpBI->biSize == sizeof(BITMAPINFOHEADER) )
{
if ( lpBI->biClrUsed)
nColors = lpBI->biClrUsed;
else if
(
( lpBI->biBitCount == 1) ||
( lpBI->biBitCount == 4) ||
( lpBI->biBitCount == 8)
)
{
nColors = ( 1 << lpBI->biBitCount);
}
else
nColors = 0;
// create a palette if one does not already exist
if ( !*pPal)
{
*pPal = PaletteFromW3DIB( (LPBITMAPINFO) lpBI);
if ( *pPal)
{
hOldPal = SelectPalette( hDC, *pPal, FALSE);
RealizePalette( hDC);
SelectPalette( hDC, hOldPal, FALSE);
}
}
if ( *pPal)
hOldPal = SelectPalette( hDC, *pPal, FALSE);
else
hOldPal = NULL;
hBit = CreateDIBitmap
(
hDC,
lpBI,
CBM_INIT,
( (LPSTR) ( lpBI + 1)) + ( nColors * sizeof(RGBQUAD) ),
(LPBITMAPINFO) lpBI,
DIB_RGB_COLORS
);
if ( hOldPal)
SelectPalette( hDC, hOldPal, FALSE);
}
ReleaseDC( GetFocus(), hDC);
GlobalUnlock( hData);
}
return hBit;
}
/* When a user selects edit.paste, get the data from
the clipboard. This routine prefers CF_META over
CF_DIB over CF_BITMAP
*/
void TBitScrollWindow::CMPaste(TMessage&)
{
if ( OpenClipboard( HWindow) )
{
HPALETTE hNewPal = PaletteFromClip( GetClipboardData( CF_PALETTE) );
HBITMAP hNewBit;
RECT rcClient;
POINT ptSize;
if ( hNewPal)
{
// realize the new palette
HDC hDC = GetDC(HWindow);
HPALETTE hOldPal = SelectPalette( hDC, hNewPal, FALSE);
RealizePalette( hDC);
if ( hOldPal)
SelectPalette( hDC, hOldPal, FALSE);
ReleaseDC( HWindow, hDC);
}
// set meta file destination size to size of client area
GetClientRect( HWindow, &rcClient);
ptSize.x = rcClient.right - rcClient.left;
ptSize.y = rcClient.bottom - rcClient.top;
// try to get metafile 1st
hNewBit = BitmapFromMeta( (HANDLE) GetClipboardData( CF_METAFILEPICT),
hNewPal, &ptSize);
// try to get DIB format second
if ( !hNewBit)
{
hNewBit = BitmapFromhDIB( GetClipboardData( CF_DIB), &hNewPal);
}
// finally, try bitmap format
if ( !hNewBit)
{
hNewBit = DupBitmap( GetClipboardData( CF_BITMAP));
}
if ( hNewBit)
{
BITMAP bm;
GetObject( hNewBit, sizeof(BITMAP), (LPSTR) &bm);
if ( BitmapHandle)
DeleteObject( BitmapHandle);
BitmapHandle = hNewBit;
PixelWidth = bm.bmWidth;
PixelHeight = bm.bmHeight;
AdjustScroller();
SetCaption( "Clipboard");
if ( hNewPal)
{
short nColors;
if (hPal)
DeleteObject( hPal);
hPal = hNewPal;
GetObject( hNewPal, sizeof( short), (LPSTR) &nColors);
Colors = nColors;
}
else
Colors = 0;
}
else if ( hNewPal)
DeleteObject( hNewPal);
CloseClipboard();
}
}
/* If either of the "Read bitmap" menu items is selected, then we read
the bitmap resource with the ID of the menu item... */
void TBitScrollWindow::CMRead1(TMessage&)
{
if ( LoadBitmapResource( MAKEINTRESOURCE( CM_READ1) ) )
{
SetCaption( "Bitmap resource 1");
}
}
void TBitScrollWindow::CMRead2(TMessage&)
{
if ( LoadBitmapResource( MAKEINTRESOURCE( CM_READ2) ) )
{
SetCaption( "Bitmap resource 2");
}
}
/* If the the "Open..." menu item is selected, then we prompt the user
for a new bitmap file. If the user selects one and it is one that
we can read, we display it in the window and change the window's
caption to reflect the new bitmap file. */
void TBitScrollWindow::CMFileOpen(TMessage&)
{
char TempName [MAXPATH];
if (GetApplication()->ExecDialog( new TBMPFileDialog
(this, SD_FILEOPEN, strcpy(TempName, "*.bmp"))) == IDOK )
if ( LoadBitmapFile(TempName) )
{
SetCaption( TempName);
}
}
/* Adjust the Scroller range so that the the origin is the
upper-most scrollable point and the corner is the
bottom-most. */
void TBitScrollWindow::AdjustScroller()
{
RECT ClientRect;
POINT Range;
GetClientRect(HWindow, &ClientRect);
// only show scrollbars when image is larger than
// the client area.
Range.x = PixelWidth - (ClientRect.right - ClientRect.left);
if ( Range.x < 0)
Range.x = 0;
Range.y = PixelHeight - (ClientRect.bottom - ClientRect.top);
if ( Range.y < 0)
Range.y = 0;
Scroller->SetRange( Range.x, Range.y);
Scroller->ScrollTo(0, 0);
if ( !GetUpdateRect( HWindow, &ClientRect, FALSE) )
InvalidateRect(HWindow, NULL, TRUE);
}
/* Reset scroller range. */
void TBitScrollWindow::WMSize(TMessage& Msg)
{
TWindow::WMSize(Msg);
if ( (Msg.WParam != SIZEICONIC) )
AdjustScroller();
}
/* Enable and disable menu items based on status. */
void TBitScrollWindow::WMInitMenuPopup(TMessage& Msg)
{
HMENU hMenu = (HMENU) Msg.WParam;
// test for system menu
if ( !Msg.LP.Hi)
{
// test for edit menu index
if ( Msg.LP.Lo == 1)
{
if ( OpenClipboard( HWindow) )
{
if
(
( IsClipboardFormatAvailable( CF_METAFILEPICT) ) ||
( IsClipboardFormatAvailable( CF_DIB) ) ||
( IsClipboardFormatAvailable( CF_BITMAP) )
)
{
EnableMenuItem( hMenu, CM_EDITPASTE, MF_BYCOMMAND | MF_ENABLED);
}
else
{
EnableMenuItem( hMenu, CM_EDITPASTE, MF_BYCOMMAND | MF_GRAYED);
}
CloseClipboard();
}
else
{
EnableMenuItem( hMenu, CM_EDITPASTE, MF_BYCOMMAND | MF_GRAYED);
}
if ( BitmapHandle)
{
EnableMenuItem( hMenu, CM_EDITCOPY, MF_BYCOMMAND | MF_ENABLED);
}
else
{
EnableMenuItem( hMenu, CM_EDITCOPY, MF_BYCOMMAND | MF_GRAYED);
}
}
}
}
// We need to re-realize the logical palette each time
// we regain the input focus
void TBitScrollWindow::WMSetFocus(TMessage&)
{
if ( hPal)
{
HDC hDC = GetDC( HWindow);
if ( hDC)
{
HPALETTE hOldPal;
UnrealizeObject( hPal);
hOldPal = SelectPalette( hDC, hPal, FALSE);
RealizePalette( hDC);
UpdateColors( hDC);
if ( hOldPal)
SelectPalette( hDC, hOldPal, FALSE);
ReleaseDC( HWindow, hDC);
}
}
}
/* This routine accepts a pointer to a BITMAPCORE structure
and creates a GDI logical palette from the color table which
follows it, for 2, 16 and 256 color bitmaps.
It returns 0 for all others, including 24-bit DIB's
It differs from the windows DIB routine in two respects:
1) The PM 1.x DIB must have complete color tables, since
there is no ClrUsed field in the header
2) The size of the color table entries is 3 bytes, not 4
bytes.
*/
HPALETTE PaletteFromPM1DIB( BITMAPCOREINFO *pBC)
{
LPLOGPALETTE lpDstPal;
HPALETTE hRet = 0;
short nColors, n;
RGBTRIPLE *pRgb;
pRgb = pBC->bmciColors;
nColors = GetDInColors( pBC->bmciHeader.bcBitCount);
if ( nColors)
{
lpDstPal = (LPLOGPALETTE) GlobalLock( GlobalAlloc(
GHND, sizeof(LOGPALETTE) + ( (nColors - 1) * sizeof(PALETTEENTRY) )));
lpDstPal->palNumEntries = nColors;
lpDstPal->palVersion = 0x300; // Windows 3.0 version
for (n = 0; n < nColors; n++)
{
lpDstPal->palPalEntry[n].peRed = pRgb[n].rgbtRed;
lpDstPal->palPalEntry[n].peGreen = pRgb[n].rgbtGreen;
lpDstPal->palPalEntry[n].peBlue = pRgb[n].rgbtBlue;
lpDstPal->palPalEntry[n].peFlags = 0;
}
hRet = CreatePalette(lpDstPal);
GlobalFree( (HANDLE) GlobalHandle( HIWORD( lpDstPal) ) );
}
return hRet;
}
/* Copys the bitmap bit data from the file into memory.
Note that this routine reads in 32K chunks in order
to avoid crosssing a segment boundary in the call to
_lread ( which in windows 3.0 windows.h is supposed to
take an LPSTR)
*/
BOOL GetBitmapData(int TheFile, HANDLE BitsHandle, LONG BitsByteSize, LONG MaxSize)
{
LONG BytesToRead;
BYTE huge *pBits;
pBits = (BYTE huge *) GlobalLock(BitsHandle);
while ( MaxSize > 0 )
{
if (MaxSize > 32767L )
BytesToRead = 32768L;
else
BytesToRead = MaxSize;
if ( (WORD) _lread(TheFile, (LPSTR) pBits, (WORD) BytesToRead) != BytesToRead)
{
GlobalUnlock( BitsHandle);
if (BitsByteSize <= 0)
return TRUE;
else
return FALSE;
}
pBits += BytesToRead;
BitsByteSize -= BytesToRead;
MaxSize -= BytesToRead;
}
GlobalUnlock(BitsHandle);
return TRUE;
}
/* Attempt to read a Windows 3.0 device independent bitmap. */
BOOL TBitScrollWindow::ReadWin3DIB(int TheFile, char * ErrorMsg)
{
WORD size;
HDC DCHandle;
LPSTR BitsPtr;
BITMAPINFOHEADER *pBIH;
BITMAPINFO *pBI;
HANDLE BitsHandle;
HPALETTE hNewPal;
HBITMAP hBitmap;
BOOL retval;
DWORD MaxSize;
retval = FALSE;
size = sizeof(BITMAPINFOHEADER);
pBIH = (BITMAPINFOHEADER *) new BYTE[size];
if
(
( pBIH ) &&
( _lread( TheFile, (LPSTR) pBIH, size) == size)
)
{
// check number of planes. Windows 3.0 supports only 1 plane DIBS
if ( pBIH->biPlanes == 1)
{
if ( !pBIH->biClrUsed)
pBIH->biClrUsed = GetDInColors( pBIH->biBitCount);
size = (WORD) pBIH->biClrUsed * sizeof( RGBQUAD);
pBI = (BITMAPINFO *) new BYTE[ size + sizeof(BITMAPINFOHEADER)];
if ( pBI)
{
pBI->bmiHeader = *pBIH;
if ( _lread( TheFile, (LPSTR) pBI->bmiColors, size) == size)
{
// now we've got the color table. Create a pallete from it
// (don't do error checking)
hNewPal = PaletteFromW3DIB( pBI);
// some applications do not fill in the SizeImage field in
// the header. (Actually the truth is more likely that some
// drivers do not fill the field in and the apps do not
// compensate for these buggy drivers.)
// Therefore, if this field is 0, we will compute the size.
if ( pBI->bmiHeader.biSizeImage == 0)
{
// size of image = Width of a scan line * number of scan lines
// Width = Pixel Width * bits per pixel rounded to a DWORD boundary
MaxSize = pBI->bmiHeader.biSizeImage =
( ( ( (pBI->bmiHeader.biWidth * pBI->bmiHeader.biBitCount) + 31)/32) * 4) *
pBI->bmiHeader.biHeight;
if ( pBI->bmiHeader.biCompression != BI_RGB)
{
// double the size to be safe
MaxSize <<= 1;
}
}
else
MaxSize = pBI->bmiHeader.biSizeImage;
BitsHandle = GlobalAlloc( GMEM_MOVEABLE, MaxSize);
if ( BitsHandle)
{
if ( GetBitmapData(TheFile, BitsHandle, pBI->bmiHeader.biSizeImage, MaxSize) )
{
// erase the backgound to avoid ugly color changes on
// current image. Note the call to InvalidateRect
// with bErase set to FALSE. This setting should
// prevent two background erases.
DCHandle = GetDC( HWindow);
SendMessage( HWindow, WM_ERASEBKGND, DCHandle, 0);
ReleaseDC( HWindow, DCHandle);
InvalidateRect(HWindow, NULL, FALSE);
// we use the handle of the window with the focus
// (which, if this routine is called from a menu command,
// will be this window) in order to guarantee
// that the realized palette will have first
// priority on the system palette
DCHandle = GetDC( GetFocus());
if ( DCHandle)
{
HPALETTE hOldPal;
if ( hNewPal)
{
// select and realize our palette
// we have gotten the DC of the focus window just
// to make sure that all our colors are mapped
hOldPal = SelectPalette( DCHandle, hNewPal, FALSE);
RealizePalette( DCHandle);
}
else
{
hOldPal = 0;
}
BitsPtr = GlobalLock( BitsHandle);
hBitmap =
CreateDIBitmap
(
DCHandle,
&pBI->bmiHeader,
CBM_INIT,
BitsPtr,
pBI,
DIB_RGB_COLORS
);
GlobalUnlock(BitsHandle);
if ( hBitmap )
{
if ( BitmapHandle )
DeleteObject(BitmapHandle);
BitmapHandle = hBitmap;
if ( hPal)
DeleteObject( hPal);
hPal = hNewPal;
PixelWidth = (WORD) pBI->bmiHeader.biWidth;
PixelHeight = (WORD) pBI->bmiHeader.biHeight;
Colors = pBI->bmiHeader.biClrUsed;
retval = TRUE;
}
if ( hOldPal)
SelectPalette( DCHandle, hOldPal, FALSE);
ReleaseDC( GetFocus(), DCHandle);
}
else
{
strcpy( ErrorMsg, "Could not get a DC");
}
}
else
{
strcpy( ErrorMsg, "Could not read bits");
}
GlobalFree( BitsHandle);
}
else
{
strcpy( ErrorMsg, "Could get memory for bits");
}
if ( hNewPal && !retval)
DeleteObject( hNewPal);
}
else
{
strcpy( ErrorMsg, "Could not read color table");
}
delete pBI;
}
else
{
strcpy( ErrorMsg, "Could not get memory for BITMAPINFO");
}
}
else
{
strcpy( ErrorMsg, "Invalid number of planes");
}
delete pBIH;
}
else if ( pBIH)
{
strcpy( ErrorMsg, "Invalid Windows 3 DIB Header");
delete pBIH;
}
else
{
strcpy( ErrorMsg, "Could not allocate memory for BITMAPINFOHEADER");
}
return retval;
}
/* Attempt to read a PM 1.x device independent bitmap. */
BOOL TBitScrollWindow::ReadPM1DIB(int TheFile, char * ErrorMsg)
{
WORD size;
HDC DCHandle;
LPSTR BitsPtr;
BITMAPCOREHEADER *pBCH;
BITMAPCOREINFO *pBC;
HANDLE BitsHandle;
HPALETTE hNewPal;
HBITMAP hBitmap;
BOOL retval;
DWORD MaxSize;
retval = FALSE;
size = sizeof(BITMAPCOREHEADER);
pBCH = (BITMAPCOREHEADER *) new BYTE[size];
if
(
( pBCH ) &&
( _lread( TheFile, (LPSTR) pBCH, size) == size)
)
{
// check number of planes. Windows 3.0 supports only 1 plane DIBS
if ( pBCH->bcPlanes == 1)
{
size = GetDInColors( pBCH->bcBitCount) * sizeof(RGBTRIPLE);
pBC = (BITMAPCOREINFO *) new BYTE[ size + sizeof(BITMAPCOREHEADER)];
if ( pBC)
{
pBC->bmciHeader = *pBCH;
if ( _lread( TheFile, (LPSTR) pBC->bmciColors, size) == size)
{
// now we've got the color table. Create a pallete from it
// (don't do error checking)
hNewPal = PaletteFromPM1DIB( pBC);
// size of image = Width of a scan line * number of scan lines
// Width = Pixel Width * bits per pixel rounded to a DWORD boundary
MaxSize =
( ( ( (pBC->bmciHeader.bcWidth * pBC->bmciHeader.bcBitCount) + 31)/32) * 4) *
pBC->bmciHeader.bcHeight;
BitsHandle = GlobalAlloc( GMEM_MOVEABLE, MaxSize);
if ( BitsHandle)
{
if ( GetBitmapData(TheFile, BitsHandle, MaxSize, MaxSize) )
{
// erase the backgound to avoid ugly color changes on
// current image. Note the call to InvalidateRect
// with bErase set to FALSE. This setting should
// prevent two background erases.
DCHandle = GetDC( HWindow);
SendMessage( HWindow, WM_ERASEBKGND, DCHandle, 0);
ReleaseDC( HWindow, DCHandle);
InvalidateRect(HWindow, NULL, FALSE);
// we get the handle of the window with the focus
// (which, if this routine is called from a menu command,
// will be this window) in order to guarantee
// that the realized palette will have first
// priority on the system palette
DCHandle = GetDC( GetFocus());
if ( DCHandle)
{
HPALETTE hOldPal;
if ( hNewPal)
{
// select and realize our palette
// we have gotten the DC of the focus window just
// to make sure that all our colors are mapped
hOldPal = SelectPalette( DCHandle, hNewPal, FALSE);
RealizePalette( DCHandle);
}
else
{
hOldPal = 0;
}
BitsPtr = GlobalLock( BitsHandle);
hBitmap =
CreateDIBitmap
(
DCHandle,
(LPBITMAPINFOHEADER) &pBC->bmciHeader,
CBM_INIT,
BitsPtr,
(LPBITMAPINFO) pBC,
DIB_RGB_COLORS
);
GlobalUnlock(BitsHandle);
if ( hBitmap )
{
if ( BitmapHandle )
DeleteObject(BitmapHandle);
BitmapHandle = hBitmap;
if ( hPal)
DeleteObject( hPal);
hPal = hNewPal;
PixelWidth = (WORD) pBC->bmciHeader.bcWidth;
PixelHeight = (WORD) pBC->bmciHeader.bcHeight;
Colors = GetDInColors( pBC->bmciHeader.bcBitCount);
retval = TRUE;
}
if ( hOldPal)
SelectPalette( DCHandle, hOldPal, FALSE);
ReleaseDC( GetFocus(), DCHandle);
}
else
{
strcpy( ErrorMsg, "Could not get a DC");
}
}
else
{
strcpy( ErrorMsg, "Could not read bits");
}
GlobalFree( BitsHandle);
}
else
{
strcpy( ErrorMsg, "Could get memory for bits");
}
if ( hNewPal && !retval)
DeleteObject( hNewPal);
}
else
{
strcpy( ErrorMsg, "Could not read color table");
}
delete pBC;
}
else
{
strcpy( ErrorMsg, "Could not get memory for BITMAPCOREINFO");
}
}
else
{
strcpy( ErrorMsg, "Invalid number of planes");
}
delete pBCH;
}
else if ( pBCH)
{
strcpy( ErrorMsg, "Invalid PM 1.X DIB Header");
delete pBCH;
}
else
{
strcpy( ErrorMsg, "Could not allocate memory for BITMAPCOREHEADER");
}
return retval;
}
BOOL TBitScrollWindow::ReadDIB( int TheFile, char * ErrorMsg)
{
DWORD HeaderSize;
BOOL bRet;
if
(
( _lread( TheFile, (LPSTR) &HeaderSize, sizeof(HeaderSize)) != sizeof( HeaderSize) ) ||
(
( HeaderSize != sizeof( BITMAPCOREHEADER) ) &&
( HeaderSize != sizeof( BITMAPINFOHEADER) )
)
)
{
strcpy( ErrorMsg, "Not a Windows 3.x or OS/2 1.x bitmap file");
bRet = FALSE;
}
else
{
// back over the header size
_llseek( TheFile, -( (LONG) sizeof( HeaderSize)) , 1);
if ( HeaderSize == sizeof( BITMAPCOREHEADER))
{
bRet = ReadPM1DIB( TheFile, ErrorMsg);
}
else
{
bRet = ReadWin3DIB( TheFile, ErrorMsg);
}
}
return bRet;
}
/* Test if the passed resource is a Windows 3.0 ( or PM 1.x) DI bitmap
and if so read it.
Report errors if unable to do so. Adjust the Scroller to the new
bitmap dimensions. */
BOOL TBitScrollWindow::LoadBitmapResource(LPSTR Name)
{
int TheFile;
char ErrorMsg[50];
BOOL retval = TRUE;
HANDLE hFind;
HANDLE hInst = GetModule()->hInstance;
// we use the low-level resource functions here so that
// the same routines can be used to read DIB's from files
// and resources
hFind = FindResource( hInst, Name, RT_BITMAP);
if ( hFind)
{
TheFile = AccessResource( hInst, hFind);
}
else
{
TheFile = -1;
}
if ( TheFile != -1 )
{
// a bitmap resource is just like a bitmap file without
// the BITMAPFILEHEADER structure
retval = ReadDIB( TheFile, ErrorMsg);
_lclose(TheFile);
}
else
{
strcpy(ErrorMsg, "Cannot access bitmap resource");
retval = FALSE;
}
if ( retval )
{
AdjustScroller();
}
else
{
MessageBox(HWindow, ErrorMsg, BSA_NAME, MB_OK);
}
return retval;
}
/* Test if the passed file is a Windows 3.0 DI (or PM 1.x) bitmap
and if so read it.
Report errors if unable to do so. Adjust the Scroller to the new
bitmap dimensions. */
BOOL TBitScrollWindow::LoadBitmapFile(LPSTR Name)
{
int TheFile;
char ErrorMsg[50];
BOOL retval = TRUE;
BITMAPFILEHEADER bmf;
TheFile = _lopen(Name, OF_READ);
if ( TheFile != -1 )
{
// read file header and verify the signature
if
(
( _lread( TheFile, (LPSTR) &bmf, sizeof(bmf)) != sizeof( bmf) ) ||
( bmf.bfType != 0x4D42)
)
{
strcpy(ErrorMsg, "Not a Windows 3.x or OS/2 1.x bitmap file");
retval = FALSE;
}
else
{
// we ignore all other information in the file header
// since some applications do not put correct information in
// the fields...
retval = ReadDIB( TheFile, ErrorMsg);
}
_lclose(TheFile);
}
else
{
strcpy(ErrorMsg, "Cannot open bitmap file");
retval = FALSE;
}
if ( retval )
{
AdjustScroller();
}
else
{
MessageBox(HWindow, ErrorMsg, BSA_NAME, MB_OK);
}
return retval;
}
/* Responds to an incoming "paint" message by redrawing the bitmap.
(The Scroller's BeginView method, which sets the viewport origin
relative to the present scroll position, has already been called.) */
void TBitScrollWindow::Paint(HDC, PAINTSTRUCT& PaintInfo)
{
HDC MemoryDC;
HBITMAP OldBitmapHandle;
HPALETTE hOldPal;
RECT ClientRect;
if ( BitmapHandle )
{
MemoryDC = CreateCompatibleDC(PaintInfo.hdc);
OldBitmapHandle = SelectObject(MemoryDC, BitmapHandle);
if ( hPal)
hOldPal = SelectPalette( PaintInfo.hdc, hPal, FALSE);
else
hOldPal = 0;
if ( Mode == SRCCOPY )
{
if ( Colors == 2)
{
if ( hPal)
{
PALETTEENTRY pe;
GetPaletteEntries( hPal, 0, 1, &pe);
SetTextColor
(
PaintInfo.hdc,
RGB( pe.peRed, pe.peGreen, pe.peBlue)
);
GetPaletteEntries( hPal, 1, 1, &pe);
SetBkColor
(
PaintInfo.hdc,
RGB( pe.peRed, pe.peGreen, pe.peBlue)
);
}
else
{
SetBkColor(PaintInfo.hdc, 0L);
SetTextColor(PaintInfo.hdc, 0xFFFFFFL);
}
}
}
if ( IsIconic(HWindow) )
{
GetClientRect(HWindow, &ClientRect);
StretchBlt(PaintInfo.hdc, 0, 0,
ClientRect.right - ClientRect.left,
ClientRect.bottom - ClientRect.top,
MemoryDC, 0, 0, PixelWidth, PixelHeight, Mode);
}
else
BitBlt(PaintInfo.hdc, 0, 0, PixelWidth, PixelHeight,
MemoryDC, 0, 0, Mode);
if ( hOldPal)
SelectPalette( PaintInfo.hdc, hOldPal, FALSE);
SelectObject(MemoryDC, OldBitmapHandle);
DeleteDC(MemoryDC);
}
}
/* Run the BitScrollApp */
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpCmd, int nCmdShow)
{
TBitScrollApp ScrollApp(BSA_NAME, hInstance, hPrevInstance,
lpCmd, nCmdShow);
ScrollApp.Run();
return ScrollApp.Status;
}
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/