User Tools

Site Tools


converting_20programs_20from_20risc_20os_20to_20windows

Converting programs from RISC OS to Windows

by Richard Russell, October 2009

The conversion of WIMP-based BBC BASIC programs (i.e. programs having a Graphical User Interface) from RISC OS to Windows is a very broad subject, and it would be virtually impossible to provide a comprehensive guide. Therefore this article takes the form of a Case Study, dealing specifically with the conversion of one program: BasCalc. BasCalc is a relatively simple application, but it is hoped that the techniques used in its conversion to Windows may be applicable to other programs.

Sections of the program that require alteration will be listed in their 'before' and 'after' forms, with an explanation of the changes. Line numbers will be retained, partly because the original version had them and partly for the convenience of being able to refer to the program by that means. However they are not required in the final (Windows) version and may be removed using the Renumber utility if desired.

Unfortunately this Wiki doesn't provide a means to annotate the RISC OS and Windows code differently (for example using different colours). Therefore you may find it more satisfactory to compare the two versions using a utility like WinDiff, which highlights the differences. To enable you to do that the two programs are available for download as plain-text files as follows: BASCalc_RISCOS.bas and BASCalc_Windows.bas

Firstly here are some screenshots of the RISC OS and Windows versions for comparison:




Now for the conversion. The first few lines require no alteration:

     10 REM >BASCalc Source code
     20 REM (C)1999 PAUL VIGAY
     30 REM Inspired by !Calcula, by Iain Logan and thanks are due to him for the idea.
     40 REM Please feel free to examine my rudimentary wimp library and experiment to
     50 REM create your own applications. A limited number of comments have been inserted for you!
     60 version$="1.05 (12th Mar 2006)" : ver$=LEFT$(version$,4)

The first line to require a change is this one:

     70 DIM pb1% 256 : task%=&4B534154 : path$="<BASCalc$Path>."
     70 DIM pb1% 256 : task%=&4B534154 : path$=@dir$

The RISC OS path specification isn't appropriate for Windows. Under Windows it could be set to an absolute or relative path, but for convenience here we simply set it to @dir$, which in BB4W is a pre-defined 'system' variable containing the directory from which the program was loaded. Neither pb1% nor task% are required in the Windows version (in fact, pb1% isn't used even in the RISC OS version!) and can be retained or deleted as preferred.

     80 SYS "Wimp_Initialise",200,task%,"BASCalc" TO ,task_handle%
     80 SYS "SetWindowText", @hwnd%, "BASCalc"

Windows has no direct equivalent to Wimp_Initialise so here we replace the call with one which sets the window title.

     90 PROCinit
    100 ON ERROR PROCerror
    110 REPEAT
    120   SYS "Wimp_Poll",1,pb% TO reason%
 
     90 ON ERROR PROCerror
    100 PROCinit
    110 REPEAT
    120   reason% = FNwimp_poll(pb%)

Because Windows is a pre-emptive OS rather than a co-operative OS it has no direct equivalent to Wimp_Poll. However, to maintain the structure of the program, and to reduce the extent of the alterations as far as possible, the call is replaced by the function FNwimp_poll which we shall see later. Lines 90 and 100 have been swapped so that any errors occurring in PROCinit will be properly reported.

    130   CASE reason% OF
    140     WHEN 2:PROCopen(pb%!0)
    150     WHEN 3:PROCclose(pb%!0)
    160     WHEN 6:PROCmouseclick
    170     WHEN 8:PROCkeypressed
    180     WHEN 9:PROCmenu
    190     WHEN 17,18:CASE pb%!16 OF
    200         WHEN 0:end%=TRUE
    210         WHEN 2:REM This application dragged something elsewhere
    220           f$=FNgetstring(pb%+44):VDU7:END:REMf$=LEFT$(f$,LEN(f$)-1):l$=FNleafname(f$)
    230           IF pb%!12<>saveref% ERROR 1,FNmsg("err6")
    240           CASE step% OF
    250             WHEN 4:PROCcheckupgrade(f$,l$)
    260           ENDCASE
    270           oldpb%!12=oldpb%!8:oldpb%!16=3:SYS "Wimp_SendMessage",17,oldpb%,oldpb%!4
    280       ENDCASE
    290   ENDCASE
 
    130   CASE reason% OF
    160     WHEN 6:PROCmouseclick
    170     WHEN 8:PROCkeypressed
    180     WHEN 9:PROCmenu
    190     WHEN 17: end%=TRUE
    290   ENDCASE

There are no essential changes here, but for neatness lines 140-150 and 190-280 have been deleted. These perform operations needed to support RISC OS which are not required under Windows. It would do no harm, other than leaving 'dead' code, to retain them since the associated 'reason codes' won't be generated by FNwimp_poll.

    300 UNTIL end%
    310 PROCmsgend:@%=at%:SYS "Wimp_CloseDown",task_handle%,task%
    320 END
 
    300 UNTIL end%
    310 QUIT

