summaryrefslogtreecommitdiffstats
path: root/win/tclWin32Dll.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWin32Dll.c')
-rw-r--r--win/tclWin32Dll.c707
1 files changed, 615 insertions, 92 deletions
diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c
index 7c3d8a4..e5e5202 100644
--- a/win/tclWin32Dll.c
+++ b/win/tclWin32Dll.c
@@ -4,17 +4,38 @@
* This file contains the DLL entry point and other low-level bit bashing
* code that needs inline assembly.
*
- * Copyright © 1995-1996 Sun Microsystems, Inc.
- * Copyright © 1998-2000 Scriptics Corporation.
+ * Copyright (c) 1995-1996 Sun Microsystems, Inc.
+ * Copyright (c) 1998-2000 Scriptics Corporation.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "tclWinInt.h"
-#if defined(HAVE_INTRIN_H)
-# include <intrin.h>
-#endif
+
+#ifndef TCL_NO_STACK_CHECK
+/*
+ * The following functions implement stack depth checking
+ */
+typedef struct ThreadSpecificData {
+ int *stackBound; /* The current stack boundary */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+#endif /* TCL_NO_STACK_CHECK */
+
+/*
+ * The following data structures are used when loading the thunking library
+ * for execing child processes under Win32s.
+ */
+
+typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined,
+ LPVOID *lpTranslationList);
+
+typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL,
+ LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk,
+ FARPROC UT32Callback, LPVOID Buff);
+
+typedef VOID (WINAPI UTUNREGISTER)(HANDLE hModule);
/*
* The following variables keep track of information about this DLL on a
@@ -23,13 +44,160 @@
*/
static HINSTANCE hInstance; /* HINSTANCE of this DLL. */
+static int platformId; /* Running under NT, or 95/98? */
/*
+ * VC++ 5.x has no 'cpuid' assembler instruction, so we must emulate it
+ */
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1100)
+#define cpuid __asm __emit 0fh __asm __emit 0a2h
+#endif
+
+/*
+ * The following function tables are used to dispatch to either the
+ * wide-character or multi-byte versions of the operating system calls,
+ * depending on whether the Unicode calls are available.
+ */
+
+static TclWinProcs asciiProcs = {
+ 0,
+
+ (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBA,
+ (TCHAR *(WINAPI *)(TCHAR *)) CharLowerA,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileA,
+ (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryA,
+ (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *,
+ DWORD, DWORD, HANDLE)) CreateFileA,
+ (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES,
+ LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *,
+ LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessA,
+ (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileA,
+ (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileA,
+ (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileA,
+ (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameA,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryA,
+ (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesA,
+ (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *,
+ TCHAR **)) GetFullPathNameA,
+ (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA,
+ (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA,
+ (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique,
+ WCHAR *)) GetTempFileNameA,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA,
+ (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
+ WCHAR *, DWORD)) GetVolumeInformationA,
+ (HINSTANCE (WINAPI *)(CONST TCHAR *, HANDLE, DWORD)) LoadLibraryExA,
+ (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyA,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA,
+ (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA,
+ (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD,
+ WCHAR *, TCHAR **)) SearchPathA,
+ (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA,
+ (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA,
+
+ /*
+ * The three NULL function pointers will only be set when
+ * Tcl_FindExecutable is called. If you don't ever call that function, the
+ * application will crash whenever WinTcl tries to call functions through
+ * these null pointers. That is not a bug in Tcl - Tcl_FindExecutable is
+ * mandatory in recent Tcl releases.
+ */
+
+ NULL,
+ NULL,
+ /* deleted (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime, */
+ NULL,
+ NULL,
+ /* getLongPathNameProc */
+ NULL,
+ /* Security SDK - not available on 95,98,ME */
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ /* ReadConsole and WriteConsole */
+ (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleA,
+ (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleA,
+ (BOOL (WINAPI *)(LPTSTR, LPDWORD)) GetUserNameA
+};
+
+static TclWinProcs unicodeProcs = {
+ 1,
+
+ (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBW,
+ (TCHAR *(WINAPI *)(TCHAR *)) CharLowerW,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileW,
+ (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryW,
+ (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *,
+ DWORD, DWORD, HANDLE)) CreateFileW,
+ (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES,
+ LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *,
+ LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessW,
+ (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileW,
+ (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileW,
+ (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileW,
+ (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameW,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryW,
+ (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesW,
+ (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *,
+ TCHAR **)) GetFullPathNameW,
+ (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW,
+ (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW,
+ (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique,
+ WCHAR *)) GetTempFileNameW,
+ (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW,
+ (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
+ WCHAR *, DWORD)) GetVolumeInformationW,
+ (HINSTANCE (WINAPI *)(CONST TCHAR *, HANDLE, DWORD)) LoadLibraryExW,
+ (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyW,
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW,
+ (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW,
+ (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD,
+ WCHAR *, TCHAR **)) SearchPathW,
+ (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW,
+ (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW,
+
+ /*
+ * The three NULL function pointers will only be set when
+ * Tcl_FindExecutable is called. If you don't ever call that function, the
+ * application will crash whenever WinTcl tries to call functions through
+ * these null pointers. That is not a bug in Tcl - Tcl_FindExecutable is
+ * mandatory in recent Tcl releases.
+ */
+
+ NULL,
+ NULL,
+ /* deleted (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime, */
+ NULL,
+ NULL,
+ /* getLongPathNameProc */
+ NULL,
+ /* Security SDK - will be filled in on NT,XP,2000,2003 */
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ /* ReadConsole and WriteConsole */
+ (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleW,
+ (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleW,
+ (BOOL (WINAPI *)(LPTSTR, LPDWORD)) GetUserNameW
+};
+
+TclWinProcs *tclWinProcs;
+static Tcl_Encoding tclWinTCharEncoding;
+
+#ifdef HAVE_NO_SEH
+/*
+ * Need to add noinline flag to DllMain declaration so that gcc -O3 does not
+ * inline asm code into DllEntryPoint and cause a compile time error because
+ * of redefined local labels.
+ */
+
+BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
+ LPVOID reserved) __attribute__ ((noinline));
+#else
+/*
* The following declaration is for the VC++ DLL entry point.
*/
BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
LPVOID reserved);
+#endif /* HAVE_NO_SEH */
/*
* The following structure and linked list is to allow us to map between
@@ -38,8 +206,8 @@ BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
*/
typedef struct MountPointMap {
- WCHAR *volumeName; /* Native wide string volume name. */
- WCHAR driveLetter; /* Drive letter corresponding to the volume
+ CONST WCHAR *volumeName; /* Native wide string volume name. */
+ char driveLetter; /* Drive letter corresponding to the volume
* name. */
struct MountPointMap *nextPtr;
/* Pointer to next structure in list, or
@@ -58,7 +226,9 @@ TCL_DECLARE_MUTEX(mountPointMap)
* We will need this below.
*/
-#ifdef _WIN32
+extern Tcl_FSDupInternalRepProc TclNativeDupInternalRep;
+
+#ifdef __WIN32__
#ifndef STATIC_BUILD
/*
@@ -82,7 +252,7 @@ BOOL APIENTRY
DllEntryPoint(
HINSTANCE hInst, /* Library instance handle. */
DWORD reason, /* Reason this function is being called. */
- LPVOID reserved)
+ LPVOID reserved) /* Not used. */
{
return DllMain(hInst, reason, reserved);
}
@@ -100,7 +270,10 @@ DllEntryPoint(
* TRUE on sucess, FALSE on failure.
*
* Side effects:
- * Initializes most rudimentary Windows bits.
+ * Establishes 32-to-16 bit thunk and initializes sockets library. This
+ * might call some sycronization functions, but MSDN documentation
+ * states: "Waiting on synchronization objects in DllMain can cause a
+ * deadlock."
*
*----------------------------------------------------------------------
*/
@@ -109,24 +282,113 @@ BOOL APIENTRY
DllMain(
HINSTANCE hInst, /* Library instance handle. */
DWORD reason, /* Reason this function is being called. */
- TCL_UNUSED(LPVOID))
+ LPVOID reserved) /* Not used. */
{
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ TCLEXCEPTION_REGISTRATION registration;
+#endif
+
switch (reason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInst);
TclWinInit(hInst);
return TRUE;
+ case DLL_PROCESS_DETACH:
/*
- * DLL_PROCESS_DETACH is unnecessary as the user should call
- * Tcl_Finalize explicitly before unloading Tcl.
+ * Protect the call to Tcl_Finalize. The OS could be unloading us from
+ * an exception handler and the state of the stack might be unstable.
*/
+
+#if defined(HAVE_NO_SEH) && !defined(_WIN64)
+ __asm__ __volatile__ (
+
+ /*
+ * Construct an TCLEXCEPTION_REGISTRATION to protect the call to
+ * Tcl_Finalize
+ */
+
+ "leal %[registration], %%edx" "\n\t"
+ "movl %%fs:0, %%eax" "\n\t"
+ "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
+ "leal 1f, %%eax" "\n\t"
+ "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
+ "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
+ "movl %[error], 0x10(%%edx)" "\n\t" /* status */
+
+ /*
+ * Link the TCLEXCEPTION_REGISTRATION on the chain
+ */
+
+ "movl %%edx, %%fs:0" "\n\t"
+
+ /*
+ * Call Tcl_Finalize
+ */
+
+ "call _Tcl_Finalize" "\n\t"
+
+ /*
+ * Come here on a normal exit. Recover the TCLEXCEPTION_REGISTRATION
+ * and store a TCL_OK status
+ */
+
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl %[ok], %%eax" "\n\t"
+ "movl %%eax, 0x10(%%edx)" "\n\t"
+ "jmp 2f" "\n"
+
+ /*
+ * Come here on an exception. Get the TCLEXCEPTION_REGISTRATION that
+ * we previously put on the chain.
+ */
+
+ "1:" "\t"
+ "movl %%fs:0, %%edx" "\n\t"
+ "movl 0x8(%%edx), %%edx" "\n"
+
+
+ /*
+ * Come here however we exited. Restore context from the
+ * TCLEXCEPTION_REGISTRATION in case the stack is unbalanced.
+ */
+
+ "2:" "\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
+ "movl 0x8(%%edx), %%ebp" "\n\t"
+ "movl 0x0(%%edx), %%eax" "\n\t"
+ "movl %%eax, %%fs:0" "\n\t"
+
+ :
+ /* No outputs */
+ :
+ [registration] "m" (registration),
+ [ok] "i" (TCL_OK),
+ [error] "i" (TCL_ERROR)
+ :
+ "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
+ );
+
+#else
+#ifndef HAVE_NO_SEH
+ __try {
+#endif
+ Tcl_Finalize();
+#ifndef HAVE_NO_SEH
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ /* empty handler body. */
+ }
+#endif
+#endif
+
+ break;
}
return TRUE;
}
#endif /* !STATIC_BUILD */
-#endif /* _WIN32 */
+#endif /* __WIN32__ */
/*
*----------------------------------------------------------------------
@@ -175,15 +437,44 @@ TclWinInit(
hInstance = hInst;
os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
GetVersionExW(&os);
+ platformId = os.dwPlatformId;
/*
- * We no longer support Win32s or Win9x or Windows CE or Windows XP, so just
- * in case someone manages to get a runtime there, make sure they know that.
+ * We no longer support Win32s, so just in case someone manages to get a
+ * runtime there, make sure they know that.
*/
- if (os.dwPlatformId != VER_PLATFORM_WIN32_NT) {
- Tcl_Panic("Windows 7 is the minimum supported platform");
+ if (platformId == VER_PLATFORM_WIN32s) {
+ Tcl_Panic("Win32s is not a supported platform");
}
+
+ tclWinProcs = &asciiProcs;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclWinGetPlatformId --
+ *
+ * Determines whether running under NT, 95, or Win32s, to allow runtime
+ * conditional code.
+ *
+ * Results:
+ * The return value is one of:
+ * VER_PLATFORM_WIN32s Win32s on Windows 3.1. (not supported)
+ * VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95, 98, ME.
+ * VER_PLATFORM_WIN32_NT Win32 on Windows NT, 2000, XP
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclWinGetPlatformId(void)
+{
+ return platformId;
}
/*
@@ -218,12 +509,95 @@ TclWinNoBackslash(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * TclpGetStackParams --
+ *
+ * Determine the stack params for the current thread: in which
+ * direction does the stack grow, and what is the stack lower (resp.
+ * upper) bound for safe invocation of a new command? This is used to
+ * cache the values needed for an efficient computation of
+ * TclpCheckStackSpace() when the interp is known.
+ *
+ * Results:
+ * Returns 1 if the stack grows down, in which case a stack lower bound
+ * is stored at stackBoundPtr. If the stack grows up, 0 is returned and
+ * an upper bound is stored at stackBoundPtr. If a bound cannot be
+ * determined NULL is stored at stackBoundPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+#ifndef TCL_NO_STACK_CHECK
+int
+TclpGetCStackParams(
+ int **stackBoundPtr)
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ SYSTEM_INFO si; /* The system information, used to
+ * determine the page size */
+ MEMORY_BASIC_INFORMATION mbi;
+ /* The information about the memory
+ * area in which the stack resides */
+
+ if (!tsdPtr->stackBound
+ || ((UINT_PTR)&tsdPtr < (UINT_PTR)tsdPtr->stackBound)) {
+
+ /*
+ * Either we haven't determined the stack bound in this thread,
+ * or else we've overflowed the bound that we previously
+ * determined. We need to find a new stack bound from
+ * Windows.
+ */
+
+ GetSystemInfo(&si);
+ if (VirtualQuery((LPCVOID) &tsdPtr, &mbi, sizeof(mbi)) == 0) {
+
+ /* For some reason, the system didn't let us query the
+ * stack size. Nevertheless, we got here and haven't
+ * blown up yet. Don't update the calculated stack bound.
+ * If there is no calculated stack bound yet, set it to
+ * the base of the current page of stack. */
+
+ if (!tsdPtr->stackBound) {
+ tsdPtr->stackBound =
+ (int*) ((UINT_PTR)(&tsdPtr)
+ & ~ (UINT_PTR)(si.dwPageSize - 1));
+ }
+
+ } else {
+
+ /* The allocation base of the stack segment has to be advanced
+ * by one page (to allow for the guard page maintained in the
+ * C runtime) and then by TCL_WIN_STACK_THRESHOLD (to allow
+ * for the amount of stack that Tcl needs).
+ */
+
+ tsdPtr->stackBound =
+ (int*) ((UINT_PTR)(mbi.AllocationBase)
+ + (UINT_PTR)(si.dwPageSize)
+ + TCL_WIN_STACK_THRESHOLD);
+ }
+ }
+ *stackBoundPtr = tsdPtr->stackBound;
+ return 1;
+}
+#endif
+
+
+/*
*---------------------------------------------------------------------------
*
- * TclWinEncodingsCleanup --
+ * TclWinSetInterfaces --
*
- * Called during finalization to clean up any memory allocated in our
- * mount point map which is used to follow certain kinds of symlinks.
+ * A helper proc that allows the test library to change the tclWinProcs
+ * structure to dispatch to either the wide-character or multi-byte
+ * versions of the operating system calls, depending on whether Unicode
+ * is the system encoding.
+ *
+ * As well as this, we can also try to load in some additional procs
+ * which may/may not be present depending on the current Windows version
+ * (e.g. Win95 will not have the procs below).
*
* Results:
* None.
@@ -235,9 +609,137 @@ TclWinNoBackslash(
*/
void
-TclWinEncodingsCleanup(void)
+TclWinSetInterfaces(
+ int wide) /* Non-zero to use wide interfaces, 0
+ * otherwise. */
+{
+ Tcl_FreeEncoding(tclWinTCharEncoding);
+
+ if (wide) {
+ tclWinProcs = &unicodeProcs;
+ tclWinTCharEncoding = Tcl_GetEncoding(NULL, "unicode");
+ if (tclWinProcs->getFileAttributesExProc == NULL) {
+ HINSTANCE hInstance = LoadLibraryA("kernel32");
+ if (hInstance != NULL) {
+ tclWinProcs->getFileAttributesExProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS,
+ LPVOID)) GetProcAddress(hInstance,
+ "GetFileAttributesExW");
+ tclWinProcs->createHardLinkProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*,
+ LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance,
+ "CreateHardLinkW");
+ tclWinProcs->findFirstFileExProc =
+ (HANDLE (WINAPI *)(CONST TCHAR*, UINT, LPVOID, UINT,
+ LPVOID, DWORD)) GetProcAddress(hInstance,
+ "FindFirstFileExW");
+ tclWinProcs->getVolumeNameForVMPProc =
+ (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*,
+ DWORD)) GetProcAddress(hInstance,
+ "GetVolumeNameForVolumeMountPointW");
+ tclWinProcs->getLongPathNameProc =
+ (DWORD (WINAPI *)(CONST TCHAR*, TCHAR*,
+ DWORD)) GetProcAddress(hInstance, "GetLongPathNameW");
+ FreeLibrary(hInstance);
+ }
+ hInstance = LoadLibraryA("advapi32");
+ if (hInstance != NULL) {
+ tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
+ LPCTSTR lpFileName,
+ SECURITY_INFORMATION RequestedInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD nLength, LPDWORD lpnLengthNeeded))
+ GetProcAddress(hInstance, "GetFileSecurityW");
+ tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) (
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel))
+ GetProcAddress(hInstance, "ImpersonateSelf");
+ tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) (
+ HANDLE ThreadHandle, DWORD DesiredAccess,
+ BOOL OpenAsSelf, PHANDLE TokenHandle))
+ GetProcAddress(hInstance, "OpenThreadToken");
+ tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void))
+ GetProcAddress(hInstance, "RevertToSelf");
+ tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) (
+ PDWORD AccessMask, PGENERIC_MAPPING GenericMapping))
+ GetProcAddress(hInstance, "MapGenericMask");
+ tclWinProcs->accessCheckProc = (BOOL (WINAPI *)(
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ HANDLE ClientToken, DWORD DesiredAccess,
+ PGENERIC_MAPPING GenericMapping,
+ PPRIVILEGE_SET PrivilegeSet,
+ LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess,
+ LPBOOL AccessStatus)) GetProcAddress(hInstance,
+ "AccessCheck");
+ FreeLibrary(hInstance);
+ }
+ }
+ } else {
+ tclWinProcs = &asciiProcs;
+ tclWinTCharEncoding = NULL;
+ if (tclWinProcs->getFileAttributesExProc == NULL) {
+ HINSTANCE hInstance = LoadLibraryA("kernel32");
+ if (hInstance != NULL) {
+ tclWinProcs->getFileAttributesExProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS,
+ LPVOID)) GetProcAddress(hInstance,
+ "GetFileAttributesExA");
+ tclWinProcs->createHardLinkProc =
+ (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*,
+ LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance,
+ "CreateHardLinkA");
+ tclWinProcs->findFirstFileExProc = NULL;
+ tclWinProcs->getLongPathNameProc = NULL;
+ /*
+ * The 'findFirstFileExProc' function exists on some of
+ * 95/98/ME, but it seems not to work as anticipated.
+ * Therefore we don't set this function pointer. The relevant
+ * code will fall back on a slower approach using the normal
+ * findFirstFileProc.
+ *
+ * (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
+ * LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance,
+ * "FindFirstFileExA");
+ */
+ tclWinProcs->getVolumeNameForVMPProc =
+ (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*,
+ DWORD)) GetProcAddress(hInstance,
+ "GetVolumeNameForVolumeMountPointA");
+ FreeLibrary(hInstance);
+ }
+ }
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TclWinResetInterfaceEncodings --
+ *
+ * Called during finalization to free up any encodings we use. The
+ * tclWinProcs-> look up table is still ok to use after this call,
+ * provided no encoding conversion is required.
+ *
+ * We also clean up any memory allocated in our mount point map which is
+ * used to follow certain kinds of symlinks. That code should never be
+ * used once encodings are taken down.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+void
+TclWinResetInterfaceEncodings(void)
{
MountPointMap *dlIter, *dlIter2;
+ if (tclWinTCharEncoding != NULL) {
+ Tcl_FreeEncoding(tclWinTCharEncoding);
+ tclWinTCharEncoding = NULL;
+ }
/*
* Clean up the mount point map.
@@ -247,14 +749,37 @@ TclWinEncodingsCleanup(void)
dlIter = driveLetterLookup;
while (dlIter != NULL) {
dlIter2 = dlIter->nextPtr;
- ckfree(dlIter->volumeName);
- ckfree(dlIter);
+ ckfree((char*)dlIter->volumeName);
+ ckfree((char*)dlIter);
dlIter = dlIter2;
}
Tcl_MutexUnlock(&mountPointMap);
}
/*
+ *---------------------------------------------------------------------------
+ *
+ * TclWinResetInterfaces --
+ *
+ * Called during finalization to reset us to a safe state for reuse.
+ * After this call, it is best not to use the tclWinProcs-> look up table
+ * since it is likely to be different to what is expected.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+void
+TclWinResetInterfaces(void)
+{
+ tclWinProcs = &asciiProcs;
+}
+
+/*
*--------------------------------------------------------------------
*
* TclWinDriveLetterForVolMountPoint
@@ -278,11 +803,11 @@ TclWinEncodingsCleanup(void)
char
TclWinDriveLetterForVolMountPoint(
- const WCHAR *mountPoint)
+ CONST WCHAR *mountPoint)
{
MountPointMap *dlIter, *dlPtr2;
WCHAR Target[55]; /* Target of mount at mount point */
- WCHAR drive[4] = L"A:\\";
+ WCHAR drive[4] = { L'A', L':', L'\\', L'\0' };
/*
* Detect the volume mounted there. Unfortunately, there is no simple way
@@ -300,21 +825,21 @@ TclWinDriveLetterForVolMountPoint(
* mount points on the fly.
*/
- drive[0] = (WCHAR) dlIter->driveLetter;
+ drive[0] = L'A' + (dlIter->driveLetter - 'A');
/*
* Try to read the volume mount point and see where it points.
*/
- if (GetVolumeNameForVolumeMountPointW(drive,
- Target, 55) != 0) {
- if (wcscmp(dlIter->volumeName, Target) == 0) {
+ if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive,
+ (TCHAR*)Target, 55) != 0) {
+ if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
/*
* Nothing has changed.
*/
Tcl_MutexUnlock(&mountPointMap);
- return (char) dlIter->driveLetter;
+ return dlIter->driveLetter;
}
}
@@ -341,8 +866,8 @@ TclWinDriveLetterForVolMountPoint(
* Now dlPtr2 points to the structure to free.
*/
- ckfree(dlPtr2->volumeName);
- ckfree(dlPtr2);
+ ckfree((char*)dlPtr2->volumeName);
+ ckfree((char*)dlPtr2);
/*
* Restart the loop - we could try to be clever and continue half
@@ -360,28 +885,28 @@ TclWinDriveLetterForVolMountPoint(
* We couldn't find it, so we must iterate over the letters.
*/
- for (drive[0] = 'A'; drive[0] <= 'Z'; drive[0]++) {
+ for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) {
/*
* Try to read the volume mount point and see where it points.
*/
- if (GetVolumeNameForVolumeMountPointW(drive,
- Target, 55) != 0) {
+ if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive,
+ (TCHAR*)Target, 55) != 0) {
int alreadyStored = 0;
for (dlIter = driveLetterLookup; dlIter != NULL;
dlIter = dlIter->nextPtr) {
- if (wcscmp(dlIter->volumeName, Target) == 0) {
+ if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
alreadyStored = 1;
break;
}
}
if (!alreadyStored) {
- dlPtr2 = (MountPointMap *)ckalloc(sizeof(MountPointMap));
- dlPtr2->volumeName = (WCHAR *)TclNativeDupInternalRep(Target);
- dlPtr2->driveLetter = (WCHAR) drive[0];
+ dlPtr2 = (MountPointMap *) ckalloc(sizeof(MountPointMap));
+ dlPtr2->volumeName = TclNativeDupInternalRep(Target);
+ dlPtr2->driveLetter = 'A' + (drive[0] - L'A');
dlPtr2->nextPtr = driveLetterLookup;
- driveLetterLookup = dlPtr2;
+ driveLetterLookup = dlPtr2;
}
}
}
@@ -394,7 +919,7 @@ TclWinDriveLetterForVolMountPoint(
dlIter = dlIter->nextPtr) {
if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
Tcl_MutexUnlock(&mountPointMap);
- return (char) dlIter->driveLetter;
+ return dlIter->driveLetter;
}
}
@@ -403,11 +928,11 @@ TclWinDriveLetterForVolMountPoint(
* that fact and store '-1' so we don't have to look it up each time.
*/
- dlPtr2 = (MountPointMap *)ckalloc(sizeof(MountPointMap));
- dlPtr2->volumeName = (WCHAR *)TclNativeDupInternalRep((void *)mountPoint);
- dlPtr2->driveLetter = (WCHAR)-1;
+ dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
+ dlPtr2->volumeName = TclNativeDupInternalRep((ClientData)mountPoint);
+ dlPtr2->driveLetter = -1;
dlPtr2->nextPtr = driveLetterLookup;
- driveLetterLookup = dlPtr2;
+ driveLetterLookup = dlPtr2;
Tcl_MutexUnlock(&mountPointMap);
return -1;
}
@@ -417,32 +942,39 @@ TclWinDriveLetterForVolMountPoint(
*
* Tcl_WinUtfToTChar, Tcl_WinTCharToUtf --
*
- * Convert between UTF-8 and Unicode when running Windows.
+ * Convert between UTF-8 and Unicode when running Windows NT or the
+ * current ANSI code page when running Windows 95.
*
- * On Mac and Unix, all strings exchanged between Tcl and the OS are
- * "char" oriented. We need only one Tcl_Encoding to convert between
- * UTF-8 and the system's native encoding. We use NULL to represent
- * that encoding.
+ * On Mac, Unix, and Windows 95, all strings exchanged between Tcl and
+ * the OS are "char" oriented. We need only one Tcl_Encoding to convert
+ * between UTF-8 and the system's native encoding. We use NULL to
+ * represent that encoding.
*
- * On Windows, some strings exchanged between Tcl and the OS are "char"
+ * On NT, some strings exchanged between Tcl and the OS are "char"
* oriented, while others are in Unicode. We need two Tcl_Encoding APIs
* depending on whether we are targeting a "char" or Unicode interface.
*
- * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an encoding
- * of NULL should always used to convert between UTF-8 and the system's
+ * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an encoding of
+ * NULL should always used to convert between UTF-8 and the system's
* "char" oriented encoding. The following two functions are used in
- * Windows-specific code to convert between UTF-8 and Unicode strings.
- * This saves you the trouble of writing the
+ * Windows-specific code to convert between UTF-8 and Unicode strings
+ * (NT) or "char" strings(95). This saves you the trouble of writing the
* following type of fragment over and over:
*
- * encoding <- Tcl_GetEncoding("unicode");
- * nativeBuffer <- UtfToExternal(encoding, utfBuffer);
- * Tcl_FreeEncoding(encoding);
+ * if (running NT) {
+ * encoding <- Tcl_GetEncoding("unicode");
+ * nativeBuffer <- UtfToExternal(encoding, utfBuffer);
+ * Tcl_FreeEncoding(encoding);
+ * } else {
+ * nativeBuffer <- UtfToExternal(NULL, utfBuffer);
+ * }
*
- * By convention, in Windows a WCHAR is a Unicode character. If you plan
- * on targeting a Unicode interface when running on Windows, these
- * functions should be used. If you plan on targetting a "char" oriented
- * function on Windows, use Tcl_UtfToExternal() with an encoding of NULL.
+ * By convention, in Windows a TCHAR is a character in the ANSI code page
+ * on Windows 95, a Unicode character on Windows NT. If you plan on
+ * targeting a Unicode interfaces when running on NT and a "char"
+ * oriented interface while running on 95, these functions should be
+ * used. If you plan on targetting the same "char" oriented function on
+ * both 95 and NT, use Tcl_UtfToExternal() with an encoding of NULL.
*
* Results:
* The result is a pointer to the string in the desired target encoding.
@@ -455,32 +987,30 @@ TclWinDriveLetterForVolMountPoint(
*---------------------------------------------------------------------------
*/
-#if !defined(TCL_NO_DEPRECATED) && TCL_MAJOR_VERSION < 9
-#undef Tcl_WinUtfToTChar
TCHAR *
Tcl_WinUtfToTChar(
- const char *string, /* Source string in UTF-8. */
- int len, /* Source string length in bytes, or -1 for
+ CONST char *string, /* Source string in UTF-8. */
+ int len, /* Source string length in bytes, or < 0 for
* strlen(). */
Tcl_DString *dsPtr) /* Uninitialized or free DString in which the
* converted string is stored. */
{
- Tcl_DStringInit(dsPtr);
- return (TCHAR *)Tcl_UtfToWCharDString(string, len, dsPtr);
+ return (TCHAR *) Tcl_UtfToExternalDString(tclWinTCharEncoding,
+ string, len, dsPtr);
}
-#undef Tcl_WinTCharToUtf
+
char *
Tcl_WinTCharToUtf(
- const TCHAR *string, /* Source string in Unicode. */
- int len, /* Source string length in bytes, or -1 for
+ CONST TCHAR *string, /* Source string in Unicode when running NT,
+ * ANSI when running 95. */
+ int len, /* Source string length in bytes, or < 0 for
* platform-specific string length. */
Tcl_DString *dsPtr) /* Uninitialized or free DString in which the
* converted string is stored. */
{
- Tcl_DStringInit(dsPtr);
- return Tcl_WCharToUtfDString((WCHAR *)string, len >> 1, dsPtr);
+ return Tcl_ExternalToUtfDString(tclWinTCharEncoding,
+ (CONST char *) string, len, dsPtr);
}
-#endif /* !defined(TCL_NO_DEPRECATED) */
/*
*------------------------------------------------------------------------
@@ -502,21 +1032,16 @@ Tcl_WinTCharToUtf(
int
TclWinCPUID(
- int index, /* Which CPUID value to retrieve. */
- int *regsPtr) /* Registers after the CPUID. */
+ unsigned int index, /* Which CPUID value to retrieve. */
+ unsigned int *regsPtr) /* Registers after the CPUID. */
{
int status = TCL_ERROR;
-#if defined(HAVE_INTRIN_H) && defined(_WIN64) && defined(HAVE_CPUID)
-
- __cpuid((int *)regsPtr, index);
- status = TCL_OK;
-
-#elif defined(__GNUC__) && defined(HAVE_CPUID)
+#if defined(__GNUC__)
# if defined(_WIN64)
/*
* Execute the CPUID instruction with the given index, and store results
- * off 'regPtr'.
+ * off 'regsPtr'.
*/
__asm__ __volatile__(
@@ -531,7 +1056,7 @@ TclWinCPUID(
"movl %%eax, 0x0(%%edi)" "\n\t"
"movl %%ebx, 0x4(%%edi)" "\n\t"
"movl %%ecx, 0x8(%%edi)" "\n\t"
- "movl %%edx, 0xC(%%edi)" "\n\t"
+ "movl %%edx, 0xc(%%edi)" "\n\t"
:
/* No outputs */
@@ -563,7 +1088,7 @@ TclWinCPUID(
"leal 1f, %%eax" "\n\t"
"movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
"movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
- "movl %%esp, 0xC(%%edx)" "\n\t" /* esp */
+ "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
"movl %[error], 0x10(%%edx)" "\n\t" /* status */
/*
@@ -583,7 +1108,7 @@ TclWinCPUID(
"movl %%eax, 0x0(%%edi)" "\n\t"
"movl %%ebx, 0x4(%%edi)" "\n\t"
"movl %%ecx, 0x8(%%edi)" "\n\t"
- "movl %%edx, 0xC(%%edi)" "\n\t"
+ "movl %%edx, 0xc(%%edi)" "\n\t"
/*
* Come here on a normal exit. Recover the TCLEXCEPTION_REGISTRATION and
@@ -610,7 +1135,7 @@ TclWinCPUID(
*/
"2:" "\t"
- "movl 0xC(%%edx), %%esp" "\n\t"
+ "movl 0xc(%%edx), %%esp" "\n\t"
"movl 0x8(%%edx), %%ebp" "\n\t"
"movl 0x0(%%edx), %%eax" "\n\t"
"movl %%eax, %%fs:0" "\n\t"
@@ -628,13 +1153,13 @@ TclWinCPUID(
status = registration.status;
# endif /* !_WIN64 */
-#elif defined(_MSC_VER) && defined(HAVE_CPUID)
+#elif defined(_MSC_VER)
# if defined(_WIN64)
__cpuid(regsPtr, index);
status = TCL_OK;
-# elif defined (_M_IX86)
+# else
/*
* Define a structure in the stack frame to hold the registers.
*/
@@ -683,8 +1208,6 @@ TclWinCPUID(
# endif
#else
- (void)index;
- (void)regsPtr;
/*
* Don't know how to do assembly code for this compiler and/or
* architecture.