Entwickler-Ecke

Windows API - Verwendete Grafikkarte ermitteln.


MephistoFFF - So 01.03.09 22:38
Titel: Verwendete Grafikkarte ermitteln.
Schönen guten Abend miteinander!

Ich habe vor einigen Tagen sehr lange in Google und Co zugebracht, allerdings nichts wirklich brauchbares gefunden.
Meine Frage: Wie kann ich am besten die AKTUELL VERWENDETE Grafikkarte eines PCs ermitteln?
Ich habe es zwar schon geschafft, mit diesen Codes hier:
http://www.delphipraxis.net/topic17365_name+der+grafikkarte+auslesen+wie.html&highlight=grafikkarte
auf manchen PCs die aktuelle Grafikkarte zu ermitteln, allerdings wird auf vielen PCs etwas komplett falsches angezeigt, weil beispielsweise noch die Treiber der vorigen Grafikkarte in der Registry vermerkt sind.

Ich bin für jede Hilfe dankbar.

mfG


Moderiert von user profile iconNarses: Topic aus Dateizugriff verschoben am So 01.03.2009 um 23:41


jaenicke - Mo 02.03.09 01:29

Wie wäre es mit WMI und Win32_VideoController?
http://msdn.microsoft.com/en-us/library/aa394512.aspx


MephistoFFF - Mo 02.03.09 18:12

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Wie wäre es mit WMI und Win32_VideoController?
http://msdn.microsoft.com/en-us/library/aa394512.aspx


Klingt erstmal sehr gut, nur leider habe ich noch nie mit WMI gearbeitet... Wie binde ich das ganze in Delphi ein und arbeite dann damit in Delphi?

Vielen Dank.

mfG


jaenicke - Mo 02.03.09 18:15

http://lmgtfy.com/?q=delphi+wmi
Da gibts jede Menge, zum Beispiel das:
http://www.delphipraxis.net/topic24332.html


MephistoFFF - Mo 02.03.09 18:33

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
http://lmgtfy.com/?q=delphi+wmi
Da gibts jede Menge, zum Beispiel das:
http://www.delphipraxis.net/topic24332.html


Der erste Link ist unlustig ;) . trotzdem danke... und trotzdem schonwieder eine neue frage: wie importiere ich das ganze überhaupt erstmal? ich hab im google nichts brauchabres gefunden... und vor allem... wo lad ich die libary erstmal runter?

mfG


jaenicke - Mo 02.03.09 18:46

Da du Turbo Delphi vermutlich in der Explorer Edition (?) hast, kannst du sie nicht selbst importieren. Ich habe die Datei einmal in den Anhang gelegt. Das kannst du mit irgendeiner anderen Delphiversion machen, benutzen kannst du sie auch in Turbo Delphi. [meta]WbemScripting[/meta][meta]WbemScripting_TLB[/meta]


Narses - Mo 02.03.09 19:01

Moin!

Da ich bei Delphi+WMI jedesmal Hautausschlag kriege, hier noch ein Tipp: Die meisten Codes, die so im Netz in Bezug auf WMI+Delphi kursieren, haben Memory-Leaks. :shock:
Das hier ist AFAIK "sauber":

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:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
uses
  ..., Variants, WbemScripting_TLB, ActiveX;

function QueryWMI(const QueryClass, QueryProperty: String; AStrings: TStrings): Boolean;
  var
    Locator:     ISWbemLocator;
    Services:    ISWbemServices;
    ObjectSet:   ISWbemObjectSet;
    WMIObject:   ISWbemObject;
    WMIProperty: ISWbemProperty;
    Enum:        IEnumVariant;
    ObjValue:    Cardinal;
    TempObj:     OleVariant;
