Von Lazarus 1.2.6 nach Lazarus 1.8.0

Antworten
SchwabenTom
Beiträge: 49
Registriert: So 4. Jan 2015, 21:34
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von SchwabenTom »

Hallo,

ich habe ein Programm mit Lazarus 1.2.6 angefangen. Das wurde auch kompiliert und lief auch. Nach einer Pause wollte ich mich nun wieder an dieses Programm setzen. Habe Lazarus dabei auf die aktuelle Version 1.8.0 aktualisiert. Damit bekomme ich Compilerfehler. Habe aber keine Änderungen am Code gemacht. Einfach nur mit der neuen Lazarusversion kompiliert.

Windows 7, 64 bit
Lazarus 1.8.0 (für windows 64 bit)

Ich greife auf das WMI von Windows zu. Es sind OLEVariant etc. im Spiel. Einen Übergabeparamter mußte ich mit nil angeben. Dafür bekomme ich einen Compilerfehler, daß es Lazarus genauer haben mag - nicht Pointer, sondern LongWord.

Code: Alles auswählen

 
...
var WMIService   : OLEVariant;
    WbemObjectSet: OLEVariant;
    WbemObject   : Variant;
    oEnum        : IEnumVariant;
...
...
          WbemObjectSet := WMIService.ExecQuery('SELECT * FROM Msvm_VirtualSystemManagementService', 'WQL', WMI_WbemFlagForwardOnly);
          oEnum         := IUnknown(WbemObjectSet._NewEnum) as IEnumVariant;
          if oEnum.Next(1, WbemObject, nil) = 0 then     // <-- hier der Fehler, das nil will er nicht
...
 


oEnum ist ein IEnumVariant. Den dritten Übergabeparameter muß ich laut den Hilfetexten und Beispielcodes die ich fand mit nil übergeben. Das hat Lazarus in v 1.2.6 auch so compiliert. Das Kompilat lief fehlerfrei. Jetzt mit Lazarus v 1.8.0 erhalte ich den Compilerfehler

Error: Call by var for arg no. 3 has to match exactly: Got "Pointer" expected "LongWord"

Lösung ist klar :-) Ich werd ein LongWord übergeben müssen :-)

Meine Frage ist nur, was ist das LongWord von nil?

Caste ich direkt mit: LongWord(nil)?
Ist es 0?
Ist es -1?
Oder etwas anderes?

Danke und Grüße,
Tom

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von Mathias »

Es ist Nil ist gleich 0

Dieser kleiner Code bewies dies.

Code: Alles auswählen

var
  i:Integer;
begin
  i := 0;
  if nil = Pointer(i) then begin
    WriteLn('0 = nil');
  end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
kupferstecher
Beiträge: 418
Registriert: Do 17. Nov 2016, 11:52

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von kupferstecher »

SchwabenTom hat geschrieben:Caste ich direkt mit: LongWord(nil)?

Hallo Tom,
fuer pointer-gecaste gibt es PtrUInt, dann ist gewaehrleistet, dass die Bitbreite auch passt (32bit/64bit).
Obs hier in deinem speziellen Fall geht, musst du probieren.
Also ptruint(nil).

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von m.fuchs »

Mathias hat geschrieben:Es ist Nil ist gleich 0

Das stimmt sicherlich in den meisten Fällen, es muss aber nicht so sein. Es kann ja irgendwann mal eine Plattform dazukommen, in der nil dann anders definiert wird.
Deswegen immer nil verwenden (wenn nötig per Cast) anstelle von 0.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von Soner »

Für Variantentypen wie OLEVariant nimmt man für Nil NULL.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von Mathias »

m.fuchs hat geschrieben:
Mathias hat geschrieben:Es ist Nil ist gleich 0

Das stimmt sicherlich in den meisten Fällen, es muss aber nicht so sein. Es kann ja irgendwann mal eine Plattform dazukommen, in der nil dann anders definiert wird.
Deswegen immer nil verwenden (wenn nötig per Cast) anstelle von 0.


Ich bin von dieser Fehlermeldung ausgegangen:

Code: Alles auswählen

Error: Call by var for arg no. 3 has to match exactly: Got "Pointer" expected "LongWord"

Aber Normalerweise verwende ich bei einem Null-Pointer schon nil, Pointer(0) macht auch gar keine Sinn.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

SchwabenTom
Beiträge: 49
Registriert: So 4. Jan 2015, 21:34
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von SchwabenTom »

Danke für die schnellen Antworten. Bin gerade bei der Arbeit etwas stärker eingespannt ... deshalb liegt die "Frage" zur Zeit ein wenig in Warteschleife ... sorry für meine späte Rückmeldung. Die Null-Geschichte habe ich mal weiterverfolgt. Und bin gestoßen auf:

Variants.Null
VarIsNull
VarNull

---

VarNull

VarNull scheint in der varianth.inc (Zeile 21) definiert zu sein als

varnull = 1

Also ungleich 0.

Außerdem bekomme ich damit den Compilerfehler: "Error: Can't take the address of constant expressions"

----

VarIsNull ist klar, daß es nicht zu verwenden ist :-)

----

Variants.Null

Hier bekomme ich den Compilerfehler: "Error: Variable identifier expected".

----

Wenn ich es mit einer Variablen versuche, bekomme ich: Got "Variant" expected "LongWord".

Code: Alles auswählen

 
...
myTestVar: Variant;
...
myTestVar := Variants.Null;
if oEnum.Next(1, WbemObject, myTestVar) = 0 then
 


