# class WIN32OLE::Variant

`WIN32OLE::Variant` objects represents OLE variant.

Win32OLE converts Ruby object into OLE variant automatically when invoking OLE methods. If OLE method requires the argument which is different from the variant by automatic conversion of Win32OLE, you can convert the specified variant type by using `WIN32OLE::Variant` class.

    param = WIN32OLE::Variant.new(10, WIN32OLE::VARIANT::VT_R4)
    oleobj.method(param)

`WIN32OLE::Variant` does not support VT_RECORD variant. Use `WIN32OLE::Record` class instead of `WIN32OLE::Variant` if the VT_RECORD variant is needed.

### Constants

Empty

  represents VT_EMPTY OLE object.

NoParam

  represents VT_ERROR variant with DISP_E_PARAMNOTFOUND. This constants is used for not specified parameter.

      fso = WIN32OLE.new("Scripting.FileSystemObject")
      fso.openTextFile(filename, WIN32OLE::Variant::NoParam, false)

Nothing

  represents `Nothing` of VB.NET or VB.

Null

  represents VT_NULL OLE object.

### Public Class Methods

array(ary, vt)
Source

    static VALUE
    folevariant_s_array(VALUE klass, VALUE elems, VALUE vvt)
    {
        VALUE obj = Qnil;
        VARTYPE vt;
        struct olevariantdata *pvar;
        SAFEARRAYBOUND *psab = NULL;
        SAFEARRAY *psa = NULL;
        UINT dim = 0;
        UINT i = 0;

        ole_initialize();

        vt = RB_NUM2UINT(vvt);
        vt = (vt | VT_ARRAY);
        Check_Type(elems, T_ARRAY);
        obj = folevariant_s_allocate(klass);

        TypedData_Get_Struct(obj, struct olevariantdata, &olevariant_datatype, pvar);
        dim = RARRAY_LEN(elems);

        psab = ALLOC_N(SAFEARRAYBOUND, dim);

        if(!psab) {
            rb_raise(rb_eRuntimeError, "memory allocation error");
        }

        for (i = 0; i < dim; i++) {
            psab[i].cElements = RB_FIX2INT(rb_ary_entry(elems, i));
            psab[i].lLbound = 0;
        }

        psa = SafeArrayCreate((VARTYPE)(vt & VT_TYPEMASK), dim, psab);
        if (psa == NULL) {
            if (psab) free(psab);
            rb_raise(rb_eRuntimeError, "memory allocation error(SafeArrayCreate)");
        }

        V_VT(&(pvar->var)) = vt;
        if (vt & VT_BYREF) {
            V_VT(&(pvar->realvar)) = (vt & ~VT_BYREF);
            V_ARRAY(&(pvar->realvar)) = psa;
            V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar)));
        } else {
            V_ARRAY(&(pvar->var)) = psa;
        }
        if (psab) free(psab);
        return obj;
    }

Returns Ruby object wrapping OLE variant whose variant type is VT_ARRAY. The first argument should be `Array` object which specifies dimensions and each size of dimensions of OLE array. The second argument specifies variant type of the element of OLE array.

The following create 2 dimensions OLE array. The first dimensions size is 3, and the second is 4.

    ole_ary = WIN32OLE::Variant.array([3,4], VT_I4)
    ruby_ary = ole_ary.value # => [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

new(val, vartype) #→ WIN32OLE::Variant object.
Source

    static VALUE
    folevariant_initialize(VALUE self, VALUE args)
    {
        int len = 0;
        VARIANT var;
        VALUE val;
        VALUE vvt;
        VARTYPE vt;
        struct olevariantdata *pvar;

        len = RARRAY_LEN(args);
        rb_check_arity(len, 1, 3);
        VariantInit(&var);
        val = rb_ary_entry(args, 0);

        check_type_val2variant(val);

        TypedData_Get_Struct(self, struct olevariantdata, &olevariant_datatype, pvar);
        if (len == 1) {
            ole_val2variant(val, &(pvar->var));
        } else {
            vvt = rb_ary_entry(args, 1);
            vt = RB_NUM2INT(vvt);
            if ((vt & VT_TYPEMASK) == VT_RECORD) {
                rb_raise(rb_eArgError, "not supported VT_RECORD WIN32OLE::Variant object");
            }
            ole_val2olevariantdata(val, vt, pvar);
        }
        return self;
    }

