Communication Between OS/2 and WIN-OS/2 Processes

From EDM2
Jump to: navigation, search

by David Kenner

In the last volume of The Developer Connection News, I reviewed the high-level concepts of how a WIN-OS/2 process can communicate with an OS/2 process. While you can use named pipes for this purpose, we have elected to use a virtual device driver (VDD). This article describes the service routines that are contained within the VDD. If you are just starting your subscription with this release or wish to refer to the article contained in the last issue of the newsletter, you will find it, as well as its source code, on the CD-ROM that accompanies this newsletter.

This article includes the source code for the OS/2 process and the VDD that allows communication between OS/2 and WIN-OS/2. I used the Developer's Toolkit for OS/2 2.1 and the IBM C Set++ compiler to develop this sample code. The STYLE sample source code from the Toolkit provides a good Presentation Manager (PM) framework that lets us send to and receive messages from the VDD. I used the IBM C Set++ compiler for several reasons. First, drivers written in C tend to be more portable. In addition, the C Set++ compiler lets you write ring 0 code, a necessary feature for any OS/2 device driver. You must update your config.sys to load the VDD. If you have the Debug Kernel installed, you can trace through the service routines as they are being executed. In fact, the Debug Kernel will send debug information across a serial link to another system. (Refer to the Debug Kernel documentation on the CD-ROM for more information.)

The STYLE sample source code was modified as follows:

  • First, some setup work was required to get a handle to the VDD (see the OpenVirtQueue sample code on the CD-ROM) during initialization.
  • I then added another thread that would call into the VDD and block, waiting for message data to be received.
  • After message data is received, we will display the message to the screen. In addition, we added the ability to enter messages at the keyboard that will be sent to the WIN-OS/2 process. We now have a mechanism to enter, receive, and display messages.

To construct the VDD, define an entry point within the VDD named Start_Here. This corresponds to main() in a C program and will serve as the entry point that the system loader will call into when we load the VDD. The VDD will contain all the worker routines that allow message data to be copied from the context of one process to the context of the other. Most VDDs do all of their initialization at load time, and call into a companion physical device driver (PDD). During initialization, we must register the VDD with the system using the VDHRegisterVDD API. The naming convention for the VDD is up to the writer. Any application that knows the registered name of this VDD can to call the VDD for service. Registering the VDD with the system also establishes the dispatcher that will let us call into the VDD. We register our entry point with the system so that subsequent calls to DosRequestVDD will be routed through the dispatcher.

The Dispatcher

Each call into the VDD will be into the SrvDispatch procedure. This routine is prototyped as EXPENTRY, which resolves to a 32-bit far Pascal calling convention. This is the only far call within this VDD. All other calls are local to this module. Each call to SrvDispatch is done in the context of the calling task. This routine will serve as the dispatcher, based on the command that is specified as the second argument in the call to DosRequestVDD. Structure this routine , so it can service multiple threads and processes. If you have common functions that must be done either before or after each request is satisfied, put them in the dispatcher. The code for SrvDispatch follows:

LONG EXPENTRY SrvDispatch(SGID sgid,ULONG ulCommand,ULONG ulCountIn,
                          VOID pvDataIn,ULONG ulCountout,PVOID pvDataOut)
{

LONG apiRet;

#ifdef DEBUG
_interrupt(3);
#endif
do
{
  switch(ulCommand)

{
  case INIT_COMMAND:
    apiRet= OS2InitSetup();
    break;
  case POST_MESSAGE:
    apiRet=OS2PostMessage(sgid,ulCountIn,pvDataIn);
    break;
  case READ_QUEUE:
    apiRet= OS2ReadQueue(sgid,ulCountout,pvDataOut);
    break;
  case TERMINATE_COMMAND:
    OS2TerminateService();
    break;
  default:
    apiRet=TRUE;
    break;
}

}ONCE;
  return(apiRet);
}

Now, let's look at the first call that SrvDispatch handles. The function SrvInit (see the following sample code) handles all of the initialization. In the initialization code, we allocate the control structure and create a event semaphore that the readthread function will use later. Our control structure lets us keep track of multiple messages, as well as messages from multiple sessions. We will maintain a linked list of messages that we will dynamically allocate space for as each message comes in and needs to be serviced. In this VDD, we are not concerned with needing to access our data at interrupt time, so we will allocate all of our data structures as swappable. This is the preferred method because we don 't have to allocate from the fixed kernel heap.

After you complete the setup, dispatch the thread to wait for messages. The code for the SrvReadQueue function waits on the semaphore to be cleared, resets the semaphore, and returns to the calling process with the message data being stored in the local address space of the calling function.

LONG SrvReadQueue(SGID sgid,ULONG ulCountout,
                  PVOID pvDataOut)
{

#ifdef DEBUG
_interrupt(3);
#endif
do
{
 
/*
 *Wait until we get cleared and
 *if so assume we have a new message waiting for us.
 */

if(!VDHWaitEventSem(SemHandle,
   SEM_INDEFINITE_WAIT) )
{
  return(TRUE);
}
/*
 *Reset the semaphore for the next time.
 */
VDHResetEventSem(SemHandle);
/*
 *Retrieve the message data
 *and store it in pvDataOut.
 */
if(OS2ReadMessageData(sgid,ulCountout,pvDataOut) )
{
  return(TRUE);
}

}ONCE;
  return(FALSE);
}

Summary

Sending a message to the WIN-OS/2 process works in much the same way, but in reverse. The message data is copied into the input buffer for the DosRequestVDD routine. Setting the command type to POST_MESSAGE dispatches the message data to the SrvPostWinMessage routine. This routine allocates memory to make a copy of the message, files it into our local data structure, and clears the semaphore for the WIN-OS/2 side of the VDD. At this point, all we must do is send a message back to the WIN-OS/2's system queue with the right session identifier.

Stay tuned to future issues of The Developer Connection News for information on registering the WIN-OS/2's process with the VDD.

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation