ext/win32ole/win32ole.c | 43 +++++++++++++++++++++++++---------------- ext/win32ole/win32ole.h | 1 + ext/win32ole/win32ole_record.c | 28 +++++++++++---------------- ext/win32ole/win32ole_variant.c | 4 ++-- 4 files changed, 40 insertions(+), 36 deletions(-) diff --git a/ext/win32ole/win32ole.c b/ext/win32ole/win32ole.c index 582ff32..11e4a3c 100644 --- a/ext/win32ole/win32ole.c +++ b/ext/win32ole/win32ole.c @@ -2509,7 +2509,7 @@ hash2named_arg(VALUE key, VALUE val, VALUE pop) } /* clear dispatch parameters */ for(i = 0; i < index; i++ ) { - VariantClear(&(pOp->dp.rgvarg[i])); + ole_variant_clear(&(pOp->dp.rgvarg[i])); } /* raise an exception */ rb_raise(rb_eTypeError, "wrong argument type (expected String or Symbol)"); @@ -2528,6 +2528,19 @@ hash2named_arg(VALUE key, VALUE val, VALUE pop) return ST_CONTINUE; } +void +ole_variant_clear(VARIANT *pvar) +{ + if (V_VT(pvar) != VT_RECORD) { + VariantClear(pvar); + } else { + IRecordInfo *pri = V_RECORDINFO(pvar); + pri->lpVtbl->RecordDestroy(pri, V_RECORD(pvar)); + pri->lpVtbl->Release(pri); + V_VT(pvar) = VT_EMPTY; + } +} + static VALUE set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end) { @@ -2537,9 +2550,7 @@ set_argv(VARIANTARG* realargs, unsigned int beg, unsigned int end) rb_ary_clear(argv); while (end-- > beg) { rb_ary_push(argv, ole_variant2val(&realargs[end])); - if (V_VT(&realargs[end]) != VT_RECORD) { - VariantClear(&realargs[end]); - } + ole_variant_clear(&realargs[end]); } return argv; } @@ -2635,7 +2646,7 @@ ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket) if(FAILED(hr)) { /* clear dispatch parameters */ for(i = 0; i < op.dp.cArgs; i++ ) { - VariantClear(&op.dp.rgvarg[i]); + ole_variant_clear(&op.dp.rgvarg[i]); } ole_raise(hr, eWIN32OLERuntimeError, "failed to get named argument info: `%s'", @@ -2719,7 +2730,7 @@ ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket) for(i = cNamedArgs; i < op.dp.cArgs; i++) { n = op.dp.cArgs - i + cNamedArgs - 1; if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) { - VariantClear(&op.dp.rgvarg[n]); + ole_variant_clear(&op.dp.rgvarg[n]); } } } @@ -2743,9 +2754,7 @@ ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket) &excepinfo, &argErr); for(i = cNamedArgs; i < op.dp.cArgs; i++) { n = op.dp.cArgs - i + cNamedArgs - 1; - if (V_VT(&op.dp.rgvarg[n]) != VT_RECORD) { - VariantClear(&op.dp.rgvarg[n]); - } + ole_variant_clear(&op.dp.rgvarg[n]); } } } @@ -2767,7 +2776,7 @@ ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket) } else { for(i = 0; i < op.dp.cArgs; i++) { - VariantClear(&op.dp.rgvarg[i]); + ole_variant_clear(&op.dp.rgvarg[i]); } } @@ -2778,7 +2787,7 @@ ole_invoke(int argc, VALUE *argv, VALUE self, USHORT wFlags, BOOL is_bracket) StringValuePtr(v)); } obj = ole_variant2val(&result); - VariantClear(&result); + ole_variant_clear(&result); return obj; } @@ -2987,7 +2996,7 @@ ole_invoke2(VALUE self, VALUE dispid, VALUE args, VALUE types, USHORT dispkind) } obj = ole_variant2val(&result); - VariantClear(&result); + ole_variant_clear(&result); return obj; } @@ -3156,7 +3165,7 @@ ole_propertyput(VALUE self, VALUE property, VALUE value) NULL, &excepinfo, &argErr); for(index = 0; index < dispParams.cArgs; ++index) { - VariantClear(&propertyValue[index]); + ole_variant_clear(&propertyValue[index]); } if (FAILED(hr)) { v = ole_excepinfo2msg(&excepinfo); @@ -3195,7 +3204,7 @@ ole_each_sub(VALUE pEnumV) VariantInit(&variant); while(pEnum->lpVtbl->Next(pEnum, 1, &variant, NULL) == S_OK) { obj = ole_variant2val(&variant); - VariantClear(&variant); + ole_variant_clear(&variant); VariantInit(&variant); rb_yield(obj); } @@ -3256,7 +3265,7 @@ fole_each(VALUE self) &excepinfo, &argErr); if (FAILED(hr)) { - VariantClear(&result); + ole_variant_clear(&result); ole_raise(hr, eWIN32OLERuntimeError, "failed to get IEnum Interface"); } @@ -3272,11 +3281,11 @@ fole_each(VALUE self) pEnum = p; } if (FAILED(hr) || !pEnum) { - VariantClear(&result); + ole_variant_clear(&result); ole_raise(hr, rb_eRuntimeError, "failed to get IEnum Interface"); } - VariantClear(&result); + ole_variant_clear(&result); rb_ensure(ole_each_sub, (VALUE)pEnum, ole_ienum_free, (VALUE)pEnum); return Qnil; } diff --git a/ext/win32ole/win32ole.h b/ext/win32ole/win32ole.h index d61f5e2..ecf0b22 100644 --- a/ext/win32ole/win32ole.h +++ b/ext/win32ole/win32ole.h @@ -137,6 +137,7 @@ void ole_val2variant(VALUE val, VARIANT *var); void ole_val2variant2(VALUE val, VARIANT *var); void ole_val2variant_ex(VALUE val, VARIANT *var, VARTYPE vt); VALUE ole_variant2val(VARIANT *pvar); +void ole_variant_clear(VARIANT *pvar); HRESULT ole_val_ary2variant_ary(VALUE val, VARIANT *var, VARTYPE vt); VOID *val2variant_ptr(VALUE val, VARIANT *var, VARTYPE vt); HRESULT typelib_from_val(VALUE obj, ITypeLib **pTypeLib); diff --git a/ext/win32ole/win32ole_record.c b/ext/win32ole/win32ole_record.c index 28d6238..69fb213 100644 --- a/ext/win32ole/win32ole_record.c +++ b/ext/win32ole/win32ole_record.c @@ -2,7 +2,6 @@ struct olerecorddata { IRecordInfo *pri; - void *pdata; }; static HRESULT recordinfo_from_itypelib(ITypeLib *pTypeLib, VALUE name, IRecordInfo **ppri); @@ -59,7 +58,7 @@ recordinfo_from_itypelib(ITypeLib *pTypeLib, VALUE name, IRecordInfo **ppri) } static int -hash2olerec(VALUE key, VALUE val, VALUE rec) +hash2olerec(VALUE key, VALUE val, VALUE ary) { VARIANT var; OLECHAR *pbuf; @@ -68,14 +67,14 @@ hash2olerec(VALUE key, VALUE val, VALUE rec) HRESULT hr; if (val != Qnil) { - TypedData_Get_Struct(rec, struct olerecorddata, &olerecord_datatype, prec); + TypedData_Get_Struct(RARRAY_PTR(ary)[0], struct olerecorddata, &olerecord_datatype, prec); pri = prec->pri; VariantInit(&var); ole_val2variant(val, &var); pbuf = ole_vstr2wc(key); - hr = pri->lpVtbl->PutField(pri, INVOKE_PROPERTYPUT, prec->pdata, pbuf, &var); + hr = pri->lpVtbl->PutField(pri, INVOKE_PROPERTYPUT, (void *)NUM2SIZET(RARRAY_PTR(ary)[1]), pbuf, &var); SysFreeString(pbuf); - VariantClear(&var); + ole_variant_clear(&var); if (FAILED(hr)) { ole_raise(hr, eWIN32OLERuntimeError, "failed to putfield of `%s`", StringValuePtr(key)); } @@ -91,6 +90,7 @@ ole_rec2variant(VALUE rec, VARIANT *var) IRecordInfo *pri; HRESULT hr; VALUE fields; + void *pdata; TypedData_Get_Struct(rec, struct olerecorddata, &olerecord_datatype, prec); pri = prec->pri; if (pri) { @@ -98,21 +98,19 @@ ole_rec2variant(VALUE rec, VARIANT *var) if (FAILED(hr)) { ole_raise(hr, eWIN32OLERuntimeError, "failed to get size for allocation of VT_RECORD object"); } - if (prec->pdata) { - free(prec->pdata); - } - prec->pdata = ALLOC_N(char, size); - if (!prec->pdata) { + pdata = pri->lpVtbl->RecordCreate(pri); + if (!pdata) { rb_raise(rb_eRuntimeError, "failed to memory allocation of %lu bytes", (unsigned long)size); } - hr = pri->lpVtbl->RecordInit(pri, prec->pdata); + hr = pri->lpVtbl->RecordInit(pri, pdata); if (FAILED(hr)) { ole_raise(hr, eWIN32OLERuntimeError, "failed to initialize VT_RECORD object"); } fields = folerecord_to_h(rec); - rb_hash_foreach(fields, hash2olerec, rec); + rb_hash_foreach(fields, hash2olerec, rb_ary_new3(2, rec, SIZET2NUM((char *)pdata - (char *)NULL))); + pri->lpVtbl->AddRef(pri); V_RECORDINFO(var) = pri; - V_RECORD(var) = prec->pdata; + V_RECORD(var) = pdata; V_VT(var) = VT_RECORD; } else { rb_raise(eWIN32OLERuntimeError, "failed to retrieve IRecordInfo interface"); @@ -216,9 +214,6 @@ static void olerecord_free(void *ptr) { struct olerecorddata *pvar = ptr; OLE_FREE(pvar->pri); - if (pvar->pdata) { - free(pvar->pdata); - } free(pvar); } @@ -247,7 +242,6 @@ folerecord_s_allocate(VALUE klass) { struct olerecorddata *pvar; obj = TypedData_Make_Struct(klass, struct olerecorddata, &olerecord_datatype, pvar); pvar->pri = NULL; - pvar->pdata = NULL; return obj; } diff --git a/ext/win32ole/win32ole_variant.c b/ext/win32ole/win32ole_variant.c index 1731ab7..63a8a94 100644 --- a/ext/win32ole/win32ole_variant.c +++ b/ext/win32ole/win32ole_variant.c @@ -33,8 +33,8 @@ static void olevariant_free(void *ptr) { struct olevariantdata *pvar = ptr; - VariantClear(&(pvar->realvar)); - VariantClear(&(pvar->var)); + ole_variant_clear(&(pvar->realvar)); + ole_variant_clear(&(pvar->var)); free(pvar); }