Dabei habe ich mehrere Kombinationen versucht myTestVar als Variant, als OLEVariant. Und Zuweisung myTest := Variants.Null und := VarNull.
Immer die selber Compilermeldung: Got "Variant" expected "LongWord" bzw. Got "OleVariant" expected "LongWord"

Wenn ich dann das Ding als LongWord deklariere funktionierts -> myTestVar: LongWord;

Aber dann bringt er mir, daß der zweite Parameter falsch sei. Bei

if oEnum.Next(1, WbemObject, myTestVar) = 0 then

kommt der Compilerfehler: Error: Call by var for arg no. 2 has to match exactly: Got "Variant" expected "OleVariant"

Ist ja auch definiert als -> WbemObject : Variant;

Ok, also das geändert in OLEVariant und siehe da:


Code: Alles auswählen

 
...
var WMIService   : OLEVariant;
    WbemObjectSet: OLEVariant;
    WbemObject   : OLEVariant;     // <-- das ist geändert
    oEnum        : IEnumVariant;
    myTestVar      : LongWord;     // <-- das ist neu
...
...
          WbemObjectSet := WMIService.ExecQuery('SELECT * FROM Msvm_VirtualSystemManagementService', 'WQL', WMI_WbemFlagForwardOnly);
          oEnum         := IUnknown(WbemObjectSet._NewEnum) as IEnumVariant;
          myTestVar        := VarNull;     // <-- das ist neu
          if oEnum.Next(1, WbemObject, myTestVar) = 0 then     // <-- das ist geändert
...
 


So wird compiliert, keine Fehlermeldung.

Wie gesagt VarNull ist mit 1 in der varianth.inc definiert.

Übrigens: mit "myVarNull := Variants.Null" meckert der Compiler ebenfalls nicht. Kein Fehler, scheint OK.

Wenn ich Variants.Null versuche nachzuverfolgen, lande ich am Ende wieder bei VarNull. Dh. auch Variants.Null müßte also die 1 sein.

Wenn die beiden aber 1 sind. NIL aber scheints die 0 sein soll .... ???

Was übergebe ich jetzt an die Funtkion: 0 oder 1 ???

Grüße, Tom

SchwabenTom
Beiträge: 49
Registriert: So 4. Jan 2015, 21:34
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von SchwabenTom »

Nachtrag: Hat mir doch keine Ruhe gelassen. Ich dachte mir eben, daß das Problem wie üblich evtl. nicht im, sondern vorm Computer liegt (sitzt), respektive Monitor :-)

Habe also nochmal nach diesem Enum.Next gegoogelt und sofort ganz oben folgende gefunden:

1.

https://forum.lazarus.freepascal.org/in ... ic=30007.0

Der nutzt in seinem Code einmal

EnumVarinat.Next(1, WbemObject, Value)

und einmal auch das nil

EnumVarinat.Next(1, WbemObject, nil)

-> Aber was mir hier aufgefallen ist: das Value wird nicht initialisiert.

2.

http://borland.public.delphi.winapi.nar ... hods-topic

Der hat ein

while (Enum.Next(1, v, @fetched) = S_OK) do

und hat das fetched ebenfalls nicht initialisiert

3.

https://forum.lazarus.freepascal.org/in ... ic=30933.0

molly, reply #3 -> scheint mir der beste Code in diesem Zusammenhang zu sein.

while ( EnumVar.Next(1, WbemObject, NrRetValues) = 0 ) do

Hier wird NrRetValues ebenfalls nicht initialisiert. Der Name scheint anzudeuten: das ist ein Rückgabeparameter, kein Eingabeparameter.

4.

https://www.board4all.biz/threads/hdd-p ... er.610774/

Der Code sieht für mich ebenfalls sehr gut aus.

Auch hier wird iValue nicht initalisiert.


----

Conclusion

Ich hatte da wohl einen Denkfehler - oder habs falsch in der Doku gelesen, überlesen. Das ist kein Eingabeparameter. Ich kann da also keine Konstante übergeben.

Blöd, daß ich nun ein paar tausend Zeilen Code durchgehen muß, um zu sehen, wo ich sonst noch die MS-Doku falsch verstanden habe :-( Aber gut für andere, die das mit dem Enum.Next jetzt im Forum finden :-)



PS.: Wollen wir trotzdem noch die Frage klären, daß nil = 0 und NULL (mit Variants.Null und VarNull) = 1. Daß die also unterschiedlich sind. Müssen die unterschiedlich sein? Die Antwort könnte sicher interessant und auch für andere hilfreich sein.


Grüße, SchwabenTom

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Von Lazarus 1.2.6 nach Lazarus 1.8.0

Beitrag von marcov »

Die Unterschied kommt von:

------------------------------------------------------------------------
r26863 | michael | 2014-02-24 10:56:24 +0100 (Mon, 24 Feb 2014) | 1 line

* Fix IENumVariant interface to be more delphi compatible
------------------------------------------------------------------------

Den letzten Parameter ist nun kein Pointer mehr, aber ein OUT x: ULONG :

Code: Alles auswählen

// alt:
     Function  Next(celt: ULONG; OUT rgVar: VARIANT;  pCeltFetched: pULONG=nil):HResult;StdCall;
// neu:
     Function  Next(celt: ULONG; OUT rgVar: OLEVARIANT;  out pCeltFetched: ULONG):HResult;StdCall;
 


Original war es ein eingabe Zeigertyp (mit dem Idee das Next dann der "fetched" Anzahl in pceltfetched^ zuruch gab). Jetzt handelt der Compiler das ab, OUT is wie VAR, aber ohne eingabe.

Antworten