Here we can simply replace the calls to Wimp_CloseDown and PROCmsgend with QUIT. In a more complex program it may well be necessary to perform some 'cleanup' operations before exit, even in the Windows version.

    330
    340 DEF PROCmouseclick
    350 LOCAL b%,w%,i%,pos%,reason%,nextmenu%
    360 pos%=pb%!0 : ypos%=pb%!4 : b%=pb%!8 : w%=pb%!12 : i%=pb%!16
    370 lastwindow%=w% : lasticon%=i%
 
    330
    340 DEF PROCmouseclick
    350 LOCAL i%
    360 i%=pb%!16

For the mouse-click processing the information required by the Windows version is much simpler than by the RISC OS version, basically it's a single value (here i%) to indicate what control (icon in RISC OS-speak) was clicked. Again, there's not actually any need to make changes but for clarity the unnecessary variables have been deleted.

    380 CASE b% OF
    390   WHEN 1,4:CASE w% OF
    400       WHEN -2:IF open% THEN
    410           PROCclose(window%(2))
    420         ELSE
    430           PROCfront(window%(2)):SYS "Wimp_SetCaretPosition",window%(2),2,0,0,-1,LEN($arg%)
    440         ENDIF
    450       WHEN window%(2):CASE i% OF
    460           WHEN 4:PROCui(window%(2),2,arg%,""):PROCui(window%(2),3,res%,"")
    470             SYS "Wimp_SetCaretPosition",window%(2),2,0,0,-1,LEN($arg%)
    480           WHEN 11:PROCui(window%(2),8,m1%,""):mem(1)=0
    490           WHEN 12:PROCui(window%(2),9,m2%,""):mem(2)=0
    500           WHEN 13:PROCui(window%(2),10,m3%,""):mem(3)=0
    510           WHEN 20:PROCui(window%(2),17,m4%,""):mem(4)=0
    520           WHEN 21:PROCui(window%(2),18,m5%,""):mem(5)=0
    530           WHEN 22:PROCui(window%(2),19,m6%,""):mem(6)=0
    540           WHEN 23:PROCui(window%(2),8,m1%,""):mem(1)=0:PROCui(window%(2),9,m2%,""):mem(2)=0
    550             PROCui(window%(2),10,m3%,""):mem(3)=0:PROCui(window%(2),17,m4%,""):mem(4)=0
    560             PROCui(window%(2),18,m5%,""):mem(5)=0:PROCui(window%(2),19,m6%,""):mem(6)=0
    570             PROCui(window%(2),2,arg%,""):PROCui(window%(2),3,res%,"")
    580             SYS "Wimp_SetCaretPosition",window%(2),2,0,0,-1,LEN($arg%)
    590           WHEN 24:PROCinsertcode($res%)
    600         ENDCASE
    610     ENDCASE
    620   WHEN 2:CASE w% OF
    630       WHEN -2:SYS "Wimp_CreateMenu",,menu1%,pos%-60,228
    640       WHEN window%(2):SYS "Wimp_CreateMenu",,menu1%,pos%-60,ypos%
    650     ENDCASE
    660 ENDCASE
    670 ENDPROC
 
    450 CASE i% OF
    460   WHEN 4:PROCui(window%(2),2,arg%,""):PROCui(window%(2),3,res%,"")
    480   WHEN 11:PROCui(window%(2),8,m1%,""):mem(1)=0
    490   WHEN 12:PROCui(window%(2),9,m2%,""):mem(2)=0
    500   WHEN 13:PROCui(window%(2),10,m3%,""):mem(3)=0
    510   WHEN 20:PROCui(window%(2),17,m4%,""):mem(4)=0
    520   WHEN 21:PROCui(window%(2),18,m5%,""):mem(5)=0
    530   WHEN 22:PROCui(window%(2),19,m6%,""):mem(6)=0
    540   WHEN 23:PROCui(window%(2),8,m1%,""):mem(1)=0:PROCui(window%(2),9,m2%,""):mem(2)=0
    550     PROCui(window%(2),10,m3%,""):mem(3)=0:PROCui(window%(2),17,m4%,""):mem(4)=0
    560     PROCui(window%(2),18,m5%,""):mem(5)=0:PROCui(window%(2),19,m6%,""):mem(6)=0
    570     PROCui(window%(2),2,arg%,""):PROCui(window%(2),3,res%,"")
    590   WHEN 24:PROCinsertcode($res%)
    600 ENDCASE
    670 ENDPROC

The only necessary change to this code is the substitution of the calls to Wimp_SetCaretPosition (lines 470 and 580) with a suitable Windows equivalent. In fact, since these calls are non-essential, for convenience (and laziness!) they have here simply been deleted.

However, in Windows, the outer CASE b% OF and CASE w% OF constructs aren't required, so for neatness and clarity lines 380-440 and 610-660 have been removed and in line 450 the WHEN window%(2) has been deleted. Again, it would do no harm to retain this 'dead' code (so long as the original lines 350 and 360 are kept) because FNwimp_poll does not return values which would cause it to be activated.

    680
    690 DEF PROCkeypressed
    700 LOCAL key%,window%,icon%,k%,len%,process%
    710 key%=pb%!24 : window%=pb%!0 : icon%=pb%!4 : process%=FALSE
 
    680
    690 DEF PROCkeypressed
    700 LOCAL icon%
    710 icon%=pb%!4

Here we have a very similar situation to PROCmouseclick; once again the information required by the Windows version is simpler than the RISC OS version: just the control (icon) into which input was entered (icon%). In Windows, handling of keyboard input to an 'edit box' does not require the attention of the main program. Checking that the key pressed was Return (Enter), which in the RISC OS version was done here, has been transferred into FNwimp_poll in the Windows version.

    720 CASE window% OF
    730   WHEN window%(2):CASE key% OF
    740       WHEN 13:CASE icon% OF
    750           WHEN 2:PROCcalc
    760           WHEN 8:mem(1)=VAL($m1%)
    770           WHEN 9:mem(2)=VAL($m2%)
    780           WHEN 10:mem(3)=VAL($m3%)
    790           WHEN 17:mem(4)=VAL($m4%)
    800           WHEN 18:mem(5)=VAL($m5%)
    810           WHEN 19:mem(6)=VAL($m6%)
    820         ENDCASE
    830         SYS "Wimp_SetCaretPosition",window%(2),2,0,0,-1,LEN($arg%)
    840       OTHERWISE process%=TRUE
    850     ENDCASE
    860   OTHERWISE process%=TRUE
    870 ENDCASE
    880 IF process% SYS "Wimp_ProcessKey",key%
    890 ENDPROC
 
    740 CASE icon% OF
    750   WHEN 2:PROCcalc
    760   WHEN 8:mem(1)=VAL($m1%)
    770   WHEN 9:mem(2)=VAL($m2%)
    780   WHEN 10:mem(3)=VAL($m3%)
    790   WHEN 17:mem(4)=VAL($m4%)
    800   WHEN 18:mem(5)=VAL($m5%)
    810   WHEN 19:mem(6)=VAL($m6%)
    820 ENDCASE
    890 ENDPROC

Once again the only essential change is the substitution or removal of Wimp_SetCaretPosition (line 830) but here the superfluous CASE window% OF and CASE key% OF constructs (lines 720-730 and 830-880) and the WHEN 13 (in line 740) have been deleted. The Wimp_ProcessKey has no equivalent in Windows (it is related to the co-operative nature of RISC OS).

    900
    910 DEF PROCmenu
    920 LOCAL menu%,b%,w%,ptr%,i%
    930 w%=lastwindow%:i%=lasticon%
    940 CASE w% OF
    950   WHEN -2,window%(2):menu%=menu1%
    960 ENDCASE
    970 SYS "Wimp_DecodeMenu",,menu%,pb%,mbuffer%:SYS "Wimp_GetPointerInfo",,pb%
    980 IF LEFT$($mbuffer%,9)="Decimals." decimals%=VAL(MID$($mbuffer%,10)):$mbuffer%="Decimals"
    990 b%=pb%!8
   1000 IF b% THEN
   1010   CASE $mbuffer% OF
   1020     WHEN "Quit":end%=TRUE
   1030     WHEN "Decimals":@%=&01020000+(decimals%<<8):PROCsavechoices
   1040   ENDCASE
   1050 ENDIF
   1060 PROCmenucreate
   1070 IF b% AND 1 SYS "Wimp_CreateMenu",,menu%,pb%!0-60,228
   1080 ENDPROC
 
    900
    910 DEF PROCmenu
    920 LOCAL select%, pt{}
    930 DIM pt{x%,y%} : SYS "GetCursorPos", pt{}
    940 select% = FNtrackpopupmenu(menu1%, &100, pt.x%, pt.y%)
    950 CASE select% OF
    960   WHEN 100: SYS "ShellExecute", @hwnd%, 0, @dir$+"BASCalc.txt", 0, "", 1
    970   WHEN 101:
    980     showfull% = NOT showfull%
    990     PROCsizewindow
   1000     PROCsavechoices
   1010   WHEN 109: end%=TRUE
   1020   WHEN 200,201,202,203,204,205,206,207,208,209,210:
   1030     SYS "CheckMenuItem", menu2%, 200+decimals%, 0
   1040     SYS "CheckMenuItem", menu2%, select%, 8
   1050     decimals% = select%-200 : @%=&01020000+(decimals%<<8)
   1060     PROCsavechoices
   1070 ENDCASE
   1080 ENDPROC

