Page 1 of 1

OleDefaultArg() : Harbour Replacement?

PostPosted: Mon Jun 17, 2013 1:30 am
by nageswaragunupudi
I am trying to make some of my old ole and ado libraries comaptible with Harbour. In this process I got stuck up with some issues like finding equivalents in Harbour for function OleDefaultArg() and NULL.

In xHarbour, we use OleDefaultArg() where we need to skip arguments in some cases. NIL does not work.

I give an example here for testing:

Code: Select all  Expand view

function JetConnectionCount( oCn )

   local oRs   := oCn:OpenSchema( -1, OleDefaultArg(), "{947bb102-5d43-11d1-bdbf-00c04fb92675}" )
   local nRet  := oRs:RecordCount()
   oRs:Close()

return nRet
 


The above function works perfectly in xHarbour. We can not use "nil" as second parameter.
I am not able to find a substitute in Harbour to use in the place of OleDefaultArg(). I have similar usage in many other functions. This is preveting me from making my libraries fully compatible with Harbour.

Similary I use VTWrapper( 0 ) for NULL (through translates) in some of my functions. This is also not possible with Harbour.

The functions OleDefaultArg() and VTWrapper class are available in win32ole.prg in xHarbour.
For quick reference, I reproduce relevant extracts.
Code: Select all  Expand view

#define VT_ERROR 10
#define DISP_E_PARAMNOTFOUND  (0x80020004)

//----------------------------------------------------------------------------//

function OleDefaultArg()
return VTWrapper( VT_ERROR, DISP_E_PARAMNOTFOUND )

//----------------------------------------------------------------------------//

CLASS VTWrapper

   DATA vt
   DATA Value

   METHOD New( vt, xVal ) CONSTRUCTOR

ENDCLASS

//----------------------------------------------------------------------------//

METHOD New( vt, xVal ) CLASS VTWrapper

   ::vt     := vt
   ::Value  := xVal

return Self

//----------------------------------------------------------------------------//
 


May be the solution is easy, but is eluding me.
I request any one who has found or can find a solution to my problem to help me.

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Mon Jun 17, 2013 6:42 am
by Enrico Maria Giordano
NageswaraRao,

Best option is to ask to the Harbour developers groups. :-)

EMG

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Mon Jun 17, 2013 9:51 pm
by Antonio Linares
Rao,

I have been reviewing why xharbour uses this and its a way to set a OLE param as DISP_E_PARAMNOTFOUND type, but IMO xharbour way is complex without need (of couse I know I may be missing situations that I may not taking into account).

I think a better aproach is to use allow the use of nil (much more intuitive for all of us). See what xharbour does:

