Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Fehler bei SafeArry Destroy - Wer kann helfen... (https://www.delphipraxis.net/67300-fehler-bei-safearry-destroy-wer-kann-helfen.html)

Mavarik 12. Apr 2006 16:20


Fehler bei SafeArry Destroy - Wer kann helfen...
 
Hallo Zusammen...

Folgene Routinen liefert leider immer einen Fehler
"EVariantBadVarTypeError"

Wer hat eine Idee?

Delphi-Quellcode:
procedure TMainform.SpeedButton14Click(Sender: TObject);
var
  ValOut : OLEVariant;
  Val   : PSafeArray;
  sBuffer: WideString;
  T     : TVarType;
  i,
  iMin,
  iMax: integer;
begin
  Combobox1.Items.Clear;
  TVariantArg(ValOUT).VT := VT_BYREF or VT_ARRAY;
  TVariantArg(ValOUT).ppArray := nil;
  TargetCommando(2233,EmptyParam,ValOut);   // IDM_GETBLOCKFMTS
  Val := PSafeArray(TVariantArg(ValOUT).ppArray);

   // Die Anzahl der Elemente im Array bestimmen
  ActiveX.SafeArrayGetLBound(Val, 1, iMin);
  ActiveX.SafeArrayGetUBound(Val, 1, iMax);

  // Die einzelnen Strings auslesen
  for i := iMin to iMax do
    begin
      ActiveX.SafeArrayGetElement(Val, i, sBuffer);
      Combobox1.Items.Add(SBuffer);
    end;
   // Vorsicht, Leak...
a->  ActiveX.SafeArrayDestroyData(Val); // EVariantBadVarTypeError
b->  ActiveX.SafeArrayDestroy(Val);    // EVariantBadVarTypeError
end;
Sowohl Lösung a als auch b...

Danke im voraus

Frank :coder:

PS.: Die Anleitung zu diesem Kommando gibt es hier (msdn)

Mavarik 13. Apr 2006 08:51

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Halo nochmal...

Das Problem stellt sich noch besser/schlechter da...

Delphi-Quellcode:
procedure TMainform.SpeedButton14Click(Sender: TObject);
var
  ValOut : OLEVariant;
  Val   : PSafeArray;
  sBuffer: WideString;
  T     : TVarType;
  i,
  iMin,
  iMax: integer;
begin
  Combobox1.Items.Clear;
  TVariantArg(ValOUT).VT := VT_BYREF or VT_ARRAY;
  TVariantArg(ValOUT).ppArray := nil;
  TargetCommando(2233,EmptyParam,ValOut);   // IDM_GETBLOCKFMTS
  Val := PSafeArray(TVariantArg(ValOUT).ppArray);

   // Die Anzahl der Elemente im Array bestimmen
  ActiveX.SafeArrayGetLBound(Val, 1, iMin);
  ActiveX.SafeArrayGetUBound(Val, 1, iMax);

  // Die einzelnen Strings auslesen
  for i := iMin to iMax do
    begin
      ActiveX.SafeArrayGetElement(Val, i, sBuffer);
      Combobox1.Items.Add(SBuffer);
    end;

   Caption := 'Cool'; // <- Auch hier gibt es den gleichen Fehler...

   // Vorsicht, Leak...
//a->  ActiveX.SafeArrayDestroyData(Val); // EVariantBadVarTypeError
//b->  ActiveX.SafeArrayDestroy(Val);    // EVariantBadVarTypeError
end;
:wiejetzt:

jetzt verstehe ich gar nix mehr....

Hat den keiner eine Idee?

Frank :coder:

shmia 13. Apr 2006 09:12

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Hi Mavaric,
du hast dich in ein Problem verrannt, bei dem du SafeArrays und TVarType munter durcheinander
mischelst.
Du musst zurück an den Anfang und erst mal erklären, was du überhaupt erreichen möchtest.
Warum lässt du dich z.B. auf einen "Krieg" mit SafeArrays ein, obwohl man
damit bei Automatisierung nicht im Berührung kommen muss.
Man kann Parameter über ein OleVariant-Array übergeben oder entgegennehmen.

Mavarik 13. Apr 2006 09:34

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Zitat:

Zitat von shmia
Hi Mavaric,
du hast dich in ein Problem verrannt, bei dem du SafeArrays und TVarType munter durcheinander
mischelst.
Du musst zurück an den Anfang und erst mal erklären, was du überhaupt erreichen möchtest.
Warum lässt du dich z.B. auf einen "Krieg" mit SafeArrays ein, obwohl man
damit bei Automatisierung nicht im Berührung kommen muss.
Man kann Parameter über ein OleVariant-Array übergeben oder entgegennehmen.

:wall: :wiejetzt:

Danke für die Antwort, leider habe ich NIX verstanden...

Kannst Du vieleicht in Pascal antworten? Danke...

Frank :coder:

Mavarik 18. Apr 2006 09:29

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Kann mir den keiner sagen wo der Fehler liegt?

Frank :coder:

shmia 18. Apr 2006 09:53

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Ungetestet:
Delphi-Quellcode:
procedure TMainform.SpeedButton14Click(Sender: TObject);
var
  ValOut : OLEVariant;
  i: integer;
begin
  Combobox1.Items.Clear;
  TargetCommando(2233,EmptyParam,ValOut);   // IDM_GETBLOCKFMTS

  // Die einzelnen Strings auslesen
  for i := VarArrayLowBound(ValOut,1) to VarArrayHighBound(ValOut,1) do
  begin
     Combobox1.Items.Add(ValOut[i]);
  end;

Mavarik 18. Apr 2006 10:13

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Gleiche Fehlermeldung.

Außerdem fehlt der Dispose/Free und in der Anleitung steht extra drin, dass man sich darum selber kümmern muss.

Frank :coder:

shmia 18. Apr 2006 10:43

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Zitat:

Zitat von Mavarik
Außerdem fehlt der Dispose/Free und in der Anleitung steht extra drin, dass man sich darum selber kümmern muss.

Das mag für C++ gelten. Bei Delphi werden Variants aber finalisiert.
Aber man sollte die Variant-Variable erst mal analysieren:
Delphi-Quellcode:
  TargetCommando(2233,EmptyParam,ValOut);   // IDM_GETBLOCKFMTS
ShowMessage(VarVarTypeAsString(ValOut)); // Variant Datentyp anzeigen
Und hier die Hilfsfunktionen:
Delphi-Quellcode:
function VarTypeAsString(const vt: Integer): string;
begin
   case vt and varTypeMask of
      varEmpty:    Result := 'Empty';
      varNull:     Result := 'Null';
      varSmallint: Result := 'SmallInt';
      varInteger:  Result := 'Integer';
      varSingle:   Result := 'Single';
      varDouble:   Result := 'Double';
      varCurrency: Result := 'Currency';
      varDate:     Result := 'Date';
      varOleStr:   Result := 'OleStr';
      varDispatch: Result := 'Dispatch';
      varError:    Result := 'Error';
      varBoolean:  Result := 'Boolean';
      varVariant:  Result := 'Variant';
      varUnknown:  Result := 'Unknown';
      varString:   Result := 'String';
      varAny:      Result := 'Any';
      varByte:     Result := 'Byte';
      // folgende Konstanten sind in Unit ActiveX deklariert
     
      VT_UI4:      Result := 'LongWord';
      VT_PTR:      Result := 'Pointer';
      VT_DECIMAL:  Result := 'Decimal (16Byte)';
      VT_VOID:     Result := 'void';
      VT_SAFEARRAY: Result := 'safe-array';
      VT_USERDEFINED: Result := 'UserDef';
      VT_LPSTR:    Result := 'PChar';
      VT_FILETIME: Result := 'Filetime';
      VT_BLOB:     Result := 'Blob';
      VT_STREAM:   Result := 'Stream';
      VT_STORAGE:  Result := 'Storage';
      VT_STREAMED_OBJECT: Result := 'Streamed Obj';
      VT_STORED_OBJECT: Result := 'Stored Obj';
      VT_BLOB_OBJECT: Result := 'Blob Obj';
      VT_CF:       Result := 'Clipboard Format';
      VT_CLSID:    Result := 'Class ID';

   else
      Result := Format('0x%.8x',[vt]);
   end;

   if (vt and varArray) <> 0 then
      Result := 'array of ' + Result;
   if (vt and varByRef) <> 0 then
      Result := '*'+Result;
end;

function VarVarTypeAsString(const v: Variant): string;
begin
   Result := VarTypeAsString(VarType(v));
end;
Wenn es sich bei dem Variant um ein Array handelt, wird das Ergebnis "array of ..." sein.
Wenn es ein Array ist, dann wird man jedes einzelne Element unter die Lupe nehmen.
Mindestens eines dieser Elemente hat einen VarType, der von Delphi nicht unterstützt wird.

Mavarik 18. Apr 2006 19:52

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Ich erhalte als Antwort: Array of Empty...

Aber wenn ich die Combobox mit meiner Routine auslese, erhalte ich die "richtigen" Strings!!!!

Frank :wiejetzt:

shmia 19. Apr 2006 08:51

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Zitat:

Zitat von Mavarik
Ich erhalte als Antwort: Array of Empty...

Wie lauten den die Datentypen der einzelnen Elemente ?
Delphi-Quellcode:
for i := VarArrayLowBound(ValOut,1) to VarArrayHighBound(ValOut,1) do
   s := s + Format('[%d]=%s'#13#10, [i,VarVarTypeAsString(ValOut[i]]);
ShowMessage(s);

Mavarik 19. Apr 2006 09:22

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Hi!

Es lautet immer Empty auch für alle einzelnen Elemente...

Auf diese Struktur kann man nur über das PSaveArray Construct zugreifen!!!

Frank :coder:

shmia 19. Apr 2006 10:28

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Zitat:

Zitat von Mavarik
Auf diese Struktur kann man nur über das PSaveArray Construct zugreifen!!!

Das ist entweder Absicht oder Blödheit seitens Microsoft. :wall:
Es wäre ein Leichtes gewesen, ein Variant-Array von OleStr(=BSTR) aufzubauen.

Auf http://www.kbalertz.com/kb_Q315482.aspx wird ein C# Codeschnipsel gezeigt.
Das lässt sich auf Delphi übertragen.

Mavarik 19. Apr 2006 12:04

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Nun ja... Also wenn Du Dir meine ursprüngliche Nachricht ansiehst, habe ich es genau so gemacht!

Frank :wiejetzt:

shmia 19. Apr 2006 13:58

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
Zitat:

Zitat von Mavarik
Nun ja... Also wenn Du Dir meine ursprüngliche Nachricht ansiehst, habe ich es genau so gemacht!

Ähnlich, aber nicht gleich. Aber wir sind schon auf der richtigen Spur.
Vor dem Aufruf an TargetCommando braucht/soll ValOut nicht vorbereitet werden.
Am Ende gibt du das SafeArray mit SafeArrayDestroy frei.
Die Exception EVariantBadVarTypeError könnte darauf hindeuten,
dass Delphi selbst versucht ValOut zu finalisieren und in diesem speziellen Fall
aber ein Problem hat ein "Array of Empty" freizugeben.

Im Delphi 5 Sourcecode gibt es die Exception EVariantBadVarTypeError nicht;
du müsstest also deinen Sourcecode von D2005 danach durchsuchen.
Es wäre auch wichtig zu wissen, ob die Exception durch
SafeArrayDestroy ausgelöst ist (was ich nicht glaube) oder erst bei
Erreichen des Procedureende (meine Vermutung).

Evtl. könnte es helfen, den Typ des Variant zu ändern:
Delphi-Quellcode:
for i := iMin to iMax do
    begin
      ActiveX.SafeArrayGetElement(Val, i, sBuffer);
      Combobox1.Items.Add(SBuffer);
    end;
TVariantArg(ValOUT).VT := VT_EMPTY; // Trick: Variant ist nun kein Array mehr
ValOUT := 42;                       // Trick2: Compiler soll "denken", du benützt ValOut immer noch

Mavarik 19. Apr 2006 14:41

Re: Fehler bei SafeArry Destroy - Wer kann helfen...
 
ICH HABS! Hoffe ich jedenfalls!

Delphi-Quellcode:
  FormatCombo.Items.Clear;
  TVariantArg(ValOUT).VT := VT_BYREF or VT_SAFEARRAY;
  TVariantArg(ValOUT).ppArray := nil;
  TargetCommando(2233,EmptyParam,ValOut);   // 2233
  TVariantArg(ValOUT).VT := VT_BYREF or VT_SAFEARRAY; // EINFACH NOCHMAL SETZEN!

  Val := PSafeArray(TVariantArg(ValOUT).ppArray);
 
   // Die Anzahl der Elemente im Array bestimmen
  ActiveX.SafeArrayGetLBound(Val, 1, iMin);
  ActiveX.SafeArrayGetUBound(Val, 1, iMax);

  // Die einzelnen Strings auslesen
  for i := iMin to iMax-1 do
    begin
      try
        ActiveX.SafeArrayGetElement(Val, i, sBuffer);
        FormatCombo.Items.Add(SBuffer);
      except
//        Caption := 'Fehler';
      end;
    end;
  ActiveX.SafeArrayDestroyData(Val);
  ActiveX.SafeArrayDestroy(Val);
So gibt es keine Exception mehr...

Frank :coder:

PS.: Trotzdem danke für Deine Hilfe...


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:34 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