This is the first major change. Since the means of displaying and processing a context menu is quite different, PROCmenu has been substantially re-written. In Windows the context menu is displayed by clicking the right mouse button.

   1090
   1100 DEF PROCinit
   1110 DIM pb% 256,spr% 12,msgtext% 256,msgtrans% &500,inv% 28,outv% 28
   1120 DIM ws% 1500 :REM workspace for icons in windows
   1130 DIM wb% 1500 :REM window block (multi-purpose)
   1140 DIM mb% 500:REM menu data block
   1150 DIM md% 100:REM menu block containing in-directed data
   1160 DIM mbuffer% 256,mem(6)
   1170 nw%=2 :REM number of windows supported
   1180 DIM window%(nw%):end%=FALSE:FOR N%=1 TO 6:mem(N%)=0:NEXT N%:
        leavealone=FALSE:open%=FALSE:at%=@%:decimals%=8
   1190 PROCmsgload(path$+"Messages"):PROCloadwindows:PROCloadchoices:PROCmenucreate
   1200 @%=&01020000+(decimals%<<8)
   1210 iconbar%=FNiconbar("!BASCalc"):PROCgetmodeinfo
   1220 ENDPROC
 
   1090
   1100 DEF PROCinit
   1110 DIM pb% 256,msgtext% 256
   1160 DIM mbuffer% 256,mem(6)
   1170 nw%=2
   1180 DIM window%(nw%):end%=FALSE:at%=@%:decimals%=8:showfull%=FALSE
   1190 PROCloadwindows:PROCloadchoices:PROCmenucreate:PROCsizewindow
   1200 @%=&01020000+(decimals%<<8)
   1210 SYS "CheckMenuItem", menu2%, 200+decimals%, 8
   1220 ENDPROC

Here the changes consist mostly of (optional) deletions. The allocation of buffers in lines 1120 to 1150 is not required (along with most of line 1110); PROCmsgload can be dispensed with (as we will see later, the most convenient way of emulating the RISC OS MessageTrans facility does not require initialisation) and Windows looks after its iconbar (task bar) without user involvement.

A couple of additions have also been made: showfull%=FALSE (line 1180) and PROCsizewindow (line 1190) initialise the size of the window, and SYS “CheckMenuItem” (line 1210) initialises the 'tick' against the default number of decimal places in the relevant sub-menu (menu2%).

   1230
   1240 DEF FNiconbar(A$)
   1250 LOCAL sp$,ih%
   1260 pb%!0=-1:pb%!4=0:pb%!8=0:pb%!12=68:pb%!16=68:pb%!20=&2102
   1270 $spr%=A$:pb%!24=spr%:pb%!28=1:pb%!32=LEN(A$):SYS "Wimp_CreateIcon",,pb% TO ih%
   1280 =ih%
   1290
   1300 DEF PROCgetmodeinfo
   1310 inv%!0=4:inv%!4=5:inv%!8=6:inv%!12=7:inv%!16=11:inv%!20=12:
        inv%!24=-1:SYS "OS_ReadVduVariables",inv%,outv%
   1320 dx%=1<<(outv%!0):dy%=1<<(outv%!4):scrx%=(outv%!16+1)*dx%:scry%=(outv%!20+1)*dy%-2
   1330 ENDPROC
   1340
   1350 DEF PROCopen(handle%)
   1360 IF handle%<>-1 THEN pb%!0=handle%:SYS "Wimp_OpenWindow",,pb%
   1370 CASE handle% OF
   1380   WHEN window%(2):open%=TRUE
   1390 ENDCASE
   1400 ENDPROC
   1410
   1420 DEF PROCfront(handle%)
   1430 LOCAL mx%,my%
   1440 SYS "OS_Mouse" TO mx%,my%
   1450 pb%!0=-1:pb%!4=iconbar%:SYS "Wimp_GetIconState",,pb%:mx%=pb%!8+46:
        IF iconbar%=0 mx%=scrx%-250
   1460 IF handle%<>-1 PROCgetw(handle%):pb%!28=-1
   1470 CASE handle% OF
   1480   WHEN window%(2):pb%!4=mx%-396:pb%!12=mx%+396:REM 792x300 (main window)
   1490 ENDCASE
   1500 PROCopen(handle%)
   1510 ENDPROC
   1520
   1530 DEF PROCclose(handle%)
   1540 !pb%=handle%:SYS "Wimp_CloseWindow",,pb%
   1550 CASE handle% OF
   1560   WHEN window%(2):open%=FALSE
   1570 ENDCASE
   1580 ENDPROC
   1590
   1600 DEF PROCgetw(handle%)
   1610 !pb%=handle%:SYS "Wimp_GetWindowState",,pb%
   1620 vminx%=pb%!4:vminy%=pb%!8:vmaxx%=pb%!12:vmaxy%=pb%!16
   1630 scrollx%=pb%!20:scrolly%=pb%!24:bx%=vminx%-scrollx%:by%=vmaxy%-scrolly%
   1640 bhandle%=pb%!28:flags%=pb%!32
   1650 ENDPROC

This code is specific to RISC OS and can be deleted in its entirety. The program will still work correctly if it is left, but doing so will waste a substantial amount of memory and potentially cause confusion to somebody reading the code.

   1660
   1670 DEF PROCui(window%,icon%,ptr%,text$)
   1680 pb%!0=window%:pb%!8=0:pb%!12=0:$ptr%=text$:pb%!4=icon%:SYS "Wimp_SetIconState",0,pb%
   1690 ENDPROC
 
   1660
   1670 DEF PROCui(window%,icon%,ptr%,text$)
   1680 SYS "SetDlgItemText", window%, icon%, text$
   1690 ENDPROC

