DosBeep Replacement Sample

Release date: 
Monday, 27 January, 1997



Authors/Port authors:

This is a source code sample for replacing the DosBeep and Dos16Beep functions to make it sound on the multimedia audio device instead of the PC speaker.

This software is distributed as compressed package. You have to download and manually install it; if prerequisites are required, you will have to manually install them too.

Manual installation

Program is distributed as ZIP package: download to temporary directory and unpack to destination folder. See below for download link(s).

Following ones are the download links for manual installation:

DosBeep Replacement Sample v. 2.0 (19/4/2020, Lars Erdmann) Readme/What's new
This is a source code sample for replacing the DosBeep and Dos16Beep functions to make it sound on the multimedia audio device instead of the PC speaker. This sample replaces: - Dos32Beep (DOSCALL.286) - Dos16Beep (DOSCALLS.50) Effectively it works like this: 1) ANY application (that is, either an EXE or a DLL that this EXE binds to) that uses DosBeep can be modified to instead use the DosBeep that is implemented in NEWCALLS.DLL. That also includes any DLLs delivered with OS/2. 2) What you need to do to this EXE or DLL is to overwrite the import references that import from DOSCALLS (where ordinal 286 points to the genuine DosBeep function as implemented in the kernel: it uses the PIT to create a sound via an attached PC built-in LOW-FI speaker) and instead tell the EXE or DLL to import from NEWCALLS (which uses your soundcard to play a generated PCM sine wave stream). 3) Because there is a good chance that a number of DOSCALLS routines are bound to the exe and not only DosBeep, what NEWCALLS does is to forward all unchanged functions directly from DOSCALLS to the EXE or DLL. With the one exception of "DosBeep" which NEWCALLS replaces with its own implementation (and it binds to the genuine implementation and calls that where necessary). Let's say you have an EXE called MyApp.exe that links to a couple of functions implemented in the kernel, say, DosOpen, DosClose, DosRead, DosWrite and also DosBeep. Run this command: dllrname.exe /Q /N MyApp.exe DOSCALLS=NEWCALLS After doing so, MyApp.exe will invoke the genuine kernel functions DosOpen,DosClose, DosRead,DosWrite in DOSCALLS (because those are forwarded) but it will call the implementation of DosBeep in NEWCALLS as that has been replaced. You will have to do the "dllrname" action on every EXE and DLL where you want to have a DosBeep call replaced by the implementation in NEWCALLS.DLL. "dllrname.exe" is a tool that comes with VAC but there are free tools and serve the very same purpose. NEWCALLS.DLL has to go somewhere in your LIBPATH or BEGINLIBPATH or ENDLIBPATH, just like for any other DLL. Just a hint: You can only do this module renaming (DOSCALLS=NEWCALLS) if the modules have the very same name length (DOSCALLS and NEWCALLS have the same number of letters). That is a design limitation. Additionally, under OS/2, DLL names are limited to 8 characters (excluding file extension). Additional note: I have implemented DosBeep so that PM and also VIO applications can use it without any restrictions. I even went through some hoola hoops so that error message boxes can be displayed even from a VIO app. ==PROCEDURE== You need to modify the binary (EXE or DLL) so it can use the NEWCALLS.DLL (New DOSBeep) file instead of DOSCALL.DLL. Remember to backup the EXE or DLL before doing this. Follow the next procedure: First validate if the EXE uses DosBeep. If you have an exe called MyApp.Exe, then do this: exehdr /V MyApp.exe | find "imp" It will list all the imports. If you find something like this: REL OFF(32) 0014 imp DOSCALLS.286 Then you know that this exe uses DosBeep. Now modify the file by running: dllrname /N /Q MyApp.exe DOSCALLS=NEWCALLS You can rerun: exehdr /V MyApp.exe | find "imp" Now it will show this: REL OFF(32) 0014 imp NEWCALLS.286 Now you will know that from now on, the new DosBeep Implementation will be called. It works the very same way to patch a DLL. ==SAMPLE== There is this simple app to help you test this, file bla.c: #define INCL_BASE #include <os2.h> #include <stdio.h> #include <stdlib.h> int main(int argc,char *argv[]) { ULONG freq=0,dur=0; if (argc != 3) { printf("bla [freq] [dur]\n"); return 1; } printf("Hallo!\n"); freq = strtoul(argv[1],NULL,10); dur = strtoul(argv[2],NULL,10); if (!freq || !dur) { printf("invalid arguments\n"); return 1; } DosBeep(freq,dur); return 0; } and build it with "build.cmd". After that you can try: dllrname /N /Q bla.exe DOSCALLS=NEWCALLS /* this does the interesting part */ When you now run bla.exe, you can hear the Beep via my Speakers driven by Uniaud or via the Speakers connected via Audio USB, whatever device I choose as the default WAV device (the default WAV device will be used to play the sound). By the way: use my USBAUDIO.ZIP package to have everything to work with USB audio. And it also comes with a DLL that extends the Multimedia Setup Object to allow you to simply switch the default WAV device with a mouse click. Of course that works across the board, not only for the USB audio device but also for the UNIAUD device. ==REFERENCE== This sample is inspired by the NEWCALLS sample of "Hook code to circumvent built-in methods of OS/2" by Peter Fitzsimmons. ==LICENSE== BSD 3-Clauses ==AUTHOR== Lars Erdmann ==LINKS==
DosBeep Replacement Sample (22/1/1997, Peter Fitzsimmons) Readme/What's new
Jan 22, 1997 What is NEWCALLS.DLL? ===================== This is an example of how to redirect (or "hook") a function in a dll that you don't have the code for. My example hooks DosOpen() for PMMERGE.DLL. It works under Warp 3.0 or Warp 4.0. How it Works ============ The exe header of PMMERGE.DLL is changed so that all references to DOSCALLS.DLL go to NEWCALLS.DLL instead (IBM's compiler supplies a utility called DLLRNAME to do this). NEWCALLS.DLL contains a forwarder entry (to DOSCALLS.DLL) for every function exept Dos32Open(). The forwarder entries are created, by the linker (FWDSTAMP.EXE is NOT needed), because the *.def file both IMPORTS and EXPORTS all of the function names (except Dos32Open). Since many of the ordinals are not referenced by name (and are not documented), I forward them with a manufactured name. Example: _undoc4=DOSCALLS.4 Since the real doscalls.dll does not export a name for ordinal 4, it should not make any difference what it is called. The important thing is that an oridinal of 4 does exist, in case pmmerge.dll uses it (it will use it by ordinal number, not by name). This may seem untrustworthy, but you have to keep in mind we are redirecting DOSCALLS only for one specific piece of code (pmmerge.dll); and if we get it wrong it will fail to load. Additionally, newfwd.def IMPORTS the real Dos32Open, for its own use, by ordinal (273), and calls it _Dos32Open(). _Dos32Open() is a private name, only seen by newcalls.dll. _DOS32OPEN =DOSCALLS.273 Newcalls.c only has to contain code for one function, Dos32Open(). All other functions are automatically redirected, at load time, to the real doscalls.dll; thus there is NO runtime performance impact, only a slight (probably immeasurable) loadtime impact. Why NEWCALLS.DLL? ================= Whenever anything changes on your WPS (which can happen simply by referencing an object), changes are made to OS2.INI and/or OS2SYS.INI. Every so often (2 mins or so) these changes are written to disk. Since OS/2 2.1, *.ini files are kept completely in (swappable) memory, and are rewritten, in their entirety, whenever updates are required (this means the system will have to swap out memory equal to the size of your *.ini files, swap in the memory where the *.ini file data is, write them out, etc...this design sucks; I liked the way os/2 1.1 through 2.0 did it better). To further complicate things, the *.ini file data is written out in chunks of 32k or less. My os2*.ini files are 1.2mb; that means about 40 DosWrite's. The code for PrfOpenProfile() is in pmmerge.dll. PrfOpenProfile() calls DosOpen with the "OPEN_FLAGS_WRITE_THROUGH" bit on. This causes each DosWrite() to the *.INI files to completely update all disk structures before it returns (this is VERY slow on HPFS). It takes a good 15-20 seconds to write my *.ini files out (and this happens every few mins). Not only do I have an annoyingly loud harddisk, but the performance of my PC will sometimes crawl while the update is taking place (a priority boost is giving to threads blocked on disk i/o). My replacement DosOpen() masks off the OPEN_FLAGS_WRITE_THROUGH bit, so that all operations to the *.ini files are cached. Now my *.ini file updates are next to instant (a second or so), and a lot quieter; file system structures are only updated once, instead of after each DosWrite(). I'm sure someone at IBM thought they were being "safe" by using write-through mode. I disagree. The *.ini files are actually written as "os2.!!!" and "os2sys.!!!", then renamed to os2*.ini after they are on the disk. A power failure will only cause a problem if it occurs when the *.!!! files are renamed (regardless if you're using newcalls.dll or not). A power failure while the ini file data is being written to disk will cause the system to use the older *.ini files already present. It actually makes more sense to write the data out as fast as you can, to get ahead of the power failure. How to use NEWCALLS.DLL ======================= 1) Compile/link newcalls.c using IBM's compiler (the IBM linker is key; it creates the forwarder entries from the *.def file). Simply: icc /Gn /O /Fenewcalls.dll newcalls.c newfwd.def os2386.lib [see G.CMD] 2) Backup your original \os2\dll\pmmerge.dll. Run: \ibmcpp\bin\dllrname pmmerge.dll doscalls=NewCalls /q [see T.CMD] (You can't use the pmmerge.dll that is active; copy it somewhere else, modify the copy, boot to the command line, copy new dll to \os2\dll). This command will change all references to DOSCALLS to NEWCALLS.DLL. This only affects pmmerge.dll. It does not directly affect any programs that use pmmerge.dll. Furthermore, only DosOpen (Dos32Open actually) has replacement code -- all other entry points are forwarded to the real doscalls. There is ZERO runtime performance impact on forwarded calls (there is a slight LOAD time impact, as the loader does its stuff). 3) newcalls.dll, and the modified pmmerge.dll must be on your libpath (for example \os2\dll). Tip: - create a new dir called \newdll. - Place newcalls.dll, and the modified pmmerge.dll there. - Edit config.sys, make sure the directory \newdll comes before \os2\dll. - Leave your original pmmerge.dll in \os2\dll (this will allow Service Packs to correctly upadate your system). - Whenever you install a fixpak (service pack), repeat steps 2 and 3. 4) (optional). You might have noticed that newcalls.c prints a few messages to file handle 2 (stderr). If you want to see these, follow this procedure: a) Edit config.sys; change "runworkplace" to \os2\cmd.exe. b) reboot (you will be in a PM session, with an open command prompt window). c) enter "pmshell 2>stderr.out". All pmshell messages sent to stderr will go to this file, not just messages from newcalls.dll. d) To view the file while the shell is still running, use "type stderr.out". Peter Fitzsimmons, President, A:WARE Inc (OS/2 Contracting) Voice: 905 858 3222 Internet: Internet: Copyright (C) 1997, A:WARE Inc.  local copy
Record updated last time on: 04/06/2020 - 07:25

Translate to...

Add new comment