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:
Przemyslaw Czerpak
2009-10-27 09:34:35 +00:00
parent 6e305f8e6e
commit abb4092d09
7 changed files with 174 additions and 21 deletions

View File

@@ -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.

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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 );
}
}
}

View File

@@ -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

View File

@@ -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 );

View File

@@ -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