538 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			538 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
//
 | 
						|
// EX23WIN.CPP
 | 
						|
//
 | 
						|
//  C++/Windows Example program for ArchiveLib 2.0
 | 
						|
//
 | 
						|
//  Copyright (c) Greenleaf Software, Inc. 1994 - 1996
 | 
						|
//  All Rights Reserved
 | 
						|
//
 | 
						|
// MEMBERS/FUNCTIONS DEMONSTRATED
 | 
						|
//
 | 
						|
//   N/A
 | 
						|
//
 | 
						|
// DESCRIPTION
 | 
						|
//
 | 
						|
//  This program is used to benchmark the performance of our various
 | 
						|
//  compression engines.  The program looks at the Input Files text
 | 
						|
//  box for a wildcard specification for a group of files.  The program
 | 
						|
//  expands the wild card specification and individually compresses and
 | 
						|
//  decompresses each of the files.  The temporary files created by this
 | 
						|
//  process are deleted.
 | 
						|
//
 | 
						|
//  After the whole batch of files is done, a summary of the compression
 | 
						|
//  time and statistics is displayed.
 | 
						|
//
 | 
						|
//  If the optional Compress Only check box is checked, the
 | 
						|
//  program runs in "compress-only" mode.  In this case, the decompression
 | 
						|
//  state is skipped.  You can use this to determine the ratio between
 | 
						|
//  compression and decompresion times.
 | 
						|
//
 | 
						|
//  If the Rude Mode check box is checked, the program doesn't service
 | 
						|
//  the Windows message loop while it is compression.
 | 
						|
//
 | 
						|
//  This example program does one funky thing to try to give us real
 | 
						|
//  fast performance.  Instead of using the default buffer size of 4096
 | 
						|
//  bytes, I jack it up to a hefty 28672 bytes.  This gives us a few
 | 
						|
//  percentage points.  Just change the definition of BIG_BUFFER to
 | 
						|
//  benchmark at the default size.
 | 
						|
//
 | 
						|
//
 | 
						|
// REVISION HISTORY
 | 
						|
//
 | 
						|
//  February 1, 1996  2.0A  : Second release
 | 
						|
//
 | 
						|
 | 
						|
#define STRICT
 | 
						|
#include <windows.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <stdio.h>
 | 
						|
 | 
						|
#include "al.h"
 | 
						|
#include "ex23win.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * I don't have a 32 bit version of CTL3D.DLL for Symantec or Microsoft.
 | 
						|
 */
 | 
						|
 | 
						|
#if defined( AL_BORLAND ) || !defined( AL_FLAT_MODEL )
 | 
						|
#define AL_3D
 | 
						|
#include "ctl3d.h"
 | 
						|
#else
 | 
						|
#define Ctl3dColorChange()
 | 
						|
#define Ctl3dRegister( a )
 | 
						|
#define Ctl3dAutoSubclass( a )
 | 
						|
#define Ctl3dUnregister( a )
 | 
						|
#endif
 | 
						|
 | 
						|
#if !defined( BIG_BUFFER )
 | 
						|
#define BIG_BUFFER 28672
 | 
						|
#endif
 | 
						|
 | 
						|
HCURSOR hHourGlassCursor;
 | 
						|
HINSTANCE hInstance;
 | 
						|
 | 
						|
//
 | 
						|
// This storage object is used when compressing or decompressing.  If
 | 
						|
// the user wants to abort the compression, it just has to set the
 | 
						|
// error flag for this object.  If the object pointer is set to 0, it means
 | 
						|
// no compression is currently in progress, so the Abort button does
 | 
						|
// nothing.
 | 
						|
//
 | 
						|
ALStorage *compressed = 0;
 | 
						|
 | 
						|
extern "C" BOOL AL_EXPORT CALLBACK AboutDialogProc( HWND, UINT, WPARAM, LPARAM );
 | 
						|
 | 
						|
//
 | 
						|
// The time class is a very modest convenience.
 | 
						|
//
 | 
						|
class TIME {
 | 
						|
    public :
 | 
						|
        long milliseconds;
 | 
						|
        TIME(){ milliseconds = GetTickCount(); }
 | 
						|
        TIME( long t ){ milliseconds = t; }
 | 
						|
        TIME operator-(TIME &);
 | 
						|
};
 | 
						|
 | 
						|
