Einzelnen Beitrag anzeigen

Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#18

AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)

  Alt 13. Mär 2017, 14:59
Man kann ja dennoch das Array verwenden, aber dann eben nicht auf alle, sondern nur auf die richige Anzahl der Einträge zugreifen.
0 bis daswasdieapisagt-1

BOOL EnumPrinterDrivers(
_In_ LPTSTR pName,
_In_ LPTSTR pEnvironment,
_In_ DWORD Level,
_Out_ LPBYTE pDriverInfo,
_In_ DWORD cbBuf,
_Out_ LPDWORD pcbNeeded,
_Out_ LPDWORD pcReturned
);
Aber das Problem ist ja, dass pcbNeeded in Bytes angegeben ist und ausdrücklich nicht pcReturned * SizeOf(DRIVER_INFO_2) ist. Nichtmal ein Vielfaches von SizeOf(DRIVER_INFO_2) ist garantiert. Mit einem Array of DRIVER_INFO_2 zu arbeiten, macht doch rein von der Logik her einfach keinen Sinn.

Kann man das so machen oder ist das zu gefährlich / dümmlich ?
Macht wenig Sinn. Der 3. Aufruf der API wird fehlschlagen (bzw. noch schlimmer: zufälligen Speicher überschreiben), da dein Array nach wie vor die falsche Größe hat. Siehe oben: pcbNeeded ist kein Vielfaches von SizeOf(DRIVER_INFO_2) . Der Array Ansatz kann nicht funktionieren - du hast enweder zu wenig Platz = Buffer Overflow oder du reservierst zu viel = Logisch fragwürdig. Arrays sollte man wirklich nur dann verwenden, wenn man homogene Strukturen zusammenfassen will.

Delphi-Quellcode:
function EnumPrinterDriversW(pName: LPSTR; pEnvironment: LPSTR; Level: DWord; pDriverInfo: LPBYTE;
  cbBuf: DWord; var pcbNeeded: DWord; var cbReturned: DWord): BOOL; stdcall;
  external 'winspool.drv';

type
  DRIVER_INFO_2 = packed record
    cVersion: DWord;
    pName: LPTSTR;
    pEnvironment: LPTSTR;
    pDriverPath: LPTSTR;
    pDataFile: LPTSTR;
    pConfigFile: LPTSTR;
  end;
  PDriverInfo2 = ^TDriverInfo2;
  TDriverInfo2 = DRIVER_INFO_2;

procedure TForm6.FormCreate(Sender: TObject);
var
  Buf: Pointer;
  ErrorCode,
  pcbNeeded,
  cbReturned,
  I: DWord;
  Driver: PDriverInfo2;
begin
  EnumPrinterDriversW(nil, nil, 2, nil, 0, pcbNeeded, cbReturned);
  ErrorCode := GetLastError;
  if (ErrorCode <> ERROR_INSUFFICIENT_BUFFER) then
  begin
    RaiseLastOsError(ErrorCode);
  end;
  GetMem(Buf, pcbNeeded);
  try
    if (not EnumPrinterDriversW(nil, nil, 2, Buf, pcbNeeded, pcbNeeded, cbReturned)) then
    begin
      RaiseLastOsError;
    end;
    Driver := Buf;
    for I := 1 to cbReturned do
    begin
      ShowMessage(Driver^.pName);
      Inc(Driver);
    end;
  finally
    FreeMem(Buf);
  end;
end;
Wenn der Zugriff umbedingt über ein Array erfolgen soll, dann geht auch folgende Variante:
Delphi-Quellcode:
procedure TForm6.FormCreate(Sender: TObject);
type
  PDriverInfo2Array = ^TDriverInfo2Array;
  TDriverInfo2Array = array[0..0] of TDriverInfo2;
var
  Buf: Pointer;
  ...
  I: DWord;
  Drivers: PDriverInfo2Array;
begin
  ...
  try
    ...
    Drivers := Buf;
    for I := 0 to cbReturned - 1 do
    begin
      ShowMessage(Drivers^[I].pName);
    end;
  finally
    ...
  end;
end;
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)

Geändert von Zacherl (13. Mär 2017 um 15:24 Uhr)
  Mit Zitat antworten Zitat