Announcement

Collapse
No announcement yet.

Variant and uint64

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Variant and uint64

    How do I retrieve an unsigned quad (UINT64) from a Variant? I tried several things and they all return '0'...
    For instance Variant#(MyVariant) also returns '0'. Do I need to use VariantVT() somehow?

    [edit]
    For some reason, if I use Variant$ on places where an uint64 is expected, all goes well...
    Is this a MS docu error, or does it have another cause? (Happens with Win32_DiskDrive )
    [/edit]
    Last edited by Peter Lameijn; 30 Sep 2009, 07:48 AM.
    Regards,
    Peter

  • #2
    Purpose
    Return the numeric value contained in a Variant variable.

    Syntax
    numericvar = VARIANT#(vrntvar)

    Remarks
    The value returned by VARIANT# may be any range from BYTE to DOUBLE/QUAD/CURRENCY, depending upon the internal representation used within the Variant
    A uint64 will be out of range for a QUAD when bit 63 is set. While I'm surprised that VARIANT#() does not (allegedly, code not shown) just return the 64 bits in a sign-agnostic manner... wait a minute, I don't believe it doesn't. Let me write some test code and see what happens.

    (While I am doing this, you should make a note that VARIANT#() also does not handle VT_DECIMAL types, but there is code here to handle that for you). (Yes, I have submitted a new feature suggestion for same).

    MCM
    Michael Mattias
    Tal Systems Inc. (retired)
    Racine WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      VARIANT#(VT_UI8 var) Works here... (PB/Win 9.0.1)
      Code:
      FUNCTION PBMAIN () AS LONG
      
          LOCAL StStart AS SYSTEMTIME, STEnd AS SYSTEMTIME
          
          CALL TestVUint64()
          EXIT FUNCTION
      
      
      END FUNCTION
      
      FUNCTION TestVUint64() AS LONG
        LOCAL pV  AS VARIANTAPI PTR, v AS VARIANT
        
        LOCAL Q AS QUAD, pQ AS QUAD PTR
        
        LET V = EMPTY   '  intialize
        PV    = VARPTR (V) ' pointer
        
        @pV.vt  = %VT_UI8    ' unint 64
        pQ      = VARPTR (@pV.VD)
        Q       = 12345&&
        @pq     = Q
        
        
        ' get variant#() value from intrinsic function
        
        Q  =  VARIANT#(V)
        MSGBOX FORMAT$(Q)
      
      ' hmm, try with bit 63 set...
        LET Q = -12345&&
        @pq   = Q
        Q     = VARIANT#(V)
        MSGBOX FORMAT$(Q),, "With value -12345"
      
        
          
      END FUNCTION
      .. so you will HAVE to show your failing code if you are having problems.


      MCM
      Last edited by Michael Mattias; 30 Sep 2009, 08:39 AM. Reason: Added code to show results with bit 63 set.
      Michael Mattias
      Tal Systems Inc. (retired)
      Racine WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        Strange enough, when I use VariantVT it returns NULL string (%VT_NULL)
        But if I use Variant$ on any UINT64 member of Win32_DiskDrive, the correct value is returned...
        Regards,
        Peter

        Comment


        • #5
          Strange enough, when I use VariantVT it returns NULL string (%VT_NULL)
          But if I use Variant$ on any UINT64 member of Win32_DiskDrive, the correct value is returned...
          VT_NULL does NOT describe a "null string", it describes NULL. (Nothing, no value of any type, not even what type it isn't.)

          VARIANT$() cannot possibly return the 'correct value' of a VT_UI8 (UINT64): UINT64 is numeric; VARIANT$() returns a string.

          Here's an idea: Let's try, "SHOW FAILING CODE." (I probably should have thought of that earlier.)


          MCM
          Michael Mattias
          Tal Systems Inc. (retired)
          Racine WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            Here it is. (Bit messy, it's only a test.) Size, TotalCylinders and TotalSectors are UINT64. It's for enumerating USB storage devices.
            Code:
            ' ========================================================================================
            ' WMI example - Retrieving Disk information
            ' ========================================================================================
            
            #Compile Exe
            #Dim All
            #Include "win32api.inc"
            #Include "TB_WMILIB.INC"    ' // WMI helper functions
                                        ' see http://www.powerbasic.com/support/pb...74&postcount=3
            
            ' ========================================================================================
            ' Main
            ' ========================================================================================
            Function PBMain
            
               Local hr As Long                   ' // HRESULT
               Local oServices As Dispatch        ' // Services object
               Local vServices As Variant         ' // Services object reference
               Local oItems As Dispatch           ' // Generic collection object
               Local vItems As Variant            ' // Generic collection object reference
               Local oItem As Dispatch            ' // Generic item object
               Local vItem As Variant             ' // Generic item object reference
               Local penum As Dword               ' // Collection's enumerator reference
               Local vCount As Variant            ' // Number of items in the collection
               Local vVar As Variant              ' // General purpose variant
               Local vRes As Variant              ' // General purpose variant
               Local i As Long                    ' // Loop counter
               Local x As Long                    ' // Loop counter
               Local Result As Long
               Local Tmp As String
               Local Disp As String
               Dim vArray(0) As Variant           ' // General purpose array of variants
            
            
               ' // Connect to WMI using a moniker
               hr = WmiGetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2", vServices)
               If hr <> %S_Ok Then GoTo Terminate
               Set oServices = vServices
               vServices = Empty
               If IsFalse IsObject(oServices) Then GoTo Terminate
            
               ' // Execute a query to get a reference to the collection of running processes
               vVar = "SELECT * FROM Win32_DiskDrive WHERE InterfaceType='USB'"
               Object Call oServices.ExecQuery(vVar) To vItems
               If ObjResult Then GoTo Terminate
               Set oItems = vItems
               vItems = Empty
               If IsFalse IsObject(oItems) Then GoTo Terminate
            
               ' // Retrieve the number of items in the collection
               Object Get oItems.Count To vCount
            
               ' // Retrieve a reference to the collection's enumerator
               hr = Wmi_NewEnum(ObjPtr(oItems), penum)
               If hr <> %S_Ok Or penum = %NULL Then GoTo Terminate
            
               ' // Iterate throught the collection of objects.
               For i = 1 To Variant#(vCount)
                  ' // Retrieve a reference to the next object in the collection
                  hr = WmiEnum_NextItem(penum, vItem)
                  If hr <> %S_Ok Then Exit For
                  Set oItem = vItem
                  If IsFalse IsObject(oItem) Then Exit For
                  '------------------------------------------------------------------------
                  Object Get oItem.MediaType To vRes
                  Disp = $Cr & "MediaType: "  & $Tab & Variant$(vRes)
                  '------------------------------------------------------------------------
                  Object Get oItem.VolumeSerialNumber To vRes
                  Disp = Disp & $Cr & "VolumeSerialNumber: "  & $Tab & Variant$(vRes)
                  '------------------------------------------------------------------------
                  Object Get oItem.Model To vRes
                  Disp = Disp & $Cr & "Model: "  & $Tab & Variant$(vRes)
                  '------------------------------------------------------------------------
                  Object Get oItem.PNPDeviceID To vRes
                  Disp = Disp & $Cr & "PNP Device ID: "  & $Tab & Variant$(vRes)
                  '------------------------------------------------------------------------
                  Object Get oItem.DeviceID To vRes
                  Disp = Disp & $Cr & "Device ID: "  & $Tab & Variant$(vRes)
                  '------------------------------------------------------------------------
                  Object Get oItem.Size To vRes
                  Disp = Disp & $Cr & "Size: "  & $Tab & Variant$(Vres)'Format$(Variant#(Vres))
                  '------------------------------------------------------------------------
                  Object Get oItem.TotalCylinders To vRes
                  Disp = Disp & $Cr & "Cylinders: "  & $Tab & Variant$(vRes) 'Format$(Variant#(vRes))
                  '------------------------------------------------------------------------
                  Object Get oItem.TotalHeads To vRes
                  Disp = Disp & $Cr & "Heads: "  & $Tab & Format$(Variant#(vRes))
                  '------------------------------------------------------------------------
                  Object Get oItem.TotalSectors To vRes
                  Disp = Disp & $Cr & "Sectors: "  & $Tab & Variant$(vRes) 'Format$(Variant#(vRes))
                  '------------------------------------------------------------------------
                  Object Get oItem.BytesPerSector To vRes
                  Disp = Disp & $Cr & "BytesPerSector: "  & $Tab & Format$(Variant#(vRes))
                  '------------------------------------------------------------------------
                  Set oItem = Nothing
                  MsgBox Disp,, Tmp
               Next
            
               WmiRelease penum
               If IsObject(oItems) Then Set oItems = Nothing
            Terminate:
               If IsObject(oServices) Then Set oServices = Nothing
            End Function
            ' ========================================================================================
            Regards,
            Peter

            Comment


            • #7
              Add to display for each line the VARIANTVT() of vRes.

              Then post output.

              You have things in there like
              Code:
              Object Get oItem.TotalSectors To vRes
              Disp = Disp & $Cr & "Sectors: "  & $Tab & Variant$(vRes) 'Format$(Variant#(vRes))
              Seems to me "total sectors" should be numeric and your commented out FORMAT$(VARIANT#(vRes)) should be the correct thing to use.

              You may be getting something like VT_DECIMAL, or even a VT_ARRAY|VT_UI1 back, and VARIANT#() is just not prepared for it, e.g., my reference above to a known (to me and PB if nobody else) bug when VARIANTVT returns VT_DECIMAL.

              I suppose I could try it but I'm just a shiftless lazy person of questionable legitimacy.

              MCM
              Michael Mattias
              Tal Systems Inc. (retired)
              Racine WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                Peter,

                It doesn't return VT_NULL, but 8 (VT_BSTR), a dynamic unicode string (clean your glasses ). This is why VARIANT$ returns the correct result. I know that the M$ documentation says that it returns an unsigned 64-bit integer, but you can't blindly trust M$.

                I guess that they changed his mind and returned an string instead because many compilers don't support unsigned 64-bit integers.
                Forum: http://www.jose.it-berater.org/smfforum/index.php

                Comment


                • #9
                  OR.....

                  You could be running into compiler assumptions about the required intermediate data types when doing everything within an expression.

                  For the numeric returns, try (as demonstrated above)...

                  Code:
                  LOCAL Q AS QUAD 
                  ...
                  Object Get oItem.TotalSectors To vRes
                  Q =   VARIANT#(vRes)
                  Disp = Disp & $Cr & "Sectors: "  & $Tab & FORMAT$(Q, 18) 'specify max possible decimal digits
                  MCM
                  Michael Mattias
                  Tal Systems Inc. (retired)
                  Racine WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    Do note that a variant *can* be set to a vartype but not having any data.
                    The remark above about null string is incorrect.
                    I have met a situation that a vartype was set but a 'null' as value (pointer).
                    The PB app gpf'ed.
                    If you don't trust a certain com result you must test both vartype and data.

                    This was submitted to support a few months ago.
                    hellobasic

                    Comment


                    • #11
                      Methinks Jose hit the jackpot by testing for and finding VT_BSTR.

                      FWIW, this demo contains code you can cut and paste when you need to deal with the possibility of 'many different VT_xxxxx' (includes functions for VT_DECIMAL, VT_DATE and VT_ARRAY|VT_UI1) ...

                      Generic 'ADO' Connection and Query Tester (CC 5+/Win 9+) 11-02-08

                      MCM
                      Michael Mattias
                      Tal Systems Inc. (retired)
                      Racine WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Thanks all,

                        So it's a MS flaw after all... It would have been nice if they were consistent. (But I don't think that word is in their vocabulary )
                        Size, TotalCylinders and TotalSectors return a string, Totalheads a UINT32...

                        I now am going to try to implement this code:
                        http://www.powerbasic.com/support/pb...0&postcount=16
                        so I can get the driveletters with the physical drive...
                        Regards,
                        Peter

                        Comment


                        • #13
                          >So it's a MS flaw after all... Size, TotalCylinders and TotalSectors are UINT64
                          > ("replaced with Size, TotalCylinders and TotalSectors return a string") ...
                          > Totalheads a UINT32

                          Where does it say Size, TotalCylinders and TotalSectors are uint64? When you generate the COM interface file, everything always comes back a VARIANT....which means the burden is on you to query the returned VARIANTVT an retrieve and assign to a suitable variable.

                          I really don't want to say, "that's the beauty of the VARIANT datatype", but it is.

                          MCM
                          Michael Mattias
                          Tal Systems Inc. (retired)
                          Racine WI USA
                          [email protected]
                          http://www.talsystems.com

                          Comment


                          • #14
                            It says they are uint64 in de M$ docs: http://msdn.microsoft.com/en-us/libr...32(VS.85).aspx
                            Regards,
                            Peter

                            Comment


                            • #15
                              Those docs apply to programming in WMI script.

                              I believe COM properties and methods always return a VARIANT, which the compiler/interpreter product may or may not convert/cast to something handy.

                              Sounds like WMISCRIPT converts it to something handy. But I cannot find fault with the compiler design here... the variant it gets back is a VT_BSTR and you can't really expect it to guess that string - this time - is 'really' a zoned character decimal and therefore VARIANT#() should be able to cast it to a numeric datatype.

                              I suppose you could put in a new feature suggestion to ask that when VARIANT#() is called against VT_BSTR it perform the equivalent of VAL() on it.

                              But I would think the programmer should know, "when I call this method/property, I expect a number/string/date and therefore I must convert whatever the VARIANTVT() supplied happens to be to that target data type."

                              MCM
                              Michael Mattias
                              Tal Systems Inc. (retired)
                              Racine WI USA
                              [email protected]
                              http://www.talsystems.com

                              Comment


                              • #16
                                I believe COM properties and methods always return a VARIANT, which the compiler/interpreter product
                                may or may not convert/cast to something handy.
                                Really!? Methinks you have got that backwards.

                                Think back to the code used to access the methods of a COM server using version 8.xxx of the compiler.
                                While you are at it, have a look at the type library(not the generated include file) for that server.
                                Think Automation and Automation-compatible data types.
                                Dominic Mitchell
                                Phoenix Visual Designer
                                http://www.phnxthunder.com

                                Comment


                                • #17
                                  Maybe it's the PB compiler via the dispatch interface (OBJECT GET...TO var , OBJECT CALL.... TO var) which always returns a VARIANT?
                                  Michael Mattias
                                  Tal Systems Inc. (retired)
                                  Racine WI USA
                                  [email protected]
                                  http://www.talsystems.com

                                  Comment


                                  • #18
                                    When using Automation, what PB (and any other language that supports Automation) does is to fill an array of variants with the values and types of the parameters and call the Invoke method of the IDispatch interface. The server will delegate the call to the standard DispInvoke function or implement its own code, in which case it has to unpack the parameters, call the method or property and fill the pvarResult parameter of the Invoke method with the return value.

                                    See: http://msdn.microsoft.com/en-us/library/ms221479.aspx

                                    But the methods themselves can use any kind of types if using direct interface calls or any kind of Automation-compatible types if using Automation. This applies both to the parameters and the return values.
                                    Forum: http://www.jose.it-berater.org/smfforum/index.php

                                    Comment


                                    • #19
                                      Exactly, the COM subsystem does all the work when the client uses Automation.
                                      Dominic Mitchell
                                      Phoenix Visual Designer
                                      http://www.phnxthunder.com

                                      Comment


                                      • #20
                                        Michael, to demonstrate the fallacy of your statement, I will provide an example.

                                        The following is the PowerBASIC code that implements the TextLoc property of an ActiveX control.
                                        It returns an HRESULT and has an out parameter that returns a struct. Notice not a single variant is used.
                                        Code:
                                        FUNCTION treeINode_get_TextLoc(BYVAL pThis AS DWORD, pTextLoc AS udtTextLoc) AS LONG
                                        
                                          LOCAL trc           AS RECT
                                          LOCAL pTreeCtl      AS ITreeControl PTR
                                          LOCAL pttid         AS INode PTR
                                          LOCAL pCIFace       AS CIFace PTR
                                          LOCAL pCIFace2      AS CIFace PTR
                                          LOCAL pINodes       AS DWORD
                                          LOCAL pLoc          AS udtTextLoc PTR
                                          LOCAL hr            AS LONG
                                        
                                          pttid = pThis
                                        
                                          pCIFace = pThis
                                          pINodes = @pCIFace.pObject
                                        
                                          pCIFace2 = pINodes
                                          pTreeCtl = @pCIFace2.pObject
                                        
                                          IF VARPTR(pTextLoc) = %NULL THEN
                                            FUNCTION = %E_POINTER
                                            EXIT FUNCTION
                                          END IF
                                        
                                          hr = %E_FAIL
                                        
                                          trc.nLeft = %TGIR_LABEL
                                          IF SendMessage(@pTreeCtl.m_hWnd, %TRM_GETITEMRECT, pThis, BYVAL VARPTR(trc)) THEN
                                            IF treeINode_get_Text(pThis, pTextLoc.bstrText) = %S_OK THEN
                                              pTextLoc.nOffset = trc.nTop
                                              hr = %S_OK
                                            END IF
                                          END IF
                                        
                                          FUNCTION = hr
                                        
                                        END FUNCTION
                                        The following is an excerpt from the IDL file for the control. The interface is defined as dual
                                        because we want to allow both direct Vtbl binding and Automation.
                                        Note: In the following excerpts only the methods of interest have been included.
                                        Code:
                                          // The following two structs are here to test IRecordInfo and are not part of this library.
                                          typedef [uuid(DDC45BA7-C40E-4EB1-9554-417897C31885)]
                                          struct udtTextLoc {
                                            BSTR bstrText;
                                            long nOffset;
                                          } udtTextLoc;
                                        
                                          [
                                            uuid(18C9C171-C7B0-456C-B8D6-67AC59B40D7D),
                                            helpstring("An object in a tree control that can contain images and text."),
                                            hidden,
                                            dual,
                                            nonextensible,
                                            oleautomation
                                          ]
                                          interface ITreeNode : IDispatch
                                          {
                                            [id(0x00000019), propget, helpstring("Returns/sets a user-defined type.")]
                                            HRESULT TextLoc([out, retval] udtTextLoc* Location);
                                            [id(0x00000019), propput, helpstring("Returns/sets a user-defined type.")]
                                            HRESULT TextLoc([in] udtTextLoc* Location);
                                          };
                                        The following is an excerpt from the include file generated for the PowerBASIC compiler.
                                        Code:
                                        ' ****************************************************************************************
                                        ' Library Name: TreeControl
                                        ' Library ID:   {9D39F2C1-7047-438F-9620-5F7E2692A67F}
                                        ' Library File: F:\Phoenix3\COM\TreeCtl\Bin\TreeCtl.dll
                                        ' Description:  TreeCtl 1.0
                                        ' Code generated by Phoenix Visual Designer
                                        ' ****************************************************************************************
                                        
                                        ' ****************************************************************************************
                                        ' ProgIDs (Program identifiers)
                                        ' ****************************************************************************************
                                        
                                        $PROGID_PROMETHEUSTREECONTROL1                               = "Prometheus.TreeControl.1"
                                        
                                        ' ****************************************************************************************
                                        ' udtTextLoc
                                        ' uuid: {DDC45BA7-C40E-4EB1-9554-417897C31885}
                                        ' ****************************************************************************************
                                        
                                        TYPE udtTextLoc
                                          bstrText  	AS STRING PTR                                   ' <VT_BSTR>
                                          nOffset   	AS LONG                                         ' <VT_I4>
                                        END TYPE
                                        
                                        ' ****************************************************************************************
                                        ' coclass:        TreeControl
                                        ' clsid:          {24D9B84A-BED7-4EA2-888E-F291EB80320D}
                                        ' ProgID:         Prometheus.TreeControl
                                        ' Version ProgID: Prometheus.TreeControl.1
                                        ' Description:    Prometheus ActiveX Tree Control
                                        ' Type Flags:     [cancreate, control]
                                        ' ----------------------------------------------------------------------------------------
                                        ' Interface:      ITree
                                        ' uuid:           {0CCED9FC-7D43-4CC0-BE9C-12F3790AC8B9}
                                        ' Description:    Displays a hierarchical list of Node objects, each of which consists of a label and an optional bitmap.
                                        ' Type Flags:     [hidden, dual, nonextensible, dispatchable]
                                        ' ****************************************************************************************
                                        
                                        $CLSID_PROMETHEUSTREECONTROL = GUID$("{24D9B84A-BED7-4EA2-888E-F291EB80320D}")
                                        $IID_PROMETHEUSTREECONTROL   = GUID$("{0CCED9FC-7D43-4CC0-BE9C-12F3790AC8B9}")
                                        
                                        ' ****************************************************************************************
                                        ' coclass:        TreeNode
                                        ' clsid:          {0C154109-C88D-400D-B215-04C112AF4DDB}
                                        ' Description:    An object in a tree control that can contain images and text.
                                        ' ----------------------------------------------------------------------------------------
                                        ' Interface:      ITreeNode
                                        ' uuid:           {18C9C171-C7B0-456C-B8D6-67AC59B40D7D}
                                        ' Description:    An object in a tree control that can contain images and text.
                                        ' Type Flags:     [hidden, dual, nonextensible, dispatchable]
                                        ' ****************************************************************************************
                                        
                                        $CLSID_PROMETHEUSTREENODE = GUID$("{0C154109-C88D-400D-B215-04C112AF4DDB}")
                                        $IID_PROMETHEUSTREENODE   = GUID$("{18C9C171-C7B0-456C-B8D6-67AC59B40D7D}")
                                        
                                        INTERFACE PrometheusTreeNode $IID_PROMETHEUSTREENODE
                                          INHERIT Dual
                                          Property GET Text<&H00000000>() AS STRING
                                          Property SET Text<&H00000000>(IN BYVAL rhs AS STRING)
                                          Property GET TextLoc<&H00000019>() AS udtTextLoc
                                          Property SET TextLoc<&H00000019>(IN BYREF rhs AS udtTextLoc)
                                        END INTERFACE
                                        So far there isn't a single variant in sight. But look at what happens when the location of text
                                        is retrieved using Automation.
                                        Code:
                                        LOCAL oNode     AS INode
                                        LOCAL vLoc      AS VARIANT
                                        
                                        OBJECT GET oNode.TextLoc TO vLoc
                                        What is going on here?
                                        The COM subsystem using information from the type library allocates memory for the struct(let's call it pTextLoc)
                                        and invokes TextLoc. It then passes back to the client a variant containing the following values:
                                        Code:
                                         
                                        vLoc.vt = %VT_RECORD
                                        vLoc.br.pvRecord = pTextLoc     <-- address of memory allocated for struct
                                        vLoc.br.pRecInfo = pIRecordInfo <-- a pointer to an instance of an IRecordInfo that describes the struct
                                        Dominic Mitchell
                                        Phoenix Visual Designer
                                        http://www.phnxthunder.com

                                        Comment

                                        Working...
                                        X