begin
  Result := FALSE;
  try
    Locator := CoSWbemLocator.Create;
    try
      Services := Locator.ConnectServer('''root\cimv2''''''',''0NIL);
      if Assigned(Services) then begin
        Services.Security_.ImpersonationLevel := 3;
        ObjectSet := Services.ExecQuery('SELECT * FROM '+QueryClass,
                                        'WQL',
                                         wbemFlagForwardOnly or wbemFlagReturnWhenComplete,
                                         NIL);
        Enum := (ObjectSet._NewEnum) as IEnumVariant;
        while (Enum.Next(1, TempObj, ObjValue) = S_OK) do begin
          try
            WMIObject := IUnknown(TempObj) as ISWBemObject;
          except
            WMIObject := NIL;
          end;
          TempObj := Unassigned; // Interface in TempObj freigeben
          if Assigned(WMIObject) then begin
            WMIProperty := WMIObject.Properties_.Item(QueryProperty, 0);
            if (NOT VarIsNull(WMIProperty.Get_Value)) then
              AStrings.Add(Trim(WMIProperty.Get_Value));
          end;
        end;
        Result := TRUE;
      end;
    finally
      Services := NIL;
      Locator := NIL;
    end;
  except // Exceptions fangen (Wenn WMI nicht verfügbar/installiert ist, gibt´s eine!)
    Result := FALSE;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  QueryWMI('Win32_VideoController','Caption',Memo1.Lines);
end;
cu
Narses

//EDIT: Es gibt mittlerweile auch eine Komponenten-Version [http://www.delphi-forum.de/topic_Komponenten+zur+WMIAbfrage+TWMIConnection+TWMIQuery_94142.html] zur IDE-Integration, die mehrere Abfragen hintereinander schnell ausführen kann.


MephistoFFF - Mo 02.03.09 19:34

Vielen Vielen Dank! Das funzt bis jetzt erstmal wunderbar!
Danke euch beiden ;) :) .

mfG


Stread - Mo 04.07.11 00:18

Ich hoffe mal, dass ich das hier ausgraben darf.

Ich habe die Typenbibliothek WMI Scripting als Unit eingebunden und mit dem Code von Narses funktioniert alles super. Grafikkarten und Grafikkarten Ram werden angezeigt.
Allerdings habe ich das Gefühl dass ich die Ergebnisse nur in Memos anzeigen lassen kann? Kann ich das direkt in einem Label anzeigen lassen oder muss ich den Umweg über das Memo gehen?

Edit: Verwendet wird Delphi XE


BenBE - Mo 04.07.11 04:25

user profile iconNarses hat folgendes geschrieben Zum zitierten Posting springen:
Moin!

Da ich bei Delphi+WMI jedesmal Hautausschlag kriege, hier noch ein Tipp: Die meisten Codes, die so im Netz in Bezug auf WMI+Delphi kursieren, haben Memory-Leaks. :shock:
Das hier ist AFAIK "sauber":

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:
37:
38:
39:
function QueryWMI(const QueryClass, QueryProperty: String; AStrings: TStrings): Boolean;
var
  //...
begin
  Result := FALSE;
  try
    Locator := CoSWbemLocator.Create;
    try
      Services := Locator.ConnectServer('''root\cimv2''''''',''0NIL);
      if Assigned(Services) then begin
        Services.Security_.ImpersonationLevel := 3;
        ObjectSet := Services.ExecQuery('SELECT * FROM '+QueryClass,
                                        'WQL',
                                         wbemFlagForwardOnly or wbemFlagReturnWhenComplete,
                                         NIL);
        Enum := (ObjectSet._NewEnum) as IEnumVariant;
        while (Enum.Next(1, TempObj, ObjValue) = S_OK) do begin
          try
            WMIObject := IUnknown(TempObj) as ISWBemObject;
          except
            WMIObject := NIL;
          end;
          TempObj := Unassigned; // Interface in TempObj freigeben
          if Assigned(WMIObject) then begin
            WMIProperty := WMIObject.Properties_.Item(QueryProperty, 0);
            if (NOT VarIsNull(WMIProperty.Get_Value)) then
              AStrings.Add(Trim(WMIProperty.Get_Value));
          end;
        end;
        Result := TRUE;
      end;
    finally
      Services := NIL;
      Locator := NIL;
    end;
  except // Exceptions fangen (Wenn WMI nicht verfügbar/installiert ist, gibt´s eine!)
    Result := FALSE;
  end;
end;
cu
Narses


Ich hab da mal paar Variablen markiert, die nicht finalisiert werden via Resourcen-Schutzblock... Also zumindest nicht explizit.

Ganz von dem Services abgesehen, was bei Locator nix im gleichen Finally-Abschnitt zu suchen hat.

Nice Try. :mrgreen:

P.S.: Aber guter Hinweis bzgl. der Komponente.


jaenicke - Mo 04.07.11 05:56

user profile iconStread hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings habe ich das Gefühl dass ich die Ergebnisse nur in Memos anzeigen lassen kann?
Wie kommst du auf die Idee?
Der Parameter ist vom Typ TStrings, da kannst du auch einfach eine TStringList übergeben.


Narses - Mo 04.07.11 09:33

Moin!

user profile iconBenBE hat folgendes geschrieben Zum zitierten Posting springen:
Ich hab da mal paar Variablen markiert, die nicht finalisiert werden via Resourcen-Schutzblock... Also zumindest nicht explizit.

Ganz von dem Services abgesehen, was bei Locator nix im gleichen Finally-Abschnitt zu suchen hat.

Nice Try.
Ach Benny, du weißt doch mittlerweile, dass du mich nur dann beeindrucken kannst, wenn du auch deinen Code-Vorschlag dazu abgegeben hättest... :roll: Aber so? Nice Try! :mrgreen: Meckern kann ich auch, besser machen ist gefragt. :P

cu
Narses


Delete - Mo 04.07.11 10:50

Und das hier:

Delphi-Quelltext
1:
2:
3:
except // Exceptions fangen (Wenn WMI nicht verfügbar/installiert ist, gibt´s eine!)
    Result := FALSE;
  end;

ist auch nicht sehr schön. Ich kann dann zwar prüfen, ob der Aufruf funktioniert hat oder nicht, aber was nützt mir das, wenn ich nicht weiß, warum er fehlgeschlagen ist? Lass doch die Exception durch:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
try
  QueryWMI(...);
except
  on E: Exception do
    ShowMessage(E.Message);
end;

Weil so wie du das machst, kann dir der Kunde wirklich nur sagen: "Geht nicht." Dann wünsche ich viel Spaß bei der Fehlerdiagnose. :?


uall@ogc - Mo 04.07.11 23:16

@BenBE:
1) Warum sollten Interfaces explizit freigegeben werden? Delphi sorgt doch im Grunde dafür, dass am Ende IntfClear/FinalizeArray aufgerufen wird:


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:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
type
  ITest = interface['{5733B32B-BB90-42AC-9DD3-A27E32DF13AA}']
    procedure Execute;
  end;
  TTest = class(TInterfacedObject, ITest)
    constructor Create;
    procedure Execute;
    destructor Destroy; override;
  end;