Here the original code has been substituted with a Windows near-equivalent.

   1700
   1710 REM Setup messagetrans
   1720 DEF PROCmsgload(n$)
   1730 SYS "MessageTrans_FileInfo",,n$
   1740 SYS "OS_Module",6,,,17+LEN(n$) TO ,,msgdesc%
   1750 $(msgdesc%+16)=n$:SYS "MessageTrans_OpenFile",msgdesc%,msgdesc%+16
   1760 ENDPROC
   1770
   1780 REM Finish with messagetrans
   1790 DEF PROCmsgend
   1800 SYS "XMessageTrans_CloseFile",msgdesc%:SYS "XOS_Module",7,,msgdesc%
   1810 ENDPROC

This code is not required and may be deleted.

   1820
   1830 REM decode tag$ into relevant text from Messages file
   1840 DEF FNmsg(tag$)
   1850 LOCAL F%,L%
   1860 SYS "XMessageTrans_Lookup",msgdesc%,tag$,msgtext%,255,"","" TO ,,,L%;F%
   1870 IF F% AND 1 L%=0
   1880 msgtext%?L%=13
   1890 =$msgtext%
 
   1820
   1830 REM decode tag$ into relevant text from Messages file
   1840 DEF FNmsg(tag$)
   1860 SYS "GetPrivateProfileString","messages",tag$,"",msgtext%,256,path$+"BASCalc.ini"
   1890 = $$msgtext%

A convenient way of emulating the RISC OS MessageTrans facility is to use a file in the Windows '.INI' format. Here we are using such a file called BASCalc.ini in which the mesages are contained in a section called messages (the file is listed at the end of this article). Note the use of $$ rather than $ in line 1890.

   1900
   1910 DEF FNgetstring(a%)
   1920 LOCAL a$
   1930 WHILE ?a%<>0:a$+=CHR$(?a%):a%+=1:ENDWHILE
   1940 =a$
   1950
   1960 DEF PROCstring0(a%,a$) $a%=a$:a%?LENa$=0:ENDPROC

These routines may be deleted. BBC BASIC for Windows supports NUL-terminated strings natively using the $$ syntax.

   1970
   1980 DEF PROCerror
   1990 LOCAL message$,action$,E%,err%,a%
   2000 REMON ERROR OFF
   2010 message$=REPORT$:err%=ERR:action$=FNmsg("e1"):a%=3:message$=message$+". "+action$:VDU7
   2020 E%=FNerror(a%,err%,message$)
   2030 IF E%=2 OR end%=TRUE end%=TRUE:@%=at%:PROCmsgend:
        SYS "Wimp_CloseDown",task_handle%,task%:END
   2040 ENDPROC
 
   1970
   1980 DEF PROCerror
   1990 LOCAL message$,action$,E%,err%,a%
   2000 REMON ERROR OFF
   2010 message$=REPORT$:err%=ERR:action$=FNmsg("e1"):a%=3:message$=message$+". "+action$:VDU7
   2020 E%=FNerror(a%,err%,message$)
   2030 IF E%=2 OR end%=TRUE end%=TRUE:@%=at%:QUIT
   2040 ENDPROC

The only alterations required here are to delete the PROCmsgend:SYS “Wimp_CloseDown” and change END to QUIT. In a more complex program it may be necessary to call a 'cleanup' routine before exit.

   2050
   2060 DEF FNerror(E%,N%,M$)
   2070 SYS "Hourglass_Smash":SYS "Wimp_DragBox",,-1
   2080 !pb%=N%:$(pb%+4)=M$+CHR$(0):SYS "Wimp_ReportError",pb%,E%,"!BASCalc" TO ,E%
   2090 =E%
 
   2050
   2060 DEF FNerror(E%,N%,M$)
   2070 SYS "MessageBox", @hwnd%, M$, "Error "+STR$(N%), 49 TO E%
   2090 =E%

