// // 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 #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