Page 1 of 2

How to make a DLL

PostPosted: Sat Oct 06, 2007 4:15 pm
by Rafael Clemente
I am trying to make my first DLL but I feel quite lost. For an start, I would like to include in it just a simple "Hello World" class wihich takes an array os strings and show then in a dialog. This is an example of what I would like to accoplish:
Code: Select all  Expand view
CLASS Test FROM TDialog
      export:
         METHOD New(aTxt) CONSTRUCTOR
      hidden:
         METHOD Controles()
ENDCLASS

//────────────────────────────────────────────────────METHOD New(aTxt) CLASS Test
Default aTxt := {"Hello World!", "Hello again"}
Super():New(0,0,60,80)
ACTIVATE DIALOG Self CENTER ON INIT  ::Controles(aTxt)
RETURN Self

//────────────────────────────────────────────────────
METHOD Controles(aTxt) CLASS Test
@ 20, 0 SAY "Tu mensaje dice: "+aTxt[1] SIZE ::nWidth, 20 PIXEL
@ 50, 0 SAY "Segunda linea: "+aTxt[2] SIZE ::nWidth, 20 PIXEL
RETURN NIL


Could anybody give me a few hints about how to proceed? I have already searched in the forums but could no find any complete example (for instance, the \Samples\Testdll.prg refers to a "buildhd.bat" which I could not find anywhere)

Many thanks
Rafael

PostPosted: Sat Oct 06, 2007 11:13 pm
by Antonio Linares

PostPosted: Sun Oct 07, 2007 3:58 pm
by Rafael Clemente
Antonio:
Thank you. I could try \Samples\TestDll.prg and it works Ok.
Now, How can I pass one parameter to the called function? Something like Main(my_parameter). It would be great if the parameter could be an array.
Thanks
Rafael

[/url]

PostPosted: Sun Oct 07, 2007 3:59 pm
by Ken Wantz
Antonio,

A related question about the .bat file. One line that exists in both my copy dated April 2007 and the one you posted above dated Sept 2007 is:

Code: Select all  Expand view
echo c0d32.obj + %hdir%\obj\b32\maindll.obj + > b32.bc

I have looked everywhere for "maindll.obj" but it does not exist in the specified folder or any other folder for that matter. Is this a missing file or, as I rather suspect, is no longer required?

Regards,

Ken

PostPosted: Sun Oct 07, 2007 4:05 pm
by Rafael Clemente
Ken: See Antonio's last answer in http://fivetechsoft.com/forums/viewtopi ... ht=maindll
Regards,
Rafael

PostPosted: Sun Oct 07, 2007 5:17 pm
by Antonio Linares
Rafael,

It looks as you want to create a pcode DLL, so you need to review FWH\samples\TestDLLP.prg and pcodeDLL.prg

Please read this doc to understand the three different kinds of DLLs that Harbour can use:

/*
* $Id: windll.txt 5836 2002-12-28 00:32:44Z brianhays $
*/

Windows 32-bit DLLs with Harbour code
=====================================

Programs created with Clipper or Harbour are traditionally a
monolithic EXE containing all executable code. This includes
the Virtual Machine (VM) and the RunTime Library (RTL) as well as
your own code. Running under Windows (Win32) with Harbour, you
can now also create and use Windows DLLs that contain PRG code.

Harbour supports Win32 DLLs in 3 ways.

1) Self-contained DLLs containing functions from any platform.
(These are not what we call a "Harbour.dll", although they may
be named that. The DLL entry points are different.)
These have the VM/RTL inside them and can be used by any other
Windows program. You can create a .lib for static linking,
or use GetProcAddress as in any standard Win32 DLL.
Calling Harbour/Prg functions directly is limited to
those that take no parameters unless you include C functions
in the DLL that take parameters and then call the PRG-level
code.

To do static linking, do this to create the .lib:
implib harbour.lib harbour.dll
For the Borland C platform, use that library and import32.lib
and cw32.lib from Borland, and you are ready to go.

See contrib\delphi\hbdll for an example of a Delphi program that can
use all of Harbour's functionality by accessing a self-contained DLL.
BLD_SDLL.BAT is used there to create the DLL.


2) PCode EXEs using a Harbour.dll

A Harbour.dll is designed to be called from a Harbour app.
A pcode EXE is a small Harbour executable that does not contain the
VM/RTL. To execute its functions, it must load and access a
Harbour.dll.
If you want dynamic linking, then use this to execute a Harbour
dynamically loaded pcode DLL function or procedure:
HB_DllDo( <cFuncName> [,<params...>] ) --> [<uResult>]

This lets you have all your common code in a DLL, and have lots
of small EXEs that use it. Realize however that, even though this
may be a nice way to manage your code, each EXE may
load its own image of the Harbour.dll into memory at runtime.
In terms of Windows memory, there may not be a benefit to using pcode
EXEs over monolithic EXEs. But it may be a worthwhile maintenance
benefit to have lots of replaceable small exes.

3) PCode DLLs used from traditional EXEs
A pcode DLL does not contain the VM/RTL.
It is a library of Harbour-compiled PRG code that uses the VM/RTL
of the EXE that calls it. This has the benefit of having
replaceable modules in DLLs that don't necessarily require updating
your EXE.


The following is clipped from a msg by Antonio Linares to the Harbour
developer list explaining some of the details:

Please notice that there are three different Windows DLL entry points:
+ source/vm/
* maindll.c Windows self-contained DLL entry point
* maindllh.c Windows Harbour DLL entry point (harbour.dll)
* maindllp.c Windows pcode DLL entry point and VM/RTL routing functions

> * maindll.c Windows self-contained DLL entry point
To produce Harbour code, as DLLs, that may be used
from other programming languages applications (as VB,
Delphi, C++, etc...)

> * maindllh.c Windows Harbour DLL entry point (harbour.dll)
To produce Harbour.dll, to be just used from small pcode Harbour EXEs

> * maindllp.c Windows pcode DLL entry point and VM/RTL routing
To produce small pcode DLLs, to be used just from Harbour EXE apps.
maindllp.c is the entry point for the Harbour pcode DLLs. pcode DLLs
are quite small DLLs, that just contain pcode and/or C (using extend
api) functions.

mainwin.c is the entry point for Windows EXEs, not for DLLs.

You may use maindll.c, maindllh.c or maindllp.c based on
your needs.

If you are looking to build a Harbour.dll, then you must use
maindllh.c

PostPosted: Sun Oct 07, 2007 5:20 pm
by Antonio Linares
Rafael,

And here you have the required buildhdp.bat:

http://rapidshare.com/files/60934949/buildhdp.zip.html

And the required maindllp.obj:

http://fivetechsoft.com/forums/viewtopi ... aindllp%2A

PostPosted: Sun Oct 07, 2007 5:52 pm
by Rafael Clemente
Antonio:
In fact, I am trying to write a function in FWH than can be called from a VisualBasic program. I have been told that VB can not link external objects of Libs (at least, that's what muy customer says) and, tehrefore, the only way to incorporate my function to his program is through a DLL.

I had already read the document you included and I think the DLL I need is type 1) , not pcode. Or may be it is?

Rafael

PostPosted: Sun Oct 07, 2007 6:55 pm
by Antonio Linares
Rafael,

Yes, you need type 1, as it has to include the VM/RTL to make it self-contained, so you can use it from any EXE (VB, etc.)

PostPosted: Sun Oct 07, 2007 6:58 pm
by Antonio Linares
Rafael,

If you review inside Harbour's maindll.c module, you find these functions (they show the way to get into the DLL from outside):
Code: Select all  Expand view
HB_EXPORT LONG PASCAL HBDLLENTRY( char * cProcName )
{
   hb_itemDoC( cProcName, 0, 0 );

   return 0;
}

HB_EXPORT LONG PASCAL HBDLLENTRY1( char * cProcName, LONG pItem )
{
   hb_itemDoC( cProcName, 1, ( PHB_ITEM ) pItem, 0 );

   return 0;
}

HB_EXPORT LONG PASCAL HBDLLENTRY2( char * cProcName, LONG pItem1, LONG pItem2 )
{
   hb_itemDoC( cProcName, 2, ( PHB_ITEM ) pItem1, ( PHB_ITEM ) pItem2, 0 );

   return 0;
}

What parameters do you want to send from VB to the DLL ?

PostPosted: Sun Oct 07, 2007 9:18 pm
by Rafael Clemente
Antonio: Thanks to your suggestions, my DLL is working now!!! :-))) When called from an FWH program, I can now display a "Hello World" dialog. Many thanks!

However, I would like to be able to call this DLL from an application written in Visual Basic. I have been reviewing your exchange with maurucio jornao in december 28, 2005 and it seems to me that this is going to be much more complicated. I am not proficient in C. Could you suggest an easy way to do it or I just better forget about the whole thing?

Thanks again

Rafael

PostPosted: Sun Oct 07, 2007 9:24 pm
by Antonio Linares
Rafael,

What types of values do you want to send from VB to the DLL, and what type of value do you want to return from the DLL ?

PostPosted: Sun Oct 07, 2007 9:30 pm
by Rafael Clemente
Antonio:
I would like to pass at least one string; better two strings and better yet, an array of strings (although I guess this may be more difficult)

Rafael

PostPosted: Mon Oct 08, 2007 6:38 am
by Antonio Linares
Rafael,

You could send just one string using a format similar like this:

"one;two;three;four;five"

so you will be able to build an array from it inside the DLL. Is that ok for you ?

PostPosted: Mon Oct 08, 2007 6:51 am
by Antonio Linares
To do it, just include this function in your DLL:

Code: Select all  Expand view
#pragma BEGINDUMP

#include <hbapi.h>
#include <hbapiitm.h>

HB_EXPORT LONG PASCAL TEST( char * cProcName, char * cParam )
{
   PHB_ITEM pItem = hb_itemPutC( NULL, cParam );

   hb_itemDoC( cProcName, 1, ( PHB_ITEM ) pItem, 0 );
   hb_itemRelease( pItem );

   return 0;
}

#pragma ENDDUMP


From VB you have to declare:

Declare Function TEST Lib "MyDLL.dll" (ByVal cProcName As String, ByVal cParam As String ) As Long