Category : BASIC Source Code
Archive   : QBFAQR01.ZIP
Filename : MIXLANG.DOC
From: HOWARD MENCHER
Subj: MIXED LANGUAGE PROG -1-
---------------------------------------------------------------------------
Subj: MIXED LANG PROG PART 1
---------------------------------------------------------------------------
--The following is a list of the versions needed for these routines:
BASIC BASCOM 6.00+ QB 4.00+
QUICK C 1.0 OR C 5.0
--Some rules to follow:
1. Use the same math package for both languages (for example using the alt-
ernate math package in BASCOM 6.00 requires the use of the alternate math
package in C5.1).
2. Compile the C, FORTRAN, PASCAL, or MASM routine in the medium or large
memory model.
3. The BASIC .OBJ file must be the first .OBJ in the LINK command.
4. LINK with the /NOE option.
5. Use the /NOD LINK option when using specific component libraries; these
libraries must be specified on the library LINK line.
6. Use the /NOI LINK option when using routines of the same name, but in
different cases (e.g. upper case vs. lower case- ASUB vs. aSub).
7. When passing a BASIC string descriptor to a routine DON'T try extending
its length - a "String Space Corrupt" error will be received.
8. Both C and BASIC graphics can't be used at the same time; if your C
libraries were built with graphics included, you will need to rebuild
them or else multiple definition errors will occur.
9. Simplified segment directives are used in MASM, this is why MASM 5.00 is
needed.
--To use the executable (.EXE) program in CodeView:
1. Compile both BASIC and C, FORTRAN, MASM or PASCAL programs with the /ZI
option.
2. LINK with the /CO option.
Passing a FIXED LENGTH string to C by NEAR REFERENCE: BAS7.BAS/ C7.C
DECLARE SUB StringNear CDECL (_
BYVAL p1o AS INTEGER,_
SEG p3 AS INTEGER)
CLS
DIM a AS STRING * 15
a = "This is a test" + CHR$(0)
CALL StringNear(VARPTR(a), LEN(a))
END
#include
void StringNear(a,len)
char near *a;
int *len;
{
int i;
printf("The string is : %s \n\n",a);
printf(" Index Value Character\n");
for (i=0;i < *len; i++)
{
printf(" %2d %3d %c\n",i,a[i],a[i]);
};
}
<<<<< END PART 1 >>>>>
---------------------------------------------------------------------------
Subj: MIXED LANG PROG PART 2 Conf: (11) QBASIC
---------------------------------------------------------------------------
Passing FIXED LENGTH String to C by FAR REFERENCE
DECLARE SUB StringFar CDECL (_
BYVAL p1o AS INTEGER,_
BYVAL p1s AS INTEGER,_
SEG p3 AS INTEGER)
CLS
DIM array AS STRING * 15
a = "This is a test" + CHR$(0)
CALL StringFar(VARPTR(a), VARSEG(a), LEN(a))
END
#include
void StringFar(a,len)
char far *a;
int *len;
{
int i;
printf("The string is : %s \n\n",array);
printf(" Index Value Character\n");
for (i=0;i < *len; i++)
{
printf(" %2d %3d %c\n",i,a[i],a[i]);
};
}
Passing an arrray of VARIABLE LENGTH STRINGS: BAS15.BAS/ C15.C
DECLARE SUB StringArray CDECL (_
BYVAL p1o AS INTEGER,_
BYVAL p2s AS INTEGER)
CLS
DIM array$(10)
FOR i = 0 TO 10
array$(i) = STRING$(9, 65 + i) + CHR$(0)
NEXT i
CALL StringArray(VARPTR(array$(0)), VARSEG(array$(0)))
END
#include
struct struct_string{ /* structure that looks like a */
int length; /* string descriptor */
char *address;
};
void StringArray(string)
struct struct_string far *string;
{
int i;
printf(" Index Length String\n");
for (i=0;i < 10; i++)
{
printf(" %2d %3d %s\n",i,string->length,
string->address);
string++;
};
}
---------------------------------------------------------------------------
Subj: MIXED LANG PROG PART 3 Conf: (11) QBASIC
---------------------------------------------------------------------------
Passing an array of FIXED LENGTH STRINGS to C
DECLARE SUB StringFar CDECL (_
length%,_
num%,_
BYVAL p3o AS INTEGER,_
BYVAL p3s AS INTEGER)
CLS
DIM array(10) AS STRING * 10
length% = 10
num% = 3
FOR i = 0 TO 10
array(i) = STRING$(9, 65 + i) + CHR$(0)
NEXT i
CALL StringFar(length%, num%, VARPTR(array(0)),_
VARSEG(array(0)))
END
#include
void StringFar(len,num,array)
int *len;
int *num;
char far *array;
{
int i;
printf("The string length is : %d \n\n",*len);
printf("The number of elements is : %d \n\n",*num);
printf(" Index String\n");
for (i=0;i < *num; i++)
{
printf(" %2d %s\n",i,array);
array=array+*len;
};
}
---------------------------------------------------------------------------
Subj: MIXED LANG PROG PART 4 Conf: (11) QBASIC
---------------------------------------------------------------------------
Passing an array of USER DEFINED TYPES to C
TYPE record
a AS INTEGER
b AS STRING * 20
c AS SINGLE
END TYPE
DECLARE SUB TypeArray CDECL (_
BYVAL p1o AS INTEGER,_
BYVAL p1s AS INTEGER)
CLS
DIM element(10) AS record
FOR I = 0 TO 10
element(I).a = 128 + I
element(I).b = STR$(I) + ". " + DATE$ + CHR$(0)
element(I).c = 39.6 * I
NEXT I
CALL TypeArray(VARPTR(element(0)), VARSEG(element(0)))
END
#include
struct record{
int a;
char b[20];
float c;
};
void TypeArray(element)
struct record far *element;
{
int i;
for (i=0;i<3;i++)
{
printf("Record[%d].A = %d\n",i,element->a);
printf("Record[%d].B = %s\n",i,element->b);
printf("Record[%d].C = %f\n",i,element->c);
printf("\n");
element++;
};
}
---------------------------------------------------------------------------
Subj: MIXED LANG PROG PART 5 Conf: (11) QBASIC
---------------------------------------------------------------------------
Passing BASIC 2-D array of VARIABLE LENGTH STRINGS
DECLARE SUB TwoStringArray CDECL (_
BYVAL p1o AS INTEGER,_
BYVAL p1s AS INTEGER)
CLS
DIM array$(4, 4)
FOR i = 0 TO 4
FOR j = 0 TO 4
array$(i, j) = STRING$(5, 65 + (i + j)) + CHR$(0)
NEXT j
NEXT i
CALL TwoStringArray(VARPTR(array$(0, 0)),_
VARSEG(array$(0, 0)))
END
#include
struct struct_string{
int length;
char *address;
};
struct string_array{
struct struct_string x[5][5];
};
void TwoStringArray(array)
struct string_array far *array;
{
int i,j;
for (i=0;i < 5; i++)
{
for(j=0;j<5;j++)
{
printf(" %s ",array->x[i][j].address);
};
printf("\n");
};
}
<<<< CONTINUED >>>>
---------------------------------------------------------------------------
Subj: MIXED LANG PROG 8 Conf: (11) QBASIC
---------------------------------------------------------------------------
/***************************************************************************
* This example program should give you some help if you are trying to call
* routines written for QuickBasic from C. In the process of converting
* many of our QB stuff to C, we found that we didn't want to "give up" the
* nice QB libraries we had.
*
* The problem is, the QB4 manual has some GROSS errors in it concerning
* calling QB stuff from C. The example on page 310 (passing strings from
* C to QB) is wrong. It should read:
*
* char cstr [] = "ABC";
* struct dodo {
* int sd_len; /* THESE ARE REVERSED IN MANUAL! */
* char near *sd_addr; /* MUST DEFINE AS NEAR! */
* } near str_des; /* best to define as near */
*
* (Page 307 clearly shows that the 2 byte length comes FIRST and the 2
* byte address comes second - ever wonder if MS tests their examples?
* Obviously they didn't in this case!)
*
*
* Rather than going through all the ins-n-outs of why, (because frankly,
* I'm not sure in some cases) I thought I'd simply provide a copy of a
* program we wrote to call a routine written for QB. Note that the routine
* is an Assembler routine WRITTEN FOR QB (i.e. it isn't written in QB).
* This really doesn't make any difference, but it just lets you know that
* if you have a bunch of commercial QB libraries, you should be able to use
* them with C.
*
* The routine we are calling is called CRC. It's purpose is to calculate
* a CRC on a record. (Thanks to Tom Hanlin and Wayne Hammerly of Hammerly
* computers for providing this great routine for QB programmers!) In
* QB you would call it as:
*
* CALL CRC(STRING$,HICRC%,LOCRC%)
*
* The string is what you pass to the subroutine, and the HICRC and LOCRC are
* integers returned to you. We basically want to do the same thing from C.
* The calling sequence in C is:
*
* crc(&str_des,&hicrc,&locrc);
*
* Note that you have to set the C program up to handle all this as shown in
* the program.
*
* By the way, this program was compiled under large model and worked fine.
* The only thing we wanted to do later was pass a string which had been
* malloc'ed. This meant that it was no longer a NEAR string and could not
* possibly be NEAR (i.e. defined within the function itself.) We had to
* actually modify the assembler source to get this working since near stuff
* passes only a two byte address (which is what QB routines expect.) So,
* make SURE you define everything you are going to passing to QB routines
* as NEAR or use medium or small model (where everything is near by default.)
*
* I am sorry that I could NOT include the CRC.OBJ module with this file.
* I didn't because I didn't write it and it belongs to Tom Hanlin and Wayne
* Hammerly. But, chances are, if you're reading this you are aware of the
* ADVBAS series for QB. You can simply use the CRC module found in that
* library. If you don't have ADVBAS (library for QB) I suggest you download
* it from CompuServe or any of the thousands of BBS's which have it. By
* the way, PROBAS (the commercial version of ADVBAS) also has CRC in it.
* (Actually, I used CRC2 from PROBAS which is faster because it does a
* table lookup for CRC. CRC2 called from my C program is lightning fast!)
*
* By the way, I've only been coding in C for about 8 days now so if you see
* any gross inefficiency or my explanation isn't correct "to the letter"
* please forgive me. But, I'm sure there are a lot of QB/C programmers out
* there who will find this information useful regardless of any small
* inaccuracies there may be in the explanation.
*
* Jim Kloss
* Nochange Software - Home of "XChange" Unattended File Transfer
* 540 Silver Pine Trail
* Roswell, GA 30076-3323
* (404)587-3815 voice
* (404)641-8270 data
****************************************************************************/
---------------------------------------------------------------------------
Subj: MIXED LANG PROG PART 9 Conf: (11) QBASIC
---------------------------------------------------------------------------
#include
#include
/***************************************************************************
* The format for the routine is CRC2(STRING$,HICRC%,LOCRC%) where we pass
* it the STRING$ and it returns the HICRC% and LOCRC%. Note that we must
* define the routine as 'fortran' (or 'pascal') to tell C that the
* parameters are put onto the stack in the exact opposite order that it
* normally puts them on. (No, there is not a 'basic' that I know of...)
* The following statement is required to tell C about the QB function. It
* is a prototype really and defines the kinds of variables you will be
* sending and receiving.
****************************************************************************/
extern void fortran crc2(struct dodo near *,int near *, int near *);
/***************************************************************************
* Everything must be declared NEAR which basic is going to work with since
* it must work in the default data segment.
****************************************************************************/
struct dodo {
unsigned int sd_len;
unsigned char near *sd_addr;
} near str_des;
/***************************************************************************
* Main Program.
****************************************************************************/
void main()
{
char temp[200];
unsigned hicrc,locrc;
strcpy(temp,"This is a test."); /* results should be 236 and 29 as hi/lo *
str_des.sd_addr = temp;
str_des.sd_len = strlen(temp);
hicrc=locrc=0;
printf("%u is the hicrc and %u is the locrc before call on %s\n",hicrc,locrc
crc(&str_des,&hicrc,&locrc);
printf("%u is the hicrc and %u is the locrc after call on %s\n",hicrc,locrc,
printf("If everything worked right, the results should be 236 and 29!");
}
HOWIE
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/