dcsimg
Results 1 to 11 of 11

Thread: [RESOLVED] Generic PROPVARIANT Reader method?

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Apr 2019
    Posts
    27

    Resolved [RESOLVED] Generic PROPVARIANT Reader method?

    Hi VB-enthusiasts

    I am trying to find an elegant way to read IPropertyStore values according the VARENUM value of the PROPVARIANT.

    The basic idea is to send PROPVARIANT variable to the PropvariantReader class/module and get the return value as a property. Something like this:

    Code:
    Option Explicit
    
    Private mLastVarenum    As VarEnum
    Private mBlobValue      As DATA_BLOB
    Private mStringValue    As String
    
    Property Get BlobValue() As DATA_BLOB
        BlobValue = mBlobValue
    End Property
    
    Property Let BlobValue(ByRef value As DATA_BLOB)
        mBlobValue = value
    End Property
    
    Property Get StringValue() As String
        StringValue = mStringValue
    End Property
    
    Property Let StringValue(ByVal value As String)
        mStringValue = value
    End Property
    
    Property Get GetValue(ByVal ve As VarEnum) As Variant
        Select Case mLastVarenum
            Case VarEnum.VT_BLOB: GetValue = mBlobValue
        End Select
    End Property
    
    Public Function PropvarReader(ByRef propVar As PROPVARIANT) As VarEnum
        
        Select Case propVar.vt
            Case VarEnum.VT_LPWSTR
                mStringValue = GetStringFromPointer(propVar.vData)
            Case VarEnum.VT_BLOB
                Dim blob As DATA_BLOB
                
                With blob
                    .cbSize = propVar.vData
                    .pBlobData = propVar.PadBytes
                End With
                
                mBlobValue = blob
            Case Else
                'PropvarReader = CStr(propVar.vData)
        End Select
        PropvarReader = propVar.vt
        mLastVarenum = propVar.vt
    End Function
    Now, I can get the value from my form, for example:

    Code:
                Dim ve As VarEnum
                ve = IPropertyStore.GetPropertyKeyValue(PKEY_AudioEngine_DeviceFormat)
    
                If ve = VT_BLOB Then
                    Dim wave As WAVEFORMATEX
                    RtlMoveMemory ByVal wave, ByVal modPropvarReader.BlobValue.pBlobData, Len(wave)
                End If
    GetPropertyKeyValue is helper function, that gets PROPVARIANT value from IPropertyStore and send it to PropvariantReader class/module.

    Of course, I would know what to expect from the PKEY, so I could get the result like this:

    Code:
        Call IPropertyStore.GetPropertyKeyValue(PKEY_DeviceClass_IconPath)
        ExtractDeviceIcon picIcon.hdc, modPropvarReader.StringValue
    However, I would love to get is more like this, without specifying the type of the return value. Also, it would be helpful if enumerating all available properties.
    Code:
        ExtractDeviceIcon picIcon.hdc, modPropvarReader.GetValue
    Is it possible? Some know workaround, that I am missing?

    Thanks
    Last edited by npac4o; Jan 25th, 2020 at 06:24 PM.

  2. #2
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,401

    Re: Universal PROPVARIANT Reader?

    You can use the Variant type, with PropVariantToVariant and the normal typeof operator (it will return the type even if not supported). If VB doesn't support it and PropVariantChangeType can't help, you have to work with it as bytes. Look at my sig and the oleexp sample project list for numerous examples of IPropertyStore use. There is a project that enumerates all present props too.

  3. #3

    Thread Starter
    Junior Member
    Join Date
    Apr 2019
    Posts
    27

    Re: Universal PROPVARIANT Reader?

    I have tried PropVariantToVariant , however, I cannot get BLOB and it's one of the major property types. TypeOf returns vbDataObject(13) and I could not get the BLOB at all. But that's not the problem, actually, there is not a problem, I just try to get the values in more convenient manner. I can make it works, however I have to tell explicitly what value type to return, instead of returning generic type. I doubt that I would ever need to enumerate all properties.

    Name:  WAVEFORMATEX.PNG