Here SYS “Wimp_ReportError” has been substituted with SYS “MessageBox”. Fortunately the codes returned for OK (1) and CANCEL (2) are the same as in RISC OS!

   2100
   2110 DEF PROCmenucreate
   2120 LOCAL loop%,pass%,T$,C1%,C2%,C3%,C4%,W%,H%,V%,NI%,items%
   2130 menu1%=0:menu2%=0
   2140 FOR pass%=0 TO 2 STEP 2
   2150   P%=mb%:indir%=md%
   2160   menu1%=P%
   2170   RESTORE 2540
   2180   [ OPT pass%
   2190   EQUS "BASCalc":EQUB 0:EQUD 0:EQUB 7:EQUB 2:EQUB 3:EQUB 0:EQUD 120:EQUD 44:EQUD 0
   2200   ]
   2210   FOR items%=1 TO 3
   2220     READ t$
   2230     nm%=-1:f4%=indir%:f6%=LEN(t$):$f4%=t$:indir%=indir%+f6%+1:f%=0
   2240     CASE t$ OF
   2250       WHEN "Info":f%=0:nm%=window%(1)
   2260       WHEN "Decimals":nm%=menu2%
   2270       WHEN "Quit":f%=&80
   2280     ENDCASE
   2290     [ OPT pass%
   2300     EQUD f%:EQUD nm%:EQUB 49:EQUB 1:EQUB 0:EQUB 7:EQUD f4%:EQUD -1:EQUD f6%
   2310     ]
   2320   NEXT items%
   2330   menu2%=P%
   2340   RESTORE 2580
   2350   [ OPT pass%
   2360   EQUS "Decimals":EQUD 0:EQUB 7:EQUB 2:EQUB 3:EQUB 0:EQUD 120:EQUD 44:EQUD 0
   2370   ]
   2380   FOR items%=0 TO 10
   2390     READ t$
   2400     nm%=-1:f4%=indir%:f6%=LEN(t$):$f4%=t$:indir%=indir%+f6%+1:f%=0
   2410     IF items%=decimals% f%+=1
   2420     CASE t$ OF
   2430       WHEN "10":f%=&80
   2440     ENDCASE
   2450     [ OPT pass%
   2460     EQUD f%:EQUD nm%:EQUB 49:EQUB 1:EQUB 0:EQUB 7:EQUD f4%:EQUD -1:EQUD f6%
   2470     ]
   2480   NEXT items%
   2490 NEXT pass%
   2500 IF P%-mb%>450 ERROR 1,FNmsg("e2")+" ("+STR$(P%-mb%)+")"
   2510 IF indir%-md%>50 ERROR 1,FNmsg("e3")+" ("+STR$(indir%-md%)+")"
   2520 ENDPROC
   2530
   2540 REM data for menu 1
   2550 DATA Info,Decimals,Quit
   2560
   2570 REM data for menu 2
   2580 DATA 0,1,2,3,4,5,6,7,8,9,10
   2590
 
   2100
   2110 DEF PROCmenucreate
   2120 SYS "CreatePopupMenu" TO menu2%
   2130 SYS "AppendMenu", menu2%, 0, 200, "0"
   2140 SYS "AppendMenu", menu2%, 0, 201, "1"
   2150 SYS "AppendMenu", menu2%, 0, 202, "2"
   2160 SYS "AppendMenu", menu2%, 0, 203, "3"
   2170 SYS "AppendMenu", menu2%, 0, 204, "4"
   2180 SYS "AppendMenu", menu2%, 0, 205, "5"
   2190 SYS "AppendMenu", menu2%, 0, 206, "6"
   2200 SYS "AppendMenu", menu2%, 0, 207, "7"
   2210 SYS "AppendMenu", menu2%, 0, 208, "8"
   2220 SYS "AppendMenu", menu2%, 0, 209, "9"
   2230 SYS "AppendMenu", menu2%, 0, 210, "10"
   2240
   2250 SYS "CreatePopupMenu" TO menu1%
   2260 SYS "AppendMenu", menu1%, 0, 100, "&Info"
   2270 SYS "AppendMenu", menu1%, 16, menu2%, "&Decimals"
   2280 SYS "AppendMenu", menu1%, 0, 101, "&Show full"
   2290 SYS "AppendMenu", menu1%, 0, 109, "&Quit"
   2300 ENDPROC

This is another case where the RISC OS and Windows code is quite different. Also, an extra menu item (Show full) has been added to the Windows version as a more convenient way of switching between the two window sizes.

   2590
   2600 DEF PROCloadwindows
   2610 LOCAL W%,window$,N%
   2620 SYS "Wimp_OpenTemplate",,path$+"Templates":wm%=ws%+4500
   2630 RESTORE 2760
   2640 FOR W%=1 TO nw%
   2650   READ window$:SYS "Wimp_LoadTemplate",,wb%,ws%,wm%,-1,window$,0 TO ,,ws%
   2660   CASE window$ OF
   2670     WHEN "info":$(wb%!(88+128+20))=version$
   2680     WHEN "main":arg%=wb%!(88+(2*32)+20):res%=wb%!(88+(3*32)+20)
   2690       m1%=wb%!(88+(8*32)+20):m2%=wb%!(88+(9*32)+20):m3%=wb%!(88+(10*32)+20)
   2700       m4%=wb%!(88+(17*32)+20):m5%=wb%!(88+(18*32)+20):m6%=wb%!(88+(19*32)+20)
   2710   ENDCASE
   2720   SYS "Wimp_CreateWindow",,wb% TO window%(W%)
   2730 NEXT W%
   2740 SYS "Wimp_CloseTemplate"
   2750 ENDPROC
   2760 DATA info,main
 
   2590
   2600 DEF PROCloadwindows
   2605 INSTALL @lib$+"WINLIB2A"
   2610 window% = FN_newdialog("BASCalc",0,0,264,95,8,1000)
   2615 window%!16=&508800C4 : REM remove title bar and make child window
   2620 PROC_static(window%,"Argument:",0,0,6,60,16,2)
   2625 PROC_static(window%,"Result:",1,0,24,60,16,2)
   2630 PROC_editbox(window%,"",2,65,4,152,14,&81)
   2635 PROC_editbox(window%,"",3,65,22,152,14,1)
   2640 PROC_pushbutton(window%,"Clear",4,220,4,40,15,0)
   2645 PROC_static(window%,"M1",5,0,44,19,16,2)
   2650 PROC_static(window%,"M2",6,0,62,19,16,2)
   2655 PROC_static(window%,"M3",7,0,80,19,16,2)
   2660 PROC_editbox(window%,"",8,22,41,67,14,1)
   2665 PROC_editbox(window%,"",9,22,59,67,14,1)
   2670 PROC_editbox(window%,"",10,22,77,67,14,1)
   2675 PROC_pushbutton(window%,"Clear",11,93,41,34,15,0)
   2680 PROC_pushbutton(window%,"Clear",12,93,59,34,15,0)
   2685 PROC_pushbutton(window%,"Clear",13,93,77,34,15,0)
   2690 PROC_static(window%,"M4",14,132,44,19,16,2)
   2695 PROC_static(window%,"M5",15,132,62,19,16,2)
   2700 PROC_static(window%,"M6",16,132,80,19,16,2)
   2705 PROC_editbox(window%,"",17,155,41,67,14,1)
   2710 PROC_editbox(window%,"",18,155,59,67,14,1)
   2715 PROC_editbox(window%,"",19,155,77,67,14,1)
   2720 PROC_pushbutton(window%,"Clear",20,226,41,34,15,0)
   2725 PROC_pushbutton(window%,"Clear",21,226,59,34,15,0)
   2730 PROC_pushbutton(window%,"Clear",22,226,77,34,15,0)
   2735 PROC_pushbutton(window%,"AC",23,234,22,26,15,0)
   2740 PROC_pushbutton(window%,"»",24,220,22,12,15,0)
   2745 PROC_showdialog(window%)
   2750 DIM arg% 255,res% 255,m1% 255,m2% 255,m3% 255,m4% 255,m5% 255,m6% 255
   2755 window%(2) = !window%
   2760 ENDPROC

