Entwickler-Ecke

Windows API - API: EnumMonitors benutzen


NeoInDerMATRIX - Do 20.01.05 03:47
Titel: API: EnumMonitors benutzen
Hi,

ich habe ein kleines Problem. Ich benötige die Function "EnumMonitorsA" aus "WinSpool.drv". Soweit so gut. Allerdings habe ich jetzt das problem das ich es nicht hin bekomme die Function koreckt aufzurufen. Ich bekomme per OSError abfrage immer mitgeteilt das ich die Parameter falsch übergebe. Das WinSDK ist leider auch nicht wirklich hilfreich.


Delphi-Quelltext
1:
Function EnumMonitors(AServerName: pChar; ALevel: DWord; ABuffer: Pointer; ABufferSize: DWord; ABufferNeed: Pointer; ABufferReturned: Pointer): Boolean; StdCallExternal 'WinSpool.drv' Name 'EnumMonitorsA';                    


Ich denke ich sehe den Wald for lauter Bäumen nicht.

Also so weit ich das jetzt weis, muss ich die Function einmal mit ABufferSize:=0 aufrufen um die Benötigte Puffer größe zu bekommen. Allerdings bekomme ich dabei bereits einen Fehler. Ich denke ich habe das ganze falsch nach Delphi übersetzt. Deshalb hier die definition aus dem SDK:

Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
BOOL EnumMonitors(
  LPTSTR pName,       // server name
  DWORD Level,        // information level
  LPBYTE pMonitors,   // monitor information buffer
  DWORD cbBuf,        // size of monitor information buffer
  LPDWORD pcbNeeded,  // bytes received or required
  LPDWORD pcReturned  // number of monitors received
);


Ich hoffe das mir einer von euch helfen kann.

Thx & Cu
Neo


Delete - Do 20.01.05 03:49

Deklarier die letzten beiden Parameter mal als var Parameter, du willst ja was zurück bekommen. Sorry, da stimmt noch mehr nicht.


NeoInDerMATRIX - Do 20.01.05 04:01

Hi,

@Luckie: Ja das habe ich bereits probiert. Allerdings macht das bei dem letztem Parameter nicht wirklich sin, wenn ich das aus dem SDK richtig verstanden habe!
Aber auch als Var bekomme ich eine Fehler.

Aber trotzdem danke.

Cu
Neo


Delete - Do 20.01.05 04:27

Was willst du eigentlich damit in Erfahrung birngen? Die Anzahl der Monitore? dann wäre wohl Suche im MSDN ENUMDISPLAYDEVICES oder Suche im MSDN ENUMDISPLAYMONITORS die richtige Wahl. Ich weiß nämlich gar nicht, ob man diese Funktion so aus der drv Datei aufrufen kann. Denn theoretisch sollte es so gehen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
type
  TMONITOR_INFO_1 = record
    Name: PChar;
  end;
  PMONITOR_INFO_1 = ^TMONITOR_INFO_1;

function EnumMonitors(Name: PChar; Level: DWord; Monitors: Pointer;
  cbBuffer: DWord; var pcbNeeded: DWORD; var pcReturned: DWORD): Boolean;
  stdcallexternal 'WinSpool.drv' Name 'EnumMonitorsA';

procedure TForm1.Button1Click(Sender: TObject);
var
  Needed       : DWORD;
  Returned     : DWORD;
  Monitors     : Pointer;
  pWork        : Pointer;
  i            : Integer;
begin
  Monitors := nil;

  if (not EnumMonitors(nil1, Monitors, 0, Needed, Returned) and (GetLastError =
    ERROR_INSUFFICIENT_BUFFER)) then
  begin
    EnumMonitors(nil1, Monitors, Needed, Needed, Returned);
    pWork := Monitors;
    for i := 0 to Returned - 1 do
    begin
      ShowMessage(PMONITOR_INFO_1(pWork)^.Name);
      Inc(Integer(pWork), sizeof(TMONITOR_INFO_1));
    end;
  end;
end;

Aber beim zweiten Aufruf bekomme ich eine AccessViolation.


NeoInDerMATRIX - Do 20.01.05 22:21

Hi Luckie,

also die anzahl der Monitore habe ich schon. Ich benötige noch den Treiber für den Monitor und den rest der Strings aus der Monitor_Info_2 strucktur.

Laut WinSDK soll das euch eigentlich nicht aus der WinSpool.drv gelesen werden sondern aus der WinSpool.lib. Allerdings ist dies nicht möglich. Da ich diese nicht als DLL oder so laden kann. Und nach suchen auf meinem System war nur eine WinSpool.drv vorhanden. Aus diesem grund habe ich das versucht. Und als ich nur den Fehlercode Ungültiger Parameter zurückbekommen habe, dachte ich das es ja dann möglich sein müste.

Deine Code werde ich mal probieren. Ich melde mich dann auch gleich wenn ich etwas weis.
Und danke für deine Hilfe.

Cu
Neo


NeoInDerMATRIX - Do 20.01.05 23:05

