07010251.txt 01-Jul-00


Subject: Using Class in DLL
From: "Steve Gadoury" <sgadoury@sigma-rh.com>

Hi everybody,

I have a problem.  I would like to access a class and this
  class is store in a DLL.  I tried to use LoadLibrary and
  After, use CreateInstance and I have error that Variable
  does not exists when I do CreateInstance and I verified
  DLL name...
Does someone know how to do it???

Thanks
Steve


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Steve,

Please download a thread call "_VOLOadLibrary()" from
  www.knowvo.com, Paul Piko has some very good explanation.
  Sorry! I donot keep this thread anymore, and can't mail to
  you. But I had write an example for you.
Try this:
MyExe.exe
---------
PROCEDURE Start()
  LOCAL ptrMyDll AS PTR
  LOCAL ptrInit AS iInit PTR
  LOCAL oMyDll AS OBJECT
  ptrMyDll:=LoadLibrary(String2Psz("MyDll"))
  ptrInit:=GetProcAddress(ptrMyDll,String2Psz("iInit"))
  PCALL(ptrInit)
  oMyDll:=CreateInstance(#MyDll, ;
    String2Psz("Call from MyExe"))
  oMyDll:Show()
  oMyDll:=NULL_OBJECT
  CollectForced()
  FreeLibrary(ptrMyDll)
RETURN
FUNCTION iInit() AS INT PASCAL
RETURN (0)
MyDll.dll
-------------
FUNCTION iInit() AS INT PASCAL
RETURN (0)
CLASS MyDll
  EXPORT pszText AS PSZ
METHOD Init(pszTxt) CLASS MyDll
  SELF:pszText:=pszTxt
METHOD Show() CLASS MyDll
  MessageBox(NULL,SELF:pszText,String2Psz("MyDll"),0)

Regards,
Wong


Subject: Re: Using Class in DLL
From: "Steve Gadoury" <sgadoury@sigma-rh.com>

Thanks Wong,

I will study this example.  I hope it will solve my
  problem....

Thanks
Steve


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Steve,

>Thanks Wong,
You are welcome! :-)
>
I will study this example.  I hope it will solve my
  problem....
<
From trial and error, I discover some rules of using
  LoadLibrary/FreeLibrary. One of it is avoid passing
  dynamic data type to the CLASS/FUNCTION, do you notice I
  pass PSZ instead of STRING in the example?
Anyway, I can assure you, LoadLibrary/FreeLibrary do work in
  VO, but with some rules.

Regards,
Wong


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Steve,

Some additional information for you.
I reviews an old posting from Paul Piko, and test it, then
  proved _VOFreeLibrary() are use to free VO Classes in the
  DLL.
This function are needed for the case of two DLL files
  having the same class name. eg. runtime dynamic loading
  device driver class having common API.
See Paul Piko posting and my test program bellow.

Regards,
Wong

Paul Piko posting
-----------------
06200531.txt 20-Jun-00
FreeLibrary causing error

They're not documented anywhere, other than on Compuserve.
  See below.
On reviewing Sabo's comments, this probably isn't the cause
  of David's problem, since I don't think he's creating

  objects from the DLL.

Paul

#: 32622 S6/VO DLLs/LIBs  [CAVO20]
    29-Mar-97  00:06
Sb: #32604-DLLs loading and classes
Fm: Ralf Saborowski-CA/GmbH 70007,6012
To: Thierry PERTUY 100532,3163

Thierry,

originally VO DLLs were not designed to support
  LoadLibrary(), which explains the behaviour about classes
  not going away. Since especially after the release of 2.0
  we received a bunch requests for that feature, we have
  been playing with class unloading for the 2.0a patch
  lately.
From our tests 2.0a will now remove classes from the runtime
  when you unload a DLL. This should solve your problems.
Although, I have to mention, that this feature will be
  undocumented and unsupported for the 2.0a release.
In order to get the class unloading working, you will have
  to use special runtime functions (_VOLoadLibrary() and
  _VOFreeLibrary()) instead of the Win API functions. I
  think these functions are already in 2.0 and the
  prototypes are the same as for the Win API functions.

Sabo

_VOLoadLibrary has already been mentioned.
Are you sure you have PCALL and CCALL and the correct
  prototypes sorted out. (Pascal or Strict/C calling
  conventions).


my test program
---------------

MyExe.exe
---------
PROCEDURE Start()
  LOCAL ptrMyDll AS PTR
  LOCAL ptrInit AS iInit PTR
  LOCAL oMyDll AS OBJECT
  vShow('1') //F,F
  ptrMyDll:=LoadLibrary(String2Psz("MyDll"))
  ptrInit:=GetProcAddress(ptrMyDll,String2Psz("iInit"))
  vShow('2') //T,F
  PCALL(ptrInit)
  vShow('3') //T,T
  oMyDll:=CreateInstance(#MyDll, ;
    String2Psz("Call from MyExe"))
  oMyDll:Show()
  oMyDll:=NULL_OBJECT
  CollectForced()
  FreeLibrary(ptrMyDll)
  vShow('4') //F,T If use _VOFreeLibrary will get F,F
RETURN
FUNCTION iInit() AS INT PASCAL

RETURN (0)
PROCEDURE vShow(cPass AS STRING)
  LOCAL cIsHandle AS STRING
  LOCAL cIsClass AS STRING
  LOCAL cMessage AS STRING
  cIsHandle:=IIf(;
    GetModuleHandle(String2Psz("MyDll"))==NULL_PTR,'F','T')
  cIsClass:=IIf(IsClass(#MyDll),'T','F')
  cMessage:="Module=="+cIsHandle+_Chr(13)+_Chr(10)+;
    "Class=="+cIsClass
  MessageBox(NULL,String2Psz(cMessage),String2Psz(cPass),0)
RETURN

MyDll.dll
-------------
FUNCTION iInit() AS INT PASCAL
RETURN (0)
CLASS MyDll
  EXPORT pszText AS PSZ
METHOD Init(pszTxt) CLASS MyDll
  SELF:pszText:=pszTxt
METHOD Show() CLASS MyDll
  MessageBox(NULL,SELF:pszText,String2Psz("MyDll"),0)


Subject: Re: Using Class in DLL
From: "Steve Gadoury" <sgadoury@sigma-rh.com>

Thanks Wong,

I'm finding solution.  I'm using LoadLibrary with
  GetprocAddress and PCALL.  At this moment, I have no
  problem and I don't think I will have.

Thanks
Steve


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Steve,

>Thanks Wong,
You are welcome!  :-)
Some of peoples here will tell you "don't use
  FreeLibrary/_VOFreeLibrary". Even we are using these
  function to free the DLL, but the effort may not worth it
  for other to implement this.
So I'm also advice you to let the DLL stay in memory, but if
  you really have the need to free it as we do, then let me
  know. I may can compile some of our experience for you.

Regards,
Wong


Subject: Re: Using Class in DLL
From: "Steve Gadoury" <sgadoury@sigma-rh.com>

Thanks wong,

I just found problem.  When I freelibrary, it returns always
  false, do you know why and How can I bypass it????

Thanks for your help
Steve


Subject: Re: Using Class in DLL
From: "Geoff Schaller" <geoffsch@bigpond.net.au>

Steve,

PMFJI
...but "False". A successful freeing of the library results
  in a non-zero return value. Failure returns 0 but then you
  can use GetlastError() to find out why.

Geoff


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Steve,

>
I just found problem.  When I freelibrary, it returns always
  false, do you know why and How can I bypass it????
<
It should return TRUE, try example bellow.
In your case, it may be either the PTR you pass to
  FreeLibrary are not valid or the reference count already
  reach 0 (Load one Free twice).
As Geoff said, you can call GetLastError to found out the
  source of problem.
BTW: If you ever pass some dyn var to the DLL, or the DLL
  return some dyn var to the EXE, or in the DLL containt
  CLASS definition, you should use _VOFreeLibrary instead of
  FreeLibrary. Or else GPF will become your good friend.
  <bg> Try to put CollectForced() after the FreeLibrary(),
  you will see what I mean.

Regards,
Wong

//MyExe.prg 22-Jun-00
PROCEDURE Start()
  LOCAL ptrMyDll AS PTR
  LOCAL ptrInit AS iInit PTR
  LOCAL oMyDll AS OBJECT
  LOCAL cFree AS STRING
  vShow('1') //F,F
  ptrMyDll:=LoadLibrary(String2Psz("MyDll"))
  ptrInit:=GetProcAddress(ptrMyDll,String2Psz("iInit"))
  vShow('2') //T,F
  PCALL(ptrInit)
  vShow('3') //T,T
  oMyDll:=CreateInstance(#MyDll, ;

    String2Psz("Call from MyExe"))
  oMyDll:Show()
  oMyDll:=NULL_OBJECT
  CollectForced()
  cFree:=LToC(FreeLibrary(ptrMyDll))
  MessageBox(NULL,String2Psz(cFree),String2Psz("MyExe"),0)
  vShow('4') //F,T If use _VOFreeLibrary will get F,F
  //Will get GPF, should use _VOFreeLibrary instead
  CollectForced()
RETURN
PROCEDURE vShow(cPass AS STRING)
  LOCAL cIsHandle AS STRING
  LOCAL cIsClass AS STRING
  LOCAL cMessage AS STRING
  cIsHandle:=LToC(;
    GetModuleHandle(String2Psz("MyDll"))!=NULL_PTR)
  cIsClass:=LToC(IsClass(#MyDll))
  cMessage:="Module=="+cIsHandle+_Chr(13)+_Chr(10)+;
    "Class=="+cIsClass
  MessageBox(NULL,String2Psz(cMessage),String2Psz(cPass),0)
RETURN
FUNCTION iInit() AS INT PASCAL
RETURN (0)

//MyDll.prg 22-Jun-00
FUNCTION _VOCanUnload() AS LOGIC STRICT
RETURN (TRUE)
FUNCTION iInit() AS INT PASCAL
RETURN (0)
CLASS MyDll
  EXPORT pszText AS PSZ
METHOD Init(pszTxt) CLASS MyDll
  SELF:pszText:=pszTxt
METHOD Show() CLASS MyDll
  MessageBox(NULL,SELF:pszText,String2Psz("MyDll"),0)


Subject: Re: Using Class in DLL
From: "Geoff Schaller" <geoffsch@bigpond.net.au>

Hi Wong,

I don't think that the advice is "don't use..." so much as
  "Don't Need to Use..." Hence, if you don't need to do it,
  don't <g>. MS recommend against it by simply saying that
  it is generally unnecessary.
However, I acknowledge that there are times you must - eg,
  if you are about to update that dll or are doing so for
  security reasons.

Geoff


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Geoff,

>
However, I acknowledge that there are times you must - eg,

  if you are aboutto update that dll or are doing so for
  security reasons.
<
One more case:
P100.DLL contain
CLASS EntryScreen INHERIT _EntryScreen
P200.DLL also contain
CLASS EntryScreen INHERIT _EntryScreen
In MyExe.exe
LoadLibrary(String2Psz("P100"))
oMyDll:=CreateInstance(#EntryScreen)
Do something
oMyDll:=LoadLibrary(String2Psz("P200"))
//The EntryScreen object from P100/P200 ?
oMyDll:=CreateInstance(#EntryScreen)
You got 50% of the chances to be right! <vbg>

Cheers,
Wong


Subject: Re: Using Class in DLL
From: "Geoff Schaller" <geoffsch@bigpond.net.au>

Yep!   Fair comment.


Subject: Re: Using Class in DLL
From: "Stephane Hebert" <stephhebert@mypants~videotron.ca>

Wong,

This is dangerous stuff.
Won't you get a runtime error if you try that ?
If it doesn't generate a runtime error, then what are the
  options ?
GetProcAddress() allows you to specify the module handle and
  the name of a function or it's ordinal position, but would
  that work for a class ?
And what function would be used to instantiate the class
  from the address ?
Just some thoughts.

Stephane Hebert


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Stephane,

> Won't you get a runtime error if you try that ?
No.
>
If it doesn't generate a runtime error, then what are the
  options ?
<
The CLASS definition in the second DLL loaded will overwrite
  the first one.
>

GetProcAddress() allows you to specify the module handle and
  the name of a function or it's ordinal position, but would
  that work for a class ?
<
Since the CLASS definition of the first DLL has been
  overwritten, I don't think we got anyway to create an
  object from the first DLL.
>
And what function would be used to instantiate the class
  from the address ?
<
AFAIK, no function available for this purpose.
Try bellow example, it will help to explain the behaviour.

Regards,
Wong

//MyExe.prg 22-Jun-00
PROCEDURE Start()
  LOCAL ptrMyDll1 AS PTR, ptrMyDll2 AS PTR
  LOCAL ptrInit1 AS iInit PTR, ptrInit2 AS iInit PTR
  LOCAL oMyDll1 AS OBJECT, oMyDll2 AS OBJECT
  LOCAL cFree AS STRING
  vShow('1',"MyDll1") //F,F
  ptrMyDll1:=LoadLibrary(String2Psz("MyDll1"))
  ptrInit1:=GetProcAddress(ptrMyDll1,String2Psz("iInit"))
  vShow('2',"MyDll1") //T,F
  PCALL(ptrInit1)
  vShow('3',"MyDll1") //T,T
  oMyDll1:=CreateInstance(#MyDll, ;
    String2Psz("Call from MyExe"))
  oMyDll1:Show() //MyDll1
  vShow('4',"MyDll2") //F,T
  ptrMyDll2:=LoadLibrary(String2Psz("MyDll2"))
  ptrInit2:=GetProcAddress(ptrMyDll2,String2Psz("iInit"))
  vShow('5',"MyDll2") //T,T
  oMyDll2:=CreateInstance(#MyDll, ;
    String2Psz("Call from MyExe"))
  oMyDll1:Show() //MyDll1
  oMyDll2:Show() //MyDll1
  PCALL(ptrInit2)
  vShow('6',"MyDll2") //T,T
  oMyDll1:Show() //MyDll2
  oMyDll2:Show() //MyDll2
  cFree:=LToC(_VOFreeLibrary(ptrMyDll1))
  MessageBox(NULL,String2Psz(cFree),;
    String2Psz("MyDll1"),0) //T
  vShow('7',"MyDll1") //F,F
  vShow('8',"MyDll2") //T,F
  //NO EXPORTED METHOD, chose Ignore to continue
  oMyDll2:Show()
  PCALL(ptrInit2)
  vShow('9',"MyDll2") //T,F
  LoadLibrary(String2Psz("MyDll2"))
  PCALL(ptrInit2)
  vShow("10","MyDll2") //T,F
  cFree:=LToC(_VOFreeLibrary(ptrMyDll2))
  MessageBox(NULL,String2Psz(cFree),;
    String2Psz("MyDll2"),0) //T
  vShow("11","MyDll2") //T,F

  cFree:=LToC(_VOFreeLibrary(ptrMyDll2))
  MessageBox(NULL,String2Psz(cFree),;
    String2Psz("MyDll2"),0) //T
  vShow("12","MyDll2") //F,F
  ptrMyDll2:=LoadLibrary(String2Psz("MyDll2"))
  ptrInit2:=GetProcAddress(ptrMyDll2,String2Psz("iInit"))
  vShow("13","MyDll2") //T,F
  PCALL(ptrInit2)
  vShow("14","MyDll2") //T,T
  oMyDll1:Show() //MyDll2
  oMyDll2:Show() //MyDll2, value of SELF:pszText lost
  cFree:=LToC(_VOFreeLibrary(ptrMyDll2))
  MessageBox(NULL,String2Psz(cFree),;
    String2Psz("MyDll2"),0) //T
  vShow("15","MyDll2") //F,F
  CollectForced()
RETURN
PROCEDURE vShow(cPass AS STRING, cDll AS STRING)
  LOCAL cIsHandle AS STRING
  LOCAL cIsClass AS STRING
  LOCAL cMessage AS STRING
  cIsHandle:=LToC(;
    GetModuleHandle(String2Psz(cDll))!=NULL_PTR)
  cIsClass:=LToC(IsClass(#MyDll))
  cMessage:="Module=="+cIsHandle+_Chr(13)+_Chr(10)+;
    "Class=="+cIsClass
  MessageBox(NULL,String2Psz(cMessage),String2Psz(cPass),0)
RETURN
FUNCTION iInit() AS INT PASCAL
RETURN (0)

//MyDll1.prg 22-Jun-00
FUNCTION iInit() AS INT PASCAL
RETURN (0)
CLASS MyDll
  EXPORT pszText AS PSZ
METHOD Init(pszTxt) CLASS MyDll
  SELF:pszText:=pszTxt
METHOD Show() CLASS MyDll
  MessageBox(NULL,SELF:pszText,String2Psz("MyDll1"),0)

//MyDll2.prg 22-Jun-00
FUNCTION iInit() AS INT PASCAL
RETURN (0)
CLASS MyDll
  EXPORT pszText AS PSZ
METHOD Init(pszTxt) CLASS MyDll
  SELF:pszText:=pszTxt
METHOD Show() CLASS MyDll
  MessageBox(NULL,SELF:pszText,String2Psz("MyDll2"),0)


Subject: Re: Using Class in DLL
From: "Stephane Hebert" <stephhebert@mypants~videotron.ca>

Wong,

>
The CLASS definition in the second DLL loaded will overwrite
  the first one.

<
Is this true only for VO or is it a Windows feature ?
Thanks for the explanations.

Stephane Hebert


Subject: Re: Using Class in DLL
From: nswong@maxis.net.my (Wong)

Hi Stephane,

>>
The CLASS definition in the second DLL loaded will overwrite
  the first one.
<<
>Is this true only for VO or is it a Windows feature ?
I never tried this under other development tools, so I'm
  unsure about this. Sorry!
>Thanks for the explanations.
You are welcome!  :-)
BTW: If somebody say thanks to us, it's You are welcome! are
  the right way to replied? Any other way? I'm really poor
  in English, most of the English vacabulary I known are
  computer related. :-)

Regards,
Wong


Subject: Re: Using Class in DLL
From: "Stephane Hebert" <stephhebert@mypants~videotron.ca>

Wong,

>
BTW: If somebody say thanks to us, it's You are welcome! are
  the right way to replied? Any other way? I'm really poor
  in English, most of the English vacabulary I known are
  computer related. :-)
<
Well, seems you got this one right <g>

Stephane Hebert

Subject: Re: Using Class in DLL
From: Wolfgang Riedmann <wolfgang@riedmann.it>

Hi Steve,

do you need to call a function from this DLL. Only after
  this call the classes in the DLL are known to the runtime.

Wolfgang
Meran/Italy


Subject: Re: Using Class in DLL
From: "Steve Gadoury" <sgadoury@sigma-rh.com>

Thanks Wolfgang,

I will try it and if I have problems, i will post it.

Thanks
Steve