Views: 59
Size:  6.0 KB

    What I cannot do it to return VARIANT here:
    Code:
    Property Get GetValue(ByVal ve As VarEnum) As Variant
        Select Case mLastVarenum
            Case VarEnum.VT_BLOB: GetValue = mBlobValue
        End Select
    End Property
    Name:  error.png
Views: 61
Size:  4.2 KB
    Last edited by npac4o; Jan 24th, 2020 at 05:32 PM.

  4. #4

    Thread Starter
    Junior Member
    Join Date
    Apr 2019
    Posts
    27

    Re: Universal PROPVARIANT Reader?

    This is the best solution for the moment:


    clsPropvariantReader
    Code:
    Option Explicit
    
    Private mLastVarenum    As VarEnum
    Private mBlobValue      As DATA_BLOB
    Private mStringValue    As String
    Private mLongValue      As Long
    Private mBoolValue      As Boolean
    
    Friend Property Get AsBlob() As DATA_BLOB
        AsBlob = mBlobValue
    End Property
    
    Friend Property Let AsBlob(ByRef value As DATA_BLOB)
        mBlobValue = value
    End Property
    
    Property Get AsString() As String
        AsString = mStringValue
    End Property
    
    Property Let AsString(ByVal value As String)
        mStringValue = value
    End Property
    
    Property Get AsLong() As Long
        AsLong = mLongValue
    End Property
    
    Property Let AsLong(ByVal value As Long)
        mLongValue = value
    End Property
    
    Property Get AsBool() As Boolean
        AsBool = mBoolValue
    End Property
    
    Property Let AsBool(ByVal value As Boolean)
        mBoolValue = value
    End Property
    Code:
    Public Function GetPropertyKeyValue(ByVal dpType As DEVPROPTYPE) As clsPropvariantReader
        Dim propKey As PROPERTYKEY
        Dim propVar As PROPVARIANT
    
        propKey = GetPKey(dpType)
        propVar = GetValue(propKey)
        
        Set GetPropertyKeyValue = New clsPropvariantReader
           
        Select Case propVar.vt
            Case VarEnum.VT_LPWSTR
                GetPropertyKeyValue.AsString = GetStringFromPointer(propVar.vData)
            Case VarEnum.VT_BLOB
                Dim blob As DATA_BLOB
    
                With blob
                    .cbSize = propVar.vData
                    .pBlobData = propVar.PadBytes
                End With
                GetPropertyKeyValue.AsBlob = blob
            Case Else
                GetPropertyKeyValue.AsString = CStr(propVar.vData)
        End Select
        
    End Function
    and getting the property value would look like this:

    Code:
    blob = IPropertyStore.GetPropertyKeyValue(PKEY_AudioEngine_DeviceFormat).AsBlob
    friendlyName = IPropertyStore.GetPropertyKeyValue(PKEY_Device_DeviceDesc).AsString
    It looks better than the first option, but still have to specify the return type.

  5. #5
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,401

    Re: Universal PROPVARIANT Reader?

    To get a custom structure like that to avoid the error in your post, you'd have to make it a registered type in a TLB, and then the TLB has to be manually unregistered/re-registered each time you change something (you can't just overwrite like normal).

    Generate a new GUID for it, then,
    Code:
    typedef [uuid(guid)] struct DATA_BLOB
    {
      long cbSize,
      long pBlobData //Or whatever type it is
    } DATA_BLOB;
    You're probably going to run into more problems trying to avoid having to use explicit types tho. You'd probably be better off just passing around the pointer to the object/data where it's not a native VB type.

  6. #6

    Thread Starter
    Junior Member
    Join Date
    Apr 2019
    Posts
    27

    Re: Universal PROPVARIANT Reader?

    I am not using TLB, so there is nothing to override. I started a new project from scratch, using your OLEEXP, it's so useful and extremely convenient, however, there are two things, that put me away - cannot get BLOBs and IMMNotificationClient crashes, rarely, but still crashes.

    The thing is, the PROPVARIANT variable contains the type of the data that it brings, I just cannot make a generic function to return dynamic data. I can pass pointers but that makes it more complex and is...pointless I will use the code above until I find a better solution.
    Last edited by npac4o; Jan 24th, 2020 at 07:35 PM.

  7. #7
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,401

    Re: Universal PROPVARIANT Reader?

    It's not a question of overriding something, it's a question of what VB counts as a 'public type' for the purpose of 'only user-defined types defined in public object modules'. You have to associate a unique GUID with your user type, and you can't do that in VB. You don't need oleexp (and you'd have to modify it anyway by adding the struct, since it doesn't use registered types), but you do need a typelib.

  8. #8

    Thread Starter
    Junior Member
    Join Date
    Apr 2019
    Posts
    27

    Re: Generic PROPVARIANT Reader method?

    Excuse me, I didn't understand you the first time. I was wondering what that "public object module" could be. I have never had thought of making my own typelib but now I see a few more uses.

    Now the GetPropertyKeyValue(...) As Variant is capable to return whatever variable is inside the PROPVARIANT variable, without need of helper classes/modules So simple

    Thank you for your help

    P.S. Just made a few tests - if I don't change the the type library UUID, I can just override the *.tlb file after recompiling the TLB and it gets the changes without re-registering. Gorgeous!
    Any troubles with the EXE portability when using custom type libraries?! I know that I need the *.tlb only for the IDE but want to make sure that it won't break my app in different environment.
    Last edited by npac4o; Jan 25th, 2020 at 11:01 AM.

  9. #9

    Thread Starter
    Junior Member
    Join Date
    Apr 2019
    Posts
    27

    Re: Generic PROPVARIANT Reader method?

    Name:  TLBERROR.png
Views: 41
Size:  18.0 KB

    Type libraries are new for me. It works perfectly on my main machine. However, when I tired to run the compiled EXE on another machine, it doesn't run at all. Opening the VB6 IDE gives me the error above, even that I can see the type library in the References list. The *.tlb file is placed inside the project folder.

    That's the ODL code:
    Code:
    [
        uuid(86ca9b8b-914a-4f2f-8962-a1050fcc0953),
        version(1.0),
        helpstring("TheAdmin 1.0 Type Library")
    ]
    library blobLib
    {
    	typedef [uuid(c6f55eff-8418-4306-bb9a-7c7b86a3f9d4), version(1.0)]
    	struct DATA_BLOB
    	{
    	  long cbSize;
    	  long pBlobData;
    	} DATA_BLOB;
    }

  10. #10

    Thread Starter
    Junior Member
    Join Date
    Apr 2019
    Posts
    27

    Re: Generic PROPVARIANT Reader method?

    Nevermind, I have made a class DATA_BLOB and it do the job.

    Just for future reference - is it possible to create a type library that forwards an existing variable type and make it available in VB? For example to include/import "NspAPI.h" and use the BLOB type in VB6? For a UDT I have to supply an UUID and create a new global type, and obviously this is where the registration of the TLB is required. I have a few sample projects that use TLBs and the compiled EXE work perfectly on "clean" Windows, so it should be possible but I don't know how.

    Thanks.
    Last edited by npac4o; Jan 25th, 2020 at 09:03 PM.

  11. #11
    PowerPoster
    Join Date
    Jul 2010
    Location
    NYC
    Posts
    2,401

    Re: [RESOLVED] Generic PROPVARIANT Reader method?

    You technically can include headers like that with #include, but you're going to run into a lot of trouble with just MKTYPLIB, you'd want to use midl.exe instead, and there will be a whole bunch of other stuff to include, and if the type includes a variable type not supported in VB, it won't be usable (the most common issue is unsigned numbers, VB doesn't support them so you'll see <unsupported type> in the object browser and will get an error trying to use it).

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width