TIME TIME::operator-( TIME &rhs )
 | 
						|
{
 | 
						|
    return TIME( milliseconds - rhs.milliseconds );
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// This function takes two file sizes and returns the compression ratio
 | 
						|
// in the standard format we expect.
 | 
						|
//
 | 
						|
inline int ratio( long plain, long compressed )
 | 
						|
{
 | 
						|
    if ( plain == 0 )
 | 
						|
        return 0;
 | 
						|
    compressed *= 100;
 | 
						|
    return (int)( 100 - ( compressed / plain ) );
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// This function allocates a character buffer, then prints the
 | 
						|
// time into it.  It is up to the caller to free the returned
 | 
						|
// string.
 | 
						|
//
 | 
						|
char *format_time( const TIME &t )
 | 
						|
{
 | 
						|
    long m = t.milliseconds;
 | 
						|
    int hours;
 | 
						|
    int minutes;
 | 
						|
    int seconds;
 | 
						|
    int hsecs;
 | 
						|
 | 
						|
    char *s = (char *) malloc( 25 );
 | 
						|
    if ( s ) {
 | 
						|
        hours = (int) ( m / ( 1000L * 60L * 60L ));
 | 
						|
        m -= hours * ( 1000L * 60L * 60L );
 | 
						|
        minutes = (int) ( m / ( 1000L * 60L ) );
 | 
						|
        m -= minutes * (1000L * 60L );
 | 
						|
        seconds = (int)( m / ( 1000L ) );
 | 
						|
        m -= seconds * 1000L;
 | 
						|
        hsecs = (int)( m / 10L );
 | 
						|
        sprintf( s, "%02d:%02d:%02d.%02d", hours, minutes, seconds, hsecs );
 | 
						|
    }
 | 
						|
    return s;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// This is the first of two possible compression functions.  It is very
 | 
						|
// much like the main loop in EX23CON.CPP.  It just sets up a wild card
 | 
						|
// expander object, then starts chunking out file names.  Each time it
 | 
						|
// gets a new file name, it compresses it, and optionally expands it.
 | 
						|
// When the whole thing is over, the resulting stats are stuffed into
 | 
						|
// the dialog, somewhere.
 | 
						|
//
 | 
						|
 | 
						|
void NiceCompress( HWND hDlg )
 | 
						|
{
 | 
						|
    char input_name[ 128 ];
 | 
						|
    char buf[ 128 ];
 | 
						|
    long total_input = 0;
 | 
						|
    long total_compressed = 0;
 | 
						|
    int compress_only = IsDlgButtonChecked( hDlg, AL_COMPRESS_ONLY );
 | 
						|
 | 
						|
    ALWindowsMessage monitor( AL_MONITOR_OBJECTS,
 | 
						|
                              GetDlgItem( hDlg, AL_PROGRESS_TEXT ),
 | 
						|
                              AL_SEND_BYTE_COUNT,
 | 
						|
                              GetDlgItem( hDlg, AL_PROGRESS_NUMBER ) );
 | 
						|
    monitor.mlObjectStart = 0;
 | 
						|
 | 
						|
    GetDlgItemText( hDlg, AL_INPUT_FILES, input_name, 128 );
 | 
						|
    ALWildCardExpander expander( input_name );
 | 
						|
#if defined( ZIP )
 | 
						|
    ALPkCompressor compressor;
 | 
						|
    ALPkDecompressor decompressor;
 | 
						|
#else
 | 
						|
    ALGlCompressor compressor;
 | 
						|
    ALGlDecompressor decompressor;
 | 
						|
#endif
 | 
						|
//
 | 
						|
// This code clears out all the boxes on the dialog that might be left
 | 
						|
// over from the last run of this program.
 | 
						|
//
 | 
						|
    SendDlgItemMessage( hDlg, AL_DATA, LB_RESETCONTENT, 0, 0 );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_INPUT, "" );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_COMPRESSED, "" );
 | 
						|
    SetDlgItemText( hDlg, AL_RATIO, "" );
 | 
						|
    SetDlgItemText( hDlg, AL_TIME, "" );
 | 
						|
 | 
						|
    char AL_DLL_FAR *name;
 | 
						|
    TIME global_start;
 | 
						|
//
 | 
						|
// This is the loop where all of the work happens.  All we do here is
 | 
						|
// get a new file name and use it as the input file.  We then compress
 | 
						|
// to a second file, and then optionally expand to a third file.
 | 
						|
//
 | 
						|
    while ( ( name = expander.GetNextFile() ) != 0 ) {
 | 
						|
        TIME local_start;
 | 
						|
        ALFile input( name, BIG_BUFFER );
 | 
						|
        compressed = new ALFile( "", BIG_BUFFER );
 | 
						|
        ALFile output( "", BIG_BUFFER );
 | 
						|
        ALName filename( name );
 | 
						|
        filename.StripPath();
 | 
						|
        SetDlgItemText( hDlg, AL_PROGRESS_TEXT, (LPSTR) filename );
 | 
						|
        input.mpMonitor = &monitor;
 | 
						|
        compressor.Compress( input, *compressed );
 | 
						|
        if ( compressed->mStatus < AL_SUCCESS )
 | 
						|
            break;
 | 
						|
        if ( !compress_only ) {
 | 
						|
            input.mpMonitor = 0;
 | 
						|
            output.mpMonitor = &monitor;
 | 
						|
            decompressor.Decompress( *compressed, output );
 | 
						|
            output.Delete();
 | 
						|
            if ( compressed->mStatus < AL_SUCCESS )
 | 
						|
                break;
 | 
						|
        }
 | 
						|
        total_input += input.GetSize();
 | 
						|
        total_compressed += compressed->GetSize();
 | 
						|
        TIME local_stop;
 | 
						|
        char *s;
 | 
						|
        wsprintf( buf,
 | 
						|
                  "%s\t%ld\t%ld\t%d%%\t%s",
 | 
						|
                  (LPSTR) filename,
 | 
						|
                  input.GetSize(),
 | 
						|
                  compressed->GetSize(),
 | 
						|
                  ratio( input.GetSize(), compressed->GetSize() ),
 | 
						|
                  (LPSTR)( s = format_time( local_stop - local_start ) )
 | 
						|
                );
 | 
						|
        if ( s )
 | 
						|
            free( s );
 | 
						|
//
 | 
						|
// I stuff the file stats in the list box, then make sure that the currently
 | 
						|
// selected position in the list box is on the screen.
 | 
						|
//
 | 
						|
        int pos = (int) SendDlgItemMessage( hDlg,
 | 
						|
                                            AL_DATA,
 | 
						|
                                            LB_ADDSTRING,
 | 
						|
                                            0,
 | 
						|
                                            (LPARAM)(LPSTR) buf );
 | 
						|
        SendDlgItemMessage( hDlg,
 | 
						|
                            AL_DATA,
 | 
						|
                            LB_SETCURSEL,
 | 
						|
                            pos,
 | 
						|
                            0 );
 | 
						|
        SendDlgItemMessage( hDlg,
 | 
						|
                            AL_DATA,
 | 
						|
                            LB_SETCURSEL,
 | 
						|
                            (WPARAM) -1,
 | 
						|
                            0 );
 | 
						|
        compressed->Delete();
 | 
						|
        delete compressed;
 | 
						|
        compressed = 0;
 | 
						|
    }
 | 
						|
    if ( compressed ) {
 | 
						|
        delete compressed;
 | 
						|
        compressed = 0;
 | 
						|
    }
 | 
						|
    TIME global_stop;
 | 
						|
    sprintf( buf, "%ld", total_input );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_INPUT, buf );
 | 
						|
    sprintf( buf, "%ld", total_compressed );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_COMPRESSED, buf );
 | 
						|
    sprintf( buf, "%d%%", ratio( total_input, total_compressed ) );
 | 
						|
    SetDlgItemText( hDlg, AL_RATIO, buf );
 | 
						|
    char * s = format_time( global_stop - global_start );
 | 
						|
    if ( s ) {
 | 
						|
        sprintf( buf,
 | 
						|
                 "%s",
 | 
						|
                 s = format_time( global_stop - global_start ) );
 | 
						|
        SetDlgItemText( hDlg, AL_TIME, buf );
 | 
						|
        free( s );
 | 
						|
    } else
 | 
						|
        SetDlgItemText( hDlg, AL_TIME, "" );
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// In order to blow off the Windows message loop, we have to derive a new
 | 
						|
