One of the more interesting things about OS/2 1.x is how it had this interesting idea of how to strattle the bridge between old and new, and it was a very common bridge tactic where you can have a shipping program that can simply run in both the older operating system, and the new one. Naturally there is trade offs, you can’t fully take advantage of all kinds of features on the new side, you will be largely held back on the old side, but all is not lost, there is space for things that fit in the ‘same but bigger’ world where you have an overlap between old and new.
For OS X, this was the Carbon era, for Windows this was the famous Win32s extensions, and for OS/2 it’s the Family API.
As a quick example, allocating memory under MS-DOS may be limited to 640kb, but under OS/2 you have access to so much more memory, the entire capacity of an IBM AT class machine. And this also got OS/2 tools into a lot of MS-DOS developer’s hands as the early compilers and tools were built around the Family API and were able to run on so called legacy environments. Although it was far better to run on OS/2, the advantage 30+ years later is that MS-DOS emulation is more common and prevalent than OS/2, especially on non x86 processors.
Ages ago I had done a very simple video memory dump of the Microsoft Programmer’s Library giving me electronic access to the old documents, and a few queries give these as the Family API building blocks:
DOS
- DosAllocHuge
- DosAllocSeg
- DosBeep
- DosBufReset
- DosCaseMap
- DosChDir
- DosChgFilePtr
- DosCLIAccess
- DosClose
- DosCreateCSAlias
- DosDelete
- DosDevConfig
- DosDevIOCtl
- DosDupHandle
- DosEnumAttribute
- DosErrClass
- DosError
- DosExecPgm
- DosExit
- DosFileLocks
- DosFindClose
- DosFindFirst
- DosFindFirst2
- DosFindNext
- DosFreeSeg
- DosGetCollate
- DosGetCtryInfo
- DosGetDateTime
- DosGetDBCSEv
- DosGetEnv
- DosGetHugeShift
- DosGetMachineMode
- DosGetMessage
- DosGetVersion
- DosHoldSignal
- DosInsMessage
- DosMkDir
- DosMove
- DosNewSize
- DosOpen
- DosPutMessage
- DosQCurDir
- DosQCurDisk
- DosQFHandState
- DosQFileInfo
- DosQFileMode
- DosQFSInfo
- DosQPathInfo
- DosQVerify
- DosRead
- DosReallocHuge
- DosReallocSeg
- DosRmDir
- DosSelectDisk
- DosSetDateTime
- DosSetFHandState
- DosSetFileInfo
- DosSetFileMode
- DosSetFSInfo
- DosSetPathInfo
- DosSetSigHandler
- DosSetVec
- DosSetVerify
- DosSizeSeg
- DosSleep
- DosSubAlloc
- DosSubFree
- DosSubSet
- DosWrite
Keyboard
- KbdCharIn
- KbdFlushBuffer
- KbdGetStatus
- KbdPeek
- KbdSetStatus
- KbdStringIn
Video
- VioGetBuf
- VioGetConfig
- VioGetCurPos
- VioGetMode
- VioGetPhysBuf
- VioGetState
- VioReadCellStr
- VioReadCharStr
- VioScrLock
- VioScrollDn
- VioScrollLf
- VioScrollRt
- VioScrollUp
- VioScrUnLock
- VioSetCurPos
- VioSetCurType
- VioSetMode
- VioSetState
- VioShowBuf
- VioWrtCellStr
- VioWrtCharStr
- VioWrtCharStrAtt
- VioWrtNAttr
- VioWrtNCell
- VioWrtNChar
- VioWrtTTY
I’m sure this is not exhaustive by any stretch. I got the list from a simple query like this:
grep -i 'family api' os2dev.txt | awk '{print $2}' > fam.txt
grep -i 'family api' prgmr[34].txt| awk '{print $3}' >> fam.txt
sort fam.txt | uniq > family.txt
As an added bonus you really don’t have to mess with the API at all, as the LIBC will use it no doubt.
At any rate, using Microsoft C 6.00 (I can’t get the syntax right for 5.1 to save my life, I suspect I need to run it UNDER OS/2 to build for OS/2 properly), you can compile a typical stdio compliant program, and get an OS/2 executable.
The real fun is from the bind program which will convert that OS/2 program to a full Family mode app with the bind program.
And now on MS-DOS (Under OS/2) you can see very quickly that the OS/2 app won’t run, however the family mode one does!
So this is what let’s me run the older SDK tools as I’d simply forgotten about this great mode, letting you run programs in either environment.
Of course the added fun is the 3rd party product Phar Lap’s 286|Dos-Extender that provides some OS/2 services under MS-DOS in addition to greater memory but DLL’s! But that’s for another story.
**EDIT Oh and another edit, here is how to make the OS/2 program ‘window’ compatible with a link time definition file:
and then on the console:
And there we go with some magical flags & def file it’s now marked as being compatible with window mode. So no full screen VIO tricks for you!
Can you describe a bit more about what you see with C 5.1?
I’ve had this working successfully although there are plenty of quirks. If you’re using the DOS toolchain, note there’s two versions of link.exe: a real mode one, and a bound (family mode) one. Linking an OS/2 application really wants the bound one, or the one provided with the OS (which is marginally newer.) The real mode one will complain about unresolved externals despite being given doscalls.lib (it doesn’t seem to handle it correctly.) The function prototypes for things like DosWrite are included in C 5.1 headers though.
Also, by default C 5.1 generates non-windowcompat binaries, so a module definition file is needed to make a useful result. On OS/2 2.0 and above, using the whole thing from DOS boxen might be easier, because everything works in a window by default.
This is a good resource:
http://www.edm2.com/index.php/Hints_for_writing_simple_programs_for_both_OS/2_and_DOS
Note the part at the bottom – it’s possible to dynamically check which system a binary is executing from with DosGetMachineMode, and it’s possible to add extra OS/2 functions so long as you supply a DOS equivalent. Bind -n can map a list of extra functions to a generic handler function, which is useful if you use DosGetMachineMode to ensure that the OS/2 function is only invoked on OS/2.
Also, digging around showed a PC Mag article complaining that building a family mode app is often larger than just building a native DOS version and using it as a stub for the OS/2 version – ie., rather than have a single OS/2 binary with a DOS translation layer, just glue two complete binaries together. For hello world, that seems like the right thing to do.
It’s a real shame that the same e_lfanew field is used to indicate _any_ “new” header. We could have had MZ applications that contain a DOS version, an NE OS/2 version (or possibly WLO), and a PE version. Although, it’d also be great to have a single PE version for multiple architectures. Sigh…
Ive been getting an incredible amount of errors from invalid binaries, malformed binaries, missing symbols t duplicate symbols (__acrtused) and other stuff.
I just re-installed under OS/2 and got it to seemingly work though. I had it as a strictly OS/2 only setup?
doing steps 1/2/3 and it finally runs!
Thanks so much for that hint of just targeting OS/2. I manually extracted back the compiler only for realmode, and it’s acting way better now. I guess Microsoft C 6.00 is way more forging in this aspect.
Did you try running the OS/2 program with a double click from the WPS?
oh I have to find the linker def’s to make it window compatible. I have it somewhere when I was messing with Fortran 5.1. Otherwise it’ll launch a full screen session, say hi, and close in the blink of an eye.
We really take the ‘unified’ console of Windows NT for granted, as it was so fragmented back in the day.
I think it’s just “NAME FOO WINDOWCOMPAT” in a .def file, and point the linker to it. That sets a single bit in the executable which also modifies a second checksum bit. It should be possible to just mark executables after linking.
(Also, I know about the two bits because it’s possible to just recompile and diff. Unlike what happened later, the results really seem reproducible by default.)
Agree about the unified console. The Win95 one (which has no scrollback since it’s just an emulated VGA device) is unusably annoying now. That said, I started Yori so I could have tab completion on NT 3.51, and using OS/2 without tab completion is driving me nuts. OS/2 really tried to have a modern console (at least for OS/2 applications) but the shell needs work.
I found my hello world one:
NAME HELLO WINDOWCOMPAT
DESCRIPTION 'Hello world'
PROTMODE
So yeah, so confusing!
I’ve been looking into Family API a bit more, using Visual C++ as a compiler for it.
If you’re interested, first blog post: http://www.malsmith.net/blog/visual-c-os2-family/
Source code: https://github.com/malxau/os2api
Looks pretty cool!
I had messed with the MSC from the October 1991 NT, and the leaked MASM386 can assemble it, to an OMF that NT LINK386 can use, much like the Xenix 386 GAS.
The other ‘target’ I guess for family api, is 2ine? the OS/2 libraries for Linux, which give us the 64bit OS/2 we all know we need.
Also what is the msft post on creating family apps on masm6?
I haven’t looked at 2ine yet, but agree that’s another thing to look into. It’s a bit strange to be looking into OS/2-on-DOS instead of OS/2-on-Win32, which seems more applicable. Note though since it’s 16 bit code it’d need CPU emulation like winevdm – does 2ine do that?
Without CPU emulation, it’s an interesting question whether the same source code can target DOS, OS/2, and Win32 – obviously it _can_ but the logic needs to limit itself to 64Kb segments which is going to look ugly on Win32. There’s also another route of using the 32-bit OS/2 API to get a single piece of source code to support Win32, OS/2 and a DOS extender.
I don’t follow the comment about the msft post though – what msft post? That link should be to my personal blog…