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 )
|
|
|