Category : Windows 3.X Files
Archive   : PCXWIN.ZIP
Filename : PCX.C

 
Output of file : PCX.C contained in archive : PCXWIN.ZIP
/* Sample PCX Image Application
* Copyright (c) 1989, Optus Information Systems, Inc.

* This application is merely one of the sample windows applications
* included with the Windows SDK. The 'DisplayImage', 'ReadNextByte',
* and 'ReadImageSeg' routine will illustrate how to decode and
* incorporate a standard PCX image file into a compatible bitmap
* for use under the Windows environment.

* This application by no means a full featured applciation. Additional
* coding should include scrolling of bit images and internal indexing
* of larger PCX images.
*/

#include
#include
#include
#include
#include "pcx.h"

#define SEEK_SET 0 /* don't want to load stdio.h */
#define RUNMASK 0x3f /* pcx run length mask */

HANDLE hInst, hFile, hResult, hMem;
LPSTR dBuf;
BYTE fByte, fBuf[4096];
PCXHDR pHdr;
DCXHDR dHdr;
OFSTRUCT OfStruct;
RECT wRect;
HCURSOR hSaveCursor, hHourGlass;

char str[255];
int bRead, fPtr, nCnt, iRef, Ref, rLength, yPos;
int FilesOpen = FALSE, hSize = 1;

char FileName[128]; /* current filename */
char PathName[128]; /* current pathname */
char OpenName[128]; /* filename to open */
char DefPath[128]; /* default path for list box */
char DefSpec[13] = "*.pcx"; /* default search spec */
char DefExt[] = ".pcx"; /* default extension */


int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HANDLE hInstance;
HANDLE hPrevInstance;
LPSTR lpCmdLine;
int nCmdShow;
{
HWND hWnd;
MSG msg;

if ( !hPrevInstance )
if ( !GenericInit ( hInstance ) )
return ( NULL );

hInst = hInstance;

hWnd = CreateWindow ( "Generic", "Sample Application",
WS_OVERLAPPEDWINDOW | WS_HSCROLL | WS_VSCROLL, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL );

if ( !hWnd )
return ( NULL );

ShowWindow ( hWnd, nCmdShow );
UpdateWindow ( hWnd );

while ( GetMessage ( &msg, NULL, NULL, NULL ) ) {
TranslateMessage ( &msg );
DispatchMessage ( &msg );
}
return ( msg.wParam );
}

BOOL GenericInit ( hInstance )
HANDLE hInstance;
{
HANDLE hMemory;
PWNDCLASS pWndClass;
BOOL bSuccess;

hHourGlass = LoadCursor ( hInstance, IDC_WAIT );
hMemory = LocalAlloc ( LPTR, sizeof ( WNDCLASS ) );
pWndClass = (PWNDCLASS) LocalLock ( hMemory );

pWndClass->style = NULL;
pWndClass->lpfnWndProc = GenericWndProc;
pWndClass->hInstance = hInstance;
pWndClass->hCursor = LoadCursor ( NULL, IDC_ARROW );
pWndClass->hbrBackground = GetStockObject ( WHITE_BRUSH );
pWndClass->lpszMenuName = (LPSTR) "FileMenu";
pWndClass->lpszClassName = (LPSTR) "Generic";

bSuccess = RegisterClass ( pWndClass );

LocalUnlock ( hMemory );
LocalFree ( hMemory );

return ( bSuccess );
}

long FAR PASCAL GenericWndProc ( hWnd, message, wParam, lParam )
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
FARPROC lpProcAbout, lpOpenDlg;
HMENU hMenu;

switch ( message ) {
case WM_COMMAND:
switch ( wParam ) {

case IDM_OPEN:
lpOpenDlg = MakeProcInstance ( (FARPROC) OpenDlg, hInst );
DialogBox ( hInst, "Open", hWnd, lpOpenDlg );
FreeProcInstance ( lpOpenDlg );

if ( !OpenName[0] )
return ( NULL );

hFile = OpenFile ( (LPSTR) OpenName, (LPOFSTRUCT) &OfStruct, OF_READ );
if ( hFile == -1 ) {
MessageBeep ( MB_OK | MB_ICONEXCLAMATION );
MessageBox ( hWnd, (LPSTR) "Can't open file", (LPSTR) NULL, MB_OK | MB_ICONEXCLAMATION );
return ( FALSE );
}

if ( ( hMem = GlobalAlloc ( GMEM_MOVEABLE, 30000L ) ) == NULL ) {
MessageBeep ( MB_OK | MB_ICONEXCLAMATION );
MessageBox ( hWnd, (LPSTR) "Out of memory", (LPSTR) NULL, MB_OK | MB_ICONEXCLAMATION );
return ( FALSE );
}
if ( ( dBuf = GlobalLock ( hMem ) ) == NULL ) {
MessageBeep ( MB_OK | MB_ICONEXCLAMATION );
MessageBox ( hWnd, (LPSTR) "Can't lock memory", (LPSTR) NULL, MB_OK | MB_ICONEXCLAMATION );
return ( FALSE );
}

hMenu = GetMenu ( hWnd );
EnableMenuItem ( hMenu, IDM_CLOSE, MF_ENABLED );
EnableMenuItem ( hMenu, IDM_INFO, MF_ENABLED );
EnableMenuItem ( hMenu, IDM_REPAINT, MF_ENABLED );
EnableMenuItem ( hMenu, IDM_OPEN, MF_DISABLED | MF_GRAYED );

FilesOpen = TRUE;
DisplayImage ( hWnd );
break;

case IDM_CLOSE:
GlobalUnlock ( hMem );
GlobalFree ( hMem );
GetClientRect ( hWnd, &wRect );
InvalidateRect ( hWnd, &wRect, TRUE );
hMenu = GetMenu ( hWnd );
EnableMenuItem ( hMenu, IDM_CLOSE, MF_DISABLED | MF_GRAYED );
EnableMenuItem ( hMenu, IDM_INFO, MF_DISABLED | MF_GRAYED );
EnableMenuItem ( hMenu, IDM_REPAINT, MF_DISABLED | MF_GRAYED );
EnableMenuItem ( hMenu, IDM_OPEN, MF_ENABLED );
close ( hFile );
FilesOpen = FALSE;
break;

case IDM_INFO:
if ( FilesOpen ) {
sprintf ( str, "Image size is %d x %d pixels\n", pHdr.right, pHdr.bottom );
MessageBox ( hWnd, (LPSTR) str, (LPSTR) "File Information", MB_OK );
}
break;

case IDM_EXIT:
if ( FilesOpen ) {
GlobalUnlock ( hMem );
GlobalFree ( hMem );
close ( hFile );
}
DestroyWindow ( hWnd );
break;

case IDM_ABOUT:
lpProcAbout = MakeProcInstance ( About, hInst );
DialogBox ( hInst, "AboutBox", hWnd, lpProcAbout );
FreeProcInstance ( lpProcAbout );
break;

case IDM_CLEAR:
GetClientRect ( hWnd, &wRect );
InvalidateRect ( hWnd, &wRect, TRUE );
break;

case IDM_REPAINT:
DisplayImage ( hWnd );
break;

case IDM_FULL:
hSize = 1;
hMenu = GetMenu ( hWnd );
CheckMenuItem ( hMenu, IDM_FULL, MF_CHECKED );
CheckMenuItem ( hMenu, IDM_HALF, MF_UNCHECKED );
if ( FilesOpen )
DisplayImage ( hWnd );
break;

case IDM_HALF:
hSize = 2;
hMenu = GetMenu ( hWnd );
CheckMenuItem ( hMenu, IDM_FULL, MF_UNCHECKED );
CheckMenuItem ( hMenu, IDM_HALF, MF_CHECKED );
if ( FilesOpen )
DisplayImage ( hWnd );
break;
}
break;

case WM_DESTROY:
PostQuitMessage ( 0 );
break;

default:
return ( DefWindowProc( hWnd, message, wParam, lParam ) );
}
return (NULL);
}

BOOL FAR PASCAL About ( hDlg, message, wParam, lParam )
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
switch ( message ) {
case WM_INITDIALOG:
return ( TRUE );

case WM_COMMAND:
if ( wParam == IDOK ) {
EndDialog ( hDlg, NULL );
return ( TRUE );
}
break;
}
return ( FALSE );
}

/* This routine will attempt to read as many scan lines as the argument
* passed. Since each scan line may be comprised of an arbitrary number of
* bytes, it is necessary to decode the bytes line by line. This makes
* nevigation through a larger file more cumbersome utilizing a method like
* this. For larger images, it is more efficient to create a form of
* internal index for each scan line's location within the PCX image.
*/

