Author Topic: PC Speaker output to sound card?  (Read 23338 times)

Greg Barrett

  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
    • View Profile
PC Speaker output to sound card?
« on: April 02, 2020, 07:03:33 pm »
Background:  I am working with medical device software running in eComStation 2.1 on a virtual machine (currently VirtualBox 6.1). The host OS is Windows 10. The software uses the dosbeep API call to generate its audible alarms (which, as you can imagine for a medical device, are important).  Unfortunately, VirtualBox does not support PC speaker output for OS/2 family operating systems.

Is there any way, at the OS level, to redirect PC speaker output (or even just dosbeep specifically) to the sound card?

Martin Iturbide

  • OS2World NewsMaster
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4713
  • Karma: +41/-1
  • Your Friend Wil Declares...
    • View Profile
    • Martin's Personal Blog
Re: PC Speaker output to sound card?
« Reply #1 on: April 02, 2020, 07:58:38 pm »
Hi Gregg.  Welcome to the forum.

For what I read, running Windows 10 as host on VirtualBox, there is no support to pass the beeps of the Guest OS to the host machine. There is something experimental that VirtualBox has, but it only works on a Linux host and it may not work depending on the distro. (Here it is the source)

I also had tried a program (rhythm.zip) that uses the PC speaker on a ArcaOS VM (Guest) running on VirtualBox Windows 10 (host). And I confirm that it does not beep.

I'm not sure if there is something, like a driver that pass through the pc sepaker to the sound blaster or Uniaud audio driver. Maybe someone else has a different idea for a solution. You don't have the source code for the medical software on the device, right?

Regards
Martin Iturbide
OS2World NewsMaster
... just share the dream.

David Graser

  • Hero Member
  • *****
  • Posts: 870
  • Karma: +84/-0
    • View Profile
Re: PC Speaker output to sound card?
« Reply #2 on: April 02, 2020, 09:06:54 pm »
There is an old pc speaker driver for OS/2.  However, don't know if it would work, especially using a virtual machine.

https://hobbes.nmsu.edu/download/pub/os2/system/drivers/sound/IBM_Speaker_1-0-9.zip

This is the readme:
Code: [Select]

                   IBM Multimedia Presentation Manager/2
                            Speaker Audio DD
                               Version 1.1
           (C) Copyright IBM Corp. 1991, 1993  All Rights Reserved.
                     IBM is a registered trademark of the
                 International Business Machines Corporation
   U.S. Government Users Restricted Rights - Use, duplication or disclosure
            restricted by GSA ADP Schedule Contract with IBM Corp.

Introduction

   The Speaker audio device driver provide support for playing digital
   audio waveform files on the standard PC speaker by using the
   MMPM/2 audio system.   This support is important because it allows
   non-multimedia enabled systems to play short sound effects and other
   short digitized sound through the PC speaker.

   The speaker driver provides support for PCM waveform files that
   are (8-bit/16-bit, stereo/mono, 11Khz-44khz).

   This driver is intended for use under OS/2 2.1 or greater.

   The quality of sound produced from the speaker device is low
   compared to a real audio card, and will vary from machine to
   machine.

Caveat

   The standard PC speaker was not intended to play digitized waveform
   sound.  In order to produce a reasonable approximation of the
   sound contained in .WAV files, the device driver requires
   exclusive use of the CPU for an extended period of time.  This
   may have undersirable effects on performance critical multitasking
   such as communications, modem transfers, networking, etc.
   We do not recommend that this software be used in conjunction with
   communications software, time critical, or mission critical application.
   This may include printing and mouse operation during sound generation.

   If you experience problems, you should discontinue use of the
   speaker device driver.

   Interrupts are enabled while the speaker is being operated, however
   multitasking operation is suspended.

   This software is not supported by IBM technical support channels.

License

   IBM grants the right to use, reproduce, and distribute this
   speaker driver software provided that (1) it is not distributed for
   profit, (2) it is used only with licensed copies of OS/2 2.1,
   (3) the software is not modified, (4) all copyright notices
   remain with the software, (5) the end user agrees to the license.

   This speaker driver is provided in 'as is' condition without
   warranty of any kind and no support will be provided.

   IBM and its vendors takes no responibility and is not liable for
   any consequences or damages of any kind resulting from the
   use or existence of this software.

   IBM does not guarantee that the speaker driver software will run
   on all machines.  IBM is not obligated to provide any updates to
   this software.