// file class, which is what we are doing here with ALRudeFile.  This
 | 
						|
// class only needs a constructor and a new Yield function (the destructor
 | 
						|
// is here because of DLL problems when we take the default dtor.)
 | 
						|
// The Yield function does nothing.  This overrides the base class
 | 
						|
// Yield function, which services the message loop.
 | 
						|
//
 | 
						|
class AL_CLASS_TYPE ALRudeFile : public ALFile {
 | 
						|
    public :
 | 
						|
        virtual AL_PROTO ~ALRudeFile(){;}
 | 
						|
        void AL_DLL_FAR * AL_PROTO operator new( size_t size ){ return ::new char[ size ]; }
 | 
						|
        AL_PROTO ALRudeFile( const char AL_DLL_FAR *name = "" );
 | 
						|
        virtual void AL_PROTO YieldTime(){;}
 | 
						|
};
 | 
						|
 | 
						|
AL_PROTO ALRudeFile::ALRudeFile( const char AL_DLL_FAR *name )
 | 
						|
 : ALFile( name, BIG_BUFFER, AL_MIXED )
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// RudeCompress is just like NiceCompress(), except that it uses rude
 | 
						|
// files instead of ALFile.  It doesn't bother updating most of
 | 
						|
// the elements on the screen, because we want to be as rude as
 | 
						|