Once again the Windows version is quite different. Although it's possible in Windows to create a dialogue window using a template (which would be more similar to the RISC OS version) it's conventional in BB4W to incorporate the various controls using inline code as shown.

   2780
   2790 DEF PROCcalc
   ....
   2990 DEF FNparse(a$)
   ....
   3350 DEF FNconvtoupper(a$)
   ....
   3410 DEF FNstripspaces(a$)
   ....
   3510 DEF FNextractno(a$,x%,RETURN N%)
   ....
   3590 DEF FNchr(a$)
   ....
   3660 DEF FNvat(a$,t%)
   ....
   3780 DEF FNgcol(c%)
   ....
   3870 DEF FNconvtobin(a$)
   ....
   3970 DEF FNcomma(a$)
   ....
   4230 =a$

Lines 2780 to 4230 inclusive are the 'meat' of the BASCalc application and require no changes.

   4240
   4250 DEF PROCinsertcode(a$)
   4260 LOCAL N%
   4270 IF a$<>"" FOR N%=1 TO LEN(a$):SYS "OS_Byte",153,0,ASC(MID$(a$,N%,1)):NEXT N%
   4280 ENDPROC
 
   4240
   4250 DEF PROCinsertcode(a$)
   4260 LOCAL N%
   4270 IF a$<>"" FOR N%=1 TO LEN(a$):SYS "PostMessage",Focus%,258,ASC(MID$(a$,N%,1)),0:NEXT N%
   4280 ENDPROC

The SYS “OS_Byte” has been substituted with a Windows equivalent (258 is WM_CHAR).

   4290
   4300 DEF PROCloadchoices
   4310 LOCAL t%,x%,v$
   4320 SYS "OS_File",5,path$+"choices" TO t%
   4330 IF t%=1 THEN
   4340   x%=OPENIN(path$+"choices")
   4350   IF x%>0 AND x%<256 THEN
   4360     INPUT#x%,v$,decimals%
   4370     CLOSE#x%
   4380   ENDIF
   4390 ELSE
   4400   PROCsavechoices
   4410 ENDIF
   4420 ENDPROC
 
   4290
   4300 DEF PROCloadchoices
   4310 SYS "GetPrivateProfileInt","choices","decimals",8,path$+"BASCalc.ini" TO decimals%
   4320 SYS "GetPrivateProfileInt","choices","showfull",0,path$+"BASCalc.ini" TO showfull%
   4330 ENDPROC

The Windows code is again quite different. In addition to loading the user's preference as regards the decimals setting, his most recent choice for the window size is also loaded.

   4430
   4440 DEF PROCsavechoices
   4450 LOCAL x%,d%
   4460 d%=0
   4470 x%=OPENOUT(path$+"choices")
   4480 IF x%>0 AND x%<256 THEN
   4490   PRINT#x%,ver$,decimals%
   4500   CLOSE#x%
   4510 ENDIF
   4520 ENDPROC
 
   4430
   4440 DEF PROCsavechoices
   4450 LOCAL @%
   4460 SYS "WritePrivateProfileString","choices","decimals",STR$decimals%,path$+"BASCalc.ini"
   4470 SYS "WritePrivateProfileString","choices","showfull",STR$showfull%,path$+"BASCalc.ini"
   4480 ENDPROC

Here the user's most recent window size setting is saved in addition to the number of decimal places.