Installation

   1) Install the MMPM/2 base.  The MINSTALL program requires you
      to select one of the subsystems in order to do an install.  If
      you don't already have a audio card, or CD-ROM, then you
      can select Software Motion Video which doesn't require any special
      hardware other than the monitor.

      Reboot after this installation.

   2) Place the files from the SPKRDD package into a subdirectory (i.e. \spkrdd)

   3) Use the MINSTALL installation program from the MMPM/2 folder to
      select the \spkrdd directory.  Install the Speaker Driver
      package by selecting the speaker driver object and pressing Install.

   4) After install is complete, a reboot is required.

Configuration

   The speed and volume of the sound produced by the speaker device
   driver must be configured on a machine by machine basis.

   1) Select the Multimedia Setup program in the MMPM/2 folder.

   2) Select the speaker settings page, to customize the speed and
      volume of speaker.  The speaker push button will place a test
      sound, that will give you some feedback on the speed and volume
      adjustments.

Uninstall

   If you experience problems with the speaker device driver and wish to
   un-install it.

   1) Edit you config.sys, and comment out the device driver line:

      REM DEVICE=D:\MMOS2\SPKRDD.SYS

   2) Edit MMPM2.INI and remove PCSPEAKER and SPKRDDAMP and any references
      to these names.

Notes:

   1) If you install only Software Motion Video support, and then the speaker
      device driver,  the Software Motion Video support will run without
      audio support. This is preferable, since both software video and
      the speaker driver compete for the CPU.

      If however you want to try, running them both together, the
      MMPM2.INI can be updated as follows.  This will also cause the
      audio and video to be out of sync.

      [ibmdigvidplayer01]
         CONNECTORS=1,3,SPKRDDAMP,1

   2) The system sounds support, for which the speaker driver is intended for,
      will be installed automatically by the install of MMPM/2 base.  System
      sounds plays on the default device.  If you install support for
      another audio card first, then install the speaker device driver, the
      other audio card will be the default.  The default can be changed
      in the Multimedia Setup Program.

Fixes:

   1) The internal design of the drive has been modified to use a time
      critical thread rather than a timer.

   2) A defect causing problems with interrupt driven devices has been
      fixed.  It most commonly caused the mouse to lock up, but has
      also caused printing problems.
« Last Edit: April 11, 2020, 04:04:18 am by Martin Iturbide »

Greg Barrett

  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: PC Speaker output to sound card?
« Reply #3 on: April 02, 2020, 09:34:38 pm »
Thanks for the reply, but this is basically the opposite of what I'm hoping for.  I need audio intended for the PC speaker to play through the sound card instead.

There is an old pc speaker driver for OS/2.  However, don't know if it would work, especially using a virtual machine.

https://hobbes.nmsu.edu/download/pub/os2/system/drivers/sound/IBM_Speaker_1-0-9.zip

This is the readme:...
« Last Edit: April 03, 2020, 01:12:28 am by Martin Iturbide »

Martin Iturbide

  • OS2World NewsMaster
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4713
  • Karma: +41/-1
  • Your Friend Wil Declares...
    • View Profile
    • Martin's Personal Blog
Re: PC Speaker output to sound card?
« Reply #4 on: April 03, 2020, 01:19:00 am »
Hi Gregg

Can you try to specify the medical device and the software that is running there? Maybe some other solution can be thought, or maybe someone already had worked with that device and software.

You don't have the source code of the OS/2 medical application, right?

Regards
Martin Iturbide
OS2World NewsMaster
... just share the dream.

Greg Barrett

  • Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: PC Speaker output to sound card?
« Reply #5 on: April 03, 2020, 02:45:18 pm »
The software is for the Microlab F.A.M.E. from Hamilton Robotics.  We do not have the source code.

Neil Waldhauer

  • Hero Member
  • *****
  • Posts: 1024
  • Karma: +24/-0
    • View Profile
    • Blonde Guy
Re: PC Speaker output to sound card?
« Reply #6 on: April 03, 2020, 04:06:36 pm »
There ought to be a way to intercept the DosBeep call and re route it to MMOS2. DosBeep is a Control Program API, so it's in DOSCALL, isn't it? Replacing DOSCALL1.DLL would be tricky, but should be possible.

You could also load your own DLL, and binary edit the exe to change the DosBeep to a call to your own DLL.
Expert consulting for ArcaOS, OS/2 and eComStation
http://www.blondeguy.com

Martin Iturbide

  • OS2World NewsMaster
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4713
  • Karma: +41/-1
  • Your Friend Wil Declares...
    • View Profile
    • Martin's Personal Blog
Re: PC Speaker output to sound card?
« Reply #7 on: April 11, 2020, 04:06:11 am »
Hi Greg.

