214 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| //
 | |
| // VBUTIL.CPP
 | |
| //
 | |
| //  Source file for ArchiveLib 2.0
 | |
| //
 | |
| //  Copyright (c) Greenleaf Software, Inc. 1994-1996
 | |
| //  All Rights Reserved
 | |
| //
 | |
| // CONTENTS
 | |
| //
 | |
| //  ALCreateVBString()
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release
 | |
| 
 | |
| #include "arclib.h"
 | |
| #if !defined( AL_IBM )
 | |
| #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #include "memstore.h"
 | |
| #include "_vbutil.h"
 | |
| 
 | |
| //
 | |
| // NAME
 | |
| //
 | |
| //  ALCreateVBString()
 | |
| //
 | |
| // PLATFORMS/ENVIRONMENTS
 | |
| //
 | |
| //  Windows
 | |
| //  C++
 | |
| //
 | |
| // SHORT DESCRIPTION
 | |
| //
 | |
| //  Create a Visual Basic string object using the VB environment.
 | |
| //
 | |
| // C++ SYNOPSIS
 | |
| //
 | |
| //  #include "arclib.h"
 | |
| //
 | |
| //  extern "C" long _far _pascal
 | |
| //  ALCreateVBString( const char _far *string, unsigned short int l );
 | |
| //
 | |
| // C SYNOPSIS
 | |
| //
 | |
| //  This function is only used internally by the library C++ code.
 | |
| //
 | |
| // VB SYNOPSIS
 | |
| //
 | |
| //  This function is only used internally by the library C++ code.
 | |
| //
 | |
| // DELPHI SYNOPSIS
 | |
| //
 | |
| //  This function is only used internally by the library C++ code.
 | |
| //
 | |
| // ARGUMENTS
 | |
| //
 | |
| //  string  : A standard C character array that is going to be returned to
 | |
| //            a Visual Basic calling routine.
 | |
| //
 | |
| //  l       : The length of the array.  Admittedly, it would be
 | |
| //            pretty easy to figure that out here, but this routine
 | |
| //            is replacing an assembly routine that didn't know
 | |
| //            how to do it.  And besides, I like being able to pass
 | |
| //            binary data, which might not work with strlen().
 | |
| //
 | |
| // DESCRIPTION
 | |
| //
 | |
| //  If you poke around inside Microsoft's VB CDK, you will see that the
 | |
| //  actual code to create a VB string can be replaced by a function
 | |
| //  that does this:
 | |
| //
 | |
| //       mov  bx,50
 | |
| //       jmp  dword ptr ss:[20]
 | |
| //
 | |
| //  Originally, ArchiveLib created VB strings using an assembly language
 | |
| //  routine that looked just like this.  However, I didn't want everyone
 | |
| //  to have to pay the price of having an assembler just to support two
 | |
| //  lines of code.
 | |
| //
 | |
| //  Replacing this with in line assembly looked doable.  The big problem
 | |
| //  is that the VB routine located at ss:[20] expects the stack to
 | |
| //  be in just the right configuration when you call it, and that isn't
 | |
| //  always easy to accomplish in the middle of a C routine.  What makes
 | |
| //  it really difficult is that the VB guy is going to return by way of
 | |
| //  a far return.
 | |
| //
 | |
| //  Writing the assembly code to accomplish this wasn't so bad.  Using
 | |
| //  Microsoft's inline assembly it was fairly easy to make it happen.
 | |
| //  Unfortunately, Borland's assembler couldn't handle calls to local
 | |
| //  labels, and Symantec's couldn't handle calls or jumps to local labels.
 | |
| //  In both cases, you could work around this by inserting the correct
 | |
| //  bytes.
 | |
| //
 | |
| //  This was nothing compared to Watcom.  They don't even support in
 | |
| //  line assembly.  When I asked them about this, one of their developers
 | |
| //  got real snotty and pointed out that the C++ spec only requires that
 | |
| //  the asm statements pass through the compiler without generating
 | |
| //  any errors, they don't actually have to do anything.  That attitude
 | |
| //  might explain Watcom's current position in the C++ market.
 | |
| //
 | |
| //  Anyway, to make Watcom work you have to create this strange pragma,
 | |
| //  which I did, out of the goodness of my heart.  It would have been
 | |
| //  more satisfying to just not support them.
 | |
| //
 | |
| // RETURNS
 | |
| //
 | |
| //  A Visual Basic string thingy.  I'm not even sure what it is, a pointer,
 | |
| //  a handle, and index or what.  VB knows.
 | |
| //
 | |
| // EXAMPLE
 | |
| //
 | |
| // SEE ALSO
 | |
| //
 | |
| // REVISION HISTORY
 | |
| //
 | |
| //   February 14, 1996  2.0A : New release
 | |
| //
 | |
| 
 | |
| //
 | |
| // If watcom, we do it this way, everyone else is different.
 | |
| //
 | |
| #if defined( AL_WATCOM )
 | |
| 
 | |
| long call_vb( unsigned short int, unsigned short int, unsigned short int );
 | |
| #pragma aux call_vb =  \
 | |
|     0x0cc \
 | |
|     "push ax"                           \
 | |
|     "push bx"                           \
 | |
|     "push cx"                           \
 | |
|     "mov bx,50h"                        \
 | |
|     "push cs"                           \
 | |
|     0x0e8 0x02 0x00                     \
 | |
|     0x0eb 0x05                          \
 | |
|     0x36 0x0ff 0x2e 0x20 0x00           \
 | |
|     parm [ax] [bx] [cx]                 \
 | |
|     modify [ax bx cx dx si di]
 | |
| 
 | |
| extern "C" long _far _pascal
 | |
| ALCreateVBString( char *string,
 | |
|                   unsigned short int l )
 | |
| {
 | |
|     long result =
 | |
|             call_vb( (unsigned short int) (((long) string ) >> 16 ),
 | |
|                     (unsigned short int) (((long) string) & 0xffff),
 | |
|                     l );
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| #else // #if defined( AL_WATCOM )
 | |
| 
 | |
| //
 | |
| // I think this here just to make some error messages go away.
 | |
| //
 | |
| #if defined( AL_MICROSOFT )
 | |
| #pragma optimize( "", off )
 | |
| #endif
 | |
| 
 | |
| extern "C" long _far _pascal
 | |
| ALCreateVBString( const char _far *string, /* Tag protected function */
 | |
|                   unsigned short int l )
 | |
| {
 | |
|     unsigned short int string_seg = (unsigned short int) (((long) string ) >> 16 );
 | |
|     unsigned short int string_off = (unsigned short int) (((long) string) & 0xffff);
 | |
|     unsigned short int result_seg;
 | |
|     unsigned short int result_off;
 | |
| //
 | |
| // The VB routine we jump to is going to return to me with a far call,
 | |
| // so after setting the arguments up on the stack, I do a push CS before
 | |
| // a local call.  At that point the stack is set up perfectly, and I
 | |
| // can jump to the VB guy.
 | |
| //
 | |
|     _asm {
 | |
|          push  string_seg;
 | |
|          push  string_off;
 | |
|          push  l;
 | |
|          mov   bx, 0x50;
 | |
|          push  cs      //This makes my near call look like a far call
 | |
| //
 | |
| //  What you see next is three different ways of making the same
 | |
| //  four lines of ASM code work.
 | |
| //
 | |
| #if defined( AL_SYMANTEC )
 | |
|          db 0e8H
 | |
|          db 02H
 | |
|          db 00H
 | |
|          db 0ebh
 | |
|          db 05H
 | |
|          db 36H
 | |
|          db 0ffH
 | |
|          db 2eH
 | |
|          db 20H
 | |
|          db 00H
 | |
| #elif defined( AL_BORLAND )
 | |
|          db 0x0e8, 0x02, 0x00;
 | |
|          db 0xeb, 0x05;
 | |
|          jmp dword ptr ss:[0x20];
 | |
| #else
 | |
|          call  do_vb
 | |
|          jmp done
 | |
| do_vb:   jmp dword ptr ss:[0x20];
 | |
| done:
 | |
| #endif
 | |
|          mov result_seg, dx;
 | |
|          mov result_off, ax;
 | |
|     }
 | |
|     return ( (long) result_seg << 16 ) + result_off;
 | |
| }
 | |
| 
 | |
| #endif // #if defined( AL_WATCOM )
 | |
| 
 |