Returns Ruby object wrapping OLE variant. The first argument specifies Ruby object to convert OLE variant variable. The second argument specifies VARIANT type. In some situation, you need the `WIN32OLE::Variant` object to pass OLE method

    shell = WIN32OLE.new("Shell.Application")
    folder = shell.NameSpace("C:\\Windows")
    item = folder.ParseName("tmp.txt")
    # You can't use Ruby String object to call FolderItem.InvokeVerb.
    # Instead, you have to use WIN32OLE::Variant object to call the method.
    shortcut = WIN32OLE::Variant.new("Create Shortcut(\&S)")
    item.invokeVerb(shortcut)

### Public Instance Methods

variant[i,j,...] #→ element of OLE array.
Source

    static VALUE
    folevariant_ary_aref(int argc, VALUE *argv, VALUE self)
    {
        struct olevariantdata *pvar;
        SAFEARRAY *psa;
        VALUE val = Qnil;
        VARIANT variant;
        LONG *pid;
        HRESULT hr;

        TypedData_Get_Struct(self, struct olevariantdata, &olevariant_datatype, pvar);
        if (!V_ISARRAY(&(pvar->var))) {
            rb_raise(eWIN32OLERuntimeError,
                     "`[]' is not available for this variant type object");
        }
        psa = get_locked_safe_array(self);
        if (psa == NULL) {
            return val;
        }

        pid = ary2safe_array_index(argc, argv, psa);

        VariantInit(&variant);
        V_VT(&variant) = (V_VT(&(pvar->var)) & ~VT_ARRAY) | VT_BYREF;
        hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant));
        if (FAILED(hr)) {
            ole_raise(hr, eWIN32OLERuntimeError, "failed to SafeArrayPtrOfIndex");
        }
        val = ole_variant2val(&variant);

        unlock_safe_array(psa);
        if (pid) free(pid);
        return val;
    }

Returns the element of `WIN32OLE::Variant` object(OLE array). This method is available only when the variant type of `WIN32OLE::Variant` object is VT_ARRAY.

REMARK:

    The all indices should be 0 or natural number and
    lower than or equal to max indices.
    (This point is different with Ruby Array indices.)

    obj = WIN32OLE::Variant.new([[1,2,3],[4,5,6]])
    p obj[0,0] # => 1
    p obj[1,0] # => 4
    p obj[2,0] # => WIN32OLE::RuntimeError
    p obj[0, -1] # => WIN32OLE::RuntimeError

variant[i,j,...] = val #→ set the element of OLE array
Source

    static VALUE
    folevariant_ary_aset(int argc, VALUE *argv, VALUE self)
    {
        struct olevariantdata *pvar;
        SAFEARRAY *psa;
        VARIANT var;
        VARTYPE vt;
        LONG *pid;
        HRESULT hr;
        VOID *p = NULL;

        TypedData_Get_Struct(self, struct olevariantdata, &olevariant_datatype, pvar);
        if (!V_ISARRAY(&(pvar->var))) {
            rb_raise(eWIN32OLERuntimeError,
                     "`[]' is not available for this variant type object");
        }
        psa = get_locked_safe_array(self);
        if (psa == NULL) {
            rb_raise(rb_eRuntimeError, "failed to get SafeArray pointer");
        }

        pid = ary2safe_array_index(argc-1, argv, psa);

        VariantInit(&var);
        vt = (V_VT(&(pvar->var)) & ~VT_ARRAY);
        p = val2variant_ptr(argv[argc-1], &var, vt);
        if ((V_VT(&var) == VT_DISPATCH && V_DISPATCH(&var) == NULL) ||
            (V_VT(&var) == VT_UNKNOWN && V_UNKNOWN(&var) == NULL)) {
            rb_raise(eWIN32OLERuntimeError, "argument does not have IDispatch or IUnknown Interface");
        }
        hr = SafeArrayPutElement(psa, pid, p);
        if (FAILED(hr)) {
            ole_raise(hr, eWIN32OLERuntimeError, "failed to SafeArrayPutElement");
        }

        unlock_safe_array(psa);
        if (pid) free(pid);
        return argv[argc-1];
    }