I'm sorry we don't have a solution for what you are looking for.  But if it is possible for your I would like to ask you for more information about this medical device that is using OS/2.

Can you provide the me model, pictures or any information about it? I'm always curious about industrial uses of OS/2.

Regards
Martin Iturbide
OS2World NewsMaster
... just share the dream.

Lars

  • Hero Member
  • *****
  • Posts: 1271
  • Karma: +65/-0
    • View Profile
Re: PC Speaker output to sound card?
« Reply #8 on: April 12, 2020, 04:01:24 pm »
As Neil has already pointed out, there is a solution (even though a bit clunky, there is no easy way) and it is contained in here (but the changes go against DOSCALLS imports and not DOSCALL1 imports):
http://www.edm2.com/common/snippets/newc2.zip

However, the DEF file contained in this zip file needs an update /to be extended, all DOSCALLS entry points are described here:
http://home.clara.net/orac/os2/doscalls.htm

You need to adapt the sample in the ZIP file, you need to override DOS16BEEP (if your app is 16-bit) or DOS32BEEP (if you app is 32-bit) instead of DOS16OPEN /DOS32OPEN.
You then need to rename the internal References to DOSCALLS in your application to NEWCALLS (instead of renaming inside PMMERGE as the sample code is asking for). You will then need to place NEWCALLS.DLL In your application's exe file directory (preferrably).

Finally you need to know how to play a sound file via MMPM.
Sample code:
Quote
#define INCL_BASE
#include <os2.h>

#define INCL_OS2MM
#include <os2me.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>

typedef struct _STATEVECTOR
{
   USHORT usSize;
   HEV hev;
   ULONG ulBufLen;
   PVOID pBuffer;
} STATEVECTOR, *PSTATEVECTOR;

APIRET SetupData(PSZ pszFileName,PSTATEVECTOR pS)
{
   FILESTATUS3 fs={0};
   HFILE hfile=NULLHANDLE;
   ULONG ulAction=0UL;
   APIRET rc=NO_ERROR;

   rc = DosQueryPathInfo(pszFileName,FIL_STANDARD,&fs,sizeof(fs));
   if (rc == NO_ERROR) {

      pS->ulBufLen = fs.cbFile;
      rc = DosAllocMem((PPVOID)&pS->pBuffer,pS->ulBufLen,PAG_READ|PAG_WRITE|PAG_COMMIT|OBJ_ANY);

      if (rc == NO_ERROR) {
         rc = DosOpen(  pszFileName,
                        &hfile,
                        &ulAction,
                        0UL,
                        FILE_NORMAL,
                        OPEN_ACTION_OPEN_IF_EXISTS|OPEN_ACTION_FAIL_IF_NEW,
                        OPEN_ACCESS_READONLY|OPEN_SHARE_DENYNONE,
                        NULL);

         rc = DosRead(hfile,pS->pBuffer,pS->ulBufLen,&pS->ulBufLen);
         rc = DosClose(hfile);
      }
   }
   if (rc == NO_ERROR)
      return 1;
   else
      return 0;
}


