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.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user