summaryrefslogtreecommitdiffstats
path: root/win/tclWinLoad.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinLoad.c')
-rw-r--r--win/tclWinLoad.c229
1 files changed, 124 insertions, 105 deletions
diff --git a/win/tclWinLoad.c b/win/tclWinLoad.c
index 3f4d4d9..5848daa 100644
--- a/win/tclWinLoad.c
+++ b/win/tclWinLoad.c
@@ -14,24 +14,22 @@
#include "tclWinInt.h"
/*
- * Mutex protecting static data in this file;
+ * Native name of the directory in the native filesystem where DLLs used in
+ * this process are copied prior to loading, and mutex used to protect its
+ * allocation.
*/
-static Tcl_Mutex loadMutex;
+static WCHAR *dllDirectoryName = NULL;
+static Tcl_Mutex dllDirectoryNameMutex;
/*
- * Name of the directory in the native filesystem where DLLs used in this
- * process are copied prior to loading.
+ * Static functions defined within this file.
*/
-static WCHAR* dllDirectoryName = NULL;
-
-/* Static functions defined within this file */
-
-void* FindSymbol(Tcl_Interp* interp, Tcl_LoadHandle loadHandle,
- const char* symbol);
-void UnloadFile(Tcl_LoadHandle loadHandle);
-
+static void * FindSymbol(Tcl_Interp *interp,
+ Tcl_LoadHandle loadHandle, const char *symbol);
+static void InitDLLDirectoryName(void);
+static void UnloadFile(Tcl_LoadHandle loadHandle);
/*
*----------------------------------------------------------------------
@@ -75,8 +73,7 @@ TclpDlopen(
*/
nativeName = Tcl_FSGetNativePath(pathPtr);
- hInstance = LoadLibraryEx(nativeName, NULL,
- LOAD_WITH_ALTERED_SEARCH_PATH);
+ hInstance = LoadLibraryEx(nativeName,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);
if (hInstance == NULL) {
/*
* Let the OS loader examine the binary search path for whatever
@@ -85,9 +82,8 @@ TclpDlopen(
*/
Tcl_DString ds;
- const char *fileName = Tcl_GetString(pathPtr);
- nativeName = Tcl_WinUtfToTChar(fileName, -1, &ds);
+ nativeName = Tcl_WinUtfToTChar(Tcl_GetString(pathPtr), -1, &ds);
hInstance = LoadLibraryEx(nativeName, NULL,
LOAD_WITH_ALTERED_SEARCH_PATH);
Tcl_DStringFree(&ds);
@@ -96,23 +92,6 @@ TclpDlopen(
if (hInstance == NULL) {
DWORD lastError = GetLastError();
-#if 0
- /*
- * It would be ideal if the FormatMessage stuff worked better, but
- * unfortunately it doesn't seem to want to...
- */
-
- LPTSTR lpMsgBuf;
- char *buf;
- int size;
-
- size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, lastError, 0,
- (LPTSTR) &lpMsgBuf, 0, NULL);
- buf = ckalloc(TCL_INTEGER_SPACE + size + 1);
- sprintf(buf, "%d %s", lastError, (char *)lpMsgBuf);
-#endif
-
Tcl_AppendResult(interp, "couldn't load library \"",
Tcl_GetString(pathPtr), "\": ", NULL);
@@ -185,24 +164,25 @@ TclpDlopen(
*----------------------------------------------------------------------
*/
-void *
+static void *
FindSymbol(
Tcl_Interp *interp,
Tcl_LoadHandle loadHandle,
const char *symbol)
{
+ HINSTANCE hInstance = (HINSTANCE) loadHandle->clientData;
Tcl_PackageInitProc *proc = NULL;
- HINSTANCE hInstance = (HINSTANCE)(loadHandle->clientData);
/*
* For each symbol, check for both Symbol and _Symbol, since Borland
* generates C symbols with a leading '_' by default.
*/
- proc = (void*) GetProcAddress(hInstance, symbol);
+ proc = (void *) GetProcAddress(hInstance, symbol);
if (proc == NULL) {
Tcl_DString ds;
- const char* sym2;
+ const char *sym2;
+
Tcl_DStringInit(&ds);
Tcl_DStringAppend(&ds, "_", 1);
sym2 = Tcl_DStringAppend(&ds, symbol, -1);
@@ -234,7 +214,7 @@ FindSymbol(
*----------------------------------------------------------------------
*/
-void
+static void
UnloadFile(
Tcl_LoadHandle loadHandle) /* loadHandle returned by a previous call to
* TclpDlopen(). The loadHandle is a token
@@ -277,7 +257,7 @@ TclGuessPackageName(
}
/*
- *-----------------------------------------------------------------------------
+ *----------------------------------------------------------------------
*
* TclpTempFileNameForLibrary --
*
@@ -287,86 +267,125 @@ TclGuessPackageName(
* Returns the constructed file name.
*
* On Windows, a DLL is identified by the final component of its path name.
- * Cross linking among DLL's (and hence, preloading) will not work unless
- * this name is preserved when copying a DLL from a VFS to a temp file for
- * preloading. For this reason, all DLLs in a given process are copied
- * to a temp directory, and their names are preserved.
+ * Cross linking among DLL's (and hence, preloading) will not work unless this
+ * name is preserved when copying a DLL from a VFS to a temp file for
+ * preloading. For this reason, all DLLs in a given process are copied to a
+ * temp directory, and their names are preserved.
*
- *-----------------------------------------------------------------------------
+ *----------------------------------------------------------------------
*/
-Tcl_Obj*
-TclpTempFileNameForLibrary(Tcl_Interp* interp, /* Tcl interpreter */
- Tcl_Obj* path) /* Path name of the DLL in
- * the VFS */
+Tcl_Obj *
+TclpTempFileNameForLibrary(
+ Tcl_Interp *interp, /* Tcl interpreter. */
+ Tcl_Obj *path) /* Path name of the DLL in the VFS. */
{
- size_t nameLen; /* Length of the temp folder name */
- WCHAR name[MAX_PATH]; /* Path name of the temp folder */
- BOOL status; /* Status from Win32 API calls */
- Tcl_Obj* fileName; /* Name of the temp file */
- Tcl_Obj* tail; /* Tail of the source path */
+ Tcl_Obj *fileName; /* Name of the temp file. */
+ Tcl_Obj *tail; /* Tail of the source path. */
- /*
- * Determine the name of the directory to use, and create it.
- * (Keep trying with new names until an attempt to create the directory
- * succeeds)
- */
-
- nameLen = 0;
+ Tcl_MutexLock(&dllDirectoryNameMutex);
if (dllDirectoryName == NULL) {
- Tcl_MutexLock(&loadMutex);
- if (dllDirectoryName == NULL) {
- nameLen = GetTempPathW(MAX_PATH, name);
- if (nameLen >= MAX_PATH-12) {
- Tcl_SetErrno(ENAMETOOLONG);
- nameLen = 0;
- } else {
- wcscpy(name+nameLen, L"TCLXXXXXXXX");
- nameLen += 11;
- }
- status = 1;
- if (nameLen != 0) {
- DWORD id;
- int i = 0;
- id = GetCurrentProcessId();
- for (;;) {
- DWORD lastError;
- wsprintfW(name+nameLen-8, L"%08x", id);
- status = CreateDirectoryW(name, NULL);
- if (status) {
- break;
- }
- if ((lastError = GetLastError()) != ERROR_ALREADY_EXISTS) {
- TclWinConvertError(lastError);
- break;
- } else if (++i > 256) {
- TclWinConvertError(lastError);
- break;
- }
- id *= 16777619;
- }
- }
- if (status != 0) {
- dllDirectoryName = ckalloc((nameLen+1) * sizeof(WCHAR));
- wcscpy(dllDirectoryName, name);
- }
+ if (InitDLLDirectoryName() == TCL_ERROR) {
+ Tcl_AppendResult(interp, "couldn't create temporary directory: ",
+ Tcl_PosixError(interp), NULL);
+ Tcl_MutexUnlock(&dllDirectoryNameMutex);
+ return NULL;
}
- Tcl_MutexUnlock(&loadMutex);
- }
- if (dllDirectoryName == NULL) {
- Tcl_AppendResult(interp, "couldn't create temporary directory: ",
- Tcl_PosixError(interp), NULL);
}
+ Tcl_MutexUnlock(&dllDirectoryNameMutex);
+
+ /*
+ * Now we know where to put temporary DLLs, construct the name.
+ */
+
fileName = TclpNativeToNormalized(dllDirectoryName);
tail = TclPathPart(interp, path, TCL_PATH_TAIL);
if (tail == NULL) {
Tcl_DecrRefCount(fileName);
return NULL;
- } else {
- Tcl_AppendToObj(fileName, "/", 1);
- Tcl_AppendObjToObj(fileName, tail);
- return fileName;
}
+ Tcl_AppendToObj(fileName, "/", 1);
+ Tcl_AppendObjToObj(fileName, tail);
+ return fileName;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * InitDLLDirectoryName --
+ *
+ * Helper for TclpTempFileNameForLibrary; builds a temporary directory
+ * that is specific to the current process. Should only be called once
+ * per process start. Caller must hold dllDirectoryNameMutex.
+ *
+ * Results:
+ * Tcl result code.
+ *
+ * Side-effects:
+ * Creates temp directory.
+ * Allocates memory pointed to by dllDirectoryName.
+ *
+ *----------------------------------------------------------------------
+ * [Candidate for process global?]
+ */
+
+static int
+InitDLLDirectoryName(void)
+{
+ size_t nameLen; /* Length of the temp folder name. */
+ WCHAR name[MAX_PATH]; /* Path name of the temp folder. */
+ DWORD id; /* The process id. */
+ DWORD lastError; /* Last error to happen in Win API. */
+ int i;
+
+ /*
+ * Determine the name of the directory to use, and create it. (Keep
+ * trying with new names until an attempt to create the directory
+ * succeeds)
+ */
+
+ nameLen = GetTempPathW(MAX_PATH, name);
+ if (nameLen >= MAX_PATH-12) {
+ Tcl_SetErrno(ENAMETOOLONG);
+ return TCL_ERROR;
+ }
+
+ wcscpy(name+nameLen, L"TCLXXXXXXXX");
+ nameLen += 11;
+
+ id = GetCurrentProcessId();
+ lastError = ERROR_ALREADY_EXISTS;
+
+ for (i=0 ; i<256 ; i++) {
+ wsprintfW(name+nameLen-8, L"%08x", id);
+ if (CreateDirectoryW(name, NULL)) {
+ /*
+ * Issue: we don't schedule this directory for deletion by anyone.
+ * Can we ask the OS to do this for us? There appears to be
+ * potential for using CreateFile (with the flag
+ * FILE_FLAG_BACKUP_SEMANTICS) and RemoveDirectory to do this...
+ */
+
+ goto copyToGlobalBuffer;
+ }
+ lastError = GetLastError();
+ if (lastError != ERROR_ALREADY_EXISTS) {
+ break;
+ }
+ id *= 16777619;
+ }
+
+ TclWinConvertError(lastError);
+ return TCL_ERROR;
+
+ /*
+ * Store our computed value in the global.
+ */
+
+ copyToGlobalBuffer:
+ dllDirectoryName = ckalloc((nameLen+1) * sizeof(WCHAR));
+ wcscpy(dllDirectoryName, name);
+ return TCL_OK;
}
/*