void _LNK_CONV WorkerThread(void *p)
{
   #define MCI_ERROR_LENGTH 128
   CHAR errorBuffer[MCI_ERROR_LENGTH]={0};
   MMIOINFO mmioInfo;
   MMFORMATINFO mfi={0}, *pmfi=NULL;
   HMMIO hmmio;
   LONG lFormats=0;
   APIRET rc;
   STATEVECTOR state;
   PSTATEVECTOR pS=&state;
   MCI_OPEN_PARMS mop;
   MCI_PLAY_PARMS mpp;
   MCI_GENERIC_PARMS mgp;


   memcpy(&state,p,sizeof(STATEVECTOR));
   rc = DosPostEventSem(pS->hev);

   mfi.ulStructLen   = sizeof(mfi);
   mfi.ulIOProcType  = MMIO_IOPROC_DATAFORMAT;
   mfi.ulMediaType   = MMIO_MEDIATYPE_AUDIO;
   rc = mmioQueryFormatCount(&mfi,&lFormats,0UL,0UL);
   pmfi = (PMMFORMATINFO)calloc(lFormats,sizeof(*pmfi));
   if (!pmfi)
   {
      _endthread();
   }

   if (pS->pBuffer) {

      rc = mmioGetFormats(&mfi,lFormats,pmfi,&lFormats,0UL,0UL);
      /*
         We HAVE TO check the FOURCC in this reverse order !
         Why ? Because VORBIS/FLAC/MP3 IOProcs are lacking
         a data format identification !
         If we do it in this reverse order, WAV will be checked
         before those, so at least WAVs are correctly identified
         as WAVs BEFORE they are misidentified as MP3/VORBIS/FLAC
         However it is IMPOSSIBLE to tell apart VORBIS/FLAC/MP3
         for exactly the reason stated above !
      */
      for (LONG i=lFormats-1;i>=0;i--)
      {
         /*
            Seesh, AVCA IOProc traps on this simple action
            skip it
         */
         if (pmfi.fccIOProc == mmioFOURCC('A','V','C','A'))
         {
            continue;
         }

         memset(&mmioInfo,0,sizeof(mmioInfo));
         mmioInfo.fccChildIOProc = FOURCC_MEM;
         mmioInfo.pchBuffer      = (PCHAR)pS->pBuffer;
         mmioInfo.cchBuffer      = pS->ulBufLen;
         mmioInfo.ulTranslate    = MMIO_TRANSLATEHEADER|MMIO_TRANSLATEDATA;
//         mmioInfo.fccIOProc = pmfi.fccIOProc;
         mmioInfo.fccIOProc = mmioFOURCC('M','P','3',' ');
         hmmio = mmioOpen(NULL,&mmioInfo,MMIO_READ|MMIO_DENYNONE);
         if (hmmio)
         {
            break;
         }
      }

      if (hmmio) {
         memset(&mop,0,sizeof(mop));
         mop.pszElementName = (PSZ)hmmio;
         mop.pszDeviceType = (PSZ)MAKEULONG(MCI_DEVTYPE_WAVEFORM_AUDIO, 0);
         rc = mciSendCommand(0,MCI_OPEN,MCI_WAIT|MCI_READONLY|MCI_OPEN_MMIO|MCI_OPEN_TYPE_ID,&mop,0);
         if (LOUSHORT(rc) != MCIERR_SUCCESS)
         {
            mciGetErrorString(rc,errorBuffer,MCI_ERROR_LENGTH);
            printf("open MMIO failed:%s\n",errorBuffer);
         }

         memset(&mpp,0,sizeof(mpp));
         rc = mciSendCommand(mop.usDeviceID,MCI_PLAY,MCI_WAIT,&mpp,0);
         if (LOUSHORT(rc) != MCIERR_SUCCESS)
         {
            mciGetErrorString(rc,errorBuffer,MCI_ERROR_LENGTH);
            printf("open MMIO failed:%s\n",errorBuffer);
         }

         memset(&mgp,0,sizeof(mgp));
         rc = mciSendCommand(mop.usDeviceID,MCI_STOP,MCI_WAIT,&mgp,0);
         if (LOUSHORT(rc) != MCIERR_SUCCESS)
         {
            mciGetErrorString(rc,errorBuffer,MCI_ERROR_LENGTH);
            printf("open MMIO failed:%s\n",errorBuffer);
         }

         memset(&mgp,0,sizeof(mgp));
         rc = mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp,0);
         if (LOUSHORT(rc) != MCIERR_SUCCESS)
         {
            mciGetErrorString(rc,errorBuffer,MCI_ERROR_LENGTH);
            printf("open MMIO failed:%s\n",errorBuffer);
         }

         rc = mmioClose(hmmio,0);
         if (LOUSHORT(rc) != MMIO_SUCCESS)
         {
            mciGetErrorString(rc,errorBuffer,MCI_ERROR_LENGTH);
            printf("open MMIO failed:%s\n",errorBuffer);
         }
      }
      rc = DosFreeMem(pS->pBuffer);
   }
   free(pmfi);
}


int main(int argc,char *argv[])
{
   APIRET rc;
   TID tid=0;
   STATEVECTOR state={sizeof(STATEVECTOR),0};
   PSTATEVECTOR pS=&state;

   if (argc != 2)
   {
         CHAR name[_MAX_FNAME];
         _splitpath(argv[0],NULL,NULL,name,NULL);
         printf("Usage: % [sound file to play]\n",name);
         return 1;
   }

   if (SetupData(argv[1],pS))
   {
      rc = DosCreateEventSem(NULL,&(pS->hev),0UL,0UL);
      tid = _beginthread(WorkerThread,NULL,32768UL,pS);
      /*
         we have to make sure we wait until the state data
         is copied from this main thread's stack to the
         worker thread's stack
      */
      rc = DosWaitEventSem(pS->hev,SEM_INDEFINITE_WAIT);
      rc = DosCloseEventSem(pS->hev);

      /*
         DosWaitThread is only necessary in this sample program
         in a real application, the worker thread can just
         continue to operate while the main thread returns
         to the calling routine
      */
      rc = DosWaitThread(&tid,DCWW_WAIT);
   }

   return 0;
}

