Some technical help please

Post Reply
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Some technical help please

Post by xProgrammer »

Hi Antonio and other FiveLinuxers

I have been playing around with the xHarbour / FiveLinux interface to C with, amongst other things, an OpenOffice library on my list of things to do.

I know how to write C code, call it from xHarbour code, pass parameters to it and return values from it. I have yet to play with passing a variable number of parameters to my C function but that should be OK .

I can call an xHarbour function (say FUNCTION MyFunction()) from C code with HB_FUN_MYFUNCTION();. What I don't know is how to pass parameters to it from C code and how it can pass a return value back to my C code. Is this possible and how does one do it?

Also to control OpenOffice under Linux I need to use UNO objects, the provided library being C++ code. I gather I can compile and link C++ code using gcc but can I simply make a library of C++ code in this way and call it from my C code? Is parameter passing and return values handled the same?

Thanks
Doug
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Doug,

You can not directly jump from low level to high level. You need to properly set the "virtual machine" "stack frame" in order to jump from low level (C) to high level (PRG).

Here you have a working example:

test.prg

Code: Select all

function Main()

   MsgInfo( Test() )

return nil

function Another( cValue )

   MsgInfo( cValue )

return "returned from high level"

#pragma BEGINDUMP

#include <hbapi.h>
#include <hbvm.h>

HB_FUNC( TEST )
{
   // We build the virtual machine stack frame

   hb_vmPushSymbol( hb_dynsymGetSymbol( "ANOTHER" ) ); // we push the symbol of the function to call
   hb_vmPushNil(); // we push nil for a function, a codeblock for Eval, an object for a method
   hb_vmPushString( "High level access from low level", strlen( "High level access from low level" ) );
   hb_vmFunction( 1 ); // 1 --> number of supplied parameters
   
   // the returned value can be accessed using hb_stackReturnItem() --> PHB_ITEM
   // or simply calling hb_par...( -1 );
}

#pragma ENDDUMP
Last edited by Antonio Linares on Sun Oct 05, 2008 4:14 pm, edited 2 times in total.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Doug,

You can mix C and C++ code. Just remember to declare as:

Code: Select all

extern "C" 
{
...
   void C_Function_Name( ... );
};
the C functions that you are going to use from C++.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi Antonio

Thanks so much for your reply. I'm reviewing hbvm.h.

I note that if I want to call a method (say ExampleMethod) of an object (say MyObject) I would need to have:

Code: Select all

hb_vmPushSymbol( hb_dynsymGetSymbol( "EXAMPLEMETHOD" ) );
Then I gather from your reply I need to push the object onto the virtual machine stack frame. Not sure how I do this. Do I use another hb_vmPushSymbol?

Code: Select all

hb_vmPushSymbol( hb_dynsymGetSymbol( "MYOBJECT" ) );
I noticed there was also a hb_vmPushDynSym(). I saw a hb_vmPushEvalSym() for a code block.

Being able to call a method of an object from C code is probably what I will most want to do.

I note that I did discover that the address of a function (function pointer) obtained in xHarbour( with @ or HB_FuncPtr() ) does not match the pointer obtained in C code.

Thanks
Doug
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Doug,

Here you have a working example of sending a message to an object from low level:

test.prg

Code: Select all

#include "hbclass.ch"

function Main() 

   local oMyObject := TMyClass()
   
   Test( oMyObject ) 

return nil 

CLASS TMyClass

   METHOD Say( cMsg ) INLINE MsgInfo( cMsg ) 
   
ENDCLASS    

#pragma BEGINDUMP 

#include <hbapi.h> 
#include <hbvm.h> 

HB_FUNC( TEST ) 
{ 
   // We build the virtual machine stack frame 

   hb_vmPushSymbol( hb_dynsymGetSymbol( "SAY" ) ); // we push the symbol of the method
   hb_vmPush( hb_param( 1, HB_IT_OBJECT ) ); // we push the object 
   hb_vmPushString( "Calling a method from low level", strlen( "Calling a method from low level" ) ); 
   hb_vmFunction( 1 ); // 1 --> number of supplied parameters 
    
   // the returned value can be accessed using hb_stackReturnItem() --> PHB_ITEM 
   // or simply calling hb_par...( -1 ); 
} 

#pragma ENDDUMP 
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Doug,

>
I note that I did discover that the address of a function (function pointer) obtained in xHarbour( with @ or HB_FuncPtr() ) does not match the pointer obtained in C code.
>

In the early days of Harbour development the @functionName() operator returned the real C address of the function, but later on it was modified to return a "pointer" item (Harbour and xHarbour behave different on this, as Harbour returns a "symbol" item).

MsgInfo( ValType( @Time() ) ) // shows P in xHarbour and S in Harbour

In fact, you can jump to the real C address of a function as long as you don't need to set a virtual machine frame for it.

You may review this thread for more technical details:
http://forums.fivetechsoft.com/viewtopic.php?t=12588
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi Antonio

Once again thank you for your informative replies. I greatly appreciate the help and will let the concepts sink in and play around with the possibilities.

Regards
Doug
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi Antonio

I'm learning (bit by bit) but I do have another question. I can see how to have my C code "immediately" call back a method of an xHarbour object as per your example. But in a typical call back situation I would want to store the reference to the xHarbour object passed to the C function as a parameter ( oMyObject in your sample code). Is this an unsigned long?

Also I was wondering how the line

Code: Select all

hb_vwPushSymbol( hb_dynsymGetSymbol( "SAY" ) );
works given that multiple objects of different classes may have methods named Say().

Regards
Doug
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Doug,

> I would want to store the reference to the xHarbour object passed to the C function

Basically you have to block the object to avoid that the garbage collector destroys it. I recommend you to review the source code of the extend system and the item api. We manage PHB_ITEMs (pointer to "items" managed by the virtual machine).

Regarding the message: All the messages symbols are the same (for the same message). Its the object itself the one who selects the rigth code for the sent message based on its class dictionary. I recommend you to review the source code of the classes engine of Harbour/xHarbour.
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Thanks Antonio

I clearly have some study ahead of me!

Regards
Doug
Post Reply