Einzelnen Beitrag anzeigen

Daniel G
(Gast)

n/a Beiträge
 
#1

[AV] Ende einer Prozedur verursacht eine AV...

  Alt 11. Jul 2006, 23:53
N'Abend,

Ich hab' mal wieder ein kleines Problem mit einem C - Code, den ich nach Delphi portiert habe. (Ja, ich weiß, ich sollte diese verdammte Sprache endlich lernen ). Da in dem Original die AV nicht auftritt, denke ich, dass das mit meiner Portierung zu tun hat...

Nevertheless, mein Problem liegt hier:

Delphi-Quellcode:
//----------------------------------------------------------------------------
// ATA-Befehle unter Windows 2000 oder XP versenden
Function TAAMClass.SendCommand_Win2000(pATARegs: PATARegs; var pBuf;
BufSize: Cardinal; pResultSize: Cardinal): Boolean;
var
  Size: Cardinal;
  VirtualAddress: Pointer;
  pAPT: ATA_PASS_THROUGH;
  BytesReturned: LongWord;
  Status: Boolean;
  ReturnedSize: Cardinal;
begin
  Result := FALSE;
  BytesReturned := 0;

  Size := sizeof(ATA_PASS_THROUGH) + BufSize;
  // Datenpuffer mit VirtualAlloc anfordern, damit der Gerätetreiber den Speicher ansprechen kann
  VirtualAddress := VirtualAlloc(NIL, Size, MEM_COMMIT, PAGE_READWRITE);
  pAPT := ATA_PASS_THROUGH(VirtualAddress^);

  if Assigned(@pAPT) then
  begin
      //ZeroMemory(@pAPT, Size);
      // Größe des Datenpuffers setzen
      pAPT.DataBufferSize := BufSize;
      // ATA-Register setzen
      pAPT.IdeReg.bFeaturesReg := pATARegs^.Reg[0];
      pAPT.IdeReg.bSectorCountReg := pATARegs^.Reg[1];
      pAPT.IdeReg.bSectorNumberReg := pATARegs^.Reg[2];
      pAPT.IdeReg.bCylLowReg := pATARegs^.Reg[3];
      pAPT.IdeReg.bCylHighReg := pATARegs^.Reg[4];
      pAPT.IdeReg.bDriveHeadReg := pATARegs^.Reg[5];
      pAPT.IdeReg.bCommandReg := pATARegs^.Reg[6];

      if (pAPT.IdeReg.bCommandReg = $EC) then // ist es ATA IDENTIFY?
      begin
           // Windows XP merkt sich den IDE-Konfigurationssektor
          // daher vorher mit IOCTL_SCSI_RESCAN_BUS für ungültig erklären

          DeviceIoControl(fDriveHandle, IOCTL_SCSI_RESCAN_BUS, NIL, 0, NIL, 0, BytesReturned, 0);
          // eine halbe Sekunde warten
          Sleep(500);
      end;

      BytesReturned := 0;
      
      Status := DeviceIoControl(fDriveHandle, IOCTL_IDE_PASS_THROUGH,
                                    @pAPT, Size, @pAPT, Size, BytesReturned, 0);
      if not Status then
        fError := aec_CommandFailed
      else
      begin
          if Assigned(@pBuf) then
          begin
              if (BufSize <> 0) then
                ZeroMemory(@pBuf, BufSize);
              if (BytesReturned > sizeof(ATA_PASS_THROUGH)) then
              begin
                  ReturnedSize := BytesReturned - sizeof(ATA_PASS_THROUGH);
                  if (pResultSize <> 0) then
                    pResultSize := ReturnedSize;
                  if (ReturnedSize > BufSize) then
                    ReturnedSize := BufSize;
                  Move(pAPT.DataBuffer, pBuf, ReturnedSize);
              end;
          end;
          Result := TRUE;
      end;
      VirtualFree(@pAPT, Size, MEM_RELEASE);
  end
  else
    fError := aec_OutOfMemory;
end;
Nachdem die Funktion durchlaufen wurde, werde ich mit einer AV bombadiert:

Zitat:
---------------------------
Anwendungsfehler
---------------------------
Exception EAccessViolation in Modul bquiet.exe bei 57201020.

Zugriffsverletzung bei Adresse 57202020. Lesen von Adresse 57202020.


