diff --git a/ChangeLog b/ChangeLog index 3970b0e194..f4ea644cea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Sat Feb 3 14:32:58 2007 Masaki Suketa + + * ext/win32ole/win32ole.c (ole_val2olevariantdata, ole_val2variant): + fix the bug of WIN32OLE_VARIANT.new when variant type is + VT_ARRAY. + + * ext/win32ole/sample/excel1.rb: rewrite using WIN32OLE_VARIANT. + + * test/win32ole/test_win32ole.rb: add some test. + + * test/win32ole/test_win32ole_variant.rb: ditto. + Sat Feb 3 03:35:20 2007 Nobuyoshi Nakada * Makefile.in, */Makefile.sub, common.mk (vmasm): generalized. diff --git a/ext/win32ole/sample/excel1.rb b/ext/win32ole/sample/excel1.rb index e366a52839..2cad84a488 100644 --- a/ext/win32ole/sample/excel1.rb +++ b/ext/win32ole/sample/excel1.rb @@ -1,22 +1,33 @@ require 'win32ole' -#application = WIN32OLE.new('Excel.Application.5') application = WIN32OLE.new('Excel.Application') application.visible = TRUE workbook = application.Workbooks.Add(); worksheet = workbook.Worksheets(1); + +=begin worksheet.Range("A1:D1").value = ["North","South","East","West"]; worksheet.Range("A2:B2").value = [5.2, 10]; + worksheet.Range("C2").value = 8; worksheet.Range("D2").value = 20; +=end +worksheet.Range("A1:B2").value = [["North","South"], + [5.2, 10]]; + +vals = WIN32OLE_VARIANT.new([["East","West"], + [8, 20]], + WIN32OLE::VARIANT::VT_ARRAY) +worksheet.Range("C1:D2").value = vals + range = worksheet.Range("A1:D2"); range.Select chart = workbook.Charts.Add; workbook.saved = TRUE; - +sleep 0.5 application.ActiveWorkbook.Close(0); application.Quit(); diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index 0c5461d412..d4109fcb38 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.0" +#define WIN32OLE_VERSION "0.9.1" typedef HRESULT (STDAPICALLTYPE FNCOCREATEINSTANCEEX) (REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); @@ -238,9 +238,11 @@ static void oleparam_free(struct oleparamdata *pole); 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 ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim); static void * get_ptr_of_variant(VARIANT *pvar); -static void ole_set_safe_array_with_type(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim, VARTYPE vtype); +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); +static HRESULT ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vtype); static void ole_val2variant(VALUE val, VARIANT *var); static void ole_val2ptr_variant(VALUE val, VARIANT *var); static void ole_set_byref(VARIANT *realvar, VARIANT *var, VARTYPE vtype); @@ -709,8 +711,6 @@ date2time_str(double date) return rb_str_new2(szTime); } -static void ole_val2variant(); - static char * ole_wc2mb(LPWSTR pw) { @@ -931,28 +931,6 @@ ole_ary_m_entry(VALUE val, long *pid) return obj; } -static void -ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim) -{ - VALUE val1; - VARIANT var; - VariantInit(&var); - if(n < 0) return; - if(n == dim) { - val1 = ole_ary_m_entry(val, pid); - ole_val2variant(val1, &var); - SafeArrayPutElement(psa, pid, &var); - } - pid[n] += 1; - if (pid[n] < pub[n]) { - ole_set_safe_array(dim, psa, pid, pub, val, dim); - } - else { - pid[n] = 0; - ole_set_safe_array(n-1, psa, pid, pub, val, dim); - } -} - static void * get_ptr_of_variant(VARIANT *pvar) { switch(V_VT(pvar)) { @@ -968,11 +946,6 @@ static void * get_ptr_of_variant(VARIANT *pvar) case VT_UI4: return &V_UI4(pvar); break; -/* - case VT_I8: - return &V_I8(pvar); - break; -*/ case VT_R4: return &V_R4(pvar); break; @@ -997,11 +970,6 @@ static void * get_ptr_of_variant(VARIANT *pvar) case VT_BOOL: return &V_BOOL(pvar); break; -/* - case VT_VARIANT: - return &V_VARIANT(pvar); - break; -*/ case VT_UNKNOWN: return &V_UNKNOWN(pvar); break; @@ -1015,7 +983,7 @@ static void * get_ptr_of_variant(VARIANT *pvar) } static void -ole_set_safe_array_with_type(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim, VARTYPE vtype) +ole_set_safe_array(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE val, long dim, VARTYPE vtype) { VALUE val1; HRESULT hr; @@ -1027,9 +995,11 @@ ole_set_safe_array_with_type(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE if(n < 0) return; if(n == dim) { val1 = ole_ary_m_entry(val, pid); - ole_val2variant(val1, &var); + ole_val2variant2(val1, &var); VariantInit(&vart); - if (vtype != V_VT(&var)) { + if (vtype == VT_VARIANT) { + p = &var; + } else if (vtype != V_VT(&var)) { hr = VariantChangeTypeEx(&vart, &var, cWIN32OLE_lcid, 0, (VARTYPE)(vtype & ~VT_BYREF)); if (FAILED(hr)) { @@ -1050,14 +1020,121 @@ ole_set_safe_array_with_type(long n, SAFEARRAY *psa, long *pid, long *pub, VALUE } pid[n] += 1; if (pid[n] < pub[n]) { - ole_set_safe_array_with_type(dim, psa, pid, pub, val, dim, vtype); + ole_set_safe_array(dim, psa, pid, pub, val, dim, vtype); } else { pid[n] = 0; - ole_set_safe_array_with_type(n-1, psa, pid, pub, val, dim, vtype); + ole_set_safe_array(n-1, psa, pid, pub, val, dim, vtype); } } +static long +dimension(VALUE val) { + long dim = 0; + long dim1 = 0; + long len = 0; + long i = 0; + if (TYPE(val) == T_ARRAY) { + len = RARRAY_LEN(val); + for (i = 0; i < len; i++) { + dim1 = dimension(rb_ary_entry(val, i)); + if (dim < dim1) { + dim = dim1; + } + } + dim += 1; + } + return dim; +} + +static long +ary_len_of_dim(VALUE ary, long dim) { + long ary_len = 0; + long ary_len1 = 0; + long len = 0; + long i = 0; + VALUE val; + if (dim == 0) { + if (TYPE(ary) == T_ARRAY) { + ary_len = RARRAY_LEN(ary); + } + } else { + if (TYPE(ary) == T_ARRAY) { + len = RARRAY_LEN(ary); + for (i = 0; i < len; i++) { + val = rb_ary_entry(ary, i); + ary_len1 = ary_len_of_dim(val, dim-1); + if (ary_len < ary_len1) { + ary_len = ary_len1; + } + } + } + } + return ary_len; +} + +static HRESULT +ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vtype) +{ + long dim = 0; + int i = 0; + HRESULT hr = S_OK; + + SAFEARRAYBOUND *psab = NULL; + SAFEARRAY *psa = NULL; + long *pub, *pid; + + Check_Type(val, T_ARRAY); + + dim = dimension(val); + + psab = ALLOC_N(SAFEARRAYBOUND, dim); + pub = ALLOC_N(long, dim); + pid = ALLOC_N(long, dim); + + if(!psab || !pub || !pid) { + if(pub) free(pub); + if(psab) free(psab); + if(pid) free(pid); + rb_raise(rb_eRuntimeError, "memory allocation error"); + } + + for (i = 0; i < dim; i++) { + psab[i].cElements = ary_len_of_dim(val, i); + psab[i].lLbound = 0; + pub[i] = psab[i].cElements; + pid[i] = 0; + } + + /* Create and fill VARIANT array */ + if (vtype == VT_ARRAY) { + vtype = (vtype | VT_VARIANT); + } + psa = SafeArrayCreate(vtype & VT_TYPEMASK, dim, psab); + if (psa == NULL) + hr = E_OUTOFMEMORY; + else + hr = SafeArrayLock(psa); + if (SUCCEEDED(hr)) { + ole_set_safe_array(dim-1, psa, pid, pub, val, dim-1, vtype & VT_TYPEMASK); + hr = SafeArrayUnlock(psa); + } + + if(pub) free(pub); + if(psab) free(psab); + if(pid) free(pid); + + if (SUCCEEDED(hr)) { + V_VT(var) = vtype; + V_ARRAY(var) = psa; + } + else { + if (psa != NULL) + SafeArrayDestroy(psa); + } + return hr; +} + static void ole_val2variant(VALUE val, VARIANT *var) { @@ -1084,63 +1161,8 @@ ole_val2variant(VALUE val, VARIANT *var) } switch (TYPE(val)) { case T_ARRAY: - { - VALUE val1; - long dim = 0; - int i = 0; - - HRESULT hr; - SAFEARRAYBOUND *psab; - SAFEARRAY *psa; - long *pub, *pid; - - val1 = val; - while(TYPE(val1) == T_ARRAY) { - val1 = rb_ary_entry(val1, 0); - dim += 1; - } - psab = ALLOC_N(SAFEARRAYBOUND, dim); - pub = ALLOC_N(long, dim); - pid = ALLOC_N(long, dim); - - if(!psab || !pub || !pid) { - if(pub) free(pub); - if(psab) free(psab); - if(pid) free(pid); - rb_raise(rb_eRuntimeError, "memory allocation error"); - } - val1 = val; - i = 0; - while(TYPE(val1) == T_ARRAY) { - psab[i].cElements = RARRAY_LEN(val1); - psab[i].lLbound = 0; - pub[i] = psab[i].cElements; - pid[i] = 0; - i ++; - val1 = rb_ary_entry(val1, 0); - } - /* Create and fill VARIANT array */ - psa = SafeArrayCreate(VT_VARIANT, dim, psab); - if (psa == NULL) - hr = E_OUTOFMEMORY; - else - hr = SafeArrayLock(psa); - if (SUCCEEDED(hr)) { - ole_set_safe_array(dim-1, psa, pid, pub, val, dim-1); - hr = SafeArrayUnlock(psa); - } - if(pub) free(pub); - if(psab) free(psab); - if(pid) free(pid); - - if (SUCCEEDED(hr)) { - V_VT(var) = VT_VARIANT | VT_ARRAY; - V_ARRAY(var) = psa; - } - else if (psa != NULL) - SafeArrayDestroy(psa); + ole_val_ary2variant_ary(val, var, VT_VARIANT|VT_ARRAY); break; - } case T_STRING: V_VT(var) = VT_BSTR; V_BSTR(var) = ole_mb2wc(StringValuePtr(val), -1); @@ -1333,64 +1355,10 @@ ole_val2olevariantdata(VALUE val, VARTYPE vtype, struct olevariantdata *pvar) SafeArrayDestroy(psa); } } else if (vtype & VT_ARRAY) { - VALUE val1; - long dim = 0; - int i = 0; - - SAFEARRAYBOUND *psab = NULL; - SAFEARRAY *psa = NULL; - long *pub, *pid; - - Check_Type(val, T_ARRAY); - - val1 = val; - while(TYPE(val1) == T_ARRAY) { - val1 = rb_ary_entry(val1, 0); - dim += 1; - } - psab = ALLOC_N(SAFEARRAYBOUND, dim); - pub = ALLOC_N(long, dim); - pid = ALLOC_N(long, dim); - - if(!psab || !pub || !pid) { - if(pub) free(pub); - if(psab) free(psab); - if(pid) free(pid); - rb_raise(rb_eRuntimeError, "memory allocation error"); - } - val1 = val; - i = 0; - while(TYPE(val1) == T_ARRAY) { - psab[i].cElements = RARRAY_LEN(val1); - psab[i].lLbound = 0; - pub[i] = psab[i].cElements; - pid[i] = 0; - i ++; - val1 = rb_ary_entry(val1, 0); - } - /* Create and fill VARIANT array */ - psa = SafeArrayCreate(vtype & VT_TYPEMASK, dim, psab); - if (psa == NULL) - hr = E_OUTOFMEMORY; - else - hr = SafeArrayLock(psa); + hr = ole_val_ary2variant_ary(val, &(pvar->realvar), vtype); if (SUCCEEDED(hr)) { - ole_set_safe_array_with_type(dim-1, psa, pid, pub, val, dim-1, vtype& VT_TYPEMASK); - hr = SafeArrayUnlock(psa); - } - if(pub) free(pub); - if(psab) free(psab); - if(pid) free(pid); - - if (SUCCEEDED(hr)) { - V_VT(&(pvar->realvar)) = vtype; - V_ARRAY(&(pvar->realvar)) = psa; hr = VariantCopy(&(pvar->var), &(pvar->realvar)); } - else { - if (psa != NULL) - SafeArrayDestroy(psa); - } } else { if (val == Qnil) { V_VT(&(pvar->var)) = vtype; @@ -1495,6 +1463,32 @@ 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) { + long i; + VALUE obj = Qnil; + VALUE pobj = Qnil; + long *ids = ALLOC_N(long, dim); + if (!ids) { + rb_raise(rb_eRuntimeError, "memory allocation error"); + } + for(i = 0; i < dim; i++) { + ids[i] = pID[i] - pLB[i]; + } + obj = myary; + pobj = myary; + for(i = 0; i < dim-1; i++) { + obj = rb_ary_entry(pobj, ids[i]); + if (obj == Qnil) { + rb_ary_store(pobj, ids[i], rb_ary_new()); + } + obj = rb_ary_entry(pobj, ids[i]); + pobj = obj; + } + rb_ary_store(obj, ids[dim-1], val); + if (ids) free(ids); +} + static VALUE ole_variant2val(VARIANT *pvar) { @@ -1506,61 +1500,50 @@ ole_variant2val(VARIANT *pvar) if(V_ISARRAY(pvar)) { SAFEARRAY *psa = V_ISBYREF(pvar) ? *V_ARRAYREF(pvar) : V_ARRAY(pvar); long i; - long *pID, *pLB, *pUB; + long *pid, *plb, *pub; VARIANT variant; VALUE val; - VALUE val2 = Qnil; - int dim = SafeArrayGetDim(psa); VariantInit(&variant); V_VT(&variant) = (V_VT(pvar) & ~VT_ARRAY) | VT_BYREF; - pID = ALLOC_N(long, dim); - pLB = ALLOC_N(long, dim); - pUB = ALLOC_N(long, dim); + pid = ALLOC_N(long, dim); + plb = ALLOC_N(long, dim); + pub = ALLOC_N(long, dim); - if(!pID || !pLB || !pUB) { - if(pID) free(pID); - if(pLB) free(pLB); - if(pUB) free(pUB); + if(!pid || !plb || !pub) { + if(pid) free(pid); + if(plb) free(plb); + if(pub) free(pub); rb_raise(rb_eRuntimeError, "memory allocation error"); } - obj = Qnil; - for(i = 0; i < dim; ++i) { - SafeArrayGetLBound(psa, i+1, &pLB[i]); - SafeArrayGetLBound(psa, i+1, &pID[i]); - SafeArrayGetUBound(psa, i+1, &pUB[i]); + SafeArrayGetLBound(psa, i+1, &plb[i]); + SafeArrayGetLBound(psa, i+1, &pid[i]); + SafeArrayGetUBound(psa, i+1, &pub[i]); } hr = SafeArrayLock(psa); if (SUCCEEDED(hr)) { - val2 = rb_ary_new(); + obj = rb_ary_new(); while (i >= 0) { - hr = SafeArrayPtrOfIndex(psa, pID, &V_BYREF(&variant)); + hr = SafeArrayPtrOfIndex(psa, pid, &V_BYREF(&variant)); if (FAILED(hr)) break; val = ole_variant2val(&variant); - rb_ary_push(val2, val); + ary_store_dim(obj, pid, plb, dim, val); for (i = dim-1 ; i >= 0 ; --i) { - if (++pID[i] <= pUB[i]) + if (++pid[i] <= pub[i]) break; - - pID[i] = pLB[i]; - if (i > 0) { - if (obj == Qnil) - obj = rb_ary_new(); - rb_ary_push(obj, val2); - val2 = rb_ary_new(); - } + pid[i] = plb[i]; } } SafeArrayUnlock(psa); } - if(pID) free(pID); - if(pLB) free(pLB); - if(pUB) free(pUB); - return (obj == Qnil) ? val2 : obj; + if(pid) free(pid); + if(plb) free(plb); + if(pub) free(pub); + return obj; } switch(V_VT(pvar) & ~VT_BYREF){ case VT_EMPTY: @@ -1698,12 +1681,14 @@ ole_variant2val(VARIANT *pvar) return obj; } -static LONG reg_open_key(HKEY hkey, const char *name, HKEY *phkey) +static LONG +reg_open_key(HKEY hkey, const char *name, HKEY *phkey) { return RegOpenKeyEx(hkey, name, 0, KEY_READ, phkey); } -static LONG reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey) +static LONG +reg_open_vkey(HKEY hkey, VALUE key, HKEY *phkey) { return reg_open_key(hkey, StringValuePtr(key), phkey); } @@ -2363,7 +2348,8 @@ installed_code_page_proc(LPTSTR str) { } static BOOL -code_page_installed(UINT cp) { +code_page_installed(UINT cp) +{ g_cp_installed = FALSE; g_cp_to_check = cp; EnumSystemCodePages(installed_code_page_proc, CP_INSTALLED); diff --git a/test/win32ole/test_win32ole.rb b/test/win32ole/test_win32ole.rb index bcfd63f4ea..d7a9b368a1 100644 --- a/test/win32ole/test_win32ole.rb +++ b/test/win32ole/test_win32ole.rb @@ -119,6 +119,19 @@ if defined?(WIN32OLE) assert_equal("BAR", @dict1["foo"]) end + def test_invoke_with_array + @dict1.add("ary1", [1,2,3]) + assert_equal([1,2,3], @dict1["ary1"]) + + @dict1.add("ary2", [[1,2,"a"], [3,4,"b"]]) + assert_equal([[1,2,"a"], [3,4,"b"]], @dict1["ary2"]) + + @dict1.add("ary3", [[[1]]]) + assert_equal([[[1]]], @dict1["ary3"]) + + @dict1.add("ary4", [[[1], [2], [3]], [[4], [5], [6]]]) + assert_equal([[[1],[2], [3]], [[4], [5], [6]]], @dict1["ary4"]) + end end class TestWin32OLE < Test::Unit::TestCase @@ -146,9 +159,10 @@ if defined?(WIN32OLE) assert_match(/unknown OLE server: `\{000\}'/, exc.message) end - # test_s_connect was moved to test_word.rb - # def test_s_connect - # end + def test_s_connect + obj = WIN32OLE.connect("winmgmts:") + assert_instance_of(WIN32OLE, obj) + end def test_invoke_accept_symbol_hash_key fso = WIN32OLE.new('Scripting.FileSystemObject') diff --git a/test/win32ole/test_win32ole_variant.rb b/test/win32ole/test_win32ole_variant.rb index b00052e534..418ce57751 100644 --- a/test/win32ole/test_win32ole_variant.rb +++ b/test/win32ole/test_win32ole_variant.rb @@ -93,6 +93,25 @@ if defined?(WIN32OLE_VARIANT) def test_create_vt_array 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) + end + + def test_create_vt_array2 + obj = WIN32OLE_VARIANT.new([1.2, "a"], WIN32OLE::VARIANT::VT_ARRAY) + assert_equal([1.2, "a"], obj.value) + assert_equal(WIN32OLE::VARIANT::VT_ARRAY|WIN32OLE::VARIANT::VT_VARIANT, obj.vartype) + + obj = WIN32OLE_VARIANT.new([1.2, "a"]) + assert_equal([1.2, "a"], obj.value) + 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) end def test_create_vt_array_exc