os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/win/tclWin32Dll.c
First public contribution.
4 * This file contains the DLL entry point.
6 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
7 * Copyright (c) 1998-2000 Scriptics Corporation.
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 * RCS: @(#) $Id: tclWin32Dll.c,v 1.24.2.10 2006/10/17 04:36:45 dgp Exp $
15 #include "tclWinInt.h"
18 * The following data structures are used when loading the thunking
19 * library for execing child processes under Win32s.
22 typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined,
23 LPVOID *lpTranslationList);
25 typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL,
26 LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk,
27 FARPROC UT32Callback, LPVOID Buff);
29 typedef VOID (WINAPI UTUNREGISTER)(HANDLE hModule);
32 * The following variables keep track of information about this DLL
33 * on a per-instance basis. Each time this DLL is loaded, it gets its own
34 * new data segment with its own copy of all static and global information.
37 static HINSTANCE hInstance; /* HINSTANCE of this DLL. */
38 static int platformId; /* Running under NT, or 95/98? */
43 * Unlike Borland and Microsoft, we don't register exception handlers
44 * by pushing registration records onto the runtime stack. Instead, we
45 * register them by creating an EXCEPTION_REGISTRATION within the activation
49 typedef struct EXCEPTION_REGISTRATION {
50 struct EXCEPTION_REGISTRATION* link;
51 EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*,
52 struct _CONTEXT*, void* );
56 } EXCEPTION_REGISTRATION;
61 * VC++ 5.x has no 'cpuid' assembler instruction, so we
64 #if defined(_MSC_VER) && ( _MSC_VER <= 1100 )
65 #define cpuid __asm __emit 0fh __asm __emit 0a2h
69 * The following function tables are used to dispatch to either the
70 * wide-character or multi-byte versions of the operating system calls,
71 * depending on whether the Unicode calls are available.
74 static TclWinProcs asciiProcs = {
77 (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBA,
78 (TCHAR *(WINAPI *)(TCHAR *)) CharLowerA,
79 (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileA,
80 (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryA,
81 (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *,
82 DWORD, DWORD, HANDLE)) CreateFileA,
83 (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES,
84 LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *,
85 LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessA,
86 (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileA,
87 (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileA,
88 (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileA,
89 (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameA,
90 (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryA,
91 (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesA,
92 (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *,
93 TCHAR **)) GetFullPathNameA,
94 (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA,
95 (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA,
96 (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique,
97 WCHAR *)) GetTempFileNameA,
98 (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA,
99 (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
100 WCHAR *, DWORD)) GetVolumeInformationA,
101 (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryA,
102 (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyA,
103 (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA,
104 (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA,
105 (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD,
106 WCHAR *, TCHAR **)) SearchPathA,
107 (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA,
108 (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA,
110 * The three NULL function pointers will only be set when
111 * Tcl_FindExecutable is called. If you don't ever call that
112 * function, the application will crash whenever WinTcl tries to call
113 * functions through these null pointers. That is not a bug in Tcl
114 * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
118 (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime,
121 /* getLongPathNameProc */
123 /* Security SDK - not available on 95,98,ME */
124 NULL, NULL, NULL, NULL, NULL, NULL,
125 /* ReadConsole and WriteConsole */
126 (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleA,
127 (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleA
130 static TclWinProcs unicodeProcs = {
133 (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBW,
134 (TCHAR *(WINAPI *)(TCHAR *)) CharLowerW,
135 (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileW,
136 (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryW,
137 (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *,
138 DWORD, DWORD, HANDLE)) CreateFileW,
139 (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES,
140 LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *,
141 LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessW,
142 (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileW,
143 (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileW,
144 (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileW,
145 (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameW,
146 (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryW,
147 (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesW,
148 (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *,
149 TCHAR **)) GetFullPathNameW,
150 (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW,
151 (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW,
152 (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique,
153 WCHAR *)) GetTempFileNameW,
154 (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW,
155 (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
156 WCHAR *, DWORD)) GetVolumeInformationW,
157 (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryW,
158 (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyW,
159 (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW,
160 (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW,
161 (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD,
162 WCHAR *, TCHAR **)) SearchPathW,
163 (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW,
164 (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW,
166 * The three NULL function pointers will only be set when
167 * Tcl_FindExecutable is called. If you don't ever call that
168 * function, the application will crash whenever WinTcl tries to call
169 * functions through these null pointers. That is not a bug in Tcl
170 * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
174 (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime,
177 /* getLongPathNameProc */
179 /* Security SDK - will be filled in on NT,XP,2000,2003 */
180 NULL, NULL, NULL, NULL, NULL, NULL,
181 /* ReadConsole and WriteConsole */
182 (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleW,
183 (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleW
186 TclWinProcs *tclWinProcs;
187 static Tcl_Encoding tclWinTCharEncoding;
192 /* Need to add noinline flag to DllMain declaration so that gcc -O3
193 * does not inline asm code into DllEntryPoint and cause a
194 * compile time error because of redefined local labels.
197 BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
199 __attribute__ ((noinline));
204 * The following declaration is for the VC++ DLL entry point.
207 BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason,
209 #endif /* HAVE_NO_SEH */
213 * The following structure and linked list is to allow us to map between
214 * volume mount points and drive letters on the fly (no Win API exists
217 typedef struct MountPointMap {
218 CONST WCHAR* volumeName; /* Native wide string volume name */
219 char driveLetter; /* Drive letter corresponding to
220 * the volume name. */
221 struct MountPointMap* nextPtr; /* Pointer to next structure in list,
226 * This is the head of the linked list, which is protected by the
227 * mutex which follows, for thread-enabled builds.
229 MountPointMap *driveLetterLookup = NULL;
230 TCL_DECLARE_MUTEX(mountPointMap)
232 /* We will need this below */
233 extern Tcl_FSDupInternalRepProc TclNativeDupInternalRep;
240 *----------------------------------------------------------------------
244 * This wrapper function is used by Borland to invoke the
245 * initialization code for Tcl. It simply calls the DllMain
254 *----------------------------------------------------------------------
258 DllEntryPoint(hInst, reason, reserved)
259 HINSTANCE hInst; /* Library instance handle. */
260 DWORD reason; /* Reason this function is being called. */
261 LPVOID reserved; /* Not used. */
263 return DllMain(hInst, reason, reserved);
267 *----------------------------------------------------------------------
271 * This routine is called by the VC++ C run time library init
272 * code, or the DllEntryPoint routine. It is responsible for
273 * initializing various dynamically loaded libraries.
276 * TRUE on sucess, FALSE on failure.
279 * Establishes 32-to-16 bit thunk and initializes sockets library.
281 *----------------------------------------------------------------------
284 DllMain(hInst, reason, reserved)
285 HINSTANCE hInst; /* Library instance handle. */
286 DWORD reason; /* Reason this function is being called. */
287 LPVOID reserved; /* Not used. */
290 EXCEPTION_REGISTRATION registration;
294 case DLL_PROCESS_ATTACH:
295 DisableThreadLibraryCalls(hInst);
299 case DLL_PROCESS_DETACH:
301 * Protect the call to Tcl_Finalize. The OS could be unloading
302 * us from an exception handler and the state of the stack might
306 __asm__ __volatile__ (
309 * Construct an EXCEPTION_REGISTRATION to protect the
310 * call to Tcl_Finalize
312 "leal %[registration], %%edx" "\n\t"
313 "movl %%fs:0, %%eax" "\n\t"
314 "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
315 "leal 1f, %%eax" "\n\t"
316 "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
317 "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
318 "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
319 "movl %[error], 0x10(%%edx)" "\n\t" /* status */
322 * Link the EXCEPTION_REGISTRATION on the chain
324 "movl %%edx, %%fs:0" "\n\t"
329 "call _Tcl_Finalize" "\n\t"
332 * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
333 * and store a TCL_OK status
336 "movl %%fs:0, %%edx" "\n\t"
337 "movl %[ok], %%eax" "\n\t"
338 "movl %%eax, 0x10(%%edx)" "\n\t"
342 * Come here on an exception. Get the EXCEPTION_REGISTRATION
343 * that we previously put on the chain.
347 "movl %%fs:0, %%edx" "\n\t"
348 "movl 0x8(%%edx), %%edx" "\n"
352 * Come here however we exited. Restore context from the
353 * EXCEPTION_REGISTRATION in case the stack is unbalanced.
357 "movl 0xc(%%edx), %%esp" "\n\t"
358 "movl 0x8(%%edx), %%ebp" "\n\t"
359 "movl 0x0(%%edx), %%eax" "\n\t"
360 "movl %%eax, %%fs:0" "\n\t"
365 [registration] "m" (registration),
367 [error] "i" (TCL_ERROR)
369 "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
372 #else /* HAVE_NO_SEH */
375 } __except (EXCEPTION_EXECUTE_HANDLER) {
376 /* empty handler body. */
386 #endif /* !STATIC_BUILD */
387 #endif /* __WIN32__ */
390 *----------------------------------------------------------------------
392 * TclWinGetTclInstance --
394 * Retrieves the global library instance handle.
397 * Returns the global library instance handle.
402 *----------------------------------------------------------------------
406 TclWinGetTclInstance()
412 *----------------------------------------------------------------------
416 * This function initializes the internal state of the tcl library.
422 * Initializes the tclPlatformId variable.
424 *----------------------------------------------------------------------
429 HINSTANCE hInst; /* Library instance handle. */
434 os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
436 platformId = os.dwPlatformId;
439 * We no longer support Win32s, so just in case someone manages to
440 * get a runtime there, make sure they know that.
443 if (platformId == VER_PLATFORM_WIN32s) {
444 panic("Win32s is not a supported platform");
447 tclWinProcs = &asciiProcs;
451 *----------------------------------------------------------------------
453 * TclWinGetPlatformId --
455 * Determines whether running under NT, 95, or Win32s, to allow
456 * runtime conditional code.
459 * The return value is one of:
460 * VER_PLATFORM_WIN32s Win32s on Windows 3.1. (not supported)
461 * VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95.
462 * VER_PLATFORM_WIN32_NT Win32 on Windows NT
467 *----------------------------------------------------------------------
471 TclWinGetPlatformId()
477 *-------------------------------------------------------------------------
479 * TclWinNoBackslash --
481 * We're always iterating through a string in Windows, changing the
482 * backslashes to slashes for use in Tcl.
485 * All backslashes in given string are changed to slashes.
490 *-------------------------------------------------------------------------
495 char *path) /* String to change. */
499 for (p = path; *p != '\0'; p++) {
508 *----------------------------------------------------------------------
510 * TclpCheckStackSpace --
512 * Detect if we are about to blow the stack. Called before an
513 * evaluation can happen when nesting depth is checked.
516 * 1 if there is enough stack space to continue; 0 if not.
521 *----------------------------------------------------------------------
525 TclpCheckStackSpace()
529 EXCEPTION_REGISTRATION registration;
534 * We can recurse only if there is at least TCL_WIN_STACK_THRESHOLD
535 * bytes of stack space left. alloca() is cheap on windows; basically
536 * it just subtracts from the stack pointer causing the OS to throw an
537 * exception if the stack pointer is set below the bottom of the stack.
541 __asm__ __volatile__ (
544 * Construct an EXCEPTION_REGISTRATION to protect the
547 "leal %[registration], %%edx" "\n\t"
548 "movl %%fs:0, %%eax" "\n\t"
549 "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
550 "leal 1f, %%eax" "\n\t"
551 "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
552 "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
553 "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
554 "movl %[error], 0x10(%%edx)" "\n\t" /* status */
557 * Link the EXCEPTION_REGISTRATION on the chain
559 "movl %%edx, %%fs:0" "\n\t"
562 * Attempt a call to __alloca, to determine whether there's
563 * sufficient memory to be had.
566 "movl %[size], %%eax" "\n\t"
568 "call __alloca" "\n\t"
571 * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
572 * and store a TCL_OK status
574 "movl %%fs:0, %%edx" "\n\t"
575 "movl %[ok], %%eax" "\n\t"
576 "movl %%eax, 0x10(%%edx)" "\n\t"
580 * Come here on an exception. Get the EXCEPTION_REGISTRATION
581 * that we previously put on the chain.
584 "movl %%fs:0, %%edx" "\n\t"
585 "movl 0x8(%%edx), %%edx" "\n\t"
588 * Come here however we exited. Restore context from the
589 * EXCEPTION_REGISTRATION in case the stack is unbalanced.
593 "movl 0xc(%%edx), %%esp" "\n\t"
594 "movl 0x8(%%edx), %%ebp" "\n\t"
595 "movl 0x0(%%edx), %%eax" "\n\t"
596 "movl %%eax, %%fs:0" "\n\t"
601 [registration] "m" (registration),
603 [error] "i" (TCL_ERROR),
604 [size] "i" (TCL_WIN_STACK_THRESHOLD)
606 "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
608 retval = (registration.status == TCL_OK);
610 #else /* !HAVE_NO_SEH */
612 #ifdef HAVE_ALLOCA_GCC_INLINE
613 __asm__ __volatile__ (
614 "movl %0, %%eax" "\n\t"
615 "call __alloca" "\n\t"
617 : "i"(TCL_WIN_STACK_THRESHOLD)
620 alloca(TCL_WIN_STACK_THRESHOLD);
621 #endif /* HAVE_ALLOCA_GCC_INLINE */
623 } __except (EXCEPTION_EXECUTE_HANDLER) {}
624 #endif /* HAVE_NO_SEH */
630 *----------------------------------------------------------------------
632 * TclWinGetPlatform --
634 * This is a kludge that allows the test library to get access
635 * the internal tclPlatform variable.
638 * Returns a pointer to the tclPlatform variable.
643 *----------------------------------------------------------------------
653 *---------------------------------------------------------------------------
655 * TclWinSetInterfaces --
657 * A helper proc that allows the test library to change the
658 * tclWinProcs structure to dispatch to either the wide-character
659 * or multi-byte versions of the operating system calls, depending
660 * on whether Unicode is the system encoding.
662 * As well as this, we can also try to load in some additional
663 * procs which may/may not be present depending on the current
664 * Windows version (e.g. Win95 will not have the procs below).
672 *---------------------------------------------------------------------------
677 int wide) /* Non-zero to use wide interfaces, 0
680 Tcl_FreeEncoding(tclWinTCharEncoding);
683 tclWinProcs = &unicodeProcs;
684 tclWinTCharEncoding = Tcl_GetEncoding(NULL, "unicode");
685 if (tclWinProcs->getFileAttributesExProc == NULL) {
686 HINSTANCE hInstance = LoadLibraryA("kernel32");
687 if (hInstance != NULL) {
688 tclWinProcs->getFileAttributesExProc =
689 (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS,
690 LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExW");
691 tclWinProcs->createHardLinkProc =
692 (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*,
693 LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance,
695 tclWinProcs->findFirstFileExProc =
696 (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
697 LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance,
699 tclWinProcs->getVolumeNameForVMPProc =
700 (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*,
701 DWORD)) GetProcAddress(hInstance,
702 "GetVolumeNameForVolumeMountPointW");
703 FreeLibrary(hInstance);
705 hInstance = LoadLibraryA("advapi32");
706 if (hInstance != NULL) {
707 tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
709 SECURITY_INFORMATION RequestedInformation,
710 PSECURITY_DESCRIPTOR pSecurityDescriptor,
711 DWORD nLength, LPDWORD lpnLengthNeeded))
712 GetProcAddress(hInstance, "GetFileSecurityW");
713 tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) (
714 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel))
715 GetProcAddress(hInstance, "ImpersonateSelf");
716 tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) (
717 HANDLE ThreadHandle, DWORD DesiredAccess,
718 BOOL OpenAsSelf, PHANDLE TokenHandle))
719 GetProcAddress(hInstance, "OpenThreadToken");
720 tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void))
721 GetProcAddress(hInstance, "RevertToSelf");
722 tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) (
723 PDWORD AccessMask, PGENERIC_MAPPING GenericMapping))
724 GetProcAddress(hInstance, "MapGenericMask");
725 tclWinProcs->accessCheckProc = (BOOL (WINAPI *)(
726 PSECURITY_DESCRIPTOR pSecurityDescriptor,
727 HANDLE ClientToken, DWORD DesiredAccess,
728 PGENERIC_MAPPING GenericMapping,
729 PPRIVILEGE_SET PrivilegeSet,
730 LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess,
731 LPBOOL AccessStatus)) GetProcAddress(hInstance,
733 FreeLibrary(hInstance);
737 tclWinProcs = &asciiProcs;
738 tclWinTCharEncoding = NULL;
739 if (tclWinProcs->getFileAttributesExProc == NULL) {
740 HINSTANCE hInstance = LoadLibraryA("kernel32");
741 if (hInstance != NULL) {
742 tclWinProcs->getFileAttributesExProc =
743 (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS,
744 LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExA");
745 tclWinProcs->createHardLinkProc =
746 (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*,
747 LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance,
749 tclWinProcs->findFirstFileExProc =
750 (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
751 LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance,
753 tclWinProcs->getLongPathNameProc = NULL;
754 tclWinProcs->getVolumeNameForVMPProc =
755 (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*,
756 DWORD)) GetProcAddress(hInstance,
757 "GetVolumeNameForVolumeMountPointA");
758 FreeLibrary(hInstance);
765 *---------------------------------------------------------------------------
767 * TclWinResetInterfaceEncodings --
769 * Called during finalization to free up any encodings we use.
770 * The tclWinProcs-> look up table is still ok to use after
771 * this call, provided no encoding conversion is required.
773 * We also clean up any memory allocated in our mount point
774 * map which is used to follow certain kinds of symlinks.
775 * That code should never be used once encodings are taken
784 *---------------------------------------------------------------------------
787 TclWinResetInterfaceEncodings()
789 MountPointMap *dlIter, *dlIter2;
790 if (tclWinTCharEncoding != NULL) {
791 Tcl_FreeEncoding(tclWinTCharEncoding);
792 tclWinTCharEncoding = NULL;
794 /* Clean up the mount point map */
795 Tcl_MutexLock(&mountPointMap);
796 dlIter = driveLetterLookup;
797 while (dlIter != NULL) {
798 dlIter2 = dlIter->nextPtr;
799 ckfree((char*)dlIter->volumeName);
800 ckfree((char*)dlIter);
803 Tcl_MutexUnlock(&mountPointMap);
807 *---------------------------------------------------------------------------
809 * TclWinResetInterfaces --
811 * Called during finalization to reset us to a safe state for reuse.
812 * After this call, it is best not to use the tclWinProcs-> look
813 * up table since it is likely to be different to what is expected.
821 *---------------------------------------------------------------------------
824 TclWinResetInterfaces()
826 tclWinProcs = &asciiProcs;
830 *--------------------------------------------------------------------
832 * TclWinDriveLetterForVolMountPoint
834 * Unfortunately, Windows provides no easy way at all to get hold
835 * of the drive letter for a volume mount point, but we need that
836 * information to understand paths correctly. So, we have to
837 * build an associated array to find these correctly, and allow
838 * quick and easy lookup from volume mount points to drive letters.
840 * We assume here that we are running on a system for which the wide
841 * character interfaces are used, which is valid for Win 2000 and WinXP
842 * which are the only systems on which this function will ever be called.
844 * Result: the drive letter, or -1 if no drive letter corresponds to
845 * the given mount point.
847 *--------------------------------------------------------------------
850 TclWinDriveLetterForVolMountPoint(CONST WCHAR *mountPoint)
852 MountPointMap *dlIter, *dlPtr2;
853 WCHAR Target[55]; /* Target of mount at mount point */
854 WCHAR drive[4] = { L'A', L':', L'\\', L'\0' };
857 * Detect the volume mounted there. Unfortunately, there is no
858 * simple way to map a unique volume name to a DOS drive letter.
859 * So, we have to build an associative array.
862 Tcl_MutexLock(&mountPointMap);
863 dlIter = driveLetterLookup;
864 while (dlIter != NULL) {
865 if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
867 * We need to check whether this information is
868 * still valid, since either the user or various
869 * programs could have adjusted the mount points on
872 drive[0] = L'A' + (dlIter->driveLetter - 'A');
873 /* Try to read the volume mount point and see where it points */
874 if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive,
875 (TCHAR*)Target, 55) != 0) {
876 if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
877 /* Nothing has changed */
878 Tcl_MutexUnlock(&mountPointMap);
879 return dlIter->driveLetter;
883 * If we reach here, unfortunately, this mount point is
884 * no longer valid at all
886 if (driveLetterLookup == dlIter) {
888 driveLetterLookup = dlIter->nextPtr;
890 for (dlPtr2 = driveLetterLookup;
891 dlPtr2 != NULL; dlPtr2 = dlPtr2->nextPtr) {
892 if (dlPtr2->nextPtr == dlIter) {
893 dlPtr2->nextPtr = dlIter->nextPtr;
899 /* Now dlPtr2 points to the structure to free */
900 ckfree((char*)dlPtr2->volumeName);
901 ckfree((char*)dlPtr2);
903 * Restart the loop --- we could try to be clever
904 * and continue half way through, but the logic is a
905 * bit messy, so it's cleanest just to restart
907 dlIter = driveLetterLookup;
910 dlIter = dlIter->nextPtr;
913 /* We couldn't find it, so we must iterate over the letters */
915 for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) {
916 /* Try to read the volume mount point and see where it points */
917 if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive,
918 (TCHAR*)Target, 55) != 0) {
919 int alreadyStored = 0;
920 for (dlIter = driveLetterLookup; dlIter != NULL;
921 dlIter = dlIter->nextPtr) {
922 if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
927 if (!alreadyStored) {
928 dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
929 dlPtr2->volumeName = TclNativeDupInternalRep(Target);
930 dlPtr2->driveLetter = 'A' + (drive[0] - L'A');
931 dlPtr2->nextPtr = driveLetterLookup;
932 driveLetterLookup = dlPtr2;
937 for (dlIter = driveLetterLookup; dlIter != NULL;
938 dlIter = dlIter->nextPtr) {
939 if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
940 Tcl_MutexUnlock(&mountPointMap);
941 return dlIter->driveLetter;
945 * The volume doesn't appear to correspond to a drive letter -- we
946 * remember that fact and store '-1' so we don't have to look it
949 dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
950 dlPtr2->volumeName = TclNativeDupInternalRep((ClientData)mountPoint);
951 dlPtr2->driveLetter = -1;
952 dlPtr2->nextPtr = driveLetterLookup;
953 driveLetterLookup = dlPtr2;
954 Tcl_MutexUnlock(&mountPointMap);
959 *---------------------------------------------------------------------------
961 * Tcl_WinUtfToTChar, Tcl_WinTCharToUtf --
963 * Convert between UTF-8 and Unicode when running Windows NT or
964 * the current ANSI code page when running Windows 95.
966 * On Mac, Unix, and Windows 95, all strings exchanged between Tcl
967 * and the OS are "char" oriented. We need only one Tcl_Encoding to
968 * convert between UTF-8 and the system's native encoding. We use
969 * NULL to represent that encoding.
971 * On NT, some strings exchanged between Tcl and the OS are "char"
972 * oriented, while others are in Unicode. We need two Tcl_Encoding
973 * APIs depending on whether we are targeting a "char" or Unicode
976 * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an
977 * encoding of NULL should always used to convert between UTF-8
978 * and the system's "char" oriented encoding. The following two
979 * functions are used in Windows-specific code to convert between
980 * UTF-8 and Unicode strings (NT) or "char" strings(95). This saves
981 * you the trouble of writing the following type of fragment over and
985 * encoding <- Tcl_GetEncoding("unicode");
986 * nativeBuffer <- UtfToExternal(encoding, utfBuffer);
987 * Tcl_FreeEncoding(encoding);
989 * nativeBuffer <- UtfToExternal(NULL, utfBuffer);
992 * By convention, in Windows a TCHAR is a character in the ANSI code
993 * page on Windows 95, a Unicode character on Windows NT. If you
994 * plan on targeting a Unicode interfaces when running on NT and a
995 * "char" oriented interface while running on 95, these functions
996 * should be used. If you plan on targetting the same "char"
997 * oriented function on both 95 and NT, use Tcl_UtfToExternal()
998 * with an encoding of NULL.
1001 * The result is a pointer to the string in the desired target
1002 * encoding. Storage for the result string is allocated in
1003 * dsPtr; the caller must call Tcl_DStringFree() when the result
1004 * is no longer needed.
1009 *---------------------------------------------------------------------------
1013 Tcl_WinUtfToTChar(string, len, dsPtr)
1014 CONST char *string; /* Source string in UTF-8. */
1015 int len; /* Source string length in bytes, or < 0 for
1017 Tcl_DString *dsPtr; /* Uninitialized or free DString in which
1018 * the converted string is stored. */
1020 return (TCHAR *) Tcl_UtfToExternalDString(tclWinTCharEncoding,
1021 string, len, dsPtr);
1025 Tcl_WinTCharToUtf(string, len, dsPtr)
1026 CONST TCHAR *string; /* Source string in Unicode when running
1027 * NT, ANSI when running 95. */
1028 int len; /* Source string length in bytes, or < 0 for
1029 * platform-specific string length. */
1030 Tcl_DString *dsPtr; /* Uninitialized or free DString in which
1031 * the converted string is stored. */
1033 return Tcl_ExternalToUtfDString(tclWinTCharEncoding,
1034 (CONST char *) string, len, dsPtr);
1038 *------------------------------------------------------------------------
1042 * Get CPU ID information on an Intel box under Windows
1045 * Returns TCL_OK if successful, TCL_ERROR if CPUID is not
1046 * supported or fails.
1049 * If successful, stores EAX, EBX, ECX and EDX registers after
1050 * the CPUID instruction in the four integers designated by 'regsPtr'
1052 *----------------------------------------------------------------------
1056 TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve */
1057 unsigned int * regsPtr ) /* Registers after the CPUID */
1061 EXCEPTION_REGISTRATION registration;
1063 int status = TCL_ERROR;
1065 #if defined(__GNUC__) && !defined(_WIN64)
1068 * Execute the CPUID instruction with the given index, and
1069 * store results off 'regPtr'.
1072 __asm__ __volatile__ (
1075 * Construct an EXCEPTION_REGISTRATION to protect the
1076 * CPUID instruction (early 486's don't have CPUID)
1078 "leal %[registration], %%edx" "\n\t"
1079 "movl %%fs:0, %%eax" "\n\t"
1080 "movl %%eax, 0x0(%%edx)" "\n\t" /* link */
1081 "leal 1f, %%eax" "\n\t"
1082 "movl %%eax, 0x4(%%edx)" "\n\t" /* handler */
1083 "movl %%ebp, 0x8(%%edx)" "\n\t" /* ebp */
1084 "movl %%esp, 0xc(%%edx)" "\n\t" /* esp */
1085 "movl %[error], 0x10(%%edx)" "\n\t" /* status */
1088 * Link the EXCEPTION_REGISTRATION on the chain
1090 "movl %%edx, %%fs:0" "\n\t"
1093 * Do the CPUID instruction, and save the results in
1094 * the 'regsPtr' area
1097 "movl %[rptr], %%edi" "\n\t"
1098 "movl %[index], %%eax" "\n\t"
1100 "movl %%eax, 0x0(%%edi)" "\n\t"
1101 "movl %%ebx, 0x4(%%edi)" "\n\t"
1102 "movl %%ecx, 0x8(%%edi)" "\n\t"
1103 "movl %%edx, 0xc(%%edi)" "\n\t"
1106 * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
1107 * and store a TCL_OK status
1109 "movl %%fs:0, %%edx" "\n\t"
1110 "movl %[ok], %%eax" "\n\t"
1111 "movl %%eax, 0x10(%%edx)" "\n\t"
1115 * Come here on an exception. Get the EXCEPTION_REGISTRATION
1116 * that we previously put on the chain.
1119 "movl %%fs:0, %%edx" "\n\t"
1120 "movl 0x8(%%edx), %%edx" "\n\t"
1123 * Come here however we exited. Restore context from the
1124 * EXCEPTION_REGISTRATION in case the stack is unbalanced.
1128 "movl 0xc(%%edx), %%esp" "\n\t"
1129 "movl 0x8(%%edx), %%ebp" "\n\t"
1130 "movl 0x0(%%edx), %%eax" "\n\t"
1131 "movl %%eax, %%fs:0" "\n\t"
1136 [index] "m" (index),
1137 [rptr] "m" (regsPtr),
1138 [registration] "m" (registration),
1140 [error] "i" (TCL_ERROR)
1142 "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" );
1143 status = registration.status;
1145 #elif defined(_MSC_VER) && !defined(_WIN64)
1147 /* Define a structure in the stack frame to hold the registers */
1157 /* Execute the CPUID instruction and save regs in the stack frame */
1175 /* Copy regs back out to the caller */
1177 regsPtr[0]=regs.dw0;
1178 regsPtr[1]=regs.dw1;
1179 regsPtr[2]=regs.dw2;
1180 regsPtr[3]=regs.dw3;
1183 } __except( EXCEPTION_EXECUTE_HANDLER ) {
1187 /* Don't know how to do assembly code for
1188 * this compiler and/or architecture */