Finally here are the FNwimp_poll, FNtrackpopupmenu and PROCsizewindow routines which are specific to the Windows version:

        DEF FNwimp_poll(pb%)
        LOCAL click%, reason%, fg%, L%
        PRIVATE icon%
        Queue$ = "" : !^wParam$ = ^@wparam% : ?(^wParam$+4) = 4
        ON SYS Queue$ += wParam$ : RETURN
        ON CLOSE Queue$ += CHR$(0)+CHR$(0)+CHR$(3)+CHR$(0) : RETURN
        REPEAT
          WAIT 1
          IF Queue$<>"" THEN
            click% = !!^Queue$
            Queue$ = MID$(Queue$,5)
          ENDIF
        UNTIL click% OR INKEY(-12)
        SYS "GetDlgItem",window%(2),icon% TO Focus%
        IF click% = 24 SYS "PostMessage",window%(2),40,Focus%,1
        IF click% = 0 SYS "GetForegroundWindow" TO fg% : IF fg% = @hwnd% click% = &20000
        IF click% = 1 click% = icon% OR &10000 ELSE icon% = click% AND &FFFF : REM return key
        CASE click% >> 16 OF
          WHEN 0: reason% = 6 : pb%!8 = 1 : pb%!12 = window%(2) : pb%!16 = icon% : REM mouse
          WHEN 1,512: reason% = 8 : pb%!0 = window%(2) : pb%!4 = icon% : pb%!24 = 13 : REM key
          WHEN 2: reason% = 9 : REM menu
          WHEN 3: reason% = 17 : pb%!16 = 0 : REM close
        ENDCASE
        SYS "GetDlgItemText",window%(2),2,arg%,256 TO L% : arg%?L%=13
        SYS "GetDlgItemText",window%(2),3,res%,256 TO L% : res%?L%=13
        SYS "GetDlgItemText",window%(2),8, m1%,256 TO L% : m1%?L%=13
        SYS "GetDlgItemText",window%(2),9, m2%,256 TO L% : m2%?L%=13
        SYS "GetDlgItemText",window%(2),10,m3%,256 TO L% : m3%?L%=13
        SYS "GetDlgItemText",window%(2),17,m4%,256 TO L% : m4%?L%=13
        SYS "GetDlgItemText",window%(2),18,m5%,256 TO L% : m5%?L%=13
        SYS "GetDlgItemText",window%(2),19,m6%,256 TO L% : m6%?L%=13
        = reason%
 
        DEF FNtrackpopupmenu(hmenu%,flags%,x%,y%)
        LOCAL M%, O%, P%, T%
        DIM P% LOCAL 54
        SYS "GetWindowLong", @hwnd%, -4 TO O%
        [OPT 2
        .T%
        push 0
        push @hwnd%
        push 0
        push y%
        push x%
        push flags%
        push hmenu%
        call "TrackPopupMenu"
        ret 16
        .M% cmp dword [esp+8],&500 : jz T% : jmp O%
        ]
        SYS "SetWindowLong", @hwnd%, -4, M%
        SYS "SendMessage", @hwnd%, &500, 0, 0 TO T%
        SYS "SetWindowLong", @hwnd%, -4, O%
        SYS "SendMessage", @hwnd%, 0, 0, 0
        = T%
 
        DEF PROCsizewindow
        LOCAL rc{}, style%
        DIM rc{l%,t%,r%,b%}
        rc.l% = 0 : rc.t% = 0 : rc.r% = 267
        IF showfull% rc.b% = 97 ELSE rc.b% = 43
        SYS "CheckMenuItem", menu1%, 101, showfull% AND 8
        SYS "MapDialogRect", window%(2), rc{}
        SYS "GetWindowLong", @hwnd%, -16 TO style%
        SYS "AdjustWindowRect", rc{}, style%, 0
        SYS "SetWindowPos", @hwnd%, 0, 0, 0, rc.r%-rc.l%, rc.b%-rc.t%, 6
        ENDPROC

Here is what BASCalc.ini looks like; it may be compared with the equivalent RISC OS message file:

  [messages]
  # Messages file for !BASCalc
  # ©1999 Paul Vigay

  # Current VAT rate
  vat=17.5

  # If money is set to Yes then VAT calculations will be rounded to the nearest penny,
  # otherwise left as a decimal value
  money=Yes

  # Application messages - DO NOT CHANGE!
  e1=Click OK to continue or CANCEL to Quit application
  e2=Menu data too long for mb% block
  e3=Menu data too long for md% block

  berr18=Division by zero
  berr20=Number too big
  berr21=Negative root
  berr22=Log range!
  berr23=Accuracy lost!
  berr24=Exponent range!
  berr26=Unknown variable
  berr27=Missing bracket
  berr28=Bad binary/hex

  chr0/chr=null
  chr1=send chr to prnt
  chr2=Printer ON
  chr3=Printer OFF
  chr7=bell
  chr8=cursor back
  chr9=tab
  chr10=LF
  chr11=cursor up
  chr12=cls
  chr13=CR
  chr30=home
  chr32=space
  chr127=delete

  [choices]
  decimals=8
  showfull=-1
This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information
converting_20programs_20from_20risc_20os_20to_20windows.txt · Last modified: 2018/04/14 20:49 by richardrussell