06302156.txt 30-Jun-00


Subject: Runtime DLL switching
From: "Will Chapman" <willchapman@dial.pipex.com>

I have an application that relies on a one of a number of
  different DLL's to interface with different hardware and
  data sources.
Thus, the main app calls a standard _DLL FUNCTION,
  say,GetUserData() and the current DLL responds by
  gathering that information from its own data.
Normally, each user only uses one DLL - so I handle this by
  renaming the appropriate DLL to the standard DLL name that
  is identified in each _DLL FUNCTION.
However, I would also like to be able to swap DLL's in mid-
  stream presumably this would be done by using
  LoadLibrary() and FreeLibrary() but then I guess I will
  need to replace the _DLL FUNCTIONS with calls via the
  LOadLibrary PTR?
Can anyone give me any clues in this direction (or
  suggestions for alternative approaches)?

Thanks....
Will Chapman


Subject: Re: Runtime DLL switching
From: nswong@my-deja.com (Wong)

Hi Will,

Just an idea. :-)
MyApp.ini
[Default DLL]
Data Source=Source1.dll
PROCEDURE Start()
  GetPrivateProfileString(...)
  DataSourceSet(lpReturnedString)
RETURN
Approach 1:
CLASS DataSource
  PROTECT cDataSource
METHOD Init() CLASS DataSource
  SELF:cDataSource:=DataSourceGet()
METHOD GetUserData() CLASS DataSource
  DO CASE
  CASE GetDataSource()=="Source1.dll"
    uVal:=GetUserData1()
  CASE GetDataSource()=="Source2.dll"
    uVal:=GetUserData2()
  ....
RETURN (uVal)
Approach 2:
CLASS DataSource
  PROTECT ptrModule
METHOD Init() CLASS DataSource
  SELF:ptrModule:=LoadLibrary(String2Psz(DataSourceGet()))
METHOD GetUserData() CLASS DataSource
  LOCAL ptrGetUserData AS PTR
  ptrGetUserData:=GetProcAddress(SELF:ptrModule,;
    String2Psz("GetUserData"))

  uVal:=PCALL(ptrGetUserData)
RETURN (uVal)

Regards,
Wong


Subject: Re: Runtime DLL switching
From: "Will Chapman" <willchapman@dial.pipex.com>

Wong

I think your second idea is the better approach
  (coincidentally, I've been playing with the same idea
  since I spotted some code like it on KnowVO).
The problem is compounded by the fact that there are likely
  to be many customised DLLs - one for each type of EPOS
  software and hardware in fact (of which there are dozens
  in the UK) - so hardcoding anything is going to be a
  pain. At the moment I handle these variations with
  Registry entries but this doesn't solve the problem of one
  client needing to switch mid-stream between one DLL and
  another. So the only option is for them to re-boot the app
  - not very elegant.
Thanks for your input..

Will Chapman


Subject: Re: Runtime DLL switching
From: nswong@maxis.net.my (Wong)

Hi Will,

Most of the peripheral provided a way to identify them, in
  each DLL we can put a function lValid() to report the
  peripheral attached is't supported by this particular DLL.
CLASS DataSource
  PROTECT ptrModule
METHOD Init() CLASS DataSource
  LOCAL acDLL, iS
  //DataSourceGet() put as first item to avoid loading
  //  too many DLLs
  acDLL:={DataSourceGet(),"Source1.dll","Source2.dll",;
    "Source3.dll"}
  iS:=1; lValid:=FALSE
  DO WHILE iS<=ALen(acDLL) .AND. !lValid
    ptrModule:=LoadLibrary(String2Psz(acDLL[nS]))
    ptrlValid:=GetProcAddress(ptrModule,;
      String2Psz("lValid"))
    lValid:=PCALL(ptrlValid)
    ++iS
  ENDDO
  IF lValid
    SELF:ptrModule:=ptrModule
  ELSE
    MessageBox(NULL,String2Psz("Equitment not supported"),;
      String2Psz("DataSource"),0)
  ENDIF

HTH,
Wong


Subject: SV: Runtime DLL switching
From: "Mathias Hakansson" <mathias.hakansson@tendata.se>

Here's one way of doing it. I have made a wrapper class that
  interfaces with a dll that can interface the databases in
  a another program made by a company that we are
  cooperating with. The init method recieves a path to the
  dll, loads the dll and initializes the function pointers
  that are used later when you call methods. See example
  below.
class XorBase4
  protect db as long
  protect hinst as ptr
  protect pszclient,pszpath as psz
  protect _foretag,_path as string
  export failed as logic
  // Pointers to functions
  protect pOpenClient   as OpenClient   ptr
  protect pCloseClient  as CloseClient   ptr
  protect pXGetAccount  as XGetAccount   ptr
  protect pGetReservedAccount as GetReservedAccount ptr
  protect pGetStandardText as GetStandardText  ptr
  protect pVoucherRowAdd  as VoucherRowAdd  ptr
  method Init(ftg,path) class XorBase4
  local p as psz
  p := StringAlloc(path + "\xorbase4.dll")
  self:hinst := LoadLibrary(p)
  MemFree(p)
  if self:hinst == NULL
    InfoBox{,"XorBase4","Lyckades inte ladda " + ;
      path + "\xorbase4.dll"}:Show()
    self:failed := true
    return self
  endif
  // Load function pointers
  self:pOpenClient   := GetProcAddress(self:hinst,;
    String2Psz("OpenClient"))
  self:pCloseClient   := GetProcAddress(self:hinst,;
    String2Psz("CloseClient"))
  self:pXGetAccount   := GetProcAddress(self:hinst,;
    String2Psz("XGetAccount"))
  self:pGetReservedAccount := GetProcAddress(self:hinst,;
    String2Psz("GetReservedAccount"))
  self:pGetStandardText  := GetProcAddress(self:hinst,;
    String2Psz("GetStandardText"))
  self:pVoucherRowAdd   := GetProcAddress(self:hinst,;
    String2Psz("VoucherRowAdd"))
  self:_foretag := ftg
  self:_path := path
  RegisterAxit(self)
return self
method ReserveratKonto(no) class XORBase4
  local pstr as psz
  local lyckades as long
  local konto as string
  if self:OpenClient()

    pstr := MemAlloc(7)
    lyckades := call(self:pGetReservedAccount,;
      self:db,no,pstr)
    if lyckades == 1L
      konto := Psz2String(pstr)
    endif
    MemFree(pstr)
    self:CloseClient()
  endif
return konto
method Axit() class XorBase4
  FreeLibrary(self:hinst)
This can be a beginning for you. One of the problems that I
  had was how to interpret the dates, they came as a
  dword...

Mathias