`Set` the element of `WIN32OLE::Variant` object(OLE array) to val. This method is available only when the variant type of `WIN32OLE::Variant` object is VT_ARRAY.

REMARK:

    The all indices should be 0 or natural number and
    lower than or equal to max indices.
    (This point is different with Ruby Array indices.)

    obj = WIN32OLE::Variant.new([[1,2,3],[4,5,6]])
    obj[0,0] = 7
    obj[1,0] = 8
    p obj.value # => [[7,2,3], [8,5,6]]
    obj[2,0] = 9 # => WIN32OLE::RuntimeError
    obj[0, -1] = 9 # => WIN32OLE::RuntimeError

value #→ Ruby object.
Source

    static VALUE
    folevariant_value(VALUE self)
    {
        struct olevariantdata *pvar;
        VALUE val = Qnil;
        VARTYPE vt;
        int dim;
        SAFEARRAY *psa;
        TypedData_Get_Struct(self, struct olevariantdata, &olevariant_datatype, pvar);

        val = ole_variant2val(&(pvar->var));
        vt = V_VT(&(pvar->var));

        if ((vt & ~VT_BYREF) == (VT_UI1|VT_ARRAY)) {
            if (vt & VT_BYREF) {
                psa = *V_ARRAYREF(&(pvar->var));
            } else {
                psa  = V_ARRAY(&(pvar->var));
            }
            if (!psa) {
                return val;
            }
            dim = SafeArrayGetDim(psa);
            if (dim == 1) {
                val = rb_funcall(val, rb_intern("pack"), 1, rb_str_new2("C*"));
            }
        }
        return val;
    }

Returns Ruby object value from OLE variant.

    obj = WIN32OLE::Variant.new(1, WIN32OLE::VARIANT::VT_BSTR)
    obj.value # => "1" (not Integer object, but String object "1")

value = val #→ set WIN32OLE::Variant value to val.
Source

    static VALUE
    folevariant_set_value(VALUE self, VALUE val)
    {
        struct olevariantdata *pvar;
        VARTYPE vt;
        TypedData_Get_Struct(self, struct olevariantdata, &olevariant_datatype, pvar);
        vt = V_VT(&(pvar->var));
        if (V_ISARRAY(&(pvar->var)) && ((vt & ~VT_BYREF) != (VT_UI1|VT_ARRAY) || !RB_TYPE_P(val, T_STRING))) {
            rb_raise(eWIN32OLERuntimeError,
                     "`value=' is not available for this variant type object");
        }
        ole_val2olevariantdata(val, vt, pvar);
        return Qnil;
    }

Sets variant value to val. If the val type does not match variant value type(vartype), then val is changed to match variant value type(vartype) before setting val. This method is not available when vartype is VT_ARRAY(except VT_UI1|VT_ARRAY). If the vartype is VT_UI1|VT_ARRAY, the val should be `String` object.

    obj = WIN32OLE::Variant.new(1) # obj.vartype is WIN32OLE::VARIANT::VT_I4
    obj.value = 3.2 # 3.2 is changed to 3 when setting value.
    p obj.value # => 3

vartype #→ OLE variant type.
Source

    static VALUE
    folevariant_vartype(VALUE self)
    {
        struct olevariantdata *pvar;
        TypedData_Get_Struct(self, struct olevariantdata, &olevariant_datatype, pvar);
        return RB_INT2FIX(V_VT(&pvar->var));
    }

Returns OLE variant type.

    obj = WIN32OLE::Variant.new("string")
    obj.vartype # => WIN32OLE::VARIANT::VT_BSTR