Hi,

also ich habe es jetzt zum laufen gebracht. Auch wenn es leider nicht die Information bringt die ich gesucht habe. Diese Function Listet Drucker, Modem, und komischer weise TCP/IP Port.

Was bei Luckie gefehlt hat ist nur das beim zweiten aufruf ein speicherbereich vorhanden sein muss.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
type  
  TMONITOR_INFO_1 = record  
    Name: PChar;  
  end;  
  PMONITOR_INFO_1 = ^TMONITOR_INFO_1;  

 
function EnumMonitors(Name: PChar; Level: DWord; Monitors: Pointer;  
  cbBuffer: DWord; var pcbNeeded: DWORD; var pcReturned: DWORD): Boolean;  
  stdcallexternal 'WinSpool.drv' Name 'EnumMonitorsA';  

 
procedure TForm1.Button1Click(Sender: TObject);  
var  
  Needed       : DWORD;  
  Returned     : DWORD;  
  Monitors     : Pointer;  
  pWork        : Pointer;  
  i            : Integer;  
begin  
  Monitors := nil;  

 
  if (not EnumMonitors(nil1, Monitors, 0, Needed, Returned) and (GetLastError =  
    ERROR_INSUFFICIENT_BUFFER)) then  
  begin  
    EnumMonitors(nil1, Monitors, Needed, Needed, Returned);  
    GetMem(pWork, Needed);
    for i := 0 to Returned - 1 do  
    begin  
      ShowMessage(PMONITOR_INFO_1(pWork)^.Name);  
      Inc(Integer(pWork), sizeof(TMONITOR_INFO_1));  
    end;  
    FreeMem(pWork, Needed);
  end;  
end;


So geht es dann.

Thx & Cu
Neo


Delete - Fr 21.01.05 14:31

Neo_in_der_MATRIX hat folgendes geschrieben:

Was bei Luckie gefehlt hat ist nur das beim zweiten aufruf ein speicherbereich vorhanden sein muss.

Ja, das ist mir gestern Nacht auch eingefallen. Ich ahtte imme rnoch die Netxxx-API Funktionen im Kopf, die diesen selber reservieren.

Allerdings würde ich es so machen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
type
  TMONITOR_INFO_1 = record
    Name: PChar;
  end;
  PMONITOR_INFO_1 = ^TMONITOR_INFO_1;

function EnumMonitors(Name: PChar; Level: DWord; Monitors: Pointer;
  cbBuffer: DWord; var pcbNeeded: DWORD; var pcReturned: DWORD): Boolean;
  stdcallexternal 'WinSpool.drv' Name 'EnumMonitorsA';

procedure TForm1.Button1Click(Sender: TObject);
var
  Needed       : DWORD;
  Returned     : DWORD;
  Monitors     : Pointer;
  pWork        : Pointer;
  i            : Integer;
begin
  Monitors := nil;
  if (not EnumMonitors(nil1, Monitors, 0, Needed, Returned) and (GetLastError =
    ERROR_INSUFFICIENT_BUFFER)) then
  begin
    GetMem(Monitors, Needed);
    try
      EnumMonitors(nil1, Monitors, Needed, Needed, Returned);
      pWork := Monitors;
      for i := 0 to Returned - 1 do
      begin
        ShowMessage(PMONITOR_INFO_1(pWork)^.Name);
        Inc(Integer(pWork), sizeof(TMONITOR_INFO_1));
      end;
    finally
      FreeMem(Monitors, Needed);
    end;
  end;
end;

Grund ist der: Die Informationen befinden sich im Speicherbereich von Monitors. Jetzt muss ich diese Adresse aber inkrementieren. Bin ich am Ende angelangt, kenne ich die Startadresse nicht mehr. Gebe ich also Monitors frei, gebe ich nicht den Speicher von Anfang an frei. Mit Einführung des Arbeitszeigers pWork, mit dem ich dann die Informationen abrufe, kann ich selbigen inkrementieren. Der Zeiger Monitors bleibt aber auf dem ersten Speicherbereich stehen und wenn ich dann Monitors freigebe, habe ich den ganzen Speicherbereich wieder freigegeben.

Was mich jetzt bei dir etwas wundert: Du reservierst Speicher für pWork:

Delphi-Quelltext
1:
GetMem(pWork, Needed);                    

aber keinen für Monitors. Aber im Funktionsaufruf

Delphi-Quelltext
1:
EnumMonitors(nil1, Monitors, Needed, Needed, Returned);                    

füllst du selbigen. Arbeiten tust du dann aber wieder mit pWork, nur wo weißt du pWork den gefüllten Speicherbereich von Monitors zu? So wie ich das sehe, ist es purer Zufall, dass dein Code funktioniert.


NeoInDerMATRIX - Fr 21.01.05 14:41

Ja ist egal,

ich danke dir auf jeden fall für deine Hilfe.

Cu
Neo


Delete - Fr 21.01.05 14:51

*push* Guck noch mal rein, habe noch was ergänzt.