campo-sirio/al/cpp_vb/vbutil.cpp
alex 714dd74636 Archive Library versione 2.00
git-svn-id: svn://10.65.10.50/trunk@5350 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-10-09 16:09:54 +00:00

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 )