{ This is an example of exporting your own compression algorithm into ARCDIB
  using a Turbo Pascal DLL. You can use this code as a shell by replacing
  the "YouCompress" and "YourDeCompress" functions with your own algorithms
  for compression and decompression respectively. The function exported by
  the DLL is "MyComp".

function MyComp(var IMAGEHANDLE: THandle;
                var BITSSIZE: LongInt;
                    COMPRESS: Boolean): Boolean ; export;

  Its name and parameters must not change since ARCDIB expects it that way.
  As you can see, the function returns TRUE or FALSE depending on its sucess
  - determined by you. The three parameters are:

   IMAGEHANDLE: a Windows Global Handle to a memory block containing either
                the uncompressed or compressed bytes of the bitmap image.

      BITSSIZE: the size of the bitmap bytes ("bits") before being
                compressed and the size of the compressed bits when
                expanding.

      COMPRESS: TRUE if compressing, FALSE if decompressing. If compressing,
                IMAGEHANDLE refers to a block of uncompressed bitmap "bits"
                - the same as to "bits" of a Windows DIB. If decompressing,
                then IMAGEHANDLE refers to the block of memory returned as
                a result of a previous compression.

THE CONCEPT IS THIS:
  Upon entry into "MyComp" you obtain a pointer to the memory block referred
  to by IMAGEHANDLE. You then create another global Handle of size BITSSIZE
  to use as output of your compression/decompression routine. Obtain a
  pointer to this NewHandle with GlobalLock. Then, you pass each byte
  in IMAGEHANDLE (in this case, one at a time) to either YourCompress or
  YourDeCompress routines depending on the COMPRESS flag. In each of those
  routines, you write the output to the new memory block you created
  referred to by NewHandle. Finally, you reallocate NewHandle to the size
  resulting from the compression/decompression (ie keep track of the number
  of bytes written) and get rid the passed in IMAGEHANDLE with GlobalFree
  and reassign it to Newhandle. Always pass the resulting size of the
  compressed (or expanded) bytes in BITSSIZE!
  Keep the following in mind:

         1. This alorithm ASSUMES the result of the compression will require
            a smaller block of memory than the original. For decompression,
            the result should equal the original (obiviously) and the
            GlobalReAlloc call is actually redundant because in both cases
            you create Newhandle using the original (uncompressed) size.

         2. You must keep track of the number of bytes written to the new
            handle in order to determine its new size for reallocation.

         3. Don't forget to "unlock" the new handle before returning from
            the function.

         4. If the function returns FALSE, ARCDIB flags the bitmap as being
            in compressed form and will therefore call MyComp again to
            uncompress the "bits" before displaying.

         5. If you return FALSE during compression, ARCDIB will just
            assume something went wrong in your compression and EXPECTS
            IMAGEHANDLE refer to the same block of uncompressed bytes that
            it did before the call! This could be disastorous if you somehow
            corrupt the original data so be careful not to. Worse yet, on
            decompression, returning FALSE leaves ARCDIB on a limb because,
            presumably, it passed in successfully compressed data and you
            are now telling it that there's no way back...we're doomed.

         6. Keep in mind that if the size of the bitmap is greater that
            64K, you must make your code aware of the segment boundries
            that you'll eventually cross reading and (possibly) writing
            from/to the memory blocks. This is illustrated in the example
            by creating a variant record type for a special far pointer
            that can be safely incremented using a Windows call to AHINC().

     ***** Thanks to Tom Swam (the Charles Petzold of TPW) and his book
            "Turbo Pascal for Windows 3.0 Programming" for this and MANY
            other useful tricks.

         6. When compressing/decompressing a bitmap in ARCDIB, a status
            box appears showing percent completion. In your case, I have
            no way of knowing this info so the box just kind of sits
            there and says "Please wait..". In the future, I'll provide
            some type of Callback function so that you can update the
            status yourself - or least the OPTION to, since most compression
            purest loaf the idea of delaying their algorithm unecessarily.

         7. Again, the library (DLL) name MUST remain "YourComp" and the
            compression function name MUST remain "MyComp" with the SAME
            parameters and exported index.

                                          Sine Labore Nihil...


Brendan Daunt
BETTER MAPS
(619) 598-1323
76307,2411
                                                                            }

