Two .EXEs compiled in PBCC can communicate with each just great -- up to 1000 times per second, on my machine, in the case of SHARECC.BAS, as listed below.
But how about an .EXE compiled in PBDOS and an .EXE compiled in PBCC? As of Windows XP, and certainly for SHAREDOS.BAS as listed below, the answer is "not so hot". That's where I need your help.
Please correct the "Verbose Remarks" and the source code wherever you can; I will greatly appreciate it. And be sure to read the former if nothing seems to happen when you run one program or both in succession.
But how about an .EXE compiled in PBDOS and an .EXE compiled in PBCC? As of Windows XP, and certainly for SHAREDOS.BAS as listed below, the answer is "not so hot". That's where I need your help.
Please correct the "Verbose Remarks" and the source code wherever you can; I will greatly appreciate it. And be sure to read the former if nothing seems to happen when you run one program or both in succession.
Code:
'Verbose Remarks 'for ShareCC.BAS and ShareDOS.BAS 'by E.W. Menzel, Jr. (Emil Menzel) 'July 2009 'Freeware, placed in the Public Domain 'when posted to PB Forums, August 02, 2009 'The basic program structure used here for sharing was posted by John Gleason, in: 'http://powerbasic.com/support/pbforums/showthread.php?t=40334 'I revised his program a bit for my own purposes. 'Purpose: 'At a relatively general level of discussion, study "inter process communication" 'see e.g., http://en.wikipedia.org/wiki/Inter-process_communication ' and "exchange or sharing of data between two programs" [or operating systems, 'or computers]. 'At a relatively concrete level of discussion, 'Using as an example a game controller program, which demands high performance to be of much use, '1. Verify high performance sharing of info between 2 .EXE programs, both compiled in PBCC '2. Demonstrate the obvious relative "failures to communicate" (under Windows XP) if ' one of the .EXEs is compiled in PBDOS rather than PBCC. '3. Attempt to get the most speedy communication possible between a DOS .EXE & ' a WIN .EXE. But that is a job on which I need advice from the PB gurus. 'Depending on how well we do on #3, we should be able to exploit PCCC (from PBDOS) 'to do many things we could not do otherwise. 'P.S. Before you say that a DOS program and a Windows program cannot share information at the 'speed required for the present program, think again. There are already such Windows programs 'that do the job just fine on my PBDOS programs -- 'e.g., the shareware program "Total game controller" 'So if they can do it, why not PB programmers? 'Instructions: 'In Windows XP (or NT or higher), '1. Compile ShareCC.BAS IN PBCC '2. Make an additional copy of the .EXE, e.g., naming it ShareCC2.EXE ' (Alternatively, you could simply run ShareCC.EXE twice, in step 4.) '3. Press Ctrl-Alt-Del to call up Windows Task Manager. ' In Windows Task Manager, click Processes/CPU, then CPU once more ' Watch which processes will use the most CPU in step 4 '4. Start up one .EXE, then the other .EXE 'The first program should do nothing until the second one is started. 'After #2 starts, both programs should finish very shortly. Obviously, they are sharing data. 'If you use SLEEP 0, or no SLEEP statement, just before the ITERATE DO statement, 'the programs will use up to 100% of the CPU. SLEEP 10 drops that figure (and overall 'speed) drastically. '5. Now make a copy of ShareCC.BAS, naming it (e.g.) ShareDOS.BAS 'Revise it to your own needs 'Compile it in PBDOS. Some changes will be necessary -- 'Cf SUB Sleeper vs SLEEP. BASE 0 rather than 1 for SEEK. See also the Footnote, below. 'A sample ShareDOS.BAS is provided 'After compiling, run first SHARECC.EXE & then SHAREDOS.EXE 'Wait -- it might be several minutes before anything happens '(If file c:\shar.DTA exists & is 70 bytes long & contains the words "HiHAL.Wav", something has happened) 'The action will be much faster if you get the Windows Focus back on SHARECC.EXE ' When 2 PBDOS .EXE's are run, or when 1 PBDOS & 1 PBCC .EXE are run, ' sharing can still occur, but it will be at a much slower pace (in Windows XP). ' CPU usage jumps up to almost 100%, and can be hogged almost entirely by Microsoft ' ntvdm.exe, i.e., Virtual DOS for Windows NT & higher. It seems safe to stop ntvdm.exe from ' the Windows Manager. (It will reappear the next time you run a DOS program.) But stopping ' it will also stop your running DOS program(s). To be more precise, you will not see the ' names of the PBDOS .EXEs at all; they are subsumed under ntvdm.exe. If you use 2 PBDOS ' .EXEs you will see 2 copies of ntvdm.exe, and they will split the CPU between themselves. 'What is ntvdm, & what does it do? Here is a quote from http://sourceforge.net '"Although Windows*NT (and its successors Windows*2000 and XP) is able to run DOS 'programmes within a Virtual DOS Machine (NTVDM), this environment is very limited: 'There's no access to most software and hardware that's available under a normal DOS 'environment or even within a DOS box on Windows*95/98/Me. 'The NTVDM does, however, allow to emulate nearly all DOS APIs and hardware through 'so-called Virtual Device Drivers (VDDs). Here you will find a list of available VDDs 'created here as well as links to drivers created by others." 'The list of available VDDs includes ones for joysticks, sound cards, clipboard access, 'COM port control, long file name support, and (incoming) TelNet connections. 'Important Footnote, especially if security can be an issue in your use of the programs: '(A comment by Michael Mattias on John Gleason's code) 'That code does not prevent simultaneous access... you never lock the disk file record. 'Here is an article I wrote a long time ago about using files to share data across 'processes. The code is PB/DOS, but it's not really the code which is important, it's 'the concepts. ' "Fundamentals Of Multi-User Programming." ' Article published in December 1995 issue of "BASICally Speaking" magazine ' discussing the principles of writing multi-user programs; code samples in [DOS]BASIC. 'http://www.talsystems.com/tsihome_ht...rogramming.rtf
Code:
'SHARECC.BAS 'Freeware, Public Domain, by Emil Menzel 'Compile in PBCC (I developed in in ver 5.01) $BREAK ON 'REM-out for PBDOS $COMPILE EXE $DIM ALL $INCLUDE ONCE "Win32api.INC" TYPE JoyInfoType Time AS LONG 'Windows time, in millisec 'Joystick: X,Y,Z readings range from 0 to 65536; center=32767 'Calibrate your joystick with Windows Start/ControlPanel/Game Controllers JX AS LONG 'joystick X axis JY AS LONG 'joystick Y JZ AS LONG 'joystick Z. will read 0 if your joystick is not 3-D JB AS LONG 'joystick button(s) status 'Mouse readings from Win32 api can range from 0 to max resolution of your Display, 'as set by Windows Start/ControlPanel/Display/Settings MX AS LONG 'Mouse X, on screen as a whole, according to Windows MY AS LONG 'Mouse Y, on screen as a whole, according to Windows MB AS LONG 'Mouse button(s) status 'Keyboard: Status according to win api function GetKeyState 'This does not include Shift state, etc. ' ("Needs improvement", most teachers would say) KyBd AS LONG 'Add keyboard shift status, etc here if you wish 'Add serial port, 'and old gameport status here too, as you wish ID AS SINGLE 'identify which program read or wrote to the .DTA last 'Error Messages, &/or commands from the PBDOS program, to be executed by 'the PBCC program. Message AS STRING * 30 'use fixed strings for all messages, to keep 'the .DTA file lines exactly equal in length END TYPE DECLARE SUB Sleeper(timeinsec AS SINGLE) 'for PBDOS DECLARE SUB Play(SynAsync AS INTEGER, WavFileName AS STRING) 'for PBCC/PBWIN DECLARE FUNCTION KeyStat() AS LONG 'for PBCC/PBWIN DECLARE FUNCTION PBMAIN() AS LONG '''PRINT PBMAIN 'un-REM for PBDOS FUNCTION PBMAIN () AS LONG DIM Jinfo AS JoyInfoType 'room for identifier and all member elements DIM JS AS JOYINFO 'JoyInfo is defined in win api --x,y,z status of joystick + buttons code 'At least in PBCC, JS can also be treated as a string '4 bytes for each of the various LONG integers 'This info can be passed to other subroutines in a single 16 byte string, DIM pt AS PointAPi ' as defined in win api -- x,y of (e.g.) Mouse DIM ii AS LONG DIM StickError AS LONG DIM Count0 AS QUAD DIM Count1 AS QUAD DIM t AS SINGLE DIM identifier AS SINGLE DIM ky AS STRING DIM A AS STRING DIM DataFileName AS STRING RANDOMIZE TIMER t=TIMER 'use TIX to get quad identifier guaranteed unique. '(TIMER usually okay too unless exe's run < 18/th sec. apart) DO: LOOP UNTIL TIMER > t t=TIMER identifier = t 'give this exe the unique identifier DataFileName ="c:\shar.dta" 'Warning: SHAREDOS.EXE can't read long file names KILL DataFileName 'clear previous test runs Jinfo.ID = identifier 'put unique identifier in the data OPEN DataFileName FOR BINARY LOCK SHARED AS #1 'be sure to make SHARED PUT #1,, Jinfo 'initialize. write opening string DO UNTIL ky$ = CHR$(27) OR INSTR(Jinfo.Message,"QUIT")= 1 '--------Here is the actual sharing code---------------------------------------------- DO UNTIL INSTAT 'The INSTAT check is for debug only. 'I.e., press any key to read the current Counts SEEK #1, 1 'seek to beginning GET #1,, Jinfo 'read in whole UDT IF Jinfo.ID = identifier THEN 'if it's from this exe, it's not our turn yet, so iterate after short sleep SLEEP 10 'For PBDOS program(s) CALL Sleeper(timeInSec) instead 'Adjust SLEEP time for optimal performance (for your own purposes) 'SLEEP 0 is fine ... to test max speed, anyway INCR Count0 'use for debugging or test only ITERATE DO ELSE INCR Count1 'use for debug or test only GOSUB ProcessInfo '''Jinfo.ID = identifier 'I moved this line into the GOSUB SEEK #1, 1 'seek to beginning PUT #1,, Jinfo 'and write it EXIT DO END IF LOOP '---------End of the actual sharing code---------------------------------------------- ky$ = INKEY$ GOSUB ShowInfo 'make a click... A good way (in debugging) to tell how fast the program is running 'try both SyncAsync=0 & =1 '''CAll Play (1, "SOUND111.WAV") 'see Windows WAV file collection LOOP CLOSE #1 IF DIR$(DataFileName)<>"" THEN KILL DataFileName 'delete data file PRINT "Done in" & STR$(ROUND(TIMER - t, 3)) & " sec" PRINT "Press any key" WAITKEY$ 'for PBDOS use ky$ = INPUT$(1) EXIT FUNCTION '===== GOSUBs ================================ ProcessInfo: 'First read the Message from the other program & act on it 'add your own code here '& post appropriate Messages for the other program 'Get PBCC to do what PBDOS can't do, or can't do as well. 'See, for starters, the list given on http://sourceforge.net 'in its discussion of ntvdm.exe. Running DLLs & SHELLing without using 'DOS cmd.exe would be also be relatively easy pieces. 'Next, A$ = UCASE$(TRIM$(Jinfo.Message)) IF INSTR(A$, ".WAV") THEN CALL Play(0,A$) Jinfo.Message = "ok" 'clear out old messages. New ones could be posted too 'Get the current status of Windows keybord, clock,joystick & mouse with win api's Jinfo.KyBd = KeyStat 'check keyboard & mouse buttons 'Note: this is regardless of which window has the focus now Jinfo.Time = GetTickCount 'win api current time StickError = joyGetPos(0,JS) 'win api...reads stick#0 IF StickError THEN Jinfo.Message = "StickError# "+STR$(StickError) Jinfo.JX = JS.wXpos Jinfo.JY = JS.wYpos Jinfo.JZ = JS.wZpos Jinfo.JB = JS.wButtons GetCursorPos Pt 'win api mouse pos Jinfo.Mx = Pt.x Jinfo.My = Pt.y 'better yet, get MouseButton status from Win32 api functions forbuttons, instead of this way Jinfo.MB = Jinfo.KyBd IF Jinfo.MB > 2 THEN Jinfo.MB = 0 'assuming max of 2 buttons '''ScreenToClient hWin, pt 'win api mouse pos on whichever window has the focus 'could add this info too IF Jinfo.KyBd THEN ky$ = INKEY$ 'keypress, if CONSOLE of this program has Windows focus IF ky$=CHR$(27) THEN Jinfo.Message = "QUIT" 'or add your own code for handling this 'ignore (at least here) keypresses on any other windows END IF 'IMPORTANT! if you don't call this GOSUB, put the next line in the main loop, where John Gleason had it Jinfo.ID = identifier 'otherwise, our turn to write so set ID to our identifier RETURN ShowInfo: LOCATE 10,1 PRINT "Time "+STR$(Jinfo.Time)+SPACE$(5) PRINT " JX "+ STR$(Jinfo.JX)+SPACE$(5) PRINT " JY "+STR$(Jinfo.JY)+SPACE$(5) PRINT " JZ "+STR$(Jinfo.JZ)+SPACE$(5) PRINT " JB "+STR$(Jinfo.JB)+SPACE$(5) PRINT " MX "+STR$(Jinfo.MX)+SPACE$(5) PRINT " MY "+STR$(Jinfo.MY)+SPACE$(5) PRINT " MB "+STR$(Jinfo.MB)+SPACE$(5) PRINT "KyBd "+STR$(Jinfo.Kybd)+SPACE$(5) PRINT " ID "+STR$(Jinfo.ID) PRINT " Msg "+Jinfo.Message+"|" LOCATE 23, 1 A$="Count0"+STR$(Count0)+ " Count1" + STR$(Count1)+ " ID# "+ STR$(identifier) PRINT A$ RETURN END FUNCTION $IF 0 'use for PBDOS programs only SUB Sleeper (SleepTime AS SINGLE) 'release a time slice 'ASM code from PB Support DIM t AS SINGLE DIM iswindows AS INTEGER iswindows% = ISTRUE BIT(pbvhost,8) IF UCASE$(ENVIRON$("os")) = "WINDOWS_NT" THEN iswindows% = -1 t=TIMER + SleepTime DO IF iswindows% THEN ! push ds ! mov ax, &h1680 ! int &h2f ! pop ds END IF LOOP UNTIL TIMER > t END SUB $ENDIF 'PB INKEY$ does not work on a graphics window. 'KeyStat does -- albeit the returned keycodes are not all the same as INKEY$ 'It "needs work", PB gurus and indows gurus will say 'But I leave it here as I posted it in 2005 in a thread called "NagBox" 'Use in PBCC/PBWIN only; REM-out or delete for PBDOS FUNCTION keyStat() AS LONG LOCAL I,ks AS LONG DIM kb(255) AS STATIC BYTE GetKeyBoardState kb(0) 'win api FOR I=0 TO 255 'or .. ASC("A") to ASC("Z") ks=GetKeyState(I) 'win api IF ks<0 THEN EXIT FOR NEXT '''SLEEP 50 'watch out! fast-repeating keys IF I>255 THEN I=0 FUNCTION=I END FUNCTION 'Play a .WAV file (for PBCC/PBWIN only) 'from a post by Mike Doty, on PB Forums, June 2009 SUB Play(syncOrAsync AS INTEGER, sFileName AS STRING) EXPORT LOCAL zFileName AS ASCIIZ * 128 IF LEN(sFileName) = 0 THEN sFileName = "tada" zFileName = sFileName + $NUL IF SyncOrAsync <>0 THEN SyncOrAsync = 1 CALL PlaySound(zFileName, 0% , syncOrAsync) ' sync=0=play sound until done 'async=1=start sound but don't wait END SUB
Code:
'ShareDOS.BAS '(this requires also ShareCC.BAS. See Verbose Remarks) 'Compile in PBDOS (I developed it in ver. 3.5) 'by E.W. Menzel, Jr., a.k.a. Emil Menzel 'July 2009 'Freeware, placed in the Public domain 'when posted to PB Forums August 2, 2009 $COMPILE EXE $DIM ALL TYPE JoyInfoType Time AS LONG 'Windows time, in millisec 'Joystick: X,Y,Z readings range from 0 to 65536; center=32767 'Calibrate your joystick with Windows Start/ControlPanel/Game Controllers JX AS LONG 'joystick X axis JY AS LONG 'joystick Y JZ AS LONG 'joystick Z. will read 0 if your joystick is not 3-D JB AS LONG 'joystick button(s) status 'Mouse readings from Win32 api can range from 0 to max resolution of your Display, 'as set by Windows Start/ControlPanel/Display/Settings MX AS LONG 'Mouse X, on screen as a whole, according to Windows MY AS LONG 'Mouse Y, on screen as a whole, according to Windows MB AS LONG 'Mouse button(s) status 'Keyboard: Status according to win api function GetKeyState 'This does not include Shift state, etc. ' ("Needs improvement", most teachers would say) KyBd AS LONG 'Add keyboard shift status, etc here if you wish 'Add serial port, 'and old gameport status here too, as you wish ID AS SINGLE 'identify which program read or wrote to the .DTA last 'Error Messages, &/or commands from the PBDOS program, to be executed by 'the PBCC program. Message AS STRING * 30 'use fixed strings for all messages, to keep 'the .DTA file lines exactly equal in length END TYPE DECLARE SUB Sleeper(timeinsec AS SINGLE) 'for PBDOS. release time slice DECLARE FUNCTION PBMAIN() AS STRING PRINT PBMAIN 'REM-out for PBCC FUNCTION PBMAIN () AS STRING DIM Jinfo AS JoyInfoType 'room for identifier and all member elements DIM ii AS LONG DIM LJI AS LONG DIM Count0 AS QUAD DIM Count1 AS QUAD DIM t AS SINGLE DIM identifier AS SINGLE DIM ky AS STRING DIM A AS STRING DIM Dt AS STRING DIM Msg AS STRING DIM DataFileName AS STRING RANDOMIZE TIMER t=TIMER 'use TIX to get quad identifier guaranteed unique (PBCC/PBWIN) '(TIMER usually okay too unless exe's run < 18/th sec. apart) DO: LOOP UNTIL TIMER > t t=TIMER identifier = t 'give this exe the unique identifier DataFileName ="c:\shar.dta" 'Same name as in SHARECC.BAS. Do NOT use long file names IF DIR$(DataFileName) = "" THEN PRINT "Run SHARECC.EXE before you run this program" GOTO AllDone END IF Jinfo.ID = identifier 'put unique identifier in the data Jinfo.Message = "HiHal.WAV" '.WAV is a keyword in SHARECC.exe 'HiHal.WAV is my favorite startup sound for Windows 'It is the voice of Hal, the computer in the movie "2001" 'saying: Good evening, Dave. everything's going smoothly... 'and you?...just a moment...just a moment. OPEN DataFileName FOR BINARY LOCK SHARED AS #1 'be sure to make SHARED SEEK #1,0 'SHARECC.BAS uses BASE 1, not 0 PUT #1,, Jinfo 'initialize. write opening string LJI = LEN(Jinfo) DO UNTIL ky$ = CHR$(27) '--------Here is the actual sharing code---------------------------------------------- DO UNTIL INSTAT 'The INSTAT check is for debug only. 'I.e., you can press any key to read the current Counts SEEK #1, 0 'seek to beginning... NOTE! SHARECC.BAS uses BASE 1, not 0 GET #1,, Jinfo 'read in whole UDT Msg = UCASE$(TRIM$(Jinfo.Message)) IF INSTR(Msg,"ERROR") THEN 'use your own error handler code here; e.g.: 'LOCATE 24,1: PRINT: PRINT Msg: GOTO AllDone ELSEIF Msg = "OK" OR Jinfo.ID <> identifier THEN 'assume "OK" is a Message from SHARECC.EXE INCR Count1 'this count is used for debug or test only GOSUB ProcessInfo 'do Dt$ string parsing, etc. Jinfo.ID = identifier 'otherwise, our turn to write so set e0 member to our identifier Jinfo.Message = "SOUND111.WAV" '.WAV is a keyword for SHARECC.EXE to play a file SEEK #1, 0 'seek to beginning...NOTE! ShareCC uses 1, not 0 PUT #1,, Jinfo 'and write it GOSUB ShowInfo CALL Sleeper (.05) 'release a time slice (sec) EXIT DO ELSE 'if it's from this exe, it's not our turn yet, so iterate after short sleep CALL Sleeper(.05) 'release a time slice. INCR Count0 'used for debugging or test only ITERATE DO END IF LOOP '---------End of the actual sharing code---------------------------------------------- ky$ = INKEY$ LOOP AllDone: CLOSE #1 IF DIR$(DataFileName)<>"" THEN KILL DataFileName 'delete data file PRINT "Done in" & STR$(ROUND(TIMER - t, 3)) & " sec" PRINT "Press any key" ky$ = INPUT$(1) FUNCTION = "" EXIT FUNCTION '===== GOSUBs ================================ ProcessInfo: 'add your own code here '& post appropriate Messages for the other program 'Get PBCC to do what PBDOS can't do, or can't do as 'well. See, for starters, the list given on http://sourceforge.net, 'in its discussion of ntvdm.exe. 'Running DLLs & SHELLing without using 'DOS cmd.exe are also relatively easy pieces. RETURN ShowInfo: LOCATE 10,1 PRINT "Time "+STR$(Jinfo.Time)+SPACE$(5) PRINT " JX "+ STR$(Jinfo.JX)+SPACE$(5) PRINT " JY "+STR$(Jinfo.JY)+SPACE$(5) PRINT " JZ "+STR$(Jinfo.JZ)+SPACE$(5) PRINT " JB "+STR$(Jinfo.JB)+SPACE$(5) PRINT " MX "+STR$(Jinfo.MX)+SPACE$(5) PRINT " MY "+STR$(Jinfo.MY)+SPACE$(5) PRINT " MB "+STR$(Jinfo.MB)+SPACE$(5) PRINT "KyBd "+STR$(Jinfo.Kybd)+SPACE$(5) PRINT " ID "+STR$(Jinfo.ID) PRINT " Msg "+Jinfo.Message+"|" LOCATE 23, 1 A$="Count0"+STR$(Count0)+ " Count1" + STR$(Count1)+ " ID# "+ STR$(identifier) PRINT A$ RETURN END FUNCTION 'use for PBDOS programs only SUB Sleeper (SleepTime AS SINGLE) 'release a time slice 'ASM code is from PB Support DIM t AS SINGLE DIM iswindows AS INTEGER iswindows% = ISTRUE BIT(pbvhost,8) IF UCASE$(ENVIRON$("os")) = "WINDOWS_NT" THEN iswindows% = -1 t=TIMER + SleepTime DO IF iswindows% THEN ASM push ds ASM mov ax, &h1680 ASM int &h2f ASM pop ds END IF LOOP UNTIL TIMER > t END SUB
Comment