Recent

Author Topic: how to use Variant Type  (Read 6209 times)

mastro59

  • New Member
  • *
  • Posts: 16
how to use Variant Type
« on: September 11, 2018, 07:03:28 pm »
I have to communicate to an instrument via COM Object. Starting from a VBS example, I was bale to figure out how to do the same, of course in a much nicer GUI, in FP.
this is the VBS code:
RS = " "
ScopeId = " "
set app = CreateObject("LeCroy.XStreamDSO")
for i =1 to 3
   app.Acquisition.TriggerMode = "Single"
   RS = app.Acquisition.TriggerMode
   Wscript.Echo "trigger mode: "&Rs
next
scopeId = app.InstrumentId
Wscript.Echo  "instrument model: "&scopeId

the output:
Microsoft (R) Windows Script Host Version 5.812
Copyright (C) Microsoft Corporation. All rights reserved.

trigger mode: Single
trigger mode: Single
trigger mode: Single
instrument model: LECROY,WM820Zi-B,VEN-L000006,8.5.1

very simple, espacially the part where I read the setting and model. In VBS all vairables are Variant, but conversion is done automatically. and here is the problem I can't solve in FP: how to print out the returned value in the Variant, in this case RS.
I can send the command, I can read the Variant, but do not know how to use it in this case  convert to a widestring. The returnned value is a Variant becasue it can be almost anything: real, integerl, array, string.
attached is the program
and here the key part of it:
procedure TForm1.FormCreate(Sender: TObject);
begin
   app := CreateOleObject('LeCroy.XStreamDSO');
   sleep(1000);
   app.Measure.ClearSweeps ;  // clear all acquisitions   at start up
   sleep(100);

end;

procedure TForm1.Label1Click(Sender: TObject);
begin

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 RS := ' ';
 app.Acquisition.TriggerMode := 'Single'; // send single trigger command
 RS:=app.Acquisition.TriggerMode;  //supposed  to return STOPPED
 cnt:=cnt+1; // keep track of the trigger sent - see on scope Num Count
 Label1.caption := 'Trigger pressed '+ IntToStr(cnt)  + ' Times'; 
end;   

can someone enlight me about using Variant in FP and how to acces the actual content?
thanks




Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to use Variant Type
« Reply #1 on: September 11, 2018, 07:31:05 pm »
Use the OleVariant type, not the Pascal variant type for interfacing with COM/OLE scripting.
But there's a lot more wrong with your code that I can't fix during dinner.

Is it possible for you to give us a small project that you assume should work?
Your attachment will never work. It is OK to include vbscript code in this case.
« Last Edit: September 11, 2018, 07:35:21 pm by Thaddy »
Specialize a type, not a var.

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #2 on: September 12, 2018, 10:45:08 am »
Hi, Thanks for the replay.
The instrument setting is working, the reading back the answer seems too, but I do not know how to access the Variant.
attached is the project. the uses includes the file activedsolib_1_0_tlb.pas, not used in this example.
I change the variable declaration with OLEVariant as suggested. the instrument is receiving and executing the command as before. In the zip file is the VBS directory with the similar program in VBS, and the output I get in txt. This will be difficult for anyone to test, not having an instrument near by. I will see if I can come around with something.
thanks
 

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #3 on: September 12, 2018, 12:42:01 pm »
worth to mention that I am using CSCRIPT.EXE as interpreter of the VB Script.

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: how to use Variant Type
« Reply #4 on: September 12, 2018, 05:03:13 pm »
There is nothing obviously wrong in that code, but as you noted I have no way to test it.
I would try the Olecheck() functionality, though, to see if the call succeeds.
Specialize a type, not a var.

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #5 on: September 12, 2018, 06:38:05 pm »
have really no idea of how to use Olecheck().
I believe the answer  is in the variable RS. The setting works, so I am expecting the COM object processes the command and the data are sent to the output buffer. Suppose everything is working, can someone explain how to use in general a variant type in FP? I have been reading various form in last 2 days, but have not yet been able to figure out how this works.
thanks.

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: how to use Variant Type
« Reply #6 on: September 13, 2018, 04:24:58 am »
Suppose everything is working, can someone explain how to use in general a variant type in FP?
Just like in VB. You can also emulate a collection enumeration in a for loop, such as a VB.
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. program Project1;
  3.  
  4. uses Windows, SysUtils, Variants, ComObj, ActiveX;
  5.  
  6. type
  7.   TOleCollectionEnumClass = class(TObject)
  8.   private
  9.     FEnum: IEnumVariant;
  10.     FCurrent: OleVariant;
  11.   public
  12.     constructor Create(const Collection: Variant);
  13.     function MoveNext: Boolean;
  14.     property Current: OleVariant read FCurrent;
  15.   end;
  16.  
  17. constructor TOleCollectionEnumClass.Create(const Collection: Variant);
  18. begin
  19.   FEnum := IUnknown(Collection._NewEnum) as IEnumVariant;
  20. end;
  21.  
  22. function TOleCollectionEnumClass.MoveNext: Boolean;
  23. begin
  24.   Result := FEnum.Next(1, FCurrent, PULONG(nil)^) = S_OK;
  25. end;
  26.  
  27. operator enumerator(V: Variant): TOleCollectionEnumClass;
  28. begin
  29.   Result := TOleCollectionEnumClass.Create(V);
  30. end;
  31.  
  32. procedure Test;
  33. const
  34.   WBEM_FLAG_FORWARD_ONLY = $20;
  35.   WBEM_RETURN_IMMEDIATELY = $10;
  36. var
  37.   SWbemLocator: Variant;
  38.   WMIService: Variant;
  39.   FWbemCollection: Variant;
  40.   FWbemObject: OleVariant;
  41. begin
  42.   NullStrictConvert := False;
  43.   SWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  44.   WMIService := SWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', '');
  45.   FWbemCollection := WMIService.ExecQuery('select * from Win32_OperatingSystem',
  46.     'WQL', WBEM_FLAG_FORWARD_ONLY or WBEM_RETURN_IMMEDIATELY);
  47.   for FWbemObject in FWbemCollection do
  48.   begin
  49.     Writeln('Caption=', FWbemObject.Caption);
  50.     Writeln('Version=', FWbemObject.Version);
  51.     Writeln('OSArchitecture=', FWbemObject.OSArchitecture);
  52.     Writeln('SerialNumber=', FWbemObject.SerialNumber);
  53.     Writeln('BootDevice=', FWbemObject.BootDevice);
  54.     Writeln('TotalVisibleMemorySize=', FWbemObject.TotalVisibleMemorySize);
  55.   end;
  56. end;
  57.  
  58. begin
  59.   Test;
  60. end.

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #7 on: September 23, 2018, 11:13:59 am »
Aserge: the code you posted is working. If I have well understood the lines 36-55 are doing what I want to do with my COM Object. the problem is that the LeCroy.XStreamDSO objecxt doesn't define .Caption,  .SerialNumber variable which are strings already.
Attached is a screen capture showing the code and the  Replay variable content. I have probably to use a pointer to an address but not s sure how to do this. In C# this is done in a simple way, becasue the C# compiler already gives the pointer to available fields of the dynamic (Variant) type variable:
             
            Console.WriteLine("remote controlling oscilloscope Lecroy via COM object automation");
            dynamic scope = Activator.CreateInstance(Type.GetTypeFromProgID("LeCroy.XStreamDSO"));
            dynamic CMD = scope.SaveRecall.Setup.DoRecallDefaultPanel.ActNow;
            CMD = scope.Acquisition.TriggerMode = "Auto";
            dynamic Replay = scope.InstrumentModel; // define Replay as dynamic variable and sends InstrumentModel command to scope object
            var Replayvalue = Replay.Value; // Replay.Value is a string so implicit definistion of Replayvalue as string
            var Replaytype = Replay.type; // not used but Replaytype is "string"
            Console.WriteLine("You are connected to scope model:" + Replayvalue);
            Console.WriteLine("Quary replay value: " + Replaytype);

