diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | ext/win32ole/win32ole.c | 81 | ||||
-rw-r--r-- | test/win32ole/test_win32ole_variant.rb | 33 |
3 files changed, 100 insertions, 23 deletions
@@ -1,3 +1,12 @@ +Thu Feb 8 22:44:04 2007 Masaki Suketa <masaki.suketa@nifty.ne.jp> + + * ext/win32ole/win32ole.c (ole_set_safe_array, ole_variant2val, + ole_val_ary2variant_ary): fix WIN32OLE_VARIANT.new bug when + 1st argument is empty array, and when 2nd argument is + VT_ARRAY|VT_BYREF. + + * test/win32ole/test_win32ole_variant.rb: ditto. + Thu Feb 8 22:39:09 2007 Koichi Sasada <ko1@atdot.net> * yarvtest/yarvtest.rb: check target command names. diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index d4109fcb38..7d725e4737 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -80,7 +80,7 @@ #define WC2VSTR(x) ole_wc2vstr((x), TRUE) -#define WIN32OLE_VERSION "0.9.1" +#define WIN32OLE_VERSION "0.9.2" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); @@ -239,6 +239,7 @@ static LPWSTR ole_mb2wc(char *pm, int len); static VALUE ole_wc2vstr(LPWSTR pw, BOOL isfree); static VALUE ole_ary_m_entry(VALUE val, long *pid); static void * get_ptr_of_variant(VARIANT *pvar); +static VALUE is_all_index_under(long *pid, long *pub, long dim); static void ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim, VARTYPE vtype); static long dimension(VALUE val); static long ary_len_of_dim(VALUE ary, long dim); @@ -253,6 +254,8 @@ static VALUE default_inspect(VALUE self, const char *class_name); static VALUE ole_set_member(VALUE self, IDispatch *dispatch); static VALUE fole_s_allocate(VALUE klass); static VALUE create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv); +static VALUE ary_new_dim(VALUE myary, long *pid, long *plb, long dim); +static void ary_store_dim(VALUE myary, long *pid, long *plb, long dim, VALUE val); static VALUE ole_variant2val(VARIANT *pvar); static LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey); static LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey); @@ -982,22 +985,34 @@ static void * get_ptr_of_variant(VARIANT *pvar) } } +static VALUE +is_all_index_under(long *pid, long *pub, long dim) +{ + long i = 0; + for (i = 0; i < dim; i++) { + if (pid[i] > pub[i]) { + return Qfalse; + } + } + return Qtrue; +} + static void ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim, VARTYPE vtype) { VALUE val1; - HRESULT hr; + HRESULT hr = S_OK; VARIANT var; VARIANT vart; VOID *p = NULL; VariantInit(&var); VariantInit(&vart); if(n < 0) return; - if(n == dim) { + if(n == dim - 1) { val1 = ole_ary_m_entry(val, pid); ole_val2variant2(val1, &var); VariantInit(&vart); - if (vtype == VT_VARIANT) { + if ((vtype & ~VT_BYREF) == VT_VARIANT) { p = &var; } else if (vtype != V_VT(&var)) { hr = VariantChangeTypeEx(&vart, &var, @@ -1013,14 +1028,16 @@ ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long if (p == NULL) { rb_raise(rb_eRuntimeError, "failed to get ponter of variant"); } - hr = SafeArrayPutElement(psa, pid, p); + if (is_all_index_under(pid, pub, dim) == Qtrue) { + hr = SafeArrayPutElement(psa, pid, p); + } if (FAILED(hr)) { ole_raise(hr, rb_eRuntimeError, "failed to SafeArrayPutElement"); } } pid[n] += 1; - if (pid[n] < pub[n]) { - ole_set_safe_array(dim, psa, pid, pub, val, dim, vtype); + if (pid[n] <= pub[n]) { + ole_set_safe_array(dim-1, psa, pid, pub, val, dim, vtype); } else { pid[n] = 0; @@ -1102,12 +1119,12 @@ ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vtype) for (i = 0; i < dim; i++) { psab[i].cElements = ary_len_of_dim(val, i); psab[i].lLbound = 0; - pub[i] = psab[i].cElements; + pub[i] = psab[i].cElements - 1; pid[i] = 0; } /* Create and fill VARIANT array */ - if (vtype == VT_ARRAY) { + if ((vtype & ~VT_BYREF) == VT_ARRAY) { vtype = (vtype | VT_VARIANT); } psa = SafeArrayCreate(vtype & VT_TYPEMASK, dim, psab); @@ -1116,7 +1133,7 @@ ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vtype) else hr = SafeArrayLock(psa); if (SUCCEEDED(hr)) { - ole_set_safe_array(dim-1, psa, pid, pub, val, dim-1, vtype & VT_TYPEMASK); + ole_set_safe_array(dim-1, psa, pid, pub, val, dim, vtype & VT_TYPEMASK); hr = SafeArrayUnlock(psa); } @@ -1278,7 +1295,7 @@ ole_set_byref(VARIANT *realvar, VARIANT *var, VARTYPE vtype) V_VARIANTREF(var) = realvar; } else { if (V_VT(realvar) != (vtype & ~VT_BYREF)) { - rb_raise(eWIN32OLERuntimeError, "type mismatch"); + rb_raise(eWIN32OLERuntimeError, "variant type mismatch"); } switch(vtype & ~VT_BYREF) { case VT_UI1: @@ -1355,9 +1372,14 @@ ole_val2olevariantdata(VALUE val, VARTYPE vtype, struct olevariantdata *pvar) SafeArrayDestroy(psa); } } else if (vtype & VT_ARRAY) { - hr = ole_val_ary2variant_ary(val, &(pvar->realvar), vtype); + hr = ole_val_ary2variant_ary(val, &(pvar->realvar), (vtype & ~VT_BYREF)); if (SUCCEEDED(hr)) { - hr = VariantCopy(&(pvar->var), &(pvar->realvar)); + if (vtype & VT_BYREF) { + V_VT(&(pvar->var)) = V_VT(&(pvar->realvar)) | VT_BYREF; + V_ARRAYREF(&(pvar->var)) = &(V_ARRAY(&(pvar->realvar))); + } else { + hr = VariantCopy(&(pvar->var), &(pvar->realvar)); + } } } else { if (val == Qnil) { @@ -1463,8 +1485,8 @@ create_win32ole_object(VALUE klass, IDispatch *pDispatch, int argc, VALUE *argv) return obj; } -static void -ary_store_dim(VALUE myary, long *pID, long *pLB, long dim, VALUE val) { +static VALUE +ary_new_dim(VALUE myary, long *pid, long *plb, long dim) { long i; VALUE obj = Qnil; VALUE pobj = Qnil; @@ -1473,7 +1495,7 @@ ary_store_dim(VALUE myary, long *pID, long *pLB, long dim, VALUE val) { rb_raise(rb_eRuntimeError, "memory allocation error"); } for(i = 0; i < dim; i++) { - ids[i] = pID[i] - pLB[i]; + ids[i] = pid[i] - plb[i]; } obj = myary; pobj = myary; @@ -1485,8 +1507,15 @@ ary_store_dim(VALUE myary, long *pID, long *pLB, long dim, VALUE val) { obj = rb_ary_entry(pobj, ids[i]); pobj = obj; } - rb_ary_store(obj, ids[dim-1], val); if (ids) free(ids); + return obj; +} + +static void +ary_store_dim(VALUE myary, long *pid, long *plb, long dim, VALUE val) { + long id = pid[dim - 1] - plb[dim - 1]; + VALUE obj = ary_new_dim(myary, pid, plb, dim); + rb_ary_store(obj, id, val); } static VALUE @@ -1503,7 +1532,11 @@ ole_variant2val(VARIANT *pvar) long *pid, *plb, *pub; VARIANT variant; VALUE val; - int dim = SafeArrayGetDim(psa); + UINT dim = 0; + if (!psa) { + return obj; + } + dim = SafeArrayGetDim(psa); VariantInit(&variant); V_VT(&variant) = (V_VT(pvar) & ~VT_ARRAY) | VT_BYREF; @@ -1527,11 +1560,12 @@ ole_variant2val(VARIANT *pvar) if (SUCCEEDED(hr)) { obj = rb_ary_new(); while (i >= 0) { + ary_new_dim(obj, pid, plb, dim); hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant)); - if (FAILED(hr)) - break; - val = ole_variant2val(&variant); - ary_store_dim(obj, pid, plb, dim, val); + if (SUCCEEDED(hr)) { + val = ole_variant2val(&variant); + ary_store_dim(obj, pid, plb, dim, val); + } for (i = dim-1 ; i >= 0 ; --i) { if (++pid[i] <= pub[i]) break; @@ -7272,6 +7306,9 @@ folevariant_value(VALUE self) } else { psa = V_ARRAY(&(pvar->var)); } + if (!psa) { + return val; + } dim = SafeArrayGetDim(psa); if (dim == 1) { args = rb_ary_new3(1, rb_str_new2("C*")); diff --git a/test/win32ole/test_win32ole_variant.rb b/test/win32ole/test_win32ole_variant.rb index 418ce57751..b84f5855cf 100644 --- a/test/win32ole/test_win32ole_variant.rb +++ b/test/win32ole/test_win32ole_variant.rb @@ -7,6 +7,7 @@ require "test/unit" if defined?(WIN32OLE_VARIANT) class TestWIN32OLE_VARIANT < Test::Unit::TestCase + def test_new obj = WIN32OLE_VARIANT.new('foo') assert_instance_of(WIN32OLE_VARIANT, obj) @@ -94,6 +95,10 @@ if defined?(WIN32OLE_VARIANT) obj = WIN32OLE_VARIANT.new([1.2, 2.3], WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_R8) assert_equal([1.2, 2.3], obj.value) assert_equal(WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_R8, obj.vartype) + + obj = WIN32OLE_VARIANT.new([1.2, 2.3], WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_R8|WIN32OLE::VARIANT::VT_BYREF) + assert_equal([1.2, 2.3], obj.value) + assert_equal(WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_R8|WIN32OLE::VARIANT::VT_BYREF, obj.vartype) end def test_create_vt_array2 @@ -106,12 +111,39 @@ if defined?(WIN32OLE_VARIANT) assert_equal(WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_VARIANT, obj.vartype) end + def test_create_vt_nested_array obj = WIN32OLE_VARIANT.new([[1.2, "a", "b"], [3.4, "C", "D"]], WIN32OLE::VARIANT::VT_ARRAY) assert_equal([[1.2, "a", "b"], [3.4, "C", "D"]], obj.value) obj = WIN32OLE_VARIANT.new([[1.2, "a", "b"], [3.4, "C", "D"]]) assert_equal([[1.2, "a", "b"], [3.4, "C", "D"]], obj.value) + + obj = WIN32OLE_VARIANT.new([[1.2, "a", "b"], [3.4, "C", "D"], [5.6, "E", "F"]]) + assert_equal([[1.2, "a", "b"], [3.4, "C", "D"], [5.6, "E", "F"]], obj.value) + + obj = WIN32OLE_VARIANT.new([[[1.2], [3.4]], [[5.6], [7.8]], [[9.1],[9.2]]]) + assert_equal([[[1.2], [3.4]], [[5.6], [7.8]], [[9.1],[9.2]]], obj.value) + end + + def test_create_vt_array3 + obj = WIN32OLE_VARIANT.new([]) + assert_equal([], obj.value) + + obj = WIN32OLE_VARIANT.new([[]]) + assert_equal([[]], obj.value) + + obj = WIN32OLE_VARIANT.new([[],[]]) + assert_equal([[],[]], obj.value) + + obj = WIN32OLE_VARIANT.new([], WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_BYREF) + assert_equal([], obj.value) + + obj = WIN32OLE_VARIANT.new([[]], WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_BYREF) + assert_equal([[]], obj.value) + + obj = WIN32OLE_VARIANT.new([[],[]], WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_BYREF) + assert_equal([[],[]], obj.value) end def test_create_vt_array_exc @@ -168,6 +200,5 @@ if defined?(WIN32OLE_VARIANT) assert_nil(WIN32OLE_VARIANT::Null.value) end - end end |