![]() |
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
SizeOf(TDriverInfo2);
Hatte ich auch schon probiert ergibt bei mir aber 24 byte pcbNeeded / 24 ergibt aber ( 10112 / 24 = 421 ) obwohl es halt nur 18 Treiber sind. Funktioniert also auch net. Da ich bei mir ja weiß das ich 18 Treiber installiert habe ergibt sich bei mir ein Teiler von 10112 / 18 = 561 aber der Wert ist nicht überall gleich auf nem anderen Rechner muss der z.B. 429 sein. Das andere mit GetMem muss ich mir nochmal in Ruhe anschauen.. |
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Ok, das bestätigt dann auf jeden Fall meine Vermutung, dass im Buffer auch noch die dazugehörigen Strings abgelegt werden und nicht nur die
Delphi-Quellcode:
Strukturen. Mit dem
DRIVER_INFO_2
Delphi-Quellcode:
Beispiel sollte es aber funktionieren. Zur Erklärung:
GetMem
Delphi-Quellcode:
ist hier als Zeiger deklariert, welcher nach dem Aufruf der API dann auf die erste
Buf
Delphi-Quellcode:
Struktur zeigt. Mit dem
DRIVER_INFO_2
Delphi-Quellcode:
wird der Zeiger um
Inc
Delphi-Quellcode:
erhöht, zeigt also danach auf das 2./3./n-te Element.
SizeOf(TDriverInfo2)
Hier fällt mir grade auf, dass in meinem Beisüiel das
Delphi-Quellcode:
am Ende so natürlich nicht funktioniert, da sich der Zeiger ja geändert hat. Den initialen Buffer-Pointer (direkt nach dem
FreeMem
Delphi-Quellcode:
Aufruf) müsstest du dir also sichern, bevor du anfängst zu iterieren.
GetMem
|
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Zitat:
Dann war mein Geschwafel ("kein Puffer, nimm einfach ein Array") definitiv falsch. |
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Man kann ja dennoch das Array verwenden, aber dann eben nicht auf alle, sondern nur auf die richige Anzahl der Einträge zugreifen.
|
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Kann man dann aber nicht so schön inkrementieren :)
|
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
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 ); |
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Dumme Frage aber kann ich es nicht auch einfach so machen:
statt 2x EnumPrinterDrivers aufzurufen rufe ich es 3x auf (1x um die nötige Buffersize zu ermitteln, 1x mit dem pBuffer in der Größe von BytesNeeded um den ItemsCount zu erhalten, 1x der finale aufruf mit dem @array[0] (=SetLength(array, ItemsReturned))
Delphi-Quellcode:
Kann man das so machen oder ist das zu gefährlich / dümmlich ?:|
function GetPrinterDrivers(): boolean;
var aDriverList : array of TDriverInfo2; pBuffer : Pointer; BytesNeeded : DWORD; ItemsReturned : DWORD; ErrorTxt : array [0..500] of char; i : integer; begin // BufferSize ermitteln if not EnumPrinterDrivers(nil, nil, 2, nil, 0, BytesNeeded, ItemsReturned) then begin if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin try // pBuffer Speicher reservieren pBuffer := System.AllocMem(BytesNeeded); // Anz. Items des Arrays ermitteln if EnumPrinterDrivers(nil, nil, 2, pBuffer, BytesNeeded, BytesNeeded, ItemsReturned) then begin // Array Länge setzen SetLength(aDriverList, ItemsReturned); result := EnumPrinterDrivers(nil, nil, 2, @aDriverList[0], BytesNeeded, BytesNeeded, ItemsReturned); end; finally // Speicher freigeben FreeMem(pBuffer); end; end; end; |
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Zitat:
Zitat:
Delphi-Quellcode:
in Bytes angegeben ist und ausdrücklich nicht
pcbNeeded
Delphi-Quellcode:
ist. Nichtmal ein Vielfaches von
pcReturned * SizeOf(DRIVER_INFO_2)
Delphi-Quellcode:
ist garantiert. Mit einem
SizeOf(DRIVER_INFO_2)
Delphi-Quellcode:
zu arbeiten, macht doch rein von der Logik her einfach keinen Sinn.
Array of DRIVER_INFO_2
Zitat:
Delphi-Quellcode:
ist kein Vielfaches von
pcbNeeded
Delphi-Quellcode:
. 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.
SizeOf(DRIVER_INFO_2)
Delphi-Quellcode:
Wenn der Zugriff umbedingt über ein Array erfolgen soll, dann geht auch folgende Variante:
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;
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; |
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Ok, ich hab es jetzt wie in deinem ersten Beispiel gemacht.
Ist das mit pStart und FreeMem so in Ordnung?
Delphi-Quellcode:
function GetPrinterDrivers(): boolean;
var Buffer : PDriverInfo2; pStart : Pointer; i : Integer; BytesNeeded : DWORD; ItemsReturned : DWORD; begin if not EnumPrinterDrivers(nil, nil, 2, nil, 0, BytesNeeded, ItemsReturned) then begin if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin GetMem(Buffer, BytesNeeded); pStart := Buffer; try if EnumPrinterDrivers(nil, nil, 2, Buffer, BytesNeeded, BytesNeeded, ItemsReturned) then begin for i := 1 to ItemsReturned do begin Form1.Memo1.Lines.Add(i.ToString +' :: '+Buffer.pName); inc(Buffer); end; end; finally Buffer := pStart; FreeMem(Buffer); end; end; end; |
AW: EnumPrinterDrivers = Zugriffsverletzung (Anfängerfrage)
Auch wenn ich schon einmal Quark erzählt habe traue ich mich trotzdem noch:
Sieht gut aus, allerdings - Könnte man pStart auch vom Typ PDriverInfo2 sein lassen. - Mach in der Doku unbedingt fest was deine Methode denn angeblich zurückgibt - Denn momentan ist der Rückgabewert uU nicht definiert |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:57 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz