1133 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1133 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //
 | |
| // MEMWIN.CPP
 | |
| //
 | |
| //  Source file for ArchiveLib 2.0
 | |
| //
 | |
| //  Copyright (c) Greenleaf Software, Inc. 1994-1996
 | |
| //  All Rights Reserved
 | |
| //
 | |
| // CONTENTS
 | |
| //
 | |
| //  ALWinMemory::operator new()
 | |
| //  ALWinMemory::ALWinMemory()
 | |
| //  newALWinMemory()
 | |
| //  newALWinMemoryVB32()
 | |
| //  ALWinMemory::~ALWinMemory()
 | |
| //  ALWinMemory::_LoadBuffer( long address )
 | |
| //  ALWinMemory::Delete()
 | |
| //  ALWinMemory::GrowUserBuffer()
 | |
| //  ALWinMemory::_FlushBuffer( long address )
 | |
| //  ALWinMemory::Close()
 | |
| //  ALWinMemory::Create()
 | |
| //  ALWinMemory::Open()
 | |
| //  ALWinMemory::Clone()
 | |
| //  ALWinMemoryCopyBufferVB()
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  This file contains all the code for ALWinMemory.  This works hand
 | |
| //  in hand with ALMemoryBase.
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release
 | |
| //
 | |
| 
 | |
| #include "arclib.h"
 | |
| #if !defined( AL_IBM )
 | |
| #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #if defined( AL_VB )
 | |
| #include "_vbutil.h"
 | |
| #endif
 | |
| 
 | |
| //
 | |
| // Problem here with PowerPack and others that use the NT
 | |
| // API, but don't support the whole thing
 | |
| //
 | |
| #ifdef IsBadWritePtr
 | |
| #undef IsBadWritePtr
 | |
| #endif
 | |
| 
 | |
| #include <windows.h>
 | |
| #include "memstore.h"
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::operator new()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Memory allocator used when ArchiveLib resides in a 16 bit DLL.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //
 | |
| //  void * ALWinMemory::operator new( size_t size )
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  size  :  The number of bytes that the compiler has decided will be
 | |
| //           necessary to construct a new ALWinMemory object.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  When using a DLL, it is easy to get into a dangerous situation when
 | |
| //  creating objects whose ctor and dtor are both in the DLL.  The problem
 | |
| //  arises because when you create an object using new, the memory for
 | |
| //  the object will be allocated from the EXE.  However, when you destroy
 | |
| //  the object using delete, the memory is freed inside the DLL.  Since
 | |
| //  the DLL doesn't really own that memory, bad things can happen.
 | |
| //
 | |
| //  But, you say, won't the space just go back to the Windows heap regardless
 | |
| //  of who tries to free it?  Maybe, but maybe not.  If the DLL is using
 | |
| //  a subsegment allocation scheme, it might do some sort of local free
 | |
| //  before returning the space to the windows heap.  That is the point where
 | |
| //  you could conceivably cook your heap.
 | |
| //
 | |
| //  By providing our own version of operator new inside this class, we
 | |
| //  ensure that all memory allocation for the class will be done from
 | |
| //  inside the DLL, not the EXE calling the DLL.
 | |
| //
 | |
| //  NOTE!!!:  Don't get confused about one thing.  This function isn't
 | |
| //            allocating the buffer that's going to hold the data you
 | |
| //            write using functions such as WriteChar().  It is just
 | |
| //            allocating the space for the object itself!
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  A pointer to some memory that should have been pulled out of the
 | |
| //  heap for the DLL.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| 
 | |
| #if defined( AL_BUILDING_DLL )
 | |
| 
 | |
| void AL_DLL_FAR * AL_PROTO
 | |
| ALWinMemory::operator new( size_t size )  /* Tag protected function */
 | |
