diff --git a/harbour/ChangeLog b/harbour/ChangeLog index c0f24d0e4c..e68706f7c2 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,36 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-10-27 10:34 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/hbapi.h + * harbour/src/vm/garbage.c + * added emulation for hb_gcAlloc() function covered by HB_LEGACY_LEVEL2 + It will be removed in the future but now it gives a time for 3-rd party + code developers to updated existing code and switch to hb_gcAllocate() + + * harbour/contrib/hbwin/hbwinole.h + * harbour/contrib/hbwin/olecore.c + + added hb_oleItemGetCallBack() and hb_oleItemSetCallBack() + functions and support for user defined items bound with + OLE GC pointer item + + * harbour/contrib/hbwin/axcore.c + * bound callback function with OLE item so it will be automatically + released with OLE object + + * harbour/contrib/hbwin/tests/testax.prg + ! destroy window + * enabled destructor + + So far MS-Windows users haven't defined expected behavior for OLE code + so I took my own arbitrary decision and bound callback with OLE GC item. + When last copy of this item is cleared then callback is unregistered + and freed. It means that it can happen before AX window is closed. + If you prefer different behavior then please clearly define what + you need and I can try to change existing code. + Now testax.prg should cleanly execute without any GPF traps and + resource leaks. + 2009-10-27 09:33 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * contrib/hbwin/tests/testdll.prg * Minor. diff --git a/harbour/contrib/hbwin/axcore.c b/harbour/contrib/hbwin/axcore.c index 6cc76a4c4b..e4310a6e88 100644 --- a/harbour/contrib/hbwin/axcore.c +++ b/harbour/contrib/hbwin/axcore.c @@ -437,6 +437,8 @@ HB_FUNC( __AXREGISTERHANDLER ) /* ( pDisp, bHandler [, cID] ) --> pSink */ pSink->lpVtbl = ( IDispatchVtbl * ) &ISink_Vtbl; pSink->count = 0; pSink->pItemHandler = hb_itemNew( pItemBlock ); + hb_oleItemSetCallBack( hb_param( 1, HB_IT_POINTER ), + &pSink->pItemHandler ); pSink->rriid = rriid; lOleError = HB_VTBL( pCP )->Advise( HB_THIS_( pCP ) ( IUnknown* ) pSink, &dwCookie ); pSink->pConnectionPoint = pCP; diff --git a/harbour/contrib/hbwin/hbwinole.h b/harbour/contrib/hbwin/hbwinole.h index dcf867ad65..b7992f6556 100644 --- a/harbour/contrib/hbwin/hbwinole.h +++ b/harbour/contrib/hbwin/hbwinole.h @@ -110,6 +110,8 @@ HB_EXPORT void hb_oleVariantUpdate( VARIANT* pVariant, PHB_ITEM pItem ); HB_EXPORT IDispatch* hb_oleParam( int iParam ); HB_EXPORT IDispatch* hb_oleItemGet( PHB_ITEM pItem ); HB_EXPORT PHB_ITEM hb_oleItemPut( PHB_ITEM pItem, IDispatch* pDisp ); +HB_EXPORT PHB_ITEM hb_oleItemGetCallBack( PHB_ITEM pItem ); +HB_EXPORT void hb_oleItemSetCallBack( PHB_ITEM pItem, PHB_ITEM* pCallBack ); /* activex control */ HB_EXPORT BOOL hb_oleAxInit( void ); diff --git a/harbour/contrib/hbwin/olecore.c b/harbour/contrib/hbwin/olecore.c index fc572d93b0..fb45feed5c 100644 --- a/harbour/contrib/hbwin/olecore.c +++ b/harbour/contrib/hbwin/olecore.c @@ -74,6 +74,12 @@ static PHB_DYNS s_pDyns_hb_oleauto; static PHB_DYNS s_pDyns_hObjAccess; static PHB_DYNS s_pDyns_hObjAssign; +typedef struct +{ + IDispatch* pDisp; + PHB_ITEM* pCallBack; +} HB_OLE; + typedef struct { HRESULT lOleError; @@ -118,30 +124,47 @@ static void hb_olecore_init( void* cargo ) static HB_GARBAGE_FUNC( hb_ole_destructor ) { - IDispatch** ppDisp = ( IDispatch** ) Cargo; + HB_OLE * pOle = ( HB_OLE * ) Cargo; + IDispatch * pDisp = pOle->pDisp; - if( *ppDisp ) + if( pDisp ) { - HB_VTBL( *ppDisp )->Release( HB_THIS( *ppDisp ) ); - *ppDisp = NULL; + pOle->pDisp = NULL; + if( pOle->pCallBack && *pOle->pCallBack ) + { + PHB_ITEM pCallBack = *pOle->pCallBack; + *pOle->pCallBack = NULL; + pOle->pCallBack = NULL; + hb_itemRelease( pCallBack ); + } + HB_VTBL( pDisp )->Release( HB_THIS( pDisp ) ); } } +static HB_GARBAGE_FUNC( hb_ole_mark ) +{ + HB_OLE * pOle = ( HB_OLE * ) Cargo; + + if( pOle->pCallBack && *pOle->pCallBack ) + hb_gcMark( *pOle->pCallBack ); +} + static const HB_GC_FUNCS s_gcOleFuncs = { hb_ole_destructor, - hb_gcDummyMark + hb_ole_mark }; static HB_GARBAGE_FUNC( hb_oleenum_destructor ) { - IEnumVARIANT** ppEnum = ( IEnumVARIANT** ) Cargo; + IEnumVARIANT** ppEnum = ( IEnumVARIANT** ) Cargo; + IEnumVARIANT* pEnum = *ppEnum; - if( *ppEnum ) + if( pEnum ) { - HB_VTBL( *ppEnum )->Release( HB_THIS( *ppEnum ) ); *ppEnum = NULL; + HB_VTBL( pEnum )->Release( HB_THIS( pEnum ) ); } } @@ -154,10 +177,10 @@ static const HB_GC_FUNCS s_gcOleenumFuncs = IDispatch* hb_oleParam( int iParam ) { - IDispatch** ppDisp = ( IDispatch** ) hb_parptrGC( &s_gcOleFuncs, iParam ); + HB_OLE * pOle = ( HB_OLE * ) hb_parptrGC( &s_gcOleFuncs, iParam ); - if( ppDisp && *ppDisp ) - return *ppDisp; + if( pOle && pOle->pDisp ) + return pOle->pDisp; hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); return NULL; @@ -166,18 +189,48 @@ IDispatch* hb_oleParam( int iParam ) IDispatch* hb_oleItemGet( PHB_ITEM pItem ) { - return ( IDispatch* ) hb_itemGetPtrGC( pItem, &s_gcOleFuncs ); + HB_OLE * pOle = ( HB_OLE * ) hb_itemGetPtrGC( pItem, &s_gcOleFuncs ); + return pOle ? pOle->pDisp : NULL; } PHB_ITEM hb_oleItemPut( PHB_ITEM pItem, IDispatch* pDisp ) { - IDispatch** ppDisp; + HB_OLE * pOle = ( HB_OLE * ) hb_gcAllocate( sizeof( HB_OLE ), &s_gcOleFuncs ); - ppDisp = ( IDispatch** ) hb_gcAllocate( sizeof( IDispatch* ), &s_gcOleFuncs ); - *ppDisp = pDisp; + pOle->pDisp = pDisp; + pOle->pCallBack = NULL; - return hb_itemPutPtrGC( pItem, ppDisp ); + return hb_itemPutPtrGC( pItem, pOle ); +} + + +PHB_ITEM hb_oleItemGetCallBack( PHB_ITEM pItem ) +{ + HB_OLE * pOle = ( HB_OLE * ) hb_itemGetPtrGC( pItem, &s_gcOleFuncs ); + return pOle && pOle->pCallBack ? *pOle->pCallBack : NULL; +} + + +void hb_oleItemSetCallBack( PHB_ITEM pItem, PHB_ITEM* pCallBack ) +{ + HB_OLE * pOle = ( HB_OLE * ) hb_itemGetPtrGC( pItem, &s_gcOleFuncs ); + + if( pOle ) + { + if( pOle->pCallBack && *pOle->pCallBack ) + { + PHB_ITEM pCallBack = *pOle->pCallBack; + *pOle->pCallBack = NULL; + pOle->pCallBack = NULL; + hb_itemRelease( pCallBack ); + } + if( pCallBack ) + { + pOle->pCallBack = pCallBack; + hb_gcUnlock( *pCallBack ); + } + } } diff --git a/harbour/contrib/hbwin/tests/testax.prg b/harbour/contrib/hbwin/tests/testax.prg index 81b9d92d77..9192f78995 100644 --- a/harbour/contrib/hbwin/tests/testax.prg +++ b/harbour/contrib/hbwin/tests/testax.prg @@ -17,23 +17,22 @@ PROCEDURE Main() WAIT "Make sure we are 'Active Window'" oMSCAL := HActiveX():Init( WAPI_GetActiveWindow(), "MSCAL.Calendar", 0, 0, 300, 300 ) WAIT "Press any key to exit" - oMSCAL:Close() RETURN CLASS HActiveX DATA oOLE + DATA hWnd METHOD Init METHOD Event ERROR HANDLER OnError -// DESTRUCTOR Close - METHOD Close + DESTRUCTOR Close ENDCLASS METHOD Init( hWnd, cProgId, nTop, nLeft, nWidth, nHeight, cID ) CLASS HActiveX LOCAL nStyle := WS_CHILD + WS_VISIBLE + WS_CLIPCHILDREN win_AxInit() - hWnd := WAPI_CreateWindowEX( 0, "AtlAxWin", cProgId, nStyle, nLeft, nTop, nWidth, nHeight, hWnd, 0 ) - ::oOLE := WIN_AxGetControl( hWnd, { | event, ... | ::Event( event, ... ) }, cID ) + ::hWnd := WAPI_CreateWindowEX( 0, "AtlAxWin", cProgId, nStyle, nLeft, nTop, nWidth, nHeight, hWnd, 0 ) + ::oOLE := WIN_AxGetControl( ::hWnd, { | event, ... | ::Event( event, ... ) }, cID ) RETURN self PROCEDURE Event( ... ) CLASS HActiveX @@ -48,6 +47,8 @@ METHOD OnError() CLASS HActiveX METHOD Close() CLASS HActiveX wapi_OutputDebugString( "Close" ) + WAPI_DestroyWindow( ::hWnd ) + ::hWnd := NIL ::oOLE := NIL wapi_OutputDebugString( "After Close" ) RETURN NIL diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index d3d9837a88..40f4350a93 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -587,6 +587,10 @@ extern HB_EXPORT void hb_gcDummyMark( void * Cargo ); /* dummy GC mark func extern PHB_ITEM hb_gcGripGet( HB_ITEM_PTR pItem ); extern void hb_gcGripDrop( HB_ITEM_PTR pItem ); +#ifdef HB_LEGACY_LEVEL2 +extern HB_EXPORT void * hb_gcAlloc( ULONG ulSize, HB_GARBAGE_FUNC_PTR pCleanupFunc ); +#endif + #ifdef _HB_API_INTERNAL_ extern const HB_GC_FUNCS * hb_gcFuncs( void *pBlock ); /* return cleanup function pointer */ extern void hb_gcAttach( void * pBlock ); diff --git a/harbour/src/vm/garbage.c b/harbour/src/vm/garbage.c index ede2289b19..4d7c4d1bb5 100644 --- a/harbour/src/vm/garbage.c +++ b/harbour/src/vm/garbage.c @@ -748,6 +748,63 @@ void hb_gcCollectAll( BOOL fForce ) } } +#ifdef HB_LEGACY_LEVEL2 +typedef struct _HB_GC_ALLOC_FUNCS +{ + HB_GC_FUNCS funcs; + struct _HB_GC_ALLOC_FUNCS * pNext; +} HB_GC_ALLOC_FUNCS; + +static HB_GC_ALLOC_FUNCS * s_pAllocFuncs = NULL; + +static void hb_gcAllocExit( void ) +{ + while( s_pAllocFuncs ) + { + HB_GC_ALLOC_FUNCS * pFuncs = s_pAllocFuncs; + s_pAllocFuncs = pFuncs->pNext; + hb_xfree( pFuncs ); + } +} + +void * hb_gcAlloc( ULONG ulSize, HB_GARBAGE_FUNC_PTR pCleanupFunc ) +{ + HB_GC_ALLOC_FUNCS * pFuncs = s_pAllocFuncs, ** pFuncsPtr; + + while( pFuncs ) + { + if( pFuncs->funcs.clear == pCleanupFunc ) + break; + pFuncs = pFuncs->pNext; + } + + if( !pFuncs ) + { + pFuncs = ( HB_GC_ALLOC_FUNCS * ) hb_xgrab( sizeof( HB_GC_ALLOC_FUNCS ) ); + pFuncs->funcs.clear = pCleanupFunc; + pFuncs->funcs.mark = hb_gcDummyMark; + pFuncs->pNext = NULL; + HB_GC_LOCK + pFuncsPtr = &s_pAllocFuncs; + while( *pFuncsPtr ) + { + if( ( *pFuncsPtr )->funcs.clear == pCleanupFunc ) + { + hb_xfree( pFuncs ); + pFuncs = *pFuncsPtr; + break; + } + pFuncsPtr = &( *pFuncsPtr )->pNext; + } + if( *pFuncsPtr == NULL ) + *pFuncsPtr = pFuncs; + HB_GC_UNLOCK + } + + return hb_gcAllocate( ulSize, &pFuncs->funcs ); +} +#endif + /* MTNOTE: It's executed at the end of HVM cleanup code just before * application exit when other threads are destroyed, so it * does not need additional protection code for MT mode, [druzus] @@ -783,6 +840,10 @@ void hb_gcReleaseAll( void ) } s_bCollecting = FALSE; + +#ifdef HB_LEGACY_LEVEL2 + hb_gcAllocExit(); +#endif } /* service a single garbage collector step