int ReadImageSeg ( lMax )
int lMax;
{
register int iCnt = 0, lRef = 0;

while ( 1 ) {
if ( lRef >= pHdr.hWidth ) {
if ( ++iRef > pHdr.bottom || ++iCnt > lMax )
break;
lRef = 0;
}
if ( !GetNextByte() )
break;
if ( fByte >= 0xc0 ) {
rLength = fByte & RUNMASK;
if ( !GetNextByte() )
break;
while ( rLength-- ) {
lRef++;
dBuf[Ref++] = fByte;
}
}
else {
lRef++;
dBuf[Ref++] = fByte;
}
}
return ( iCnt - 1 );
}

/* To display the PCX image, we must first create a device context for the
* image we wish to draw in the client area. Afterwards, a bitmap image
* must be created which will be the destination of the decoded image from
* the PCX file. Once we scan our image, we may utilize the SetBitmapBits
* function to supply a pointer to our newly created bitmap bits. From
* here, the BitBlt function handles the rest.

* This routine will continue until an EOF or the bottom of the client
* area has been reached.
*/

void DisplayImage ( hWnd )
HWND hWnd;
{
HDC hDc, hMemoryDC;
HBITMAP hBitmap;

hSaveCursor = SetCursor ( hHourGlass );
hDc = GetDC ( hWnd );
SetMapMode ( hDc, MM_ANISOTROPIC );
SetWindowExt ( hDc, hSize, hSize ); /* scale bits */
SetViewportExt ( hDc, 1, 1 );
yPos = 0;

GetClientRect ( hWnd, &wRect );
wRect.bottom *= hSize; /* explode to scale */
wRect.right *= hSize;

lseek ( hFile, 0L, SEEK_SET );
read ( hFile, (char *) &pHdr, sizeof ( PCXHDR ) );

hMemoryDC = CreateCompatibleDC ( hDc );
hBitmap = CreateBitmap ( pHdr.hWidth << 3, 128, 1, 1, (LPSTR) dBuf );

iRef = nCnt = fPtr = 0;

while ( 1 ) {
Ref = 0;
if ( ( bRead = ReadImageSeg ( 128 ) ) == -1 )
break;

SetBitmapBits ( hBitmap, (LONG) pHdr.hWidth * bRead, (LPSTR) dBuf );
SelectObject ( hMemoryDC, hBitmap );
BitBlt ( hDc, 0, yPos, wRect.right, bRead, hMemoryDC, 0, 0, SRCCOPY );

if ( bRead < 128 ) {
wRect.top = yPos + bRead;
InvalidateRect ( hWnd, &wRect, TRUE );
break;
}
yPos += 128;
if ( yPos >= wRect.bottom )
break;
}

DeleteDC ( hMemoryDC );
DeleteObject ( hBitmap );
ReleaseDC ( hWnd, hDc );
SetCursor ( hSaveCursor );
}

HANDLE FAR PASCAL OpenDlg ( hDlg, message, wParam, lParam )
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
switch ( message ) {
case WM_COMMAND:
switch ( wParam ) {

case ID_LISTBOX:
switch ( HIWORD ( lParam ) ) {
case LBN_SELCHANGE:
if ( !DlgDirSelect ( hDlg, str, ID_LISTBOX ) ) {
SetDlgItemText ( hDlg, ID_EDIT, str );
SendDlgItemMessage ( hDlg, ID_EDIT, EM_SETSEL, NULL, MAKELONG ( 0, 0x7fff ) );
}
else {
strcat ( str, DefSpec );
DlgDirList ( hDlg, str, ID_LISTBOX, ID_PATH, 0x4010 );
}
break;

case LBN_DBLCLK:
SendMessage ( hDlg, WM_COMMAND, IDOK, 0L );
break;
}
return ( TRUE );

case IDOK:
GetDlgItemText ( hDlg, ID_EDIT, OpenName, 128 );

if ( _lstrchr ( OpenName, '*' ) || _lstrchr ( OpenName, '?' ) ) {
SeparateFile ( hDlg, (LPSTR) str, (LPSTR) DefSpec, (LPSTR) OpenName );
UpdateListBox ( hDlg );
return ( TRUE );
}
if ( !OpenName[0] ) {
MessageBox ( hDlg, "No file selected", NULL, MB_OK | MB_ICONQUESTION );
return ( TRUE );
}
GetDlgItemText ( hDlg, ID_PATH, DefPath, 128 );

EndDialog ( hDlg, NULL );
return ( TRUE );

case IDCANCEL:
OpenName[0] = 0;
EndDialog ( hDlg, NULL );
return ( TRUE );
}
break;

case WM_INITDIALOG:
UpdateListBox ( hDlg );
SetDlgItemText ( hDlg, ID_EDIT, DefSpec );
SendDlgItemMessage ( hDlg, ID_EDIT, EM_SETSEL, NULL, MAKELONG ( 0, 0x7fff ) );
SetFocus(GetDlgItem ( hDlg, ID_EDIT ) );
return ( FALSE );
}
return FALSE;
}

