[Compuware Corporation] [Compuware NuMega home page]                [NuMega Lab]
[teal]

 [DriverStudio]    [Image][Image]
   Home
 [Driver Products]        Driver Technical Tips
   DriverStudio          A Better Way to Provide VxD to VxD Services
   DriverBundle
   Previews              When a VxD wants to export services to other VxDs, the conventional approach is
   Compatibility         to create a VxD service table. The VxD service table contains the addresses of
 [Downloads]             the services to be exported, and there is a pointer to the table in the VxD's
                          Device Data Block (DDB). Other VxDs call the exported services using macro
 Wizards                  VxDCall. This macro issues instruction INT 20h, which is trapped by the system.
   Utilities             The system's INT 20h handler examines the DWORD that immediately follows the
   NT source             INT instruction to determine which VxD service is being called. The exporter
 examples                 VxD is identified by a device ID constant, and the service within that VxD by
   VxD source            an ordinal value. The INT 20h locates the DDB of the exporter VxD, finds its
 examples                 service table, extracts the function address, and then patches over the INT 20h
   WDM source            in the caller's instruction stream with a CALL instruction that invokes the
 examples                 target VxD service.
 [Resources]  
 Technical papers         While this mechanism is certainly tried and true, it has some disadvantages.
   Useful links          First, the declaration of the VxD service table requires use of a few ugly
   Technical tips        macros. Then the address of the table and the service count must be inserted
 [Support]               into the DDB. These details create opportunities to introduce bugs. Ensuring
                          matching calling sequences and calling conventions (i.e. __stdcall vs. __cdecl)
 Support                  complicates it further. Another headache is obtaining a unique device ID to
   Knowledge base        designate the exporter VxD. VxD ID constants are allocated only by Microsoft,
   Problem               so if you arbitrarily assign one, then your VxD could conflict with some other
 submission               VxD.
   Product
 registration             There is an alternative approach to exporting VxD services which addresses some
   Release notes         of these problems. You can use the system service Directed_Sys_Control to send
 [Shop NuMega]           a control message to the exporter VxD. Typically, the control message that you
 Buy it!                  send is the general purpose W32_DEVICEIOCONTROL. In other words, a VxD can
   Price list            export a set of services, each of which corresponds to a unique identifier
   How to buy            passed with the W32_DEVICEIOCONTROL message.
   Sales offices
                          In the VxD that exports the services, using this method is as simple as adding
                          cases to a switch statement in the handler for W32_DEVICEIOCONTROL. However,
 [Y2K Compliance]         the first step is to create a shared include file that defines the set of
                          identifiers for the services. This is done with macro CTL_CODE:

 [More information]       // my_ioctls.h

                          #define IOCTL_MYDRIVER_SERVICE_1 \
                                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS)
                          #define IOCTL_MYDRIVER_SERVICE_2 \
                                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)
                          #define IOCTL_MYDRIVER_SERVICE_3 \
                                  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_NEITHER, FILE_ANY_ACCESS)

                          The code above defines three constants that identify the exported services. So
                          the handler for W32_DEVICEIOCONTROL in the exporter VxD looks like this (using
                          VtoolsD):

                          DWORD OnW32Deviceiocontrol(PIOCTLPARAMS p)
                          {
                                  switch (p->dioc_IOCtlCode)
                                  {
                                  case DIOC_OPEN:         // CreateFile
                                  case DIOC_CLOSEHANDLE:  // handle closed
                                          return DEVIOCTL_NOERROR;

                                  case IOCTL_MYDRIVER_SERVICE_1:
                                          // implement service 1
                                          break;
                                  case IOCTL_MYDRIVER_SERVICE_2:
                                          // implement service 2
                                          break;
                                  case IOCTL_MYDRIVER_SERVICE_3:
                                          // implement service 3
                                          break;

                                  default:
                                          return 1; // bad function
                                  }
                          }

                          In order to use Directed_Sys_Control from the calling VxD to send a message to
                          the exporter VxD, you must first locate the DDB of the exporter VxD. This has
                          to be done just once, not each time the calling VxD sends a message.

                          To locate the DDB of the target device, use system service Get_DDB. Once you
                          have a valid DDB pointer, use this function to call the exported service:

                          BOOL SendDeviceIoControl(
                                  PDDB pDdb,               // pointer to DDB of exporter VxD
                                  ULONG IoctlCode,         // dioc_IOCtlCode
                                  PVOID InputBuffer,       // dioc_InBuf
                                  ULONG SizeOfInputBuffer, // dioc_cbInBuf
                                  PVOID OutputBuffer,      // dioc_OutBuf
                                  ULONG SizeOfOutputBuffer,// dioc_cbOutBuf
                                  PULONG pBytesReturned    // dioc_bytesret
                                  )
                          {
                                  ALLREGS regs;   // register struct passed to Directed_Sys_Ctrl
                                  IOCTLPARAMS io; // Ioctl param struct passed to target device

                                  if ( pDdb == NULL )
                                          return FALSE;

                                  // set up the ioctl params
                                  io.dioc_IOCtlCode = IoctlCode;
                                  io.dioc_InBuf = InputBuffer;
                                  io.dioc_cbInBuf = SizeOfInputBuffer;
                                  io.dioc_OutBuf = OutputBuffer;
                                  io.dioc_cbOutBuf = SizeOfOutputBuffer;
                                  io.dioc_bytesret = pBytesReturned;

                                  // clear the regs structure
                                  memset(&regs, 0, sizeof(regs));

                                  // put a pointer to the ioctl param struct in the register struct
                                  regs.RESI = (DWORD)&io;

                                  // send the message to the target device
                                  Directed_Sys_Control(pDdb, W32_DEVICEIOCONTROL, &regs);

                                  return (regs.REAX == DEVIOCTL_NOERROR);
                          }

                          The parameters to the SendDeviceIoControl become the indicated members of the
                          IOCTLPARAMS structure that the exporter VxD receives in its handler for control
                          message W32_DEVICEIOCONTROL. You can customize a set of services using this
                          general mechanism.

                          Compared to the conventional VxD service table method, the Directed_Sys_Control
                          method has some clear advantages. It avoids the use of complicated and error
                          prone macros. There is a single fixed calling convention which can be safely
                          adapted to an arbitrary set of services. You don't need to obtain a unique
                          device ID constant from Microsoft. And if you will be porting the VxD to an NT
                          or WDM driver in the future, the code will be much easier to port.

                          One note of warning. Directed_Sys_Control does not validate the DDB pointer
                          passed to it, so the exporter VxD and its caller should establish a protocol
                          that provides the caller of some notification when the exporter unloads.

                          Back to technical tip start page.

  DriverCentral  DriverStudio  Free downloads  Resources  Support and
                          Services  Shop NuMega
     Compuware NuMega  Tel: +1 603 578-8400  Updated: 9 August 1999 
                      Problems? Contact our webmaster.
