Page 1 of 1

What is a SAFEARRAY and how do you get information from it?

Posted: Tue Jan 15, 2008 5:37 am
by SFSxOI
I'm curently working with IMAPIv2, i've run into a stumbling block with some of the items being a SAFEARRAY, like this little jewel of a C++ function in the IDiscRecorder2 Interface:

Code: Select all

get_VolumePathNames([out]  SAFEARRAY* value)
According to the msdn description at http://msdn2.microsoft.com/en-us/librar ... S.85).aspx

it says: "value
List of drive letters and NTFS mount points for the device. Each element of the list is a VARIANT of type VT_BSTR. The bstrVal member of the variant contains the path."

so I did the bstrVal member and what I get back for the
pp.variant
pp\vt = #VT_BSTR
is just a 6 digit number and when i try to convert that with Uni2Ansi(pp\bstrval) I just get a bunch of strange characters like '?+'.

Whats the secret with the SAFEARRAY thing? Is this some type of UniCode thing?

Re: What is a SAFEARRAY and how do you get information from

Posted: Tue Jan 15, 2008 9:25 am
by traumatic

Posted: Tue Jan 15, 2008 10:48 am
by Shardik
A SAFEARRAY is an array of variants and you receive a pointer to a Variant which points to the SAFEARRAY structure. I am using the following code fragment quite frequently (to query infos for administrative purposes from a Novell directory (NDS) with the Novell API [which is not shown here], because many Novell API ActiveX query functions return their result as a SAFEARRAY):

Code: Select all

Structure SAFEARRAYBOUND
  cElements.L  ; # of elements in the array dimension
  lLbound.L    ; Lower bounds of the array dimension
EndStructure

Structure SAFEARRAY
  cDims.W
  fFeatures.W
  cbElements.L
  cLocks.L
  pvData.L
  rgsabound.SAFEARRAYBOUND[60]
EndStructure

Procedure.S GetVariantString(*Variant.VARIANT)
  Protected String.S = ""

  If VariantChangeType_(*Variant, *Variant, 0, #VT_BSTR) = #S_OK
    String = PeekS(*Variant\bstrVal, -1, #PB_Unicode)
    VariantClear_(*Variant)
  Else
    Debug "VariantChangeType() failed!"
  EndIf

  ProcedureReturn String  
EndProcedure

Define *Variant.VARIANT
Define *VariantArray.SAFEARRAY

*Variant = PeekL(*value)
*VariantArray = *Variant\parray

For i = 1 To *VariantArray\rgsabound[0]\cElements
  *Variant = *VariantArray\pvData + (i - 1) * 16
  Debug GetVariantString(*Variant)
Next i
Try to use the return value

Code: Select all

*value = get_VolumePathNames(value.SAFEARRAY)
in my above example after adding your interface definitions and the other stuff.

Here you can find a fine tutorial about SAFEARRAY (unfortunately only in German, but the VisualBASIC codes and the images should be self explaining (especially figure 3) :wink:):
http://www.activevb.de/tutorials/tut_sa ... array.html

Posted: Wed Jan 16, 2008 1:13 am
by SFSxOI
removed code from this post, sending corect code to tips section

Posted: Thu Jan 17, 2008 3:57 am
by SFSxOI
Never mind the above post...finally got the safearray thing working. What a PITA! Why the heck does MS need to make it so difficult.

Anyway, thank you for your help folks. :)

post the working code above in the corected post.

Posted: Thu Jan 17, 2008 4:45 am
by harff182
This code does NOT work with 2 Drives !!!!!!!!

Please, have a look at the code I put in the other thread and compare.

Posted: Thu Jan 17, 2008 5:30 am
by SFSxOI
sure it does, look at the other post. Works fine here for multiple drives on Windows Vista Ultimate.
harff182 wrote:This code does NOT work with 2 Drives !!!!!!!!

Please, have a look at the code I put in the other thread and compare.

Posted: Thu Jan 17, 2008 2:31 pm
by harff182
The code above in your post from 16 Jan 2008 1:13:14 can not work correctly on any computer IMHO, especially here, when I write this answer.

At first, the Uni2Ansi() is missing.

If I insert the Procedure, that jack pointed at in the other thread, I get this:
Debugger wrote:drive: 2 is ID: \\?\ide#cdromhl-dt-st_dvdram_gsa-4163b_______________a106____#334b354333313242313020322020202020202020#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}
Media Type is Unknown or no media loaded
HL-DT-ST
DVDRAM GSA-4163B
A106
\\?\Volume{fcfbbcce-478a-11dc-bd62-806d6172696f}\
Your Drive Path is: Y:\
Environment is supported!
Device can eject and reload media!
Legacy number is: 1
Recorder is supported
\\?\ide#cdromhl-dt-st_dvdram_gsa-4163b_______________a106____#334b354333313242313020322020202020202020#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}

drive: 2 is ID: \\?\ide#cdromtsstcorp_cd#dvdw_sh-s182d_______________sb06____#5&39971a7a&0&0.1.0#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}
Media Type is Unknown or no media loaded
HL-DT-ST
DVDRAM GSA-4163B
A106
\\?\Volume{fcfbbcce-478a-11dc-bd62-806d6172696f}\
Your Drive Path is: Y:\
Environment is supported!
Device can eject and reload media!
Legacy number is: 1
Recorder is supported
\\?\ide#cdromhl-dt-st_dvdram_gsa-4163b_______________a106____#334b354333313242313020322020202020202020#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}
[/b]
It debuggs output twice for "drive: 2", a third drive I don't have !

If I replace

Code: Select all

Debug "drive:   " +Str(count) +"   is ID:    " +Uni2Ansi(pp\bstrval)
by

Code: Select all

Debug "drive:   " +Str(x) +"   is ID:    " +Uni2Ansi(pp\bstrval)
I get this:
Debugger wrote:drive: 0 is ID: \\?\ide#cdromhl-dt-st_dvdram_gsa-4163b_______________a106____#334b354333313242313020322020202020202020#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}
Media Type is Unknown or no media loaded
HL-DT-ST
DVDRAM GSA-4163B
A106
\\?\Volume{fcfbbcce-478a-11dc-bd62-806d6172696f}\
Your Drive Path is: Y:\
Environment is supported!
Device can eject and reload media!
Legacy number is: 1
Recorder is supported
\\?\ide#cdromhl-dt-st_dvdram_gsa-4163b_______________a106____#334b354333313242313020322020202020202020#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}

drive: 1 is ID: \\?\ide#cdromtsstcorp_cd#dvdw_sh-s182d_______________sb06____#5&39971a7a&0&0.1.0#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}
Media Type is Unknown or no media loaded
HL-DT-ST
DVDRAM GSA-4163B
A106
\\?\Volume{fcfbbcce-478a-11dc-bd62-806d6172696f}\
Your Drive Path is: Y:\
Environment is supported!
Device can eject and reload media!
Legacy number is: 1
Recorder is supported
\\?\ide#cdromhl-dt-st_dvdram_gsa-4163b_______________a106____#334b354333313242313020322020202020202020#{53f56308-b6bf-11d0-94f2-00a0c91efb8b}
Now the drives are "enumerated" correctly, but the rest of the debug-output for drive 1 is the same as for drive 0, which is not correct, as they are different models from different vendors with different media inside to test.

If someone reads and tries the code above, who has installed more than 1 drive (like me) and does not know about the other thread, he will most probably fail and be disappointed.

That, and only that, was my point, as I truely respect your work because it led me to a proc I can now use in my video-database to determine the media my movies are on.