{ TTest }

constructor TTest.Create;
begin
  inherited;
  writeln('Create');
end;

destructor TTest.Destroy;
begin
  writeln('Destroy');
  inherited;
end;

procedure TTest.Execute;
begin
  raise Exception.Create('adsad');
end;

procedure aha;
var
  a, b: ITest;
begin
  a := nil;
  b := nil;
  try
    a := TTest.Create;
    b := TTest.Create;
    a.Execute;
  except
    writeln('exception');
  end;
end;

begin
  ReportMemoryLeaksOnShutdown := True;
  try
    aha;
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
  ReadLn;
end.


2. Interfaces sind mit NIL initialisiert (sollte auch bei lokalen Variablen so sein) ansonsten würde die IntfClear Funktion nicht sauber funktionieren:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
procedure aha;
var
  a, b: ITest;
begin
// hack mir a auf was anderes als Nil zu setzen
  asm
    lea eax, dword ptr [ebp-$4]
    inc dword ptr [eax]
  end;

  a := nil// Exception
  b := nil;

// @IntfClear:
00405EB4 8B10             mov edx,[eax]
00405EB6 85D2             test edx,edx <<< explizit auf nil getestet
00405EB8 740E             jz $00405ec8
00405EBA C70000000000     mov [eax],$00000000
00405EC0 50               push eax
00405EC1 52               push edx
00405EC2 8B02             mov eax,[edx]


Demnach wäre der Code nichts anderes als:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
   Servies := nil;
   Locator := CoSWbemLocator.Create;
   try
     Services := Locator.ConnectServer('''root\cimv2''''''',''0NIL);
   finally
     Locator := nil;
     Services := nil;
   end;

// entsprechend in Objekten:
   Obj2 := nil;
   Obj1 := TObject.Create;
   try
     Obj2 := Locator.ConnectServer('''root\cimv2''''''',''0NIL);
   finally
     FreeAndNil(Obj1);
     FreeAndNil(Obj2);
   end;


Dies ist eine (meiner Meinung nach) uebeliche Methode um viele verschachtelte try/finallys zu vermeiden und somit "sauber"

@Luckie:
Das ist einfach eine Designansicht. Es ist durchaus sinnvoll eine Funktion zu schreiben die die Exceptions abfaengt und dann ggf. loggt. Dafuer hat die Funktion ja auch einen Boolean als Rueckgabewert. Entweder sie funktioniert oder eben nicht. Ausserhalb kann ja immer noch "if not QueryWMI(..) then ShowMessage('Fehler, blablub bitte log "C:\fehler.log an Administrator xyz schicken')" angezeigt werden, denn bei Fehlern mit irgendwelchen Write/Read Exception klicken die Benutzer gerne die Fehlermeldung weg und rufen dann an ohne diese kopiert zu haben und sagen nur xyz funktioniert nicht.

Ansonsten könnte man auch einfach eine Prozedure raus machen und immer Exceptions werfen wie in Java, hier wird eher der WinAPI-Ansatz gewaehlt (keine Exception mit Rueckgabewert und ggf. Abfrage ubeer etwas wie GetLastError, Log-Datei bzw. Erkennung eines Fehlers am Rueckgabewert)