Yes, there is a problem with my "free library until zero use count".
The following three programs need changing and compiling.
Replace the following function in SQLitening.Bas and compile.
'============================<[ Run Proc ]>============================
Function slRunProc alias "slRunProc" (rsProcName as String, _
blParm1 as Long, _
blParm2 as Long, _
bsParm3 as String, _
bsParm4 as String, _
optional byval rsModChars as String)Export as Long
' ProcName is the one character library suffix followed by the name of the
' entry to be called within the library. ProcName may also contain an
' optional password. This password is separated from the proc name by the
' $BS character. The full library name is SQLiteningProcs + the one
' character suffix. A ProcName of AStoreOrder^TallWalk (^ is the $BS)
' would has the following three parts:
' 1. A is the library name suffix so SQLiteningProcsA.Dll would be
' loaded.
' 2. StoreOrder is the entry name.
' 3. TallWalk is the optional password.
' If you are only loading or unloading the library (L or U modchar passed)
' then the ProcName is only the one character library suffix.
' SQLiteningProcsA.Bas is included as a sample proc library. There are
' two sample entries coded there; Entry1 is called by this slRunProc while
' Entry2 is invoked by using the SQLite load_extension function.
' ModChars:
' Em = Return errors. This will override the global return errors flag.
' m is the optional message display modifier and can be:
' 0 = No message is displayed. This is the default.
' 1 = Display a warning message with OK button. Error is
' returned when OK pressed.
' 2 = Display a question message with OK and Cancel buttons.
' If they press OK, error is returned. If they press
' Cancel, will exit process.
' e = Do not return errors, display message and exit process. This
' will override the global return errors flag.
' L = Load the library. Pass only the one character library prefix
' in ProcName. Useful if you know you will be running procs many
' times from this library. This is required for creating SQLite
' custom functions. You must later unload the library.
' U = Unload the library. Pass only the one character library prefix
' in ProcName. Required if your previously loaded the library.
' u = Do not unload the library after running the proc. Pass the one
' character library prefix and entry name in ProcName. You must
' later unload the library.
Local lhProcsLibHand as Dword
Local lhRutAddr as Dword
' Must handle differently if running remote
if guFlags.AreRunningRemote then
' Running remote so run remote proc
irGetRutAddress "SQLiteRunProc", lhRutAddr
call dword lhRutAddr using UsingRunProcRemote(ghDab, rsProcName, blParm1, blParm2, bsParm3, bsParm4, rsModChars) to glLastError
else
' Running local so check if they passed an entry name
if len(mid$(rsProcName, 2)) then
' Yes we have an entry name so load and get address
lhProcsLibHand = LoadLibrary("SQLiteningProcs" & left$(rsProcName, 1))
lhRutAddr = GetProcAddress(lhProcsLibHand, bycopy parse$(mid$(rsProcName, 2), $BS, 1))
if lhRutAddr then
call dword lhRutAddr using UsingRunProcLocal(ghDab, 0, blParm1, blParm2, bsParm3, bsParm4) to glLastError
else
glLastError = -19
end if
' Free the lib if we can
if isfalse instr(rsModChars, "u") then FreeLibrary(lhProcsLibHand)
else
' No entry name then just load or free lib
if instr(rsModChars, "L") then
lhProcsLibHand = LoadLibrary("SQLiteningProcs" & left$(rsProcName, 1))
elseif instr(rsModChars, "U") then
lhProcsLibHand = GetModuleHandle("SQLiteningProcs" & rsProcName)
FreeLibrary(lhProcsLibHand)
end if
end if
end if
if glLastError then goto ErrorRut
' Exit OK
exit function
ErrorRut:
irHandleError "Run Proc " & rsProcName, rsModChars
function = glLastError
End Function
Replace the following function in SQLiteningClient.Bas and compile.
'============================<[ Run Proc ]>============================
Function SQLiteRunProc alias "SQLiteRunProc" (byval rhDab as Dword, _
rsProcName as String, _
blParm1 as Long, _
blParm2 as Long, _
bsParm3 as String, _
bsParm4 as String, _
optional byval rsModChars as String)Export as Long
' String to be passed is as follows:
' 1 - 4 = blParm1
' 5 - 8 = blParm2
' 9 - 12 = length of rsProcName
' 13 - ?? = rsProcName
' ?? - ?? = length of bsParm3
' ?? - ?? = bsParm3
' ?? - ?? = length of bsParm4
' ?? - ?? = bsParm4
' String to be returned is as follows:
' 1 - 4 = blParm1
' 5 - 8 = blParm2
' 9 - ?? = length of bsParm3
' ?? - ?? = bsParm3
' ?? - ?? = length of bsParm4
' ?? - ?? = bsParm4
Local llOffset, llLength as Long
Local lsA as String
' Call proc on server
function = DoRequest(%reqRunProc, rhDab, _
iif&(instr(rsModChars, "L"), 1, 0) + iif&(instr(rsModChars, "U"), 2, 0) + + iif&(instr(rsModChars, "u"), 4, 0), _
mkl$(blParm1) & mkl$(blParm2) & mkl$(len(rsProcName)) & rsProcName & _
mkl$(len(bsParm3)) & bsParm3 & mkl$(len(bsParm4)) & bsParm4, _
0, lsA)
' Set returning values from returning string
blParm1 = cvl(lsA, 1)
blParm2 = cvl(lsA, 5)
llOffset = 9
llLength = cvl(lsA, llOffset)
bsParm3 = mid$(lsA, llOffSet + 4, llLength)
llOffset = llOffset + llLength + 4
llLength = cvl(lsA, llOffset)
bsParm4 = mid$(lsA, llOffSet + 4, llLength)
End Function
Replace the following function in SQLiteningServer.Bas and compile.
'============================<[ Run Proc ]>============================
Function RunProc(byval rhDab as Dword, _
byval rlFlags as Long, _
rsDataIn as String, _
wsDataOut as String, _
byval rlTcpFileNumber as Long) as Long
' DataIn is as follows:
' 1 - 4 = blParm1
' 5 - 8 = blParm2
' 9 - 12 = length of rsProcName
' 13 - ?? = rsProcName
' ?? - ?? = length of bsParm3
' ?? - ?? = bsParm3
' ?? - ?? = length of bsParm4
' ?? - ?? = bsParm4
' DataOu is as follows:
' 1 - 4 = blParm1
' 5 - 8 = blParm2
' 9 - ?? = length of bsParm3
' ?? - ?? = bsParm3
' ?? - ?? = length of bsParm4
' ?? - ?? = bsParm4
' Flags: 1=Load, 2=Unload, 4=Don't Unload
Local lhProcsLibHand as Dword
Local lhRutAddr as Dword
Local llRC as Long
Local llOffset, llLength as Long
Local llParm1, llParm2 as Long
Local lsParm3, lsParm4 as String
' Check password
llRC = CheckFileAccesss(">" & mid$(rsDataIn, 13, cvl(rsDataIn, 9)), 16, rlTcpFileNumber)
if llRC = 0 then
' Set parms
llParm1 = cvl(rsDataIn, 1)
llParm2 = cvl(rsDataIn, 5)
llOffset = 13 + cvl(rsDataIn, 9)
llLength = cvl(rsDataIn, llOffset)
lsParm3 = mid$(rsDataIn, llOffSet + 4, llLength)
llOffset = llOffset + llLength + 4
llLength = cvl(rsDataIn, llOffset)
lsParm4 = mid$(rsDataIn, llOffSet + 4, llLength)
' Check if they passed an entry name
if len(mid$(rsDataIn, 13 + 1, cvl(rsDataIn, 9) - 1)) then
' Yes we have an entry name so load and get address
lhProcsLibHand = LoadLibrary("SQLiteningProcs" & left$(mid$(rsDataIn, 13, cvl(rsDataIn, 9)), 1))
lhRutAddr = GetProcAddress(lhProcsLibHand, parse$(mid$(rsDataIn, 13 + 1, cvl(rsDataIn, 9) - 1), $BS, 1))
if lhRutAddr then
call dword lhRutAddr using UsingRunProc(rhDab, rlTcpFileNumber, llParm1, llParm2, lsParm3, lsParm4) to llRC
else
llRC = -19
end if
' Free the lib if we can
if isfalse (rlFlags and 4) then FreeLibrary(lhProcsLibHand)
else
' No entry name then just load or free lib
if (rlFlags and 1) then lhProcsLibHand = LoadLibrary("SQLiteningProcs" & left$(mid$(rsDataIn, 13, cvl(rsDataIn, 9)), 1))
if (rlFlags and 2) then
lhProcsLibHand = GetModuleHandle("SQLiteningProcs" & left$(mid$(rsDataIn, 13, cvl(rsDataIn, 9)), 1))
FreeLibrary(lhProcsLibHand)
end if
end if
end if
'Build returning data out and return
wsDataOut = mkl$(llParm1) & mkl$(llParm2) & mkl$(len(lsParm3)) & lsParm3 & mkl$(len(lsParm4)) & lsParm4
function = llRC
End Function
Now to answer your question. Yes it would be best to keep your high use
procs, including SQLite custom function, in a single separate library so
it can be loaded and unloaded. The SQLite custom functions must stay in
memory and you will get a performance gain by also keeping high use ones
in memory. You probably don't want to waste the memory on low use procs.
Note that you can now load and unload the library with seperate calls to
RunProc. If, for example, your library is suffix "T" and your entry is
"CreateFunction" then the first line below will load the Dll, the second
line will create the custom function, while the third line (run when your
are done with costom function) will unload the library.
slRunProc "T", 0, 0, "", "", "L"
slRunProc "TCreateFunction", 0, 0, "", ""
slRunProc "T", 0, 0, "", "", "U"
Another way to accomplish the same thing with one less call to the server is
to use the "u" modchar on the call to create the custom function (shown in
line one below) and then unload the library, when you no longer need it,
with line two.
slRunProc "TCreateFunction", 0, 0, "", "", "u"
slRunProc "T", 0, 0, "", "", "U"