dynamic definition is equivalent to Variant in FP
I need to know how to pass to a string the value the variable Replay contains. I see from the watch window  that VSTRING ha value $a4e2434; is this the pointer to the string I want to print?
« Last Edit: September 23, 2018, 11:28:46 am by mastro59 »

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: how to use Variant Type
« Reply #8 on: September 23, 2018, 01:13:16 pm »
I can't help you until we're on the same level. That is, the properties, no properties. On the screen one thing, in code another. You're trying to ask how to work with an entity that is only on your machine. It is difficult for me to understand whether it is such a non-standard, or a bug in the code. Either the full source, or let's go to the objects available to everyone.

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #9 on: September 23, 2018, 02:18:06 pm »
attached the zip file containing all files automation.*
I was able to figure out how to do what I want, but it is not clear why, so I am still looking for some help.
essentially the solution is this:
RSstring := VarToStr(Replay.Value);
I tried using the C# way to address the variable and VarToStr() is doing the rest.
Without the  code in C# I would have never been able to figure this out , so probably what I am doing  is working but is not the right way to do it in FP.
thanks

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: how to use Variant Type
« Reply #10 on: September 23, 2018, 03:37:53 pm »
Where and what error occur?

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #11 on: September 25, 2018, 11:07:34 am »
in the original code I was trying to retrieve the response to the scopeId command using the following instructions:
Replay:= scope.InstrumentID   ;
RSstring := VarToStr(Replay); 

this was giving me a casting error, attached screen shot.

solved with the instruction
RSstring := VarToStr(Replay.Value);

what I do not understand is how to figure out that the .Value is the solution. I did becasue in the C# code I was doing something similar and the debugger was sowing me the structure of the RSstring, a DYnamic variable, and in the dynamic view I sow the Value defined as string containing the correct scopeId string.

In Free Pascal I can not see all this;the questions are then:  how do I know the structure of the variant variable RSstring? and how do I access the various fields of this "record"?
thanks

« Last Edit: September 25, 2018, 04:50:37 pm by mastro59 »

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #12 on: September 25, 2018, 05:13:46 pm »
error screen shot attached

ASerge

  • Hero Member
  • *****
  • Posts: 2223
Re: how to use Variant Type
« Reply #13 on: September 25, 2018, 06:13:51 pm »
in the original code I was trying to retrieve the response to the scopeId command using the following instructions:
Replay:= scope.InstrumentID   ;
RSstring := VarToStr(Replay); 

this was giving me a casting error, attached screen shot.

solved with the instruction
RSstring := VarToStr(Replay.Value);
What if RSstring := Replay.Value?

mastro59

  • New Member
  • *
  • Posts: 16
Re: how to use Variant Type
« Reply #14 on: September 26, 2018, 11:00:58 am »
good, this is working...
I beleive I understood how FP is working.
the value of a variant variable is access using.Value or .value suffix to the variable.
just by coincidence the C# code was referring to the same string using .Value, but in this case it must be with capital V.

thanks for the help
« Last Edit: September 26, 2018, 11:32:23 am by mastro59 »

 

TinyPortal © 2005-2018