Click here to visit our sponsor

Contents


Project news

Site news


    The QB.Scene and the QB Times have merged! NightWolf (from the Programming Oasis) & Jorden (from Future Software) are now co-operating on the magazine, which means you'll get the best of both worlds.

    V Planet! Quickbasic Magazine V Planet! is starting the QB Expo soon. The QB Expo will be a chance for QB programmers of all skill levels to show off their newest material. It's still in the planning-stages, so nothing is sure yet.

    Welcome to the QB Cult Magazine! It looks like 2000 is becoming the year of QB Magazines! After the amazing popularity of QBasic: The Magazine, we've had QB Times, QB On Acid, QB.Scene, QBSI and now the QB Cult magazine! It's got a little news but a ton of tutorials. Take a look at it by clicking the link that will take you to Xybertech.


Transforming text Do you want to transform your text? Here are a few tips to modify your text to any kind of form ! The screen mode I used is screen 9. It is a 640 x 350 screen mode. The first you should have to do is to save the text in a matrix, like the following example : ' text$ is the text to save DIM txtmatrix(LEN(textin$) * 9, 13) ' we must dim the matrix to keep it in memory LOCATE 1, 1: PRINT text$ ' the text is printed on the screen so that it can be saved. If the text you want to save ' is already there, you can remove this line ! FOR i = 0 TO LEN(textin$) * 8 ' in screen 9, the characters width is 8 FOR j = 1 TO 13 ' in screen 9, the characters height is a little less than 13, 'but if the text is 'already modified (with underlining, for example), the best thing to do is to reserve 'more memory for the matrix txtmatrix(i, j) = POINT(i, j) ' here is the way to save each dot of the text in the matrix. NEXT j, i Now that your text is saved, you can modify it ! For example, to flip the text horizontaly, add this code after saving the text matrix : FOR i = 630 TO 630 - (LEN(textin$) * 8) STEP -1 ' we must start from the right of the screen (640*350 in screen 9) FOR j = 1 TO 13 IF txtmatrix((630 - i), j) <> 0 THEN PSET (i, j), txtmatrix((630 - i), j) ' I add the test because on slow computers, the program printed the black dots too and it ' was a waste of time ! NEXT j, i To flip the text vertically, you can draw a separation line using this line of code : LINE (0, 14)-(LEN(textin$) * 8, 14) To flip the text, that's the same sub as previously but now J is reversed, not I. So you must use that sub : FOR i = 1 TO LEN(textin$) * 8 FOR j = 14 TO 1 STEP -1 IF txtmatrix(i, 14 - j) <> 0 THEN PSET (i, j + 14), txtmatrix(i, 14 - j) NEXT j, i And if you want to create a nice effect on the vertical flipping, transform the third line of code to the following : IF txtmatrix(i, 14 - j) <> 0 THEN PSET (i + j, j + 14), txtmatrix(i, 14 - j) so that the text is inclined. Using it, you can make an italic font, but without reversing. There are many different ways to transform a text : you can apply a font, you can do anything. If you want more examples, check out my site at http://maxxsoftware.50megs.com or download EFFECTS.BAS from the GFX section on Future Software Website. Thanx for reading this article and I hope I explained it correctly ! (if you didn't, feel free to email me! -By Maxx -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- U S I N G T H E M O D E M I N Q B A S I C Written by: Matthew River Knight of HORIZONS Interactive Entertainment -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- The modem has probably been the most influential computing device that has yet been created. Its creation has resulted in a complete change in the world of business and advertising, has resulted in cheaper and more efficient international communication, and last, but certainly not least, has had a huge impact on both the computer professional and the hobbyist. To most, the modem is a little magic box that opens our computer to the world. In reality, it is very simple to use, and more importantly, to program. The modem takes bytes of data, turns it into a noise, and sends it over the phone line. Theoretically, if you could whistle fast enough and at the right pitches, you could send a file with the sounds you make. Basically, the computer sends a file over the modem like this: the modem sends an ASCII character to tell the other computer it is sending a file. It then breaks up that file into chunks and sends it in chunks of bytes. The modem then waits for an ASCII character from the other computer telling it that all is well, and to send the next chunk. That is all very interesting, you say, but how do I do it in Qbasic? Well, that is very simple. There are just 4 commands you are going to need to do some modem communications! They are as follows: OPEN COM.........Open up the modem for use by Qbasic. INPUT$...........Get data from the modem. LOC..............Tells you if the modem has any data from an outside source. PRINT #..........Send data to the modem. To start work with the modem, you have to open a "path" to it. This is just like opening a file, except you use the "OPEN COM" statement. Here is a sample: OPEN "COM2:2400,N,8,1,RB2048,TB2048" FOR RANDOM AS #1 Now, you wonder what that all means, but it really is quite simple, you just must remember this little secret: opened devices (like the modem) act just like opened files! Now back to the example code above. I know it looks confusing at first, but dont worry, the only thing you need to concern your- self with is the number between "COM" and ":" and the number between ":" and ",N". All the other stuff deals with transmition settings and the RB TB things deal with uploading and downloading. The first value is the COM port number that your modem is on. Because Qbasic was made a long time ago, you only have access to ports 1 and 2. If your modem is on another port, dont worry, there is a way around that which involves switching the memory addresses on the COM ports. Dont worry about that now though, I'll go into that in another article some time. The 2nd number is the Baud. BAUD is the speed of the modem. Qbasic cant access COM ports at any higher speed than 9600, so if you have a 56K modem, Qbasic can still use it, but it wont go any faster than 9600. Dont worry about this too much though, I am busy writing a library that gives you access to the modem at any speed. To send data to your modem you use the PRINT #n statement, where n is the file number (in the example, 1.) But there is no point sending stuff like "Hello world" to your modem right now, because you are not connected to anything. All you have done with the "OPEN COM" statement, is made a path from your modem to your program so they can talk to each other. Hmmm, this is quite a problem. So how do we get connected to something then? Well, when you want your modem to talk to an outside source, like a BBS, you have to tell the modem to dial a number. To do this you must know that all modems have a set of commands eched in their read-only-memory chips that allow them to do different things. You cant just say "Hey modem, dial 555-314-545", you gotta talk in the modems lingo! This is alot easier than it sounds. All of these commands begin with "AT". Here are the most used ones: -------------------------------------------------------------------------- MODEM LANGUAGE | TRANSLATION TO ENGLISH -------------------------------------------------------------------------- "ATDT###-###-####" | "Hey modem, dial ###-###-####" "ATZ" | "Hang up the phone!" "ATS0=#" | "Wait until you someone calls and the phone rings | # number of times, then try to connect modems." "ATM2H1L#" | "Set your speaker volume at # (1-3)" -------------------------------------------------------------------------- So, if you wanted to call someone with the modem, you would first use an OPEN COM statement, to get the path between your modem and your prog set up, then you would use an INPUT statement to get the phone number to dial as a string, then use PRINT #n to talk to the modem. I think now is a pretty good time for an example! Here is a simple phone dialer: (Replace COM# with the COM port your modem is on.) CLS PRINT "Openning a path to your modem..." OPEN "COM2:2400,N,8,1,RB7048,TB7048" FOR RANDOM AS #1 PRINT "Please enter the phone number you wish to call" INPUT PhoneNumber$ PRINT "Talking to your modem..." PRINT #1, "ATDT"; PhoneNumber$ PRINT "There you go, pick up the phone and talk!" PRINT "Press the ESC key to hang up!" DO LOOP UNTIL INKEY$ = CHR$(27) PRINT #1, "ATZ" Now that wasnt so hard was it? But here comes the biggest problem of modem control in Qbasic, HOW DO I READ WHAT COMES FROM THE MODEM? Well there is a little function called LOC that does this. The syntax is: LOC(n) where n is the file number, which if you used my sample, would be 1. LOC tells you where in a file you are. File? But I am trying to access the modem! As I said before, files and devices work the same way. But with a modem, LOC tells if it has received anything. Fine, now you know if the modem is getting stuff, but how do you know what it is getting? For that you use the INPUT$(x,y) statement. x is the number of bytes to get from a file/device and y is the number of the opened file/device. x should ALWAYS be 1. I know this means that only 1 character can be read on each pass, but this way EVERY character is read, and none are skipped. If you were getting an 11 byte transmittion, and x was 2, only the first 10 characters would be read (because it is a multiple of 2.) The last part would be skipped. This is the way for NORMAL communications. Keep x as 1! There is just one more modem command to talk about, namely, the "ATSO=#" command, which you use to wait for a call. But I think it is best explained with an example. Oh, what the heck, lets just put everything we have learned here together into a fully commented communications program. You can use this to call up any BBS and interact with it. Note that it has no uploading or downloading capabilities, though. I will have to cover this, along with some other stuff, in another tutorial some time. CLS PRINT "HORIZONS Interactive Entertainment - BasHack v1." PRINT "What COM port does your modem use?" INPUT ">", port$ baud$ = "9600" '9600 should work fine with most modems. If you have 'an older one use 2400. 'Open up that com port. OPEN "COM" + port$ + ":" + baud$ + ",N,8,1,RB2048,TB2048" FOR RANDOM AS #1 PRINT "OPTIONS:" PRINT "1-Dial up to another computer" PRINT "2-Wait for a call" PRINT "3-Quit" DO a = VAL(INKEY$) LOOP UNTIL a >= 1 AND a <= 3 IF a = 3 THEN CLOSE : SYSTEM IF a = 2 THEN GOTO wait PRINT "Number to call?" INPUT ">", number$ PRINT #1, "ATDT" + number 'Tell the modem to dail the number. GOTO chat wait: PRINT #1, "ATS0=1" 'Tell modem to conect after 1 ring. 'When a modem connects it returns "CONNECT ####" 'The next hunk of code waits until the modem connects before moving on a$ = "" DO IF LOC(1) THEN a$ = a$ + INPUT$(1, 1) 'if anything in modem add it to a$ LOOP UNTIL INSTR(a$, "CONNECT") 'Wait until modem have connected. chat: 'If you where waiting for a call, alot of ASCII characters will be printed 'on the screen. Dont worry, that just the computers getting in sync and 'talking. You also will not see what you type. CLS PRINT "You are now ready to chat, press ESC to quit." DO t$ = INKEY$ IF LEN(t$) THEN PRINT #1, t$ 'if you typed something send it to the modem 'this will be send by the modem to the other 'computer IF LOC(1) THEN r$ = INPUT$(1, 1)'if the is something to get, get it and save 'it as r$ IF LEN(r$) THEN PRINT r$; 'if r$ <> "" then print it. the ";" means a 'line is not started LOOP UNTIL t$ = CHR$(27) 'keep doing this until ESC is pressed PRINT #1, "ATZ" 'tell the modem to hang up CLOSE 'close the open com statment And thats it! Simple huh? Now you have a cool program that you can use to talk with your friends over the modem in Qbasic! Before I leave you to experiment with your newly aquired knowledge, I would like to extend my thanks to the following people who have helped me some way along the line with my programming in general: LordAcidus, Petter Holmberg, Tek, ZKman, and last but not least, Christian Garms. You guys have helped me alot. Happy hacking everyone! ASM part 3 by abionnnn -learn asm in 1 hour flat Lesson no.6 8-bit registers =========================== There are alot of stuff I left out in the last issue for the sake of simplicisty. I've also done a complentary tutorial included called "segments tutorial". These are some of the registers and their uses. 8-bit registers are simple to understand. Let take a small look, remeber you don't have to get what all these mean yet, just browse through them, we'll get back to them later on. First I'd like you to pay attention to the first three Register Use ======== ==== AX Calculation and Main register |__AL Low byte and Int function index (Lower AX) 8-bit register |__AH High byte (Higher AX) 8-bit register BX Calculation and basic Pointer |__BL Lower bit (Lower BX) 8-bit register |__BH High bit (Higher BX) 8-bit register CX Calculation and counter |__CL Lower bit (Lower CX) 8-bit register |__CH High bit (Higher CX) 8-bit register DX Calculation and Data |__DL Lower bit (Lower DX) 8-bit register |__DH High bit (Higher DX) 8-bit register SI Pointer DI Another pointer BP "Byte Pointer" mainly used to access stack and preform data movement SP "Stack Pointer" Points to first byte to the stack IP Code pointer points to current byte of code CS "Code Segment" Points to segment of current code cannot be changed, and even if it can would crash your system. DS "Data Segment" Points to segment of data area ES Extra segment, for use in misc. function FS Same as above GS Same as above We all know what is AX and how AX is used. We all also know it's a 16-bit register (like an integer). But what in a blue moon is AL and AH? Quite simple, really. AH and AL are respectably the higher and lower bytes of AX. Here's an example: AX=1004 in binary AX= 0 0 0 0 0 0 1 1 1 1 1 0 1 1 0 0 | | | | | | | | | | | | | | | | \-------------/ \-------------/ Higher Byte Lower Byte Well we have a number in AX (1004), when writen in binary it equals 0000001111101100. But what if we split it into two bytes? One we'll call the Higher Byte AH and we'll call the Lower Bit AL. So, if AX=1004 then, AX= 0 0 0 0 0 0 1 1 1 1 1 0 1 1 0 0 | | | | | | | | | | | | | | | | \-------------/ \-------------/ Higher Byte Lower Byte = AH = AL AH = 00000011 = 3 AL = 11101100 = 236 It is also interesting to know that thanks to AH and AL, you could manipulate AX in many ways. Here's a formula you really might find handy: AX=AH*256+AL Now that you know how AX, AL and AH behave, I can safely tell you that (as you have probably assumed) this counts to BX, CX and DX as well. Lesson no.8 Segment Registers and memory ======================================== It is very important to know your Segment registers. The ones you'll often see are CS, DS and ES. These are used almost all the time to access parts of the memory. You can't address a segment practically without using a segment register. The disadvantages of these Registers though is that they are rather slow, and you can't address them an immediate value. = ( There are techniques around this for example: mov ax,segment mov ds,ax You can use segments to address parts of the memory, much like POKE and PEEK. But you also need an offset (if you have'nt already,which you should by now, read the segment tutorial). To use an offset is rather simple, you can put your offset in di,si,bx or dx (which ever one picks your fancy) and you put square brackets around it. That is practically an offset pointer. Here's an example: MOV BX,140h ;Offset MOV AX,3h ;Value to poke MOV [BX],AL ;why AL? because we only want to poke 1 byte (8-bit) This basically goes pokes 3 into the memory location 140h. But what segment you might ask? As QB has DEF SEG to address the default data segment, your processor uses the DS register for that job. So really you are writing 3h to DS:0140. Here's an example using a diffrent segment. MOV BX,140h ;offset MOV AX,3h ;value to poke MOV CX,0A000h ;new segment MOV DS,CX ;our little trick to change the segment = ) MOV [BX],AL ;writes 3 to DS:BX This would write 3 to A000:0140. The same code could have been writen like this: MOV BX,140h ;offset MOV AX,3h ;value to poke MOV CX,0A000h ;new segment MOV DS,CX ;our little trick to change the segment = ) MOV DS:[BX],AL ;writes 3 to DS:BX Which specifies that we want to use DS as the segment. This just makes things look clearer, but is not needed as DS is the default data segment. But what if you don't want to use DS? maybe you want to use CS or ES... You'd simply do this: MOV BX,140h MOV AX,3h MOV CX,0A000h MOV ES,CX MOV ES:[BX],AL ;writes 3 to ES:BX ----------- Pretty simple is'nt it? Well, since you've loyally finished this course you will find the next one more interesting as we get into new and exciting opcodes. These should make your life easier. Also we might be getting on on how to make your own library. All that coming next month! -abionnnn ASM part 5 by abionnnn -learn asm in 1 hour flat Before I start, I'd like to make 2 correction to previous articals. *****Correction 1: In the segment tutorial I said 2 byte pointers for 32-bit, what I meant to say was 4 byte pointers. Thank god I picked it up while proof-reading it agian!***** *****Correction 2: In issue#2 I said retf to exit the program. I don't know what I was thinking, but I'm sorry if it crashed your computer. Infact if we meet one day, you can hit me over the head with a stick = P Use retn or better still function 4C like in issue#3***** Lesson no.7 Basics of The Stack =============================== Lets get on to something a little bit interesting and very important (and even more important if you want to make libraries). You might have read a bit about the "Stack". How the stack works is beyond the scope of this chapter, however I will teach you how to use and abuse it = P After coding a while, you'll probably think it gets pretty cramed with the small amount of registers you can use. It gets tacky and some times you might want to "backup" a value a register has. There is a way to do this and obviously it involves the stack or I would'nt be mentioning it (hehehe = P). The two fundimental commands to use the stack are: PUSH POP PUSH saves a value of a register (or a memory location but lets not get on to that yet) on the stack, and POP basically takes this value which was saved out of the stack and in the register. For example: MOV AX,3 ;Give AX a value of 3 PUSH AX ;PUSH AX (3) onto the stack MOV AX,5 ;Give AX a value of 5 POP AX ;POP AX off the stack Well, lets take this simple code step by step. First AX is given a value of 3: "MOV AX,3". Then AX is push on the stack: "PUSH AX", after this AX is given a value of 5: "MOV AX,5". To finish it all AX is pulled out of the stack: "POP AX". As you probably (or hopefully as my maths teacher used to say = )) have figured out AX ends up having a value of 3. The reason for this is PUSH AX, pushed the value of AX (which was 3 at the time) onto the stack then at the end, even after AX was given 5, POP AX pops 3 out of the stack and puts it into AX agian. Now, you might find this handy later on, but you don't have to give AX a register. You can also give it a immediate value! The above code could have been writen like this: PUSH 3 ;PUSH 3 on the stack MOV AX,5 ;Give AX a value of 5 POP AX ;POP AX off the stack Reading that, you'd relise it's not important what register you pop the value of the stack onto, infact you can re-write the code before the one above like this: MOV AX,3 ;Give AX a value of 3 PUSH AX ;PUSH AX (3) onto the stack MOV AX,5 ;Give AX a value of 5 POP DX ;POP DX off the stack MOV AX,DX ;Put the value of DX into AX So you pushed the value of AX, being 3, onto the stack and poped it out as DX! And at the end you moved DX into AX (MOV AX,DX). If you run that code, both AX and DX would end up being 3! As you'd realise the stack is very easy to use, but there is one more thing you have to learn. What if you want to push more than 1 register? Would you do something like this PUSH AX ;PUSH AX onto the stack PUSH BX ;PUSH BX onto the stack POP AX ;POP AX off the stack POP BX ;POP BX off the stack Sounds right does'nt it? We push AX, then BX then we POP AX then BX. Sad to say, but it does'nt work like this. Think of the stack, as a stack of papers. You put one paper labeled A on the floor and then put another paper labeled B down on the floor. When you go to pick up the one on the top you don't pick up A but you pick up B! Here's a simple diagram: First we PUSH AX (put AX on the stack) The Stack | | | | |===============| <-- AX |_______________| Then we PUSH BX (put BX on the stack) The Stack | | |===============| <-- BX |===============| <-- AX |_______________| What's at the top of the stack? BX! This is why you can PUSH one register and POP out another one, because the stack does'nt keep track of what you pushed and where you pushed it, it simply pops out the one on the top! If you are ever confused think of "first in last serve", but for now here is another example: MOV AX,3 ;Give AX a value of 3 MOV DX,5 ;Give DX a value of 5 PUSH AX ;PUSHs AX (3) on the stack PUSH DX ;PUSHs DX (5) on the stack ADD AX,DX ;ADDs DX into AX (3+5=8) PUSH AX ;PUSHs DX (8) on the stack POP CX ;POPs 8 off the stack and into CX POP DX ;POPs 5 off the stack and into DX POP AX ;POPs 3 off the stack and into AX So AX has a value of 3 and DX has a value of 5. We then push AX then DX onto the stack so it'll look like this: The Stack | | | | |===============| <-- DX (5) |===============| <-- AX (3) |_______________| When the add DX into AX which gives the value of 8. After this we push AX (which has the value of 8 now) onto the stack agian, so it should look like this: The Stack | | |===============| <-- AX (8) |===============| <-- DX (5) |===============| <-- AX (3) |_______________| The operations to flow are: POP CX ;POPs 8 off the stack and into CX POP DX ;POPs 5 off the stack and into DX POP AX ;POPs 3 off the stack and into AX When then pop out 8 and put it in CX, then pop 5 out for DX, and finnally 3 out for AX. So it's going to do this: The Stack | | |===============| <-- AX (8) ==> CX |===============| <-- DX (5) ==> DX |===============| <-- AX (3) ==> AX |_______________| So CX=8, DX=5 and AX=3. Pretty simple if taken step by step, and I promise this will be very very handy to you when you start programming biggies. Now, should I make another chapter? Should I? Ah what the heck, it's 1999 (is it? Don't tell me it's over already = P) so lets go have some fun! -=-=-=-=-=-=-=-=-=- Technicals: In a .com (Copy of Memory) file the stack in the memory actually begins at the last byte [of the 64K memory image] and rises by the occasion from there. Too much pushing (and I mean too much) without poping will gradually bring the stack ontop of the actual program trashing it with garbage. (BTW, this is something you don't want for anarchists out there ... heh heh heh) -=-=-=-=-=-=-=-=-=- Lesson no.8 Procedures 2 ======================== Now there are two ways of teaching this, one way is the assembler way and the other one is the debugger way (remeber Lesson 5, Diffrent approach). Each have their advantages (learning wise), so we'll use them both. Here's an example from Lesson 4 (edited because of retf ... hit me) 1E7D:0100 CALL 200 RETN ... 1E7D:0200 MOV AX,1 INT 33h RETN Well so we did'nt complicate things, I did'nt explain what the heck 1E7D was. Basically, 1E7D is the current segment the program resides. Now, we already know what CALL does (it's like a SUB) and retn (like END SUB) so in QB it would have looked like this: CALL asub EXIT SUB asub ... 'Show the mouse END SUB asub You would probably think that the way above there is quite messy. There is another way however, a diffrent approach. I'll be honest with you though, you'll end up with nearly exactly the same compiled code but the source code will look better. Lets look at the previous example in a diffrent way (and it gives me a chance to further explain the stack): .STACK 100h ;This gives us 256 (100h) bytes worth ;of stack space, where we can push and ;pop .CODE ;This is the code segment (CS) CALL showmouse ;CALL the procedure "showmouse" mov ax,4C00h ;the prefered way to exit a program int 21h ;Use the function 4C to exit showmouse PROC ;like saying SUB showmouse mov ax,1 ;Use function 1 int 33h ;of int 33h retn ;return showmouse ENDPROC Hey, this kinda looks like a .BAS file in a text editor eh? PROC is like SUB and ENDPROC is like END SUB. But remeber, you always have to have the retn at the end it's what gets you back to the main section. Without the retn, your program will most definatly crash, and if you got complex routines that mess with the hard drive to come, you can kiss your computer goodbye. I can't stress enough how important it is to return to the main code section because when you make libraries for QB, you'll probably want control back to your program, not what ever garbage is after your little routine. Now, on to a part which you've probably been waiting ages for. How to implement such functions in QB. It's all rather simple really, but it does require a linker and a library creator (which ussally come with QB) and a little bit of patience. Compiling and Linking can be a hassel sometimes, but there are make utilities out there to make life just that little bit easier so I suggest you grab one. First you'd make a assembler file which looks like this: .model medium,basic .stack 100h ;enough for us and BASIC .data ;Where you would place all your variables ;(explained later,data segment) .code ;the code segment begins here PUBLIC showmouse ;Declare "showmouse" to QB showmouse PROC ;Like SUB showmouse mov ax, 1 ;Function 1 of int 33h ;Int 33 ret ;Return to BASIC showmouse ENDP ;Like END SUB showmouse END ;END the whole thing Notice the PUBLIC up there? Well, that's needed for QB to access the procedure (showmouse) we've made. It's like DECLARE SUB if you think about it. Anyway, from here you'd compile the code as a .obj file then link as a .QLB file like this: C:\PROJECT\MOUSE>tasm32 mouse.asm mouse.obj Turbo Assembler Version 5.0 Copyright (c) 1988, 1996 Borland International Assembling file: mouse.asm Error messages: None Warning messages: None Passes: 1 C:\PROJECT\MOUSE>link /qu mouse.obj Microsoft (R) Overlay Linker Version 3.69 Copyright (C) Microsoft Corp 1983-1988. All rights reserved. Run File [MOUSE.QLB]: List File [NUL.MAP]: Libraries [.LIB]: bqlb45.lib TASM is used here, but any other compiler would do just fine, if it can generate .obj files (But I recommend the Borland TASM compiler). Now, you would load up QB using the library like so: QB /L mouse When inside QB, you'd make a statment like this: DECLARE SUB showmouse That's all there is to it! Well, not quite but we'll learn more later on! I hope your busting with ideas for stuff to put into QB! I'll be back next issue with stuff on linking ASM with QB. Hey that's what this whole thing is about is'nt it? = ) -abionnnn

Link to us




Credits


    EditorsRegular WritersSubmissions
    Jorden Chamid
    Nightwolf