// possible.  One kind of not rude thing here is the hourglass cursor
 | 
						|
// we put up to let you know that you aren't going to be able to do
 | 
						|
// anything else for a while.
 | 
						|
//
 | 
						|
void RudeCompress( HWND hDlg )
 | 
						|
{
 | 
						|
    char input_name[ 128 ];
 | 
						|
    char buf[ 128 ];
 | 
						|
    long total_input = 0;
 | 
						|
    long total_compressed = 0;
 | 
						|
    int compress_only = IsDlgButtonChecked( hDlg, AL_COMPRESS_ONLY );
 | 
						|
 | 
						|
 | 
						|
    HCURSOR old_cursor = SetCursor( hHourGlassCursor );
 | 
						|
    GetDlgItemText( hDlg, AL_INPUT_FILES, input_name, 128 );
 | 
						|
    ALWildCardExpander expander( input_name );
 | 
						|
#if defined( ZIP )
 | 
						|
    ALPkCompressor compressor;
 | 
						|
    ALPkDecompressor decompressor;
 | 
						|
#else
 | 
						|
    ALGlCompressor compressor;
 | 
						|
    ALGlDecompressor decompressor;
 | 
						|
#endif
 | 
						|
    SendDlgItemMessage( hDlg, AL_DATA, LB_RESETCONTENT, 0, 0 );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_INPUT, "" );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_COMPRESSED, "" );
 | 
						|
    SetDlgItemText( hDlg, AL_RATIO, "" );
 | 
						|
    SetDlgItemText( hDlg, AL_TIME, "" );
 | 
						|
    SetDlgItemText( hDlg, AL_PROGRESS_NUMBER, "" );
 | 
						|
 | 
						|
    char AL_DLL_FAR *name;
 | 
						|
    TIME global_start;
 | 
						|
    while ( ( name = expander.GetNextFile() ) != 0 ) {
 | 
						|
        TIME local_start;
 | 
						|
        ALRudeFile input( name );
 | 
						|
        compressed = new ALRudeFile;
 | 
						|
        ALRudeFile output;
 | 
						|
        ALName filename( name );
 | 
						|
        filename.StripPath();
 | 
						|
        SetDlgItemText( hDlg, AL_PROGRESS_TEXT, (LPSTR) filename );
 | 
						|
        compressor.Compress( input, *compressed );
 | 
						|
        if ( compressed->mStatus < AL_SUCCESS )
 | 
						|
            break;
 | 
						|
        if ( !compress_only ) {
 | 
						|
            decompressor.Decompress( *compressed, output );
 | 
						|
            output.Delete();
 | 
						|
            if ( compressed->mStatus < AL_SUCCESS )
 | 
						|
                break;
 | 
						|
        }
 | 
						|
        total_input += input.GetSize();
 | 
						|
        total_compressed += compressed->GetSize();
 | 
						|
        compressed->Delete();
 | 
						|
        delete compressed;
 | 
						|
        compressed = 0;
 | 
						|
    }
 | 
						|
    if ( compressed ) {
 | 
						|
        delete compressed;
 | 
						|
        compressed = 0;
 | 
						|
    }
 | 
						|
    TIME global_stop;
 | 
						|
    sprintf( buf, "%ld", total_input );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_INPUT, buf );
 | 
						|
    sprintf( buf, "%ld", total_compressed );
 | 
						|
    SetDlgItemText( hDlg, AL_TOTAL_COMPRESSED, buf );
 | 
						|
    sprintf( buf, "%d%%", ratio( total_input, total_compressed ) );
 | 
						|
    SetDlgItemText( hDlg, AL_RATIO, buf );
 | 
						|
    char * s = format_time( global_stop - global_start );
 | 
						|
    if ( s ) {
 | 
						|
        sprintf( buf,
 | 
						|
                 "%s",
 | 
						|
                 s = format_time( global_stop - global_start ) );
 | 
						|
        SetDlgItemText( hDlg, AL_TIME, buf );
 | 
						|
        free( s );
 | 
						|
    } else
 | 
						|
        SetDlgItemText( hDlg, AL_TIME, "" );
 | 
						|
    SetCursor( old_cursor );
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// This text message used to be in the RC file, but for some reason
 | 
						|