From the code, skip the stuff you are not interested in (for example, setting up a second thread, or querying all sound formats, there is no need to query that if you know you are going to play a WAV file).


« Last Edit: April 12, 2020, 04:13:50 pm by Lars »

Lars

  • Hero Member
  • *****
  • Posts: 1271
  • Karma: +65/-0
    • View Profile
Re: PC Speaker output to sound card?
« Reply #9 on: April 15, 2020, 08:49:27 pm »
Because the corona virus is giving me too much time, I hacked together a NEWCALLS.DLL that will generate a "beep" of given freq and duration as a WAV file and play that via MMPM and will therefore serve as a direct replacement of the "DosBeep" API function.
Find attached, including source code. It's free, whoever it may serve a purpose.

Lars

Martin Iturbide

  • OS2World NewsMaster
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4713
  • Karma: +41/-1
  • Your Friend Wil Declares...
    • View Profile
    • Martin's Personal Blog
Re: PC Speaker output to sound card?
« Reply #10 on: April 15, 2020, 10:25:48 pm »
That is awesome Lars.

How goes it has to be installed?  run the cmd and reboot? or I need to copy the DLL into /DLL ?
Did you tried it with some specific tool that make the speakers sound?

Regards
Martin Iturbide
OS2World NewsMaster
... just share the dream.

Lars

  • Hero Member
  • *****
  • Posts: 1271
  • Karma: +65/-0
    • View Profile
Re: PC Speaker output to sound card?
« Reply #11 on: April 16, 2020, 07:20:33 am »
Hi Martin,
get this:
http://www.edm2.com/common/snippets/newc2.zip
and read the readme that it contains. That explains what it is all about. In general, you need to patch any EXE or DLL where you want to have the default API implentation of DosBeep replaced by an "MMPM" version.
You need a rename tool to patch the binary. VAC has one but there is also one on Hobbes I think.
« Last Edit: April 16, 2020, 07:24:01 am by Lars »

Martin Iturbide

  • OS2World NewsMaster
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4713
  • Karma: +41/-1
  • Your Friend Wil Declares...
    • View Profile
    • Martin's Personal Blog
Re: PC Speaker output to sound card?
« Reply #12 on: April 16, 2020, 04:38:20 pm »
Hi Lars

For what I can read the instructions it says to:
1) Backup PMMERGE.DLL
2) Copy Newcalls.dll to the OS2/DLL
3) Modify PMMERGE.DLL  with "dllrname pmmerge.dll doscalls=NewCalls /q"

Does it means that all PM applications that uses DosBeep (and PC Speaker) will play on the sound device ? or also the command line applications (non PM Applications) that uses DosBeep are going to change too?

Or, if understand you right, you can only patch the program that uses DosBeep, instead of patching OS/2's DLLs ?

Regards
« Last Edit: April 16, 2020, 04:40:10 pm by Martin Iturbide »
Martin Iturbide
OS2World NewsMaster
... just share the dream.

Lars

  • Hero Member
  • *****
  • Posts: 1271
  • Karma: +65/-0
    • View Profile
Re: PC Speaker output to sound card?
« Reply #13 on: April 16, 2020, 05:27:31 pm »
My newcalls is based on the idea of the original newcalls package by Peter Fitzsimmons but it is not the very same.

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.

You then run:
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:
https://hobbes.nmsu.edu/download/pub/os2/dev/util/dllrname.zip
https://hobbes.nmsu.edu/download/pub/os2/util/system/renmodul2_0_0.zip
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.


Lars

« Last Edit: April 16, 2020, 05:36:10 pm by Lars »

Martin Iturbide

  • OS2World NewsMaster
  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4713
  • Karma: +41/-1
  • Your Friend Wil Declares...
    • View Profile
    • Martin's Personal Blog
Re: PC Speaker output to sound card?
« Reply #14 on: April 16, 2020, 07:00:13 pm »
Thanks for the explanation Lars. Now I get what to do.

Sadly I was not able to get results. I tested two programs on an ArcaOS VM (with Uniaud working) from hobbes: rhythm.zip and os2sn2.zip.
os2sn2.zip comes with the source code, and it seems it does not use DosBeep. rhythm did not also produced any sound.

Did you tried it on some other program (executable) just to test it is working?

Regards
Martin Iturbide
OS2World NewsMaster
... just share the dream.