Subject: Re: Cross platform loading / linking mechanism. (was Re: Extension Installation and Tcl Bug) - DN [1]
davygrvy@bigfoot.com (David Gravereaux) - 08 Aug 1999 - comp.lang.tcl
----=_37ace593772404889052a4179.MFSBCHJLHS
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Paul,
Here's the logic as far as I can see through my "rosey" WIN32 goggles
:)
How's this look so far?
tclWinDlLoad.c gets dropped in tcl8.2b1/win/. That's an edit on Jan's
dlopen() routines he posted on c.l.t back in May and could be extended
to cross-over into TclpLoadFile.
* David Gravereaux *
Tomahawk Software Group
----=_37ace593772404889052a4179.MFSBCHJLHS
Content-Type: text/plain; charset=us-ascii; name=main.c
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=main.c
#include <stdlib.h>
#include <string.h>
#define _TCLDECLS /* lets make sure we don't touch ANY Tcl library functions */
#include "e:/TclCVS/tcl8.2b1/generic/tclPort.h"
#include "e:/TclCVS/tcl8.2b1/compat/dlfcn.h"
#ifdef _WIN32
char *prefix = "\\bin\\tcl";
#endif
char *sharedlibextension = TCL_SHLIB_EXT;
char *tclvers[] = { "8.4", "8.3", "8.2", "8.1", NULL };
VOID *stubTclLibHnd;
char *stubLoadErrorMsg;
static VOID stubBuildTrailing(pos, ver, dbgOnly)
char *pos;
char *ver;
int dbgOnly;
{
char *pos2;
/* append version w/o decimal */
pos2 = ver;
while (*pos2 != '\0') {
if (*pos2 != '.') *pos++ = *pos2++;
else pos2++;
};
/* if asked, add the debug suffix */
if (dbgOnly != 0) *pos++ = 'd';
/* append the extension */
pos2 = sharedlibextension;
while (*pos2 != '\0') {
*pos++ = *pos2++;
};
/* terminate it */
*pos = '\0';
};
char *Stub_LoadTcl (minVer, exact, dbgOnly)
char *minVer;
int exact;
int dbgOnly;
{
char *tclRootPath = NULL;
char tcllibfullpath[_MAX_PATH];
char *savedPos;
char *pos, *pos2;
#ifdef _WIN32
HKEY topTclKey;
HKEY subTclVer;
DWORD max_path = _MAX_PATH;
LONG result;
#endif
/* Try the environment variable first. This overrides everything. */
tclRootPath = getenv("TCL_LIBRARY_PATH");
if (tclRootPath != NULL) {
pos = tcllibfullpath;
while (*tclRootPath != '\0') {
*pos++ = *tclRootPath++;
};
/* append the bin directory and prefix */
pos2 = prefix;
while (*pos2 != '\0') {
*pos++ = *pos2++;
};
savedPos = pos;
if (exact != 0) {
/* build the end of the filename from the parameter given */
stubBuildTrailing(savedPos, minVer, dbgOnly);
/* Try it */
if ((stubTclLibHnd = dlopen(tcllibfullpath, RTLD_NOW)) != NULL)
return minVer;
/* Not successfull, save error */
//stubLoadErrorMsg = dlerror();
//return NULL;
} else {
int i = 0;
/* Try a range of filenames starting at the top and working down */
while (tclvers[i] != NULL && strcmp(tclvers[i],minVer) >= 0) {
/* build the end of the filename */
stubBuildTrailing(savedPos, tclvers[i], dbgOnly);
/* Try it */
if ((stubTclLibHnd = dlopen(tcllibfullpath, RTLD_NOW)) != NULL)
return tclvers[i];
i++;
};
}
/*
* A suitable Tcl library hasn't been found yet.
* Keep falling through.
*/
}
#ifdef _WIN32
result = RegOpenKeyEx(
HKEY_LOCAL_MACHINE, "SOFTWARE\\Scriptics\\Tcl", 0,
KEY_ENUMERATE_SUB_KEYS, &topTclKey
);
if (result != ERROR_SUCCESS) {
/* do some error thing here. */
goto Next;
};
if (exact != 0) {
/* Just try the requested only */
result = RegOpenKeyEx(
topTclKey, minVer, 0,
KEY_READ, &subTclVer
);
if (result != ERROR_SUCCESS) {
/* Subkey for exact version not found. */
goto Next;
};
/* Retrieve location and load it. */
result =
RegQueryValueEx(subTclVer, "Root", NULL, NULL, tcllibfullpath, &max_path);
if (result != ERROR_SUCCESS) {
stubLoadErrorMsg = "SubKey found in registry for exact match, but no Root value set.";
return NULL;
};
pos = tcllibfullpath + strlen(tcllibfullpath);
/* append the bin directory and prefix */
pos2 = prefix;
while (*pos2 != '\0') {
*pos++ = *pos2++;
};
savedPos = pos;
/* build the end of the filename from the parameter given */
stubBuildTrailing(savedPos, minVer, dbgOnly);
/* Try it */
if ((stubTclLibHnd = dlopen(tcllibfullpath, RTLD_NOW)) != NULL)
return minVer;
} else {
/* Enumerate the subkeys starting at the top */
int i;
/* Try a range of filenames starting at the top and working down */
for (i = 0; tclvers[i] != NULL && strcmp(tclvers[i],minVer) >= 0; i++) {
result = RegOpenKeyEx(topTclKey, tclvers[i], 0, KEY_READ, &subTclVer);
if (result != ERROR_SUCCESS) {
continue;
};
/* Try it. */
result =
RegQueryValueEx(subTclVer, "Root", NULL, NULL, tcllibfullpath, &max_path);
if (result != ERROR_SUCCESS) {
/* Odd... SubKey is there, but no Root value. */
continue;
};
pos = tcllibfullpath + strlen(tcllibfullpath);
/* append the bin directory and prefix */
pos2 = prefix;
while (*pos2 != '\0') {
*pos++ = *pos2++;
};
savedPos = pos;
/* build the end of the filename */
stubBuildTrailing(savedPos, tclvers[i], dbgOnly);
/* Try it */
if ((stubTclLibHnd = dlopen(tcllibfullpath, RTLD_NOW)) != NULL)
return tclvers[i];
};
/*
* A suitable Tcl library hasn't been found yet.
* Keep falling through.
*/
};
Next:
#endif
/* Try current directory. Last chance. You better work. */
pos = tcllibfullpath;
pos2 = "tcl";
while (*pos2 != '\0') {
*pos++ = *pos2++;
};
savedPos = pos;
if (exact != 0) {
stubBuildTrailing(savedPos, minVer, dbgOnly);
/* Try it */
if ((stubTclLibHnd = dlopen(tcllibfullpath, RTLD_NOW)) != NULL)
return minVer;
} else {
int i;
/* Try a range of filenames starting at the top and working down */
for (i = 0; tclvers[i] != NULL && strcmp(tclvers[i],minVer) >= 0; i++) {
/* build the end of the filename */
stubBuildTrailing(savedPos, tclvers[i], dbgOnly);
/* Try it */
if ((stubTclLibHnd = dlopen(tcllibfullpath, RTLD_NOW)) != NULL)
return tclvers[i];
};
}
stubLoadErrorMsg = "A proper Tcl library could not be located.";
return NULL;
}
VOID Stub_UnLoadTcl () {
dlclose(stubTclLibHnd);
};
char *Stub_LoadTclError() {
return stubLoadErrorMsg;
};
int main (int argc, char *argv[]) {
char *verloaded;
if ((verloaded = Stub_LoadTcl(/*minver*/"8.2", /*exact*/0, /*debug*/0)) == NULL) {
printf("%s", Stub_LoadTclError());
return 1;
};
printf("tcl v%s was loaded\n", verloaded);
Stub_UnLoadTcl();
return 0;
}
----=_37ace593772404889052a4179.MFSBCHJLHS
Content-Type: text/plain; charset=us-ascii; name=tclWinDlLoad.c
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename=tclWinDlLoad.c
/*
* tclWinDlLoad.c --
*
* This procedure provides a version of dlopen() that
* works with the Windows "LoadLibrary" and "GetProcAddress"
* API for dynamic loading.
*
* These routines do not contain any dependancies for the
* Tcl library so they can be used specificly for loading one
* in a Stub'd application.
*
* They could also be integrated into TclpLoadFile, should it be desired.
*
* code from a c.l.t post:
* Sub: [Request Tcl 8.1] Dynamical loading enhancement for extensions
* Date: 05/20/1999
* Author: Jan Nijtmans <jan.nijtmans@wxs.nl>
*
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
#include "../compat/dlfcn.h"
char WinErrorMsg[1024];
/*
*----------------------------------------------------------------------
*
* dlopen --
*
* This function is an alternative for the functions
* TclWinLoadLibrary and TclWinGetTclInstance.
*
* Results:
* Returns the handle of the newly loaded library, or NULL on
* failure. If path is NULL, the global library instance handle
* is returned.
*
* Side effects:
* Loads the specified library into the process.
*
*----------------------------------------------------------------------
*/
VOID *dlopen(path, mode)
const char *path;
int mode;
{
HMODULE mod;
mod = LoadLibrary(path);
if (mod <= (HMODULE) HINSTANCE_ERROR) return NULL;
return (VOID *) mod;
};
/*
*----------------------------------------------------------------------
*
* dlclose --
*
* This function is an alternative for the function
* FreeLibrary. It is responsible for removing library
* handles from the library list and remove the dll
* from memory.
*
* Results:
* -1 on error, 0 on success.
*
* Side effects:
* Unmaps and removes the specified library from the process.
*
*----------------------------------------------------------------------
*/
int
dlclose(handle)
VOID *handle;
{
BOOL rtn;
rtn = FreeLibrary((HMODULE) handle);
if (rtn != 0) return 0;
return -1;
}
/*
*----------------------------------------------------------------------
*
* dlsym --
*
* This function is an alternative for the system function
* GetProcAddress. It returns the address of a
* symbol, give the handle returned by dlopen().
*
* Results:
* Returns the address of the symbol in the dll.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
VOID *dlsym(handle, symbol)
VOID *handle;
CONST char *symbol;
{
return (VOID *) GetProcAddress((HMODULE) handle, symbol);
}
/*
*----------------------------------------------------------------------
*
* dlerror --
*
* This function returns a string describing the error which
* occurred in dlopen().
*
* Results:
* Returns an error message.
*
* Side effects:
* errno is not set.
*
*----------------------------------------------------------------------
*/
char *
dlerror()
{
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
WinErrorMsg, 1024, NULL
);
return WinErrorMsg;
}
----=_37ace593772404889052a4179.MFSBCHJLHS--
Last modified
1999-09-27
1999-09-27
(195.108.246.50)
Note: you are looking at
the snapshot of an old wiki
- much of this information
is likely to be very outdated