{***************************************************************************}
library YourComp; { Don't change this name }

uses WinTypes, WinProcs;

{ Windows function for calculating pointer offsets safely }
Procedure AHIncr; far; external 'KERNEL' index 114;

{ Variant record type for a far pointer to step through memory blocks that
  may cross segment boundries. }
Type
 LongType = record
  case word of
   0: (Ptr: Pointer);
   1: (Long: LongInt);
   2: (Lo: Word; Hi: Word);
  end;

{ Global variables }
Var h,                   { Temporary handle                              }
    NewHandle: THandle;  { New handle refers to compressed "bits"        }
    OldBits,             { Pointer to memory block in IMAGEHANDLE        }
    NewBits  : Pointer;  { Pointer to memory block in NewHandle          }
    NewSize  : LongInt;  { Resulting size of NewHandle after compression }

{ These are dummy procedures (stubs) provided to illustrate how you might
  implement your own compress/decompress algorithms.

  They are called from the exported function "MyComp" with a Byte type
  parameter which represents an uncompressed/compressed byte in the
  original IMAGEHANDLE passed to "MyComp".

  Be sure to write the output of either function to the global memory
  block in NewHandle and also keep track of the numbers of bytes written  }

 Var
  ToBits,
  ToStart,
  ToAddr    : LongType;  { Special far pointer records     }

procedure YourCompress(InByte: Byte);
{}
 Begin
  { ...compress InByte somehow  }

  ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
  ToAddr.Lo := ToStart.LO;
  Byte(ToAddr.Ptr^) := InByte;
  Inc(ToStart.Long);

  Inc(NewSize);
 End;

procedure YourDeCompress(InByte: Byte);
{}
 Begin
  { ...decompress InByte somehow }

  ToAddr.Hi := ToBits.Hi + ( ToStart.Hi * Ofs(AHIncr));
  ToAddr.Lo := ToStart.LO;
  Byte(ToAddr.Ptr^) := InByte;
  Inc(ToStart.Long);

  Inc(NewSize);
 End;


{ This is the only function exported by YourComp.DLL - header and
  results must remain the same (see above). }

function MyComp(var IMAGEHANDLE: THandle; 
                var BITSSIZE: LongInt;
                    COMPRESS: Boolean) : Boolean ; export;
{}
 Var
  OneByte     : Byte;     { Holds a byte to be compressed/decompressed }
  ImageSize,              { Size of IMAGEHANDLE                        }
  OldPtrOffSet: LongInt;  { Pointer offset into IMAGEHANDLE            }
  FromBits,
  FromStart,
  FromAddr    : LongType;  { Special far pointer records     }

 Begin
  MessageBox(GetActiveWindow, 'Dummy compress DLL for instructional purposes only.', 'YourComp.DLL', mb_IconExclamation);
  MyComp  := False;
  NewSize := 0;       { Contains the number of bytes written to NewHandle }

{ Get a pointer to the original handle }
  OldBits := GlobalLock(IMAGEHANDLE);
  If OldBits = nil Then
   Begin
    MessageBox(GetActiveWindow, 'OldBits = nil', 'MyComp ERROR',
                                 mb_TaskModal or mb_Ok);
    Exit;
   End;

{ Create new memory block (NewHandle) - same size as uncompressed block }
  NewHandle := GlobalAlloc(gmem_Moveable or gmem_ZeroInit, BITSSIZE);
  If NewHandle = 0 Then
   Begin
    MessageBox(GetActiveWindow, 'NewHandle = 0', 'MyComp ERROR',
                                 mb_TaskModal or mb_Ok);
    Exit;
   End;

{ Get a pointer to the new handle }
  NewBits := GlobalLock(NewHandle);
  If NewBits = nil Then
   Begin
    MessageBox(GetActiveWindow, 'NewBits = nil', 'MyComp ERROR',
                                 mb_TaskModal or mb_Ok);
    GlobalFree(NewHandle);
    Exit;
   End;

  FromStart.Long := 0;       { Initial pointer offset into IMAGEHANDLE      }
  FromBits.Ptr   := OldBits; { Use LongType pointer for segment "awareness" }

  ToStart.Long := 0;       { Initial pointer offset into NewHandle        }
  ToBits.Ptr   := NewBits; { Use LongType pointer for segment "awareness" }

{ Process each byte in IMAGEHANDLE }
  ImageSize := GlobalSize(IMAGEHANDLE);
  For OldPtrOffset := 0 to ImageSize-1 Do
   Begin
   { Calculate the pointer offset }
    FromAddr.Hi := FromBits.Hi + ( FromStart.Hi * Ofs(AHIncr));
    FromAddr.Lo := FromStart.LO;

   { Get a byte from the original memory block in IMAGEHANDLE }
    OneByte := Byte(FromAddr.Ptr^);

   { Now call your compression or decompression routine with OneByte }
    If Compress Then
     YourCompress(OneByte)     { procedure of your choice for compression   }
    Else
     YourDeCompress(OneByte);  { procedure of your choice for decompression }

   { Increment the pointer offset }
    Inc(FromStart.Long);
   End; { For each byte in IMAGEHANDLE }

{ Unlock the NewHandle and attempt to reallocate it with new size }
  GlobalUnlock(NewHandle);
  h := GlobalReAlloc(NewHandle, NewSize, gmem_Moveable or gmem_ZeroInit);
  if (h <> 0) Then
   Begin
    GlobalUnlock(IMAGEHANDLE);
    GlobalFree(IMAGEHANDLE);     { Get rid of original handle to "bits" }
    NewHandle := h;              { Assign NewHandle to reallocated block}
   End
  Else                           { GlobalReAlloc failed - abort }
   Begin
    GlobalFree(NewHandle);       { Free the new handle }
    MessageBox(GetActiveWindow, 'Could realloc NewHandle', 'MyComp ERROR',
                                 mb_TaskModal or mb_Ok);
    Exit;
   End;

{ Success }
  BITSSIZE    := NewSize;
  ImageHandle := NewHandle;
  MyComp      := True;

 End; { MyComp }

{- List exported routines }

exports

  MyComp   index 3;          { Export MyComp with index of 3 }

BEGIN
END. { YourComp DLL }