// Microsoft's RC.EXE decided it was too long to compile.
 | 
						|
//
 | 
						|
char *help = "This program is used to run benchmarks on ArchiveLib's "
 | 
						|
             "compression performance.  Simply enter a wild-card file "
 | 
						|
             "specification in the Input Files text box, then press the "
 | 
						|
             "Compress button.  When the program completes, it will "
 | 
						|
             "print statistics regarding compression speed and ratio.  The "
 | 
						|
             "Compress Only check box can be used to disable decompression.  "
 | 
						|
             "When the Rude Mode check box is selected the compression "
 | 
						|
             "routines will not service the Windows message loop.";
 | 
						|
//
 | 
						|
// This is the dialog procedure for our main dialog.  In this program, all
 | 
						|
// the important work gets done here.  Most of it gets down by the
 | 
						|
// handler for WM_COMMAND, which processes the button presses from the
 | 
						|
// dialog.
 | 
						|
//
 | 
						|
 | 
						|
BOOL AL_EXPORT CALLBACK MainDialogProc( HWND hDlg,
 | 
						|
                                        UINT message,
 | 
						|
                                        WPARAM wParam,
 | 
						|
                                        LPARAM )
 | 
						|
{
 | 
						|
    short int tab_stops[] = { 65, 120, 175, 195  };
 | 
						|
    switch ( message ) {
 | 
						|
//
 | 
						|
// We respond to the init message by positioning the dialog on the screen,
 | 
						|
// initializing the windows title, the setting up the initial values of
 | 
						|
// all the text boxes.
 | 
						|
//
 | 
						|
        case WM_INITDIALOG :
 | 
						|
            RECT rc;
 | 
						|
            SetDlgItemText( hDlg, AL_HELP, help );
 | 
						|
            SendDlgItemMessage( hDlg, AL_DATA, LB_SETTABSTOPS, 4, (LPARAM) (LPINT) tab_stops );
 | 
						|
/* I use this line of code to help me line up the columns...
 | 
						|
            SendDlgItemMessage( hDlg,
 | 
						|
                                AL_DATA,
 | 
						|
                                LB_ADDSTRING,
 | 
						|
                                0,
 | 
						|
                                (LPARAM)(LPSTR) "A\tB\tC\tD\tE" );
 | 
						|
*/
 | 
						|
            GetWindowRect( hDlg, &rc );
 | 
						|
            SetWindowPos( hDlg,
 | 
						|
                          NULL,
 | 
						|
                          ((GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2),
 | 
						|
                          ((GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2),
 | 
						|
                          0,
 | 
						|
                          0,
 | 
						|
                          SWP_NOSIZE | SWP_NOACTIVATE );
 | 
						|
            SetWindowText( hDlg, "Windows example 23" );
 | 
						|
            SetDlgItemText( hDlg, AL_INPUT_FILES, "C:\\DOS\\COMMAND.COM" );
 | 
						|
            SetDlgItemText( hDlg, AL_PROGRESS_TEXT, "" );
 | 
						|
            SetDlgItemText( hDlg, AL_PROGRESS_NUMBER, "" );
 | 
						|
            return( TRUE );
 | 
						|
//
 | 
						|
// Have to support this message in order to make the CTL3D stuff work.
 | 
						|
//
 | 
						|
        case WM_SYSCOLORCHANGE :
 | 
						|
           Ctl3dColorChange();
 | 
						|
           break;
 | 
						|
//
 | 
						|
// WM_COMMAND is for all the button presses.
 | 
						|
//
 | 
						|
        case WM_COMMAND :
 | 
						|
            switch ( wParam ) {
 | 
						|
//
 | 
						|
// If the user wants to compress, we do so, but only if no compression
 | 
						|
// is already in progress.
 | 
						|
//
 | 
						|
                case AL_COMPRESS :
 | 
						|
                    if ( compressed == 0 )
 | 
						|
                        if ( IsDlgButtonChecked( hDlg, AL_RUDE ) )
 | 
						|
                            RudeCompress( hDlg );
 | 
						|
                        else
 | 
						|
                            NiceCompress( hDlg );
 | 
						|
                    return TRUE;
 | 
						|
//
 | 
						|
// If the user wants to quit, I have to set one of the file objects to an
 | 
						|
// error status first.  Otherwise, the compression code will keep right on
 | 
						|
// going even after we have killed our dialog window.  Code like this is used
 | 
						|
// all over the place in all of the example programs.
 | 
						|
//
 | 
						|
                case AL_EXIT :
 | 
						|
                case WM_QUIT :
 | 
						|
                case WM_DESTROY :
 | 
						|
                    if ( compressed != 0 )
 | 
						|
                        compressed->mStatus.SetError(
 | 
						|
                                        AL_USER_ABORT,
 | 
						|
                                        "User pressed abort key" );
 | 
						|
                    else
 | 
						|
                        EndDialog( hDlg, TRUE );
 | 
						|
                    return TRUE;
 | 
						|
//
 | 
						|
// We abort a compression in progress the same way, by setting the
 | 
						|
// error code for the storage object.  Likewise, code that looks
 | 
						|
// just like this is used all throughout our example programs.
 | 
						|
//
 | 
						|
                case AL_ABORT :
 | 
						|
                    if ( compressed != 0 )
 | 
						|
                        compressed->mStatus.SetError(
 | 
						|
                                        AL_USER_ABORT,
 | 
						|
                                        "User pressed abort key" );
 | 
						|
                    return TRUE;
 | 
						|
 | 
						|
                case AL_ABOUT :
 | 
						|
                    DialogBox( hInstance, "ALAboutDialog", hDlg, AboutDialogProc );
 | 
						|
                    return TRUE;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// The about procedure just displays the about box.
 | 
						|
//
 | 
						|
BOOL AL_EXPORT CALLBACK AboutDialogProc( HWND hDlg,
 | 
						|
                                         UINT message,
 | 
						|
                                         WPARAM wParam,
 | 
						|
                                         LPARAM )
 | 
						|
{
 | 
						|
    switch ( message ) {
 | 
						|
        case WM_INITDIALOG :
 | 
						|
            RECT rc;
 | 
						|
            GetWindowRect( hDlg, &rc );
 | 
						|
            SetWindowPos( hDlg,
 | 
						|
                          NULL,
 | 
						|
                          ((GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2),
 | 
						|
                          ((GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2),
 | 
						|
                          0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
 | 
						|
            break;
 | 
						|
        case WM_QUIT :
 | 
						|
        case WM_DESTROY :
 | 
						|
            EndDialog( hDlg, TRUE );
 | 
						|
            return TRUE;
 | 
						|
        case WM_COMMAND :
 | 
						|
            switch ( wParam ) {
 | 
						|
                case IDOK :
 | 
						|
                case AL_EXIT :
 | 
						|
                    EndDialog( hDlg, TRUE );
 | 
						|
                    return TRUE;
 | 
						|
            }
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// WinMain just has to dispatch the dialog box.  It also sets up the CTL3d
 | 
						|
// stuff.
 | 
						|
//
 | 
						|
int PASCAL WinMain( HINSTANCE instance,
 | 
						|
                    HINSTANCE,
 | 
						|
                    LPSTR,
 | 
						|
                    int )
 | 
						|
{
 | 
						|
    hInstance = instance;
 | 
						|
    hHourGlassCursor = LoadCursor( NULL, IDC_WAIT );
 | 
						|
    Ctl3dRegister( instance );
 | 
						|
    Ctl3dAutoSubclass( instance );
 | 
						|
    DialogBox( instance, "ALMainDialog", 0, MainDialogProc );
 | 
						|
    Ctl3dUnregister( instance );
 | 
						|
    DestroyCursor( hHourGlassCursor );
 | 
						|
    return 0;
 | 
						|
}
 |