WaitForSingleObject with timout on CD-ROM

I have written an application which uses ASPI (from the WNASPI32.DLL) to read data from a CD-ROM drive. All is well except that some drives take an excessive time to return if there is an error on the disc. I tried to put a time-out of 1 second on the 'WaitForSingleObject' rather than the original 'INFINITE'. When I did this my application starts to crash in ring 0.

On debugging the program it seems to behave OK up-to the first time that the WaitForSingleObject returns with a time-out. Sometime after this the program crashes. Unfortunately if I step through the code it all works, this seems to indicate a timing problem that I am finding very difficult to trace, hence the high points for the answer!

Program crashes in same way on both W95 and W98.

The full code is:-
---------------- cut here -------------
#include <windows.h>
#include <stdio.h>

typedef void *LPSRB;

#define SS_PENDING                  0x00        // SRB being processed
#define SS_COMP                     0x01        // SRB completed without error

#define SENSE_LEN                   14          // Default sense buffer length
#define SRB_EVENT_NOTIFY            0x40        // Enable ASPI event notification
#define SRB_DIR_IN                  0x08        // Transfer from SCSI target to host
#define SC_EXEC_SCSI_CMD            0x02        // Execute SCSI command

typedef struct
    BYTE    SRB_Cmd;                // ASPI command code = SC_EXEC_SCSI_CMD
    BYTE    SRB_Status;             // ASPI command status byte
    BYTE    SRB_HaId;               // ASPI host adapter number
    BYTE    SRB_Flags;              // ASPI request flags
    DWORD   SRB_Hdr_Rsvd;           // Reserved
    BYTE    SRB_Target;             // Target's SCSI ID
    BYTE    SRB_Lun;                // Target's LUN number
    WORD    SRB_Rsvd1;              // Reserved for Alignment
    DWORD   SRB_BufLen;             // Data Allocation Length
    LPBYTE  SRB_BufPointer;         // Data Buffer Pointer
    BYTE    SRB_SenseLen;           // Sense Allocation Length  
    BYTE    SRB_CDBLen;             // CDB Length
    BYTE    SRB_HaStat;             // Host Adapter Status
    BYTE    SRB_TargStat;           // Target Status
    LPVOID  SRB_PostProc;           // Post routine
    BYTE    SRB_Rsvd2[20];          // Reserved for alignment
    BYTE    CDBByte[16];            // SCSI CDB
    BYTE    SenseArea[SENSE_LEN+2]; // Request Sense buffer

#define      PAGE_SIZE                  4096

void      ReadSector(int *retVal, long sector, int device, int unit, BYTE *bufPtr, int sectorSize);

BYTE      buffer[PAGE_SIZE];                              // General purpose buffer. sector data and pe file data
HANDLE      eventHandle;
SEND_ASPI_32_COMMAND_PROC            pfnSendASPI32Command;
HINSTANCE                                    hinstWNASPI32;

void main(void) {
      long                  sector;
      int                        rv;
      int                        device;
      int                        unit;

      device = 0;
      unit = 0;

      eventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
      hinstWNASPI32 = LoadLibrary("WNASPI32");
      if (!hinstWNASPI32) {
            printf("Cannot load wnaspi32.dll\n");
      pfnSendASPI32Command = (SEND_ASPI_32_COMMAND_PROC)GetProcAddress(hinstWNASPI32, "SendASPI32Command");

      if (!pfnSendASPI32Command) {
            printf("Cannot get address of SendASPI32Command\n");

      // Test disc using aspi calls
      for (sector = 16; sector < 500; sector++) {
            ReadSector(&rv, sector, device, unit, buffer, 2048);
            if (rv == SS_COMP) {
            } else {

void SendASPICmd(SRB_ExecSCSICmd *cmd) {
      if (cmd->SRB_Status == SS_PENDING) {
            WaitForSingleObject(eventHandle, INFINITE);

void      ReadSector(int *retVal, long sector, int device, int unit, BYTE *bufPtr, int sectorSize) {
      SRB_ExecSCSICmd      *srbCmd = NULL;
      BYTE      *buffer = NULL;

      *retVal = 0;
      if ((srbCmd = (SRB_ExecSCSICmd *)malloc(sizeof(SRB_ExecSCSICmd))) == NULL) {
            goto TIDY_EXIT;
      if ((buffer = (BYTE *)malloc(sectorSize)) == NULL) {
            goto TIDY_EXIT;

      memset(srbCmd, 0, sizeof(SRB_ExecSCSICmd));
      memset(buffer, 0, sectorSize);

      srbCmd->SRB_Cmd                  = SC_EXEC_SCSI_CMD;
      srbCmd->SRB_HaId            = device;
      srbCmd->SRB_Flags            = SRB_EVENT_NOTIFY | SRB_DIR_IN;
      srbCmd->SRB_Target            = unit;
      srbCmd->SRB_BufLen            = sectorSize;
      srbCmd->SRB_BufPointer      = buffer;
      srbCmd->SRB_SenseLen      = 14;
      srbCmd->SRB_CDBLen            = 10;
      srbCmd->SRB_PostProc      = eventHandle;
      srbCmd->CDBByte[0]            = 40;
      srbCmd->CDBByte[2]            = HIBYTE(HIWORD(sector));
      srbCmd->CDBByte[3]            = LOBYTE(HIWORD(sector));
      srbCmd->CDBByte[4]            = HIBYTE(LOWORD(sector));
      srbCmd->CDBByte[5]            = LOBYTE(LOWORD(sector));
      srbCmd->CDBByte[8]            = 1;


      *retVal= srbCmd->SRB_Status;
      memcpy(bufPtr, buffer, sectorSize);
      if (srbCmd) free(srbCmd);
      if (buffer) free(buffer);
--------------- cut here -----------------
Who is Participating?
nietodConnect With a Mentor Commented:
You are crashing because when the SendASPICmd(srbCmd) function times out in the ReadSector() function, you then go and delete the buffer (to clean up).  however the SendASPI32Command(cmd) is still executing asynchronously and will continue to try to use that memory.  

Let me know if you have any questions.
Wow, 2000 pts, I thought it was 200.  That hardly seems like a 2000 point answer.  But I'm not sure what else to say, unless you don't understand what I wrote.
styxAuthor Commented:
2000 points may seem a lot for such a simple answer. However as far as I am concerned it was well worth it since I had not be able to 'see the wood for the trees' for several days.
I knew your answer was correct as soon as I saw it, as indeed it turned out to be.

Having gotten past that problem however I then found that I was left with unfinished SRBs on the SCSI bus by timing out the event. I first thought I could send an ABORT SRB but the documentation told me that they rarely work! I concluded that I must set target timeouts rather than timeout the event.

The bottom line now that this problem has been solved is that I am throwing this approach away and using an alternative method!

This must be the most 'expensive' throw-away question on EE :-)

Thanks again for your timely help.

ps. This question should now put you into second place ;-)

>> This must be the most 'expensive' throw-away question on EE :-)
It may have been the most expensive period.  I've seen a few 500 point questions, I don't think I've ever seen anything more than that.  EE doesn't even show 4 digit point questions correctly.  One the question screen it was listed as 200 points not as 2000.  (Which is why I was surprised to see it was for 2000 after I answered.)
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.