| {
 | |
|     return ::new char[ size ];
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::ALWinMemory()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++  C  VB  Delphi
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Create a Windows based memory object
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  ALWinMemory::ALWinMemory(  const char *buffer_name = "",
 | |
| //                             char *user_buffer = 0,
 | |
| //                             DWORD user_buffer_size = 0,
 | |
| //                             ALCase name_case = AL_MIXED );
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  hALStorage newALWinMemory( char *buffer_name,
 | |
| //                             char *user_buffer,
 | |
| //                             DWORD user_buffer_size );
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  Declare Function newALWinMemory Lib "AL20LW"
 | |
| //    (ByVal buffer_name$, ByVal user_buffer$, ByVal user_buffer_size&) As Long
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  function newALWinMemory( buffer_name : PChar;
 | |
| //                           user_buffer : PChar;
 | |
| //                           user_buffer_size : LongInt ) : hALStorage;
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  buffer_name  : An arbitrary name assigned to the buffer.  Buffer
 | |
| //                 names don't have to be unique, because buffers aren't
 | |
| //                 named at the operating system level.  But if you are
 | |
| //                 going to insert the storage object into an archive, the
 | |
| //                 name needs to be unique so that you will be able to
 | |
| //                 extract it properly.
 | |
| //
 | |
| //  user_buffer  : If you want the ALMemory class to automatically allocate
 | |
| //                 a buffer for you, and grow it as necessary, just leave
 | |
| //                 this pointer set to 0.  If you want to use your own buffer,
 | |
| //                 which won't have the ability to grow, pass a pointer to
 | |
| //                 it in this parameter.  Note that under Windows 16 this
 | |
| //                 is a huge pointer, meaning it can span segments, and
 | |
| //                 access potentially 16 Mbytes of memory.
 | |
| //
 | |
| //  user_buffer_size : If you are passing a pointer to your own buffer,
 | |
| //                     you need to indicate how large it is here.
 | |
| //
 | |
| //  name_case    : This decides whether you want the file name to be
 | |
| //                 case sensitive when making comparisons.  MS-DOS
 | |
| //                 file names are case-insensitive.  You can make memory
 | |
| //                 buffers either mixed case, forced upper, or forced
 | |
| //                 lower.  The default of mixed case means that comparisons
 | |
| //                 will be case sensitive, which is fine.  Note that I
 | |
| //                 force C/VB/Delphi users to take the default of AL_MIXED.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  This constructor calls the base class constructor in an initializer
 | |
| //  list, which takes care of most of the dirty work right away.  After that
 | |
| //  is done, all the constructor has to do is initialize a few data members.
 | |
| //  That should be self-explanatory.  Remember that if the user doesn't
 | |
| //  supply a buffer, we are going to allocate it for her, but not until
 | |
| //  there is actually a demand for memory.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Under C/VB/Delphi, it returns a pointer to a newly constructed ALWinMemory
 | |
| //  object.  Ditto if called via new under C++.  O/W, returns nothing.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| AL_PROTO ALWinMemory::ALWinMemory(  /* Tag public function */
 | |
|                       const char AL_DLL_FAR *buffer_name /* = "" */,
 | |
|                       char AL_HUGE *user_buffer /* = 0 */,
 | |
|                       DWORD user_buffer_size /* = 0 */,
 | |
|                       ALCase name_case /* = AL_MIXED */ )
 | |
|     : ALMemoryBase( buffer_name, name_case )
 | |
| {
 | |
| #if 0
 | |
|     char buf[ 128 ];
 | |
|     wsprintf( buf,
 | |
|               "buffer_name = %s  "
 | |
|               "user_buffer = %lx  "
 | |
|               "user_buffer_size = %ld  "
 | |
|               "name_case = %d",
 | |
|               buffer_name,
 | |
|               user_buffer,
 | |
|               user_buffer_size,
 | |
|               name_case );
 | |
|     MessageBox( 0, buf, "Title", MB_OK );
 | |
| #endif
 | |
|     if ( user_buffer != 0 ) {
 | |
| #if 0
 | |
|         strncpy( buf, user_buffer, 40 );
 | |
|         buf[ 40 ] = '\0';
 | |
|         MessageBox( 0, buf, "Preview", MB_OK );
 | |
| #endif
 | |
|         mpcUserBuffer = user_buffer;
 | |
|         mfUserOwnsBuffer = 1;
 | |
|         mlUserBufferSize = user_buffer_size;
 | |
|     } else {
 | |
|         mfUserOwnsBuffer = 0;
 | |
|         mpcUserBuffer = 0;
 | |
|         mlUserBufferSize = 0;
 | |
|     }
 | |
|     mhUserMemoryHandle = 0;
 | |
| }
 | |
| 
 | |
| #if !defined( AL_NO_C )
 | |
| 
 | |
| extern "C" AL_LINKAGE hALStorage AL_FUNCTION
 | |
| newALWinMemory( char AL_DLL_FAR *buffer_name,  /* Tag public function */
 | |
|                 char AL_HUGE *user_buffer,
 | |
|                 DWORD user_buffer_size )
 | |
| {
 | |
|     if ( user_buffer_size == 0 )
 | |
|         return (hALStorage) new ALWinMemory( buffer_name );
 | |
|     else
 | |
|         return (hALStorage) new ALWinMemory( buffer_name, user_buffer, user_buffer_size );
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| //
 | |
| // Note that things are a little different here for VB32.
 | |
| // Instead of *using* the buffer passed here, we just
 | |
| // make a copy of it.
 | |
| //
 | |
| #if defined( AL_VB32 )
 | |
| 
 | |
| extern "C" AL_LINKAGE hALStorage AL_FUNCTION
 | |
| newALWinMemoryVB32( char AL_DLL_FAR *buffer_name,  /* Tag public function */
 | |
|                     LPSAFEARRAY *ppsa,
 | |
|                     size_t user_buffer_size )
 | |
| {
 | |
|     if ( user_buffer_size == 0 )
 | |
|         return (hALStorage) new ALWinMemory( buffer_name );
 | |
| //
 | |
| // I have to allocate some space, then do a copy into it.
 | |
| //
 | |
|     ALWinMemory *m = new ALWinMemory( buffer_name, 0, 0 );
 | |
|     m->mhUserMemoryHandle = GlobalAlloc( GMEM_MOVEABLE, user_buffer_size );
 | |
|     if ( m->mhUserMemoryHandle ) {
 | |
|         m->mpcUserBuffer = (char AL_HUGE *) GlobalLock( (HGLOBAL) m->mhUserMemoryHandle );
 | |
|         m->mlUserBufferSize = user_buffer_size;
 | |
|         unsigned char *p;
 | |
|         SafeArrayAccessData( *ppsa, (void **) &p );
 | |
|         memcpy( m->mpcUserBuffer, p, user_buffer_size );
 | |
|         SafeArrayUnaccessData( *ppsa );
 | |
|     } else {
 | |
|         delete m;
 | |
|         return 0;
 | |
|     }
 | |
|     return (hALStorage) m;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::~ALWinMemory()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  The destructor for ALWinMemory objects.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  ALWinMemory::~ALWinMemory()
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None, C programs have to call the base class dtor, deleteALStorage().
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  None, VB programs have to call the base class dtor, deleteALStorage().
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None, Delphi programs have to call the base class dtor, deleteALStorage().
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  The destructor has just one thing it has to do before this object
 | |
| //  goes away.  If the buffer that it has been using all along doesn't
 | |
| //  belong to the user, then it is the class's responsibility to get
 | |
| //  rid of it.
 | |
| //
 | |
| //  Note also that we check the GoodTag() function when in Debug mode.
 | |
| //  That will help catch really bad mistakes, such as trying to delete
 | |
| //  an object that is not even an ALMemory object, maybe a beer can.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Nothing.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| AL_PROTO
 | |
| ALWinMemory::~ALWinMemory()  /* Tag public function */
 | |
| {
 | |
|     AL_ASSERT( GoodTag(), "~ALWinMemory: attempting to delete invalid object" );
 | |
|     if ( !mfUserOwnsBuffer ) {
 | |
|         if ( mpcUserBuffer ) {
 | |
|             GlobalUnlock( (HGLOBAL) mhUserMemoryHandle );
 | |
|             GlobalFree( (HGLOBAL) mhUserMemoryHandle );
 | |
|             mhUserMemoryHandle= 0;
 | |
|             mpcUserBuffer = 0;
 | |
|         }
 | |
|     }
 | |
|     AL_ASSERT( GoodTag(), "~ALWinMemory: attempting to delete invalid object" );
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::_LoadBuffer()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Read memory from the big buffer into the local I/O buffer.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  void ALWinMemory::_LoadBuffer( long address );
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None, internal protected function.
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  None, internal protected function.
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None, internal protected functoin.
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  address      :  The offset in the memory object that is going to be
 | |
| //                  loaded.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  External users of an ALStorage class perform all of their access via
 | |
| //  a local I/O buffer.  Functions such as ReadChar() and WriteChar() look
 | |
| //  at a thing called mpcBuffer for their data.  When reading from
 | |
| //  mpcBuffer, you are going to run out of data from time to time.  When
 | |
| //  this happens, you will generate a call to the virtual function
 | |
| //  LoadBuffer().
 | |
| //
 | |
| //  As it happens, all of the ALMemory objects share a common version
 | |
| //  of LoadBuffer().  LoadBuffer() still has to call something a little
 | |
| //  more specialized though, and that's where this version of _LoadBuffer()
 | |
| //  comes into play.  It just performs a memcpy() routine to actually move
 | |
| //  data out of the big memory buffer and into the local I/O buffer
 | |
| //  used by ReadChar() et. al.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Nothing.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| void AL_PROTO
 | |
| ALWinMemory::_LoadBuffer( long address )  /* Tag protected function */
 | |
| {
 | |
| //
 | |
| // Some problems passing huge arrays to memcpy, got to do it inline instead
 | |
| // I think Microsoft says memcpy() will work with huge pointers as long
 | |
| // as you don't try to use the inline optimizations, but I say why take
 | |
| // chances...
 | |
| //
 | |
| // Another note: AL_HUGE is _huge for win16, but blank for win32.
 | |
| //
 | |
|     char AL_HUGE *temp = mpcUserBuffer + address;
 | |
|     for ( unsigned int i = 0 ; i < muBufferValidData ; i++ )
 | |
|         mpcBuffer[ i ] = *temp++;
 | |
| //    memcpy( mpcBuffer, mpcUserBuffer +          address, muBufferValidData );
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::Delete()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Delete the underlying buffer for the memory object.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  int ALWinMemory::Delete();
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None, C programs use the base class function deleteALStorage().
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  None, VB programs use the base class function deleteALStorage().
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None, Delphi programs use the base class function deleteALStorage().
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  This function is analogous to the unlink() RTL function for files.  It
 | |
| //  has to close the file, and get rid of its big buffer.  This is fairly
 | |
| //  easy with memory buffers, we just call GlobalFree() to delete the buffer.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Nothing.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| int AL_PROTO
 | |
| ALWinMemory::Delete()  /* Tag public function */
 | |
| {
 | |
|     if ( !mfUserOwnsBuffer ) {
 | |
|         GlobalUnlock( (HGLOBAL) mhUserMemoryHandle );
 | |
|         GlobalFree( (HGLOBAL) mhUserMemoryHandle );
 | |
|         mhUserMemoryHandle= 0;
 | |
|         mpcUserBuffer = 0;
 | |
|     }
 | |
|     return AL_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::GrowUserBuffer()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Enlarge the user buffer.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  int ALWinMemory::GrowUserBuffer( long minimum_new_size );
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None, this is an internal protected C++ function.
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  None, this is an internal protected C++ function.
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None, this is an internal protected C++ function.
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  minimum_new_size : This is the size that the caller absolutely must
 | |
| //                     have to successfully perform a write.  Anything
 | |
| //                     less than this won't do.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  Sometimes a write to a memory object goes past the current end of the
 | |
| //  buffer.  When this happens, code in the base class calls this
 | |
| //  function to attempt to enlarge the buffer.
 | |
| //
 | |
| //  Enlarging the buffer is tricky, because you have to allocate new space,
 | |
| //  then copy the old buffer into the new buffer.  This means you
 | |
| //  temporarily need a boot-load of space.  If you are lucky, GlobalReallcoc()
 | |
| //  might be able to attempt to avoid this situation.
 | |
| //
 | |
| //  We try to enlarge things by a fixed amount, large enough to prevent
 | |
| //  thrashing.  But if that doesn't fly, we can fall back and try to
 | |
| //  enlarge to the minimum acceptable size.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  AL_SUCCESS if all went well, some error code < AL_SUCCESS if not.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| int AL_PROTO
 | |
| ALWinMemory::GrowUserBuffer( long minimum_new_size )  /* Tag protected function */
 | |
| {
 | |
|     if ( mStatus < AL_SUCCESS )
 | |
|         return mStatus;
 | |
|     if ( mfUserOwnsBuffer )
 | |
|         return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
 | |
|                                    "Attempt to write past the end of a "
 | |
|                                    "user owned buffer for ALWinMemory "
 | |
|                                    "%s",
 | |
|                                    mName.GetSafeName() );
 | |
|     long trial_size = mlUserBufferSize + 16384;
 | |
|     GlobalUnlock( (HGLOBAL) mhUserMemoryHandle );
 | |
|     HGLOBAL new_handle = GlobalReAlloc( (HGLOBAL) mhUserMemoryHandle, trial_size, GMEM_MOVEABLE );
 | |
|     if ( new_handle == 0 ) {
 | |
|         trial_size = minimum_new_size;
 | |
|         new_handle = GlobalReAlloc( (HGLOBAL) mhUserMemoryHandle, trial_size, GMEM_MOVEABLE );
 | |
|     }
 | |
|     if ( new_handle == 0 ) {
 | |
|         mpcUserBuffer = (char AL_HUGE *) GlobalLock( (HGLOBAL) mhUserMemoryHandle );
 | |
|         return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
 | |
|                                  "Allocation failure when attempting to "
 | |
|                                  "allocate a buffer "
 | |
|                                  "of %ld bytes for ALMemoryBase "
 | |
|                                  "%s",
 | |
|                                  minimum_new_size,
 | |
|                                  mName.GetSafeName() );
 | |
|     }
 | |
|     mpcUserBuffer = (char AL_HUGE *) GlobalLock( new_handle );
 | |
|     mhUserMemoryHandle = new_handle;
 | |
|     mlUserBufferSize = trial_size;
 | |
|     return AL_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::_FlushBuffer()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Flush data to the big buffer.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  void ALWinMemory::_FlushBuffer( long address )
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None, internal protected C++ function.
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  None, internal protected C++ function.
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None, internal protected C++ function.
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  address : The address in the big buffer where the flush should write
 | |
| //            to.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  When performing WriteChar() or WriteBuffer() operations, ALStorage
 | |
| //  causes output to be directed to a small I/O buffer.  When this I/O
 | |
| //  buffer gets full, a call to ALFlushBuffer() is generated, which is
 | |
| //  supposed to dump that memory to a physical device.
 | |
| //
 | |
| //  When ALMemoryBase gets a call to FlushBuffer(), it handles almost
 | |
| //  everything on its own.  The one thing it can't handle, however, is
 | |
| //  the routine to copy the I/O buffer out to the big memory object.
 | |
| //  It has to really on this dinky virtual function to do the job.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Nothing.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| void AL_PROTO
 | |
| ALWinMemory::_FlushBuffer( long address )  /* Tag protected function */
 | |
| {
 | |
| //
 | |
| // Can't use memcpy with huge pointers, at least not with the optimized
 | |
| // versions.
 | |
| //
 | |
|         char AL_HUGE *temp = mpcUserBuffer + address;
 | |
|         for ( unsigned int i = 0 ; i < muWriteIndex ; i++ )
 | |
|             *temp++ = mpcBuffer[ i ];
 | |
| //        memcpy( mpcUserBuffer +          mlFilePointer, mpcBuffer, muWriteIndex );
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::Close()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Close an open big memory buffer object
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  int ALWinMemory::Close()
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  C programs should use the base class function ALStorageClose().
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  VB programs should use the base class function ALStorageClose().
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  Delphi programs should use the base class function ALStorageClose().
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  Close() is supposed to do the same thing to a memory buffer as fclose()
 | |
| //  in the RTL does to a file.  The most important thing we are concerned
 | |
| //  about is that the I/O buffer gets freed up by the base class, so this
 | |
| //  suddenly might not be a giant heavyweight object any more.
 | |
| //
 | |
| //  After freeing things up in the base class, we check to see if
 | |
| //  we have allocated more space than we really need.  If so, we do
 | |
| //  a GlobalRealloc() of some sort to give space back to the O/S.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Nothing.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| int AL_PROTO
 | |
| ALWinMemory::Close()  /* Tag public function */
 | |
| {
 | |
|     ALMemoryBase::Close();
 | |
|     if ( mStatus < AL_SUCCESS )
 | |
|         return mStatus;
 | |
|     if ( !mfUserOwnsBuffer && mlSize < mlUserBufferSize ) {
 | |
|         GlobalUnlock( (HGLOBAL) mhUserMemoryHandle );
 | |
|         HGLOBAL new_handle = GlobalReAlloc( (HGLOBAL) mhUserMemoryHandle, mlSize, GMEM_MOVEABLE );
 | |
|         if ( new_handle != 0 )
 | |
|             mhUserMemoryHandle = new_handle;
 | |
|         mpcUserBuffer = (char AL_HUGE *) GlobalLock( (HGLOBAL) mhUserMemoryHandle );
 | |
|         mlUserBufferSize = mlSize;
 | |
|     }
 | |
|     return mStatus;
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::Create()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Create the memory storage object big buffer.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  int ALWinMemory::Create( long init_size );
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  C programs should use the base class function ALStorageCreate().
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  VB programs should use the base class function ALStorageCreate().
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  Delphi programs should use the base class function ALStorageCreate().
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  init_size  :  When you create an ALMemory object of any kind, you can
 | |
| //                write out data to it at your own pace, without having any
 | |
| //                idea how much space you will need.  The storage object
 | |
| //                tries to increase its size every time you fill up
 | |
| //                the current huge buffer.  Well, if you know in advance how
 | |
| //                much space you are going to need, you can allocate the
 | |
| //                whole buffer at once, and avoid all that extra work.  So
 | |
| //                some calls to Create() now pass on an initial size using
 | |
| //                this argument.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  This is like creating a new file.  If there isn't a memory buffer
 | |
| //  already assigned to this object, we create one, with an initial
 | |
| //  allocation of 16Kbytes, or more if requested.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Either AL_SUCCESS, or an unfriendly error code.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| int AL_PROTO
 | |
| ALWinMemory::Create( long init_size )  /* Tag public function */
 | |
| {
 | |
|     ALMemoryBase::Create();
 | |
|     if ( mStatus < AL_SUCCESS )
 | |
|         return mStatus;
 | |
|     if ( mpcUserBuffer )
 | |
|         return AL_SUCCESS; //If a buffer was already created somewhere down the
 | |
|                            //line, we won't do it again.
 | |
|     if ( init_size == -1L )
 | |
|         init_size = 16384;
 | |
|     mhUserMemoryHandle = GlobalAlloc( GMEM_MOVEABLE, init_size );
 | |
|     if ( mhUserMemoryHandle ) {
 | |
|         mpcUserBuffer = (char AL_HUGE *) GlobalLock( (HGLOBAL) mhUserMemoryHandle );
 | |
|         mlUserBufferSize = init_size;
 | |
|     } else {
 | |
|         mpcUserBuffer = 0;
 | |
|         return mStatus.SetError( AL_CANT_ALLOCATE_MEMORY,
 | |
|                                  "Allocation failure when attempting to "
 | |
|                                  "create a buffer "
 | |
|                                  "of %ld bytes for ALWinMemory "
 | |
|                                  "%s in Create()",
 | |
|                                  init_size,
 | |
|                                  mName.GetSafeName() );
 | |
|     }
 | |
|     return mStatus;
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::Open()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Open an existing memory storage object.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  int ALWinMemory::Open();
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  C programs should use the base class function ALStorageOpen().
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  VB programs should use the base class function ALStorageOpen().
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  Delphi programs should use the base class function ALStorageOpen().
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  This is like opening an existing file.  Since there is supposed to be
 | |
| //  an existing memory buffer already, we gripe if we can't find one.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Either AL_SUCCESS, or an unfriendly error code.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| int AL_PROTO
 | |
| ALWinMemory::Open()  /* Tag public function */
 | |
| {
 | |
|     ALMemoryBase::Open();
 | |
|     if ( mStatus < AL_SUCCESS )
 | |
|         return mStatus;
 | |
|     if ( mpcUserBuffer == 0 )
 | |
|         return mStatus.SetError( AL_CANT_OPEN_FILE,
 | |
|                                  "Attempt to open ALWinMemory %s "
 | |
|                                  "with no buffer allocated",
 | |
|                                  mName.GetSafeName() );
 | |
|     else
 | |
|         mlSize = mlUserBufferSize;
 | |
|     return AL_SUCCESS;
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemory::Clone()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Clone this memory based storage object.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //  #include "memstore.h"
 | |
| //
 | |
| //  ALStorage ALWinMemory::Clone( const char *name,
 | |
| //                                int object_type ) const;
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None, this is an internal C++ function
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None.
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  name         :  The desired name of the new object.  Usually this will
 | |
| //                  be a name found in an Archive directory.
 | |
| //
 | |
| //  object_type  :  The type of object we want to create.  Only
 | |
| //                  AL_STORAGE_DEFAULT and AL_MEMORY_OBJECT will cause this
 | |
| //                  function to succeed.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  The virtual Clone() function is used by archiving programs to act
 | |
| //  as a virtual constructor.  When preparing to create storage objects
 | |
| //  based on the contents of an Archive directory, the archiving code can
 | |
| //  call Clone() for all the storage objects in its toolkit until it finds
 | |
| //  one that responds to its object type.
 | |
| //
 | |
| //  For example, if an archive contained an AL_MEMORY object, and we were
 | |
| //  extracting, and an ALFile object was in the toolkit, it would call
 | |
| //  ALFile::Clone() from the toolkit object, with an object type of
 | |
| //  AL_MEMORY_OBJECT.  This Clone() function would fail.  Hopefully, there
 | |
| //  would be a memory based storage object in the toolkit that would
 | |
| //  respond properly to the Clone() call.
 | |
| //
 | |
| //  Another object in the same archive might have an AL_FILE_OBJECT type.
 | |
| //  When the archiving code called Clone() again with that object type,
 | |
| //  we would successfully create the new File object in Clone().
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  Either a pointer to a newly constructed ALHugeMemory object, or a zero
 | |
| //  in case of error.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| ALStorage AL_DLL_FAR *
 | |
| ALWinMemory::Clone( const char AL_DLL_FAR *name,  /* Tag public function */
 | |
|                     int object_type ) const
 | |
| {
 | |
|     switch ( object_type ) {
 | |
|         case AL_STORAGE_DEFAULT :
 | |
|         case AL_MEMORY_OBJECT :
 | |
|             return new ALMemory( name );
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALWinMemoryCopyBufferVB()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  VB
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Copy the contents of an ALWinMemory object to a VB string.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  None, only useful to VB programs.
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  None, only useful to VB programs.
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  Declare Function ALWinMemoryCopyBufferVB Lib "AL20LW"
 | |
| //    (ByVal this_object&) As String
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  None, only useful to VB programs.
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  this_object  :  A handle for (pointer to) an ALWinMemory object.
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  This VB translation function provides access to the data stored
 | |
| //  in the buffer of an ALWinMemory object.  It does this by creating a
 | |
| //  VB string with a copy of the data.  We don't do any checking here,
 | |
| //  so it is possible to abort VB if the string is too large.
 | |
| //
 | |
| //  This function was sort of a missing link in our ability to handle
 | |
| //  memory objects in VB.  It was always easy to convert a VB string to
 | |
| //  an ALWinMemory object, but we didn't have any good way to make the
 | |
| //  reverse trip.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  A VB string that contains the contents of the memory object.
 | |
| //  Note that the memory object is still there, unchanged, but now
 | |
| //  you can easily get at its data using VB.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release.
 | |
| //
 | |
| 
 | |
| #if defined( AL_VB )
 | |
| 
 | |
| extern "C" long AL_FUNCTION
 | |
| ALWinMemoryCopyBufferVB( hALStorage this_object )  /* Tag public function */
 | |
| {
 | |
|     AL_ASSERT_OBJECT( this_object, ALWinMemory, "ALWinMemoryCopyBufferVB" );
 | |
|     ( (ALWinMemory *) this_object )->FlushBuffer();
 | |
|     return ALCreateVBString( (char _far *) ( (ALWinMemory *) this_object )->mpcUserBuffer,
 | |
|                              (unsigned short int) ( (ALWinMemory *) this_object )->GetSize() );
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 |