---------------------------
OK
---------------------------
Ich tippe mal, ich mache dort irgendwie Mist mit den Pointern. Leider kann ich mit dieser Meldung absolut nichts anfangen, da im Vergleich zu sonst dort ausnahmsweise ne Adress steht und nicht, wie gewohnt, 00000000 ()

Der äquivalente C - Code wäre:

Code:
//----------------------------------------------------------------------------
// ATA-Befehle unter Windows 2000 oder XP versenden

BOOL CWinAta::SendCommand_Win2000(PATARegs pATARegs, void *pBuf, unsigned int BufSize, unsigned int *pResultSize)
{
 
  //---------------------------------------------------
  // Definitionen und Datenstruktur für Windows 2000 und XP
  // aus dem DDK-Headerfile ntddscsi.h übernommen
 
  #define IOCTL_IDE_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
  #define FILE_ANY_ACCESS        0
  #define IOCTL_SCSI_RESCAN_BUS  CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)

  typedef struct
  {
      IDEREGS IdeReg;
      ULONG  DataBufferSize;
      UCHAR  DataBuffer[1];
  } ATA_PASS_THROUGH;
  //---------------------------------------------------
 
 
  BOOL Result = FALSE;
 
  unsigned int Size = sizeof(ATA_PASS_THROUGH) + BufSize;
  // Datenpuffer mit VirtualAlloc anfordern, damit der Gerätetreiber den Speicher ansprechen kann
  ATA_PASS_THROUGH *pAPT = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, Size, MEM_COMMIT, PAGE_READWRITE);
 
  if (pAPT)
  {
      memset(pAPT, 0, Size);
      // Größe des Datenpuffers setzen
      pAPT->DataBufferSize         = BufSize;
      // ATA-Register setzen
      pAPT->IdeReg.bFeaturesReg    = pATARegs->Reg[0];
      pAPT->IdeReg.bSectorCountReg = pATARegs->Reg[1];
      pAPT->IdeReg.bSectorNumberReg = pATARegs->Reg[2];
      pAPT->IdeReg.bCylLowReg      = pATARegs->Reg[3];
      pAPT->IdeReg.bCylHighReg     = pATARegs->Reg[4];
      pAPT->IdeReg.bDriveHeadReg   = pATARegs->Reg[5];
      pAPT->IdeReg.bCommandReg     = pATARegs->Reg[6];

      if (pAPT->IdeReg.bCommandReg == 0xEC) // ist es ATA IDENTIFY?
      {
     // Windows XP merkt sich den IDE-Konfigurationssektor
          // daher vorher mit IOCTL_SCSI_RESCAN_BUS für ungültig erklären
          DWORD BytesReturned = 0;
          (void)DeviceIoControl(Device, IOCTL_SCSI_RESCAN_BUS, NULL, 0, NULL, 0, &BytesReturned, FALSE);
          // eine halbe Sekunde warten
          Sleep(500);  
      }

      DWORD BytesReturned = 0;
     
      BOOL Status = DeviceIoControl(Device, IOCTL_IDE_PASS_THROUGH,
                                    pAPT, Size, pAPT, Size, &BytesReturned, FALSE);
      if (!Status)
        WinAtaErrorCode = aec_CommandFailed;
      else
      {
          if (pBuf)
          {
              if (BufSize)
                memset(pBuf, 0, BufSize);
              if (BytesReturned > sizeof(ATA_PASS_THROUGH))
              {
                  unsigned int ReturnedSize = BytesReturned - sizeof(ATA_PASS_THROUGH);
                  if (pResultSize)
                    *pResultSize = ReturnedSize;
                  if (ReturnedSize > BufSize)
                    ReturnedSize = BufSize;
                   
                  memcpy(pBuf, pAPT->DataBuffer, ReturnedSize);
              }
          }
          Result = TRUE;
      }
      VirtualFree(pAPT, Size, MEM_RELEASE);
  }
  else
    WinAtaErrorCode = aec_OutOfMemory;
 
  return Result;
}
Hat irgendwer eine Idee? Im Anhang ist mal das komplette Delphi - Projekt. Auf das C - Original verlinke ich lieber. Ist von der c't... es handelt sich um die "WinATA.cpp".

Download vpn Heise *klick*

Danke schonmal für's lesen.
Angehängte Dateien
Dateityp: zip bequiet_177.zip (8,4 KB, 1x aufgerufen)
  Mit Zitat antworten Zitat