Code: Select all  Expand view
           else if( hb_clsIsParent( pItem->item.asArray.value->uiClass, "VTWRAPPER" ) )
            {
               // vt := oVT:vt
               hb_vmPushSymbol( s_pSym_vt->pSymbol );
               hb_vmPush( pItem );
               hb_vmSend( 0 );

               pVariant->n1.n2.vt = ( VARTYPE ) hb_parnl( -1 );

               //value := oVT:value
               hb_vmPushSymbol( s_pSym_Value->pSymbol );
               hb_vmPush( pItem );
               hb_vmSend( 0 );

               switch( pVariant->n1.n2.vt )
               {
                  case VT_UNKNOWN:
                     pVariant->n1.n2.n3.punkVal = ( IUnknown * ) hb_parptr( -1 );
                     break;

                  case ( VT_UNKNOWN | VT_BYREF ):
                     // Hack!!! Using high 4 bytes of the union (llVal)
                     *( ( IUnknown ** ) ( &pVariant->n1.n2.n3.lVal ) + 1 ) = ( IUnknown * ) hb_parptr( -1 );
                     pVariant->n1.n2.n3.ppunkVal                           = ( IUnknown ** ) ( &pVariant->n1.n2.n3.lVal ) + 1;
                     break;

                  case VT_ERROR:
                     pVariant->n1.n2.n3.scode = hb_parni( -1 );
                     break;
 


It just creates a WTWRAPPER object to supply one parameter, that will finally return oVT:value which it is DISP_E_PARAMNOTFOUND and from the used cases we should just need this:

Code: Select all  Expand view
                 case VT_ERROR:
                     pVariant->n1.n2.n3.scode = hb_parni( -1 ); // this value is DISP_E_PARAMNOTFOUND
                     break;


then I have reviewed Harbour implementation and I just realized that they are not considering nil, so we have a chance to implement it as in Harbour static void hb_oleItemToVariantRef() HB_IT_NIL is not used, so this little fix to Harbour would be enough to accept nil:

in Harbour/contrib/hbwin/olecore.c we could do:

Code: Select all  Expand view
     case HB_IT_NIL:
         V_VT( pVariant ) = VT_ERROR;
        pVariant->n1.n2.n3.scode = DISP_E_PARAMNOTFOUND
        break;


I can email you a rebuilt hbwin.lib so you can check if nil is properly accepted, if so, I will comment this possible change to the Harbour devel list

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Mon Jun 17, 2013 9:57 pm
by Enrico Maria Giordano
Antonio,

Can it be done for xHarbour too? If yes, can you explain how?

Many thanks!

EMG

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Mon Jun 17, 2013 10:04 pm
by Antonio Linares
Enrico,

Yes, I think so, as HB_IT_NIL is neither used in xHarbour HB_EXPORT void hb_oleItemToVariant( VARIANT * pVariant, PHB_ITEM pItem ), see:

Code: Select all  Expand view
     case HB_IT_NIL:
         //pVariant->n1.n2.vt = VT_EMPTY;   // its actually commented on xharbour so it does nothing
         break;
 


so we could change it into (same code as in my proposed Harbour's change):

Code: Select all  Expand view
     case HB_IT_NIL:
          pVariant->n1.n2.vt = VT_ERROR;
          pVariant->n1.n2.n3.scode = DISP_E_PARAMNOTFOUND
         break;
 


I have not tested it yet, neither compiled it, I just figured it reviewing the code, so it could be wrong

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Mon Jun 17, 2013 10:11 pm
by Enrico Maria Giordano
Antonio,

I'll test it tomorrow.

Thank you.

EMG

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Tue Jun 18, 2013 12:26 am
by nageswaragunupudi
Mr Antonio

Thank you very much for all the time and attention.

I can email you a rebuilt hbwin.lib so you can check if nil is properly accepted, if so, I will comment this possible change to the Harbour devel list


Please send me. I shall test it. We can also test it with the sample function I posted above.

//pVariant->n1.n2.vt = VT_EMPTY; // its actually commented on xharbour so it does nothing


I saw the commented out code years back. Then I thought that if the author first wrote it and then commented it out, then there must have been some reason behind it.

I think a better approach is to use allow the use of nil (much more intuitive for all of us).


When we are working with some ole functions we need to be clear whether we mean NULL or DEFAULT when we specify a parameter. A clear distinction is necessary because in the first case we are specifying a value "NULL" and in second case we indicate the function to use Default value.

If we convert olecore.c to pass Harbour nil as DEFAULT, then we also need a way to clearly specify NULL where required. I am not sure but I guess "pVariant->n1.n2.vt = VT_EMPTY" converts our NIL as NULL and not as DEFAULT.

Note:
In VB we could write the above function I posted as
oCn.OpenSchema ( -1, , <schemaid> )
Skipping the second parameter with ", ," means use default.
Your suggested implementation will enable us write the our Harbour code also like the VB code.

When we pass arrays as paramter our NIL works well both in Harbour and xHarbour

VBCode: oCn.OpenSchema( adSchemaTables, Array( Empty, Empty, Empty, "TABLE" ) )
(x)Harbour: oCn:OpenSchema( adSchemaTables, { nil, nil, nil, "TABLE" } ) works perfectly, translating our nil as Empty of VB which in turn means NULL.

I thought bringing this to your notice would be useful.

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Tue Jun 18, 2013 10:36 am
by Antonio Linares
Rao,

If we need to supply different VT_... values, then we may consider to implement Class WTWrapper the same way as it is in xharbour.

If we just need one value, then we could use HB_IT_NIL as I suggested, though I have not tested it myself yet

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Tue Jun 18, 2013 10:44 am
by Antonio Linares

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Tue Jun 18, 2013 10:47 am
by nageswaragunupudi
Kindly think it over how best to implement.

We have before us how xHarbour implemented it. Harbour can adopt a different approach, but keeping in mind that we have a need to distinguish between NULL and DEFAULT.

As you originally said above converting Harbour language NIL as something equivalent to OleDefaultArg() seems natural and also easy to use for most ole functions.

In those cases where we explicitly specify NULL, there should be a way to do it.

If you can prepare a modified olecore.c I shall start testing and reporting the problems to you.

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Tue Jun 18, 2013 11:06 am
by nageswaragunupudi
Thanks. Checked with the new lib and here is the feedback.

oCn:OpenSchema ( -1, , <schemaid> )
is working well.

but
oCn:OpenSchema( adSchemaTables, { nil, nil, nil, "TABLE" } )
which was working earlier now fails.

Re: OleDefaultArg() : Harbour Replacement?

PostPosted: Tue Jun 18, 2013 7:20 pm
by Antonio Linares
Rao,

The problem as I commented you by chat is that when a Harbour item is going to be converted to a Variant, a call to VariantClear() is done from Harbour:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms221165(v=vs.85).aspx

and that sets the type VT_EMPTY to all params. If we know use HB_IT_NIL to set VT_ERROR, then we are changing all nils and thats not what we want. nils were working before as they had VT_EMPTY and now have VT_ERROR.

As I commented you we should copy the xharbour implementation, instead of changing Harbour in a way that won't be xharbour compatible.