void UpdateListBox ( hDlg )
HWND hDlg;
{
_lstrcpy ( str, DefPath );
_lstrcat ( str, DefSpec );
DlgDirList ( hDlg, (LPSTR) str, ID_LISTBOX, ID_PATH, 0x4010 );
SetDlgItemText ( hDlg, ID_EDIT, (LPSTR) DefSpec );
}

void ChangeDefExt ( Ext, Name )
LPSTR Ext, Name;
{
LPSTR pTptr;

pTptr = Name;
while ( *pTptr && *pTptr != '.' )
pTptr++;
if ( *pTptr ) /* true if this is an extension */
if ( !strchr ( pTptr, '*' ) && !strchr ( pTptr, '?' ) )
strcpy ( Ext, pTptr ); /* Copies the extension */
}

void SeparateFile ( hDlg, lpDestPath, lpDestFileName, lpSrcFileName )
HWND hDlg;
LPSTR lpDestPath, lpDestFileName, lpSrcFileName;
{
LPSTR lpTmp;

lpTmp = lpSrcFileName + (long) _lstrlen( lpSrcFileName );

while ( *lpTmp != ':' && *lpTmp != '\\' && lpTmp > lpSrcFileName )
lpTmp = AnsiPrev ( lpSrcFileName, lpTmp );

if ( *lpTmp != ':' && *lpTmp != '\\' ) {
_lstrcpy ( lpDestFileName, lpSrcFileName );
lpDestPath[0] = 0;
return;
}
_lstrcpy ( lpDestFileName, lpTmp + 1L );
_lstrncpy ( lpDestPath, lpSrcFileName, (int) ( lpTmp - lpSrcFileName ) + 1 );
lpDestPath[ ( lpTmp - lpSrcFileName ) + 1] = 0;
}

void AddExt ( Name, Ext )
LPSTR Name, Ext;
{
LPSTR pTptr;

pTptr = Name;
while ( *pTptr && *pTptr != '.' )
pTptr++;
if ( *pTptr != '.' ) /* If no extension, add the default */
strcat ( Name, Ext );
}

int _lstrlen ( lpStr )
LPSTR lpStr;
{
int i;
for ( i = 0; *lpStr++; i++ );
return ( i );
}

void _lstrncpy ( lpDest, lpSrc, n )
LPSTR lpDest, lpSrc;
int n;
{
while ( n-- )
if ( !( *lpDest++ = *lpSrc++ ) )
return;
}

void _lstrcat ( lpDest, lpSrc )
LPSTR lpDest, lpSrc;
{
while ( *lpDest++ );
*lpDest--; /* back up one */
while ( *lpDest++ = *lpSrc++ );
}

int _lstrchr ( lpScan, c )
LPSTR lpScan;
int c;
{
while ( *lpScan )
if ( *lpScan++ == c)
return ( TRUE );
return ( NULL );
}

void _lstrcpy ( lpDest, lpSrc )
LPSTR lpDest, lpSrc;
{
while ( *lpDest++ = *lpSrc++ );
}

int GetNextByte()
{
if ( !nCnt ) {
nCnt = read ( hFile, fBuf, 4096 );
if ( !nCnt )
return ( FALSE );
fPtr = 0;
}
nCnt--;
fByte = fBuf[fPtr++];
return ( TRUE );
}


  3 Responses to “Category : Windows 3.X Files
Archive   : PCXWIN.ZIP
Filename : PCX.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. 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/