diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c index 00dfc50e154..6bacaa01cb3 100644 --- a/dlls/vbscript/compile.c +++ b/dlls/vbscript/compile.c @@ -894,6 +894,7 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) HRESULT hres; static const WCHAR class_initializeW[] = {'c','l','a','s','s','_','i','n','i','t','i','a','l','i','z','e',0}; + static const WCHAR class_terminateW[] = {'c','l','a','s','s','_','t','e','r','m','i','n','a','t','e',0}; if(lookup_dim_decls(ctx, class_decl->name) || lookup_funcs_name(ctx, class_decl->name) || lookup_class_name(ctx, class_decl->name)) { @@ -912,6 +913,7 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) class_desc->func_cnt = 1; /* always allocate slot for default getter */ class_desc->prop_cnt = 0; class_desc->class_initialize_id = 0; + class_desc->class_terminate_id = 0; for(func_decl = class_decl->funcs; func_decl; func_decl = func_decl->next) { for(func_prop_decl = func_decl; func_prop_decl; func_prop_decl = func_prop_decl->next_prop_func) { @@ -942,6 +944,13 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl) } class_desc->class_initialize_id = i; + }else if(!strcmpiW(class_terminateW, func_decl->name)) { + if(func_decl->type != FUNC_SUB) { + FIXME("class terminator is not sub\n"); + return E_FAIL; + } + + class_desc->class_terminate_id = i; } hres = create_class_funcprop(ctx, func_decl, class_desc->funcs + (func_prop_decl ? 0 : i)); diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs index 46317b9f704..961eea27d53 100644 --- a/dlls/vbscript/tests/lang.vbs +++ b/dlls/vbscript/tests/lang.vbs @@ -491,4 +491,23 @@ Call ok(obj.getPrivateProp() = true, "obj.getPrivateProp() = " & obj.getPrivateP x = (New testclass).publicProp +Class TermTest + Public Sub Class_Terminate() + funcCalled = "terminate" + End Sub +End Class + +Set obj = New TermTest +funcCalled = "" +Set obj = Nothing +Call ok(funcCalled = "terminate", "funcCalled = " & funcCalled) + +Set obj = New TermTest +funcCalled = "" +Call obj.Class_Terminate +Call ok(funcCalled = "terminate", "funcCalled = " & funcCalled) +funcCalled = "" +Set obj = Nothing +Call ok(funcCalled = "terminate", "funcCalled = " & funcCalled) + reportSuccess() diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c index e1386bee26c..c948f134222 100644 --- a/dlls/vbscript/vbdisp.c +++ b/dlls/vbscript/vbdisp.c @@ -123,6 +123,23 @@ static HRESULT invoke_variant_prop(vbdisp_t *This, VARIANT *v, WORD flags, DISPP return hres; } +static void run_terminator(vbdisp_t *This) +{ + if(This->terminator_ran) + return; + This->terminator_ran = TRUE; + + if(This->desc->class_terminate_id) { + DISPPARAMS dp = {0}; + + This->ref++; + exec_script(This->desc->ctx, This->desc->funcs[This->desc->class_terminate_id].entries[VBDISP_CALLGET], + (IDispatch*)&This->IDispatchEx_iface, &dp, NULL); + This->ref--; + } + +} + static void clean_props(vbdisp_t *This) { unsigned i; @@ -172,8 +189,12 @@ static ULONG WINAPI DispatchEx_AddRef(IDispatchEx *iface) static ULONG WINAPI DispatchEx_Release(IDispatchEx *iface) { vbdisp_t *This = impl_from_IDispatchEx(iface); - LONG ref = InterlockedIncrement(&This->ref); + LONG ref = InterlockedDecrement(&This->ref); + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) + run_terminator(This); if(!ref) { clean_props(This); heap_free(This); diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h index 270e223a091..5dd434ad924 100644 --- a/dlls/vbscript/vbscript.h +++ b/dlls/vbscript/vbscript.h @@ -77,6 +77,7 @@ typedef struct _class_desc_t { const WCHAR *name; script_ctx_t *ctx; unsigned class_initialize_id; + unsigned class_terminate_id; unsigned func_cnt; vbdisp_funcprop_desc_t *funcs; unsigned prop_cnt; @@ -88,6 +89,7 @@ typedef struct { IDispatchEx IDispatchEx_iface; LONG ref; + BOOL terminator_ran; const class_desc_t *desc; VARIANT props[1];