tclWin32Dll.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:37k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclWin32Dll.c --
  3.  *
  4.  * This file contains the DLL entry point.
  5.  *
  6.  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
  7.  * Copyright (c) 1998-2000 Scriptics Corporation.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tclWin32Dll.c,v 1.24.2.10 2006/10/17 04:36:45 dgp Exp $
  13.  */
  14. #include "tclWinInt.h"
  15. /*
  16.  * The following data structures are used when loading the thunking 
  17.  * library for execing child processes under Win32s.
  18.  */
  19. typedef DWORD (WINAPI UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined,
  20. LPVOID *lpTranslationList);
  21. typedef BOOL (WINAPI UTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL,
  22. LPCSTR InitName, LPCSTR ProcName, UT32PROC **ThirtyTwoBitThunk,
  23. FARPROC UT32Callback, LPVOID Buff);
  24. typedef VOID (WINAPI UTUNREGISTER)(HANDLE hModule);
  25. /* 
  26.  * The following variables keep track of information about this DLL
  27.  * on a per-instance basis.  Each time this DLL is loaded, it gets its own 
  28.  * new data segment with its own copy of all static and global information.
  29.  */
  30. static HINSTANCE hInstance; /* HINSTANCE of this DLL. */
  31. static int platformId; /* Running under NT, or 95/98? */
  32. #ifdef HAVE_NO_SEH
  33. /*
  34.  * Unlike Borland and Microsoft, we don't register exception handlers
  35.  * by pushing registration records onto the runtime stack.  Instead, we
  36.  * register them by creating an EXCEPTION_REGISTRATION within the activation
  37.  * record.
  38.  */
  39. typedef struct EXCEPTION_REGISTRATION {
  40.     struct EXCEPTION_REGISTRATION* link;
  41.     EXCEPTION_DISPOSITION (*handler)( struct _EXCEPTION_RECORD*, void*,
  42.       struct _CONTEXT*, void* );
  43.     void* ebp;
  44.     void* esp;
  45.     int status;
  46. } EXCEPTION_REGISTRATION;
  47. #endif
  48. /*
  49.  * VC++ 5.x has no 'cpuid' assembler instruction, so we
  50.  * must emulate it
  51.  */
  52. #if defined(_MSC_VER) && ( _MSC_VER <= 1100 )
  53. #define cpuid __asm __emit 0fh __asm __emit 0a2h
  54. #endif
  55. /*
  56.  * The following function tables are used to dispatch to either the
  57.  * wide-character or multi-byte versions of the operating system calls,
  58.  * depending on whether the Unicode calls are available.
  59.  */
  60. static TclWinProcs asciiProcs = {
  61.     0,
  62.     (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBA,
  63.     (TCHAR *(WINAPI *)(TCHAR *)) CharLowerA,
  64.     (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileA,
  65.     (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryA,
  66.     (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, 
  67.     DWORD, DWORD, HANDLE)) CreateFileA,
  68.     (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, 
  69.     LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, 
  70.     LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessA,
  71.     (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileA,
  72.     (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileA,
  73.     (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileA,
  74.     (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameA,
  75.     (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryA,
  76.     (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesA,
  77.     (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, 
  78.     TCHAR **)) GetFullPathNameA,
  79.     (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameA,
  80.     (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameA,
  81.     (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, 
  82.     WCHAR *)) GetTempFileNameA,
  83.     (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathA,
  84.     (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD,
  85.     WCHAR *, DWORD)) GetVolumeInformationA,
  86.     (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryA,
  87.     (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyA,
  88.     (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileA,
  89.     (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryA,
  90.     (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, 
  91.     WCHAR *, TCHAR **)) SearchPathA,
  92.     (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryA,
  93.     (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesA,
  94.     /* 
  95.      * The three NULL function pointers will only be set when
  96.      * Tcl_FindExecutable is called.  If you don't ever call that
  97.      * function, the application will crash whenever WinTcl tries to call
  98.      * functions through these null pointers.  That is not a bug in Tcl
  99.      * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
  100.      */
  101.     NULL,
  102.     NULL,
  103.     (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime,
  104.     NULL,
  105.     NULL,
  106.     /* getLongPathNameProc */
  107.     NULL,
  108.     /* Security SDK - not available on 95,98,ME */
  109.     NULL, NULL, NULL, NULL, NULL, NULL,
  110.     /* ReadConsole and WriteConsole */
  111.     (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleA,
  112.     (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleA    
  113. };
  114. static TclWinProcs unicodeProcs = {
  115.     1,
  116.     (BOOL (WINAPI *)(CONST TCHAR *, LPDCB)) BuildCommDCBW,
  117.     (TCHAR *(WINAPI *)(TCHAR *)) CharLowerW,
  118.     (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *, BOOL)) CopyFileW,
  119.     (BOOL (WINAPI *)(CONST TCHAR *, LPSECURITY_ATTRIBUTES)) CreateDirectoryW,
  120.     (HANDLE (WINAPI *)(CONST TCHAR *, DWORD, DWORD, SECURITY_ATTRIBUTES *, 
  121.     DWORD, DWORD, HANDLE)) CreateFileW,
  122.     (BOOL (WINAPI *)(CONST TCHAR *, TCHAR *, LPSECURITY_ATTRIBUTES, 
  123.     LPSECURITY_ATTRIBUTES, BOOL, DWORD, LPVOID, CONST TCHAR *, 
  124.     LPSTARTUPINFOA, LPPROCESS_INFORMATION)) CreateProcessW,
  125.     (BOOL (WINAPI *)(CONST TCHAR *)) DeleteFileW,
  126.     (HANDLE (WINAPI *)(CONST TCHAR *, WIN32_FIND_DATAT *)) FindFirstFileW,
  127.     (BOOL (WINAPI *)(HANDLE, WIN32_FIND_DATAT *)) FindNextFileW,
  128.     (BOOL (WINAPI *)(WCHAR *, LPDWORD)) GetComputerNameW,
  129.     (DWORD (WINAPI *)(DWORD, WCHAR *)) GetCurrentDirectoryW,
  130.     (DWORD (WINAPI *)(CONST TCHAR *)) GetFileAttributesW,
  131.     (DWORD (WINAPI *)(CONST TCHAR *, DWORD nBufferLength, WCHAR *, 
  132.     TCHAR **)) GetFullPathNameW,
  133.     (DWORD (WINAPI *)(HMODULE, WCHAR *, int)) GetModuleFileNameW,
  134.     (DWORD (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD)) GetShortPathNameW,
  135.     (UINT (WINAPI *)(CONST TCHAR *, CONST TCHAR *, UINT uUnique, 
  136.     WCHAR *)) GetTempFileNameW,
  137.     (DWORD (WINAPI *)(DWORD, WCHAR *)) GetTempPathW,
  138.     (BOOL (WINAPI *)(CONST TCHAR *, WCHAR *, DWORD, LPDWORD, LPDWORD, LPDWORD, 
  139.     WCHAR *, DWORD)) GetVolumeInformationW,
  140.     (HINSTANCE (WINAPI *)(CONST TCHAR *)) LoadLibraryW,
  141.     (TCHAR (WINAPI *)(WCHAR *, CONST TCHAR *)) lstrcpyW,
  142.     (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR *)) MoveFileW,
  143.     (BOOL (WINAPI *)(CONST TCHAR *)) RemoveDirectoryW,
  144.     (DWORD (WINAPI *)(CONST TCHAR *, CONST TCHAR *, CONST TCHAR *, DWORD, 
  145.     WCHAR *, TCHAR **)) SearchPathW,
  146.     (BOOL (WINAPI *)(CONST TCHAR *)) SetCurrentDirectoryW,
  147.     (BOOL (WINAPI *)(CONST TCHAR *, DWORD)) SetFileAttributesW,
  148.     /* 
  149.      * The three NULL function pointers will only be set when
  150.      * Tcl_FindExecutable is called.  If you don't ever call that
  151.      * function, the application will crash whenever WinTcl tries to call
  152.      * functions through these null pointers.  That is not a bug in Tcl
  153.      * -- Tcl_FindExecutable is obligatory in recent Tcl releases.
  154.      */
  155.     NULL,
  156.     NULL,
  157.     (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime,
  158.     NULL,
  159.     NULL,
  160.     /* getLongPathNameProc */
  161.     NULL,
  162.     /* Security SDK - will be filled in on NT,XP,2000,2003 */
  163.     NULL, NULL, NULL, NULL, NULL, NULL,
  164.     /* ReadConsole and WriteConsole */
  165.     (BOOL (WINAPI *)(HANDLE, LPVOID, DWORD, LPDWORD, LPVOID)) ReadConsoleW,
  166.     (BOOL (WINAPI *)(HANDLE, const VOID*, DWORD, LPDWORD, LPVOID)) WriteConsoleW
  167. };
  168. TclWinProcs *tclWinProcs;
  169. static Tcl_Encoding tclWinTCharEncoding;
  170. #ifdef HAVE_NO_SEH
  171. /* Need to add noinline flag to DllMain declaration so that gcc -O3
  172.  * does not inline asm code into DllEntryPoint and cause a
  173.  * compile time error because of redefined local labels.
  174.  */
  175. BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, 
  176. LPVOID reserved)
  177.                         __attribute__ ((noinline));
  178. #else
  179. /*
  180.  * The following declaration is for the VC++ DLL entry point.
  181.  */
  182. BOOL APIENTRY DllMain(HINSTANCE hInst, DWORD reason, 
  183. LPVOID reserved);
  184. #endif /* HAVE_NO_SEH */
  185. /*
  186.  * The following structure and linked list is to allow us to map between
  187.  * volume mount points and drive letters on the fly (no Win API exists
  188.  * for this).
  189.  */
  190. typedef struct MountPointMap {
  191.     CONST WCHAR* volumeName;       /* Native wide string volume name */
  192.     char driveLetter;              /* Drive letter corresponding to
  193.                                     * the volume name. */
  194.     struct MountPointMap* nextPtr; /* Pointer to next structure in list,
  195.                                     * or NULL */
  196. } MountPointMap;
  197. /* 
  198.  * This is the head of the linked list, which is protected by the
  199.  * mutex which follows, for thread-enabled builds.
  200.  */
  201. MountPointMap *driveLetterLookup = NULL;
  202. TCL_DECLARE_MUTEX(mountPointMap)
  203. /* We will need this below */
  204. extern Tcl_FSDupInternalRepProc TclNativeDupInternalRep;
  205. #ifdef __WIN32__
  206. #ifndef STATIC_BUILD
  207. /*
  208.  *----------------------------------------------------------------------
  209.  *
  210.  * DllEntryPoint --
  211.  *
  212.  * This wrapper function is used by Borland to invoke the
  213.  * initialization code for Tcl.  It simply calls the DllMain
  214.  * routine.
  215.  *
  216.  * Results:
  217.  * See DllMain.
  218.  *
  219.  * Side effects:
  220.  * See DllMain.
  221.  *
  222.  *----------------------------------------------------------------------
  223.  */
  224. BOOL APIENTRY
  225. DllEntryPoint(hInst, reason, reserved)
  226.     HINSTANCE hInst; /* Library instance handle. */
  227.     DWORD reason; /* Reason this function is being called. */
  228.     LPVOID reserved; /* Not used. */
  229. {
  230.     return DllMain(hInst, reason, reserved);
  231. }
  232. /*
  233.  *----------------------------------------------------------------------
  234.  *
  235.  * DllMain --
  236.  *
  237.  * This routine is called by the VC++ C run time library init
  238.  * code, or the DllEntryPoint routine.  It is responsible for
  239.  * initializing various dynamically loaded libraries.
  240.  *
  241.  * Results:
  242.  * TRUE on sucess, FALSE on failure.
  243.  *
  244.  * Side effects:
  245.  * Establishes 32-to-16 bit thunk and initializes sockets library.
  246.  *
  247.  *----------------------------------------------------------------------
  248.  */
  249. BOOL APIENTRY
  250. DllMain(hInst, reason, reserved)
  251.     HINSTANCE hInst; /* Library instance handle. */
  252.     DWORD reason; /* Reason this function is being called. */
  253.     LPVOID reserved; /* Not used. */
  254. {
  255. #ifdef HAVE_NO_SEH
  256.     EXCEPTION_REGISTRATION registration;
  257. #endif
  258.     switch (reason) {
  259.     case DLL_PROCESS_ATTACH:
  260. DisableThreadLibraryCalls(hInst);
  261. TclWinInit(hInst);
  262. return TRUE;
  263.     case DLL_PROCESS_DETACH:
  264. /*
  265.  * Protect the call to Tcl_Finalize.  The OS could be unloading
  266.  * us from an exception handler and the state of the stack might
  267.  * be unstable.
  268.  */
  269. #ifdef HAVE_NO_SEH
  270.         __asm__ __volatile__ (
  271.             /*
  272.              * Construct an EXCEPTION_REGISTRATION to protect the
  273.              * call to Tcl_Finalize
  274.              */
  275.             "leal       %[registration], %%edx"         "nt"
  276.             "movl       %%fs:0,         %%eax"          "nt"
  277.             "movl       %%eax,          0x0(%%edx)"     "nt" /* link */
  278.             "leal       1f,             %%eax"          "nt"
  279.             "movl       %%eax,          0x4(%%edx)"     "nt" /* handler */
  280.             "movl       %%ebp,          0x8(%%edx)"     "nt" /* ebp */
  281.             "movl       %%esp,          0xc(%%edx)"     "nt" /* esp */
  282.             "movl       %[error],       0x10(%%edx)"    "nt" /* status */
  283.             /*
  284.              * Link the EXCEPTION_REGISTRATION on the chain
  285.              */
  286.             "movl       %%edx,          %%fs:0"         "nt"
  287.             /*
  288.              * Call Tcl_Finalize
  289.              */
  290.             "call       _Tcl_Finalize"                  "nt"
  291.             /*
  292.              * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
  293.              * and store a TCL_OK status
  294.              */
  295.             "movl       %%fs:0,         %%edx"          "nt"
  296.             "movl       %[ok],          %%eax"          "nt"
  297.             "movl       %%eax,          0x10(%%edx)"    "nt"
  298.             "jmp        2f"                             "n"
  299.             /*
  300.              * Come here on an exception. Get the EXCEPTION_REGISTRATION
  301.              * that we previously put on the chain.
  302.              */
  303.             "1:"                                        "t"
  304.             "movl       %%fs:0,         %%edx"          "nt"
  305.             "movl       0x8(%%edx),     %%edx"          "n"
  306.             /* 
  307.              * Come here however we exited.  Restore context from the
  308.              * EXCEPTION_REGISTRATION in case the stack is unbalanced.
  309.              */
  310.             "2:"                                        "t"
  311.             "movl       0xc(%%edx),     %%esp"          "nt"
  312.             "movl       0x8(%%edx),     %%ebp"          "nt"
  313.             "movl       0x0(%%edx),     %%eax"          "nt"
  314.             "movl       %%eax,          %%fs:0"         "nt"
  315.             :
  316.             /* No outputs */
  317.             :
  318.             [registration]      "m"     (registration),
  319.             [ok]                "i"     (TCL_OK),
  320.             [error]             "i"     (TCL_ERROR)
  321.             :
  322.             "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
  323.             );
  324. #else /* HAVE_NO_SEH */
  325. __try {
  326.     Tcl_Finalize();
  327. } __except (EXCEPTION_EXECUTE_HANDLER) {
  328.     /* empty handler body. */
  329. }
  330. #endif
  331. break;
  332.     }
  333.     return TRUE; 
  334. }
  335. #endif /* !STATIC_BUILD */
  336. #endif /* __WIN32__ */
  337. /*
  338.  *----------------------------------------------------------------------
  339.  *
  340.  * TclWinGetTclInstance --
  341.  *
  342.  * Retrieves the global library instance handle.
  343.  *
  344.  * Results:
  345.  * Returns the global library instance handle.
  346.  *
  347.  * Side effects:
  348.  * None.
  349.  *
  350.  *----------------------------------------------------------------------
  351.  */
  352. HINSTANCE
  353. TclWinGetTclInstance()
  354. {
  355.     return hInstance;
  356. }
  357. /*
  358.  *----------------------------------------------------------------------
  359.  *
  360.  * TclWinInit --
  361.  *
  362.  * This function initializes the internal state of the tcl library.
  363.  *
  364.  * Results:
  365.  * None.
  366.  *
  367.  * Side effects:
  368.  * Initializes the tclPlatformId variable.
  369.  *
  370.  *----------------------------------------------------------------------
  371.  */
  372. void
  373. TclWinInit(hInst)
  374.     HINSTANCE hInst; /* Library instance handle. */
  375. {
  376.     OSVERSIONINFO os;
  377.     hInstance = hInst;
  378.     os.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  379.     GetVersionEx(&os);
  380.     platformId = os.dwPlatformId;
  381.     /*
  382.      * We no longer support Win32s, so just in case someone manages to
  383.      * get a runtime there, make sure they know that.
  384.      */
  385.     if (platformId == VER_PLATFORM_WIN32s) {
  386. panic("Win32s is not a supported platform");
  387.     }
  388.     tclWinProcs = &asciiProcs;
  389. }
  390. /*
  391.  *----------------------------------------------------------------------
  392.  *
  393.  * TclWinGetPlatformId --
  394.  *
  395.  * Determines whether running under NT, 95, or Win32s, to allow 
  396.  * runtime conditional code.
  397.  *
  398.  * Results:
  399.  * The return value is one of:
  400.  *     VER_PLATFORM_WIN32s Win32s on Windows 3.1. (not supported)
  401.  *     VER_PLATFORM_WIN32_WINDOWS Win32 on Windows 95.
  402.  *     VER_PLATFORM_WIN32_NT Win32 on Windows NT
  403.  *
  404.  * Side effects:
  405.  * None.
  406.  *
  407.  *----------------------------------------------------------------------
  408.  */
  409. int
  410. TclWinGetPlatformId()
  411. {
  412.     return platformId;
  413. }
  414. /*
  415.  *-------------------------------------------------------------------------
  416.  *
  417.  * TclWinNoBackslash --
  418.  *
  419.  * We're always iterating through a string in Windows, changing the
  420.  * backslashes to slashes for use in Tcl.
  421.  *
  422.  * Results:
  423.  * All backslashes in given string are changed to slashes.
  424.  *
  425.  * Side effects:
  426.  * None.
  427.  *
  428.  *-------------------------------------------------------------------------
  429.  */
  430. char *
  431. TclWinNoBackslash(
  432.     char *path) /* String to change. */
  433. {
  434.     char *p;
  435.     for (p = path; *p != ''; p++) {
  436. if (*p == '\') {
  437.     *p = '/';
  438. }
  439.     }
  440.     return path;
  441. }
  442. /*
  443.  *----------------------------------------------------------------------
  444.  *
  445.  * TclpCheckStackSpace --
  446.  *
  447.  * Detect if we are about to blow the stack.  Called before an 
  448.  * evaluation can happen when nesting depth is checked.
  449.  *
  450.  * Results:
  451.  * 1 if there is enough stack space to continue; 0 if not.
  452.  *
  453.  * Side effects:
  454.  * None.
  455.  *
  456.  *----------------------------------------------------------------------
  457.  */
  458. int
  459. TclpCheckStackSpace()
  460. {
  461. #ifdef HAVE_NO_SEH
  462.     EXCEPTION_REGISTRATION registration;
  463. #endif
  464.     int retval = 0;
  465.     /*
  466.      * We can recurse only if there is at least TCL_WIN_STACK_THRESHOLD
  467.      * bytes of stack space left.  alloca() is cheap on windows; basically
  468.      * it just subtracts from the stack pointer causing the OS to throw an
  469.      * exception if the stack pointer is set below the bottom of the stack.
  470.      */
  471. #ifdef HAVE_NO_SEH
  472.     __asm__ __volatile__ (
  473.         /*
  474.          * Construct an EXCEPTION_REGISTRATION to protect the
  475.          * call to __alloca
  476.          */
  477.         "leal   %[registration], %%edx"         "nt"
  478.         "movl   %%fs:0,         %%eax"          "nt"
  479.         "movl   %%eax,          0x0(%%edx)"     "nt" /* link */
  480.         "leal   1f,             %%eax"          "nt"
  481.         "movl   %%eax,          0x4(%%edx)"     "nt" /* handler */
  482.         "movl   %%ebp,          0x8(%%edx)"     "nt" /* ebp */
  483.         "movl   %%esp,          0xc(%%edx)"     "nt" /* esp */
  484.         "movl   %[error],       0x10(%%edx)"    "nt" /* status */
  485.         
  486.         /*
  487.          * Link the EXCEPTION_REGISTRATION on the chain
  488.          */
  489.         "movl   %%edx,          %%fs:0"         "nt"
  490.         /*
  491.          * Attempt a call to __alloca, to determine whether there's
  492.          * sufficient memory to be had.
  493.          */
  494.         "movl   %[size],        %%eax"          "nt"
  495.         "pushl  %%eax"                          "nt"
  496.         "call   __alloca"                       "nt"
  497.         /*
  498.          * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
  499.          * and store a TCL_OK status
  500.          */
  501.         "movl   %%fs:0,         %%edx"          "nt"
  502.         "movl   %[ok],          %%eax"          "nt"
  503.         "movl   %%eax,          0x10(%%edx)"    "nt"
  504.         "jmp    2f"                             "n"
  505.         /*
  506.          * Come here on an exception. Get the EXCEPTION_REGISTRATION
  507.          * that we previously put on the chain.
  508.          */
  509.         "1:"                                    "t"
  510.         "movl   %%fs:0,         %%edx"          "nt"
  511.         "movl   0x8(%%edx),     %%edx"          "nt"
  512.         
  513.         /* 
  514.          * Come here however we exited.  Restore context from the
  515.          * EXCEPTION_REGISTRATION in case the stack is unbalanced.
  516.          */
  517.         
  518.         "2:"                                    "t"
  519.         "movl   0xc(%%edx),     %%esp"          "nt"
  520.         "movl   0x8(%%edx),     %%ebp"          "nt"
  521.         "movl   0x0(%%edx),     %%eax"          "nt"
  522.         "movl   %%eax,          %%fs:0"         "nt"
  523.         
  524.         :
  525.         /* No outputs */
  526.         :
  527.         [registration]  "m"     (registration),
  528.         [ok]            "i"     (TCL_OK),
  529.         [error]         "i"     (TCL_ERROR),
  530.         [size]          "i"     (TCL_WIN_STACK_THRESHOLD)
  531.         :
  532.         "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"
  533.         );
  534.     retval = (registration.status == TCL_OK);
  535. #else /* !HAVE_NO_SEH */
  536.     __try {
  537. #ifdef HAVE_ALLOCA_GCC_INLINE
  538.         __asm__ __volatile__ (
  539.             "movl  %0, %%eax" "nt"
  540.             "call  __alloca" "nt"
  541.             :
  542.             : "i"(TCL_WIN_STACK_THRESHOLD)
  543.             : "%eax");
  544. #else
  545.         alloca(TCL_WIN_STACK_THRESHOLD);
  546. #endif /* HAVE_ALLOCA_GCC_INLINE */
  547.         retval = 1;
  548.     } __except (EXCEPTION_EXECUTE_HANDLER) {}
  549. #endif /* HAVE_NO_SEH */
  550.     return retval;
  551. }
  552. /*
  553.  *----------------------------------------------------------------------
  554.  *
  555.  * TclWinGetPlatform --
  556.  *
  557.  * This is a kludge that allows the test library to get access
  558.  * the internal tclPlatform variable.
  559.  *
  560.  * Results:
  561.  * Returns a pointer to the tclPlatform variable.
  562.  *
  563.  * Side effects:
  564.  * None.
  565.  *
  566.  *----------------------------------------------------------------------
  567.  */
  568. TclPlatformType *
  569. TclWinGetPlatform()
  570. {
  571.     return &tclPlatform;
  572. }
  573. /*
  574.  *---------------------------------------------------------------------------
  575.  *
  576.  * TclWinSetInterfaces --
  577.  *
  578.  * A helper proc that allows the test library to change the
  579.  * tclWinProcs structure to dispatch to either the wide-character
  580.  * or multi-byte versions of the operating system calls, depending
  581.  * on whether Unicode is the system encoding.
  582.  *
  583.  * As well as this, we can also try to load in some additional
  584.  * procs which may/may not be present depending on the current
  585.  * Windows version (e.g. Win95 will not have the procs below).
  586.  *
  587.  * Results:
  588.  * None.
  589.  *
  590.  * Side effects:
  591.  * None.
  592.  *
  593.  *---------------------------------------------------------------------------
  594.  */
  595. void
  596. TclWinSetInterfaces(
  597.     int wide) /* Non-zero to use wide interfaces, 0
  598.  * otherwise. */
  599. {
  600.     Tcl_FreeEncoding(tclWinTCharEncoding);
  601.     if (wide) {
  602. tclWinProcs = &unicodeProcs;
  603. tclWinTCharEncoding = Tcl_GetEncoding(NULL, "unicode");
  604. if (tclWinProcs->getFileAttributesExProc == NULL) {
  605.     HINSTANCE hInstance = LoadLibraryA("kernel32");
  606.     if (hInstance != NULL) {
  607.         tclWinProcs->getFileAttributesExProc = 
  608.   (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, 
  609.   LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExW");
  610. tclWinProcs->createHardLinkProc = 
  611.   (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, 
  612.   LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, 
  613.   "CreateHardLinkW");
  614.         tclWinProcs->findFirstFileExProc = 
  615.   (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
  616.   LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, 
  617.   "FindFirstFileExW");
  618.         tclWinProcs->getVolumeNameForVMPProc = 
  619.   (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, 
  620.   DWORD)) GetProcAddress(hInstance, 
  621.   "GetVolumeNameForVolumeMountPointW");
  622. FreeLibrary(hInstance);
  623.     }
  624.     hInstance = LoadLibraryA("advapi32");
  625.     if (hInstance != NULL) {
  626. tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
  627. LPCTSTR lpFileName,
  628. SECURITY_INFORMATION RequestedInformation,
  629. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  630. DWORD nLength, LPDWORD lpnLengthNeeded))
  631. GetProcAddress(hInstance, "GetFileSecurityW");
  632. tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) (
  633. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel))
  634. GetProcAddress(hInstance, "ImpersonateSelf");
  635. tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) (
  636. HANDLE ThreadHandle, DWORD DesiredAccess,
  637. BOOL OpenAsSelf, PHANDLE TokenHandle))
  638. GetProcAddress(hInstance, "OpenThreadToken");
  639. tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void))
  640. GetProcAddress(hInstance, "RevertToSelf");
  641. tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) (
  642. PDWORD AccessMask, PGENERIC_MAPPING GenericMapping))
  643. GetProcAddress(hInstance, "MapGenericMask");
  644. tclWinProcs->accessCheckProc = (BOOL (WINAPI *)(
  645. PSECURITY_DESCRIPTOR pSecurityDescriptor,
  646. HANDLE ClientToken, DWORD DesiredAccess,
  647. PGENERIC_MAPPING GenericMapping,
  648. PPRIVILEGE_SET PrivilegeSet,
  649. LPDWORD PrivilegeSetLength, LPDWORD GrantedAccess,
  650. LPBOOL AccessStatus)) GetProcAddress(hInstance,
  651. "AccessCheck");
  652. FreeLibrary(hInstance);
  653.     }
  654. }
  655.     } else {
  656. tclWinProcs = &asciiProcs;
  657. tclWinTCharEncoding = NULL;
  658. if (tclWinProcs->getFileAttributesExProc == NULL) {
  659.     HINSTANCE hInstance = LoadLibraryA("kernel32");
  660.     if (hInstance != NULL) {
  661. tclWinProcs->getFileAttributesExProc = 
  662.   (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, 
  663.   LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExA");
  664. tclWinProcs->createHardLinkProc = 
  665.   (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, 
  666.   LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, 
  667.   "CreateHardLinkA");
  668. tclWinProcs->findFirstFileExProc = 
  669.   (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
  670.   LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, 
  671.   "FindFirstFileExA");
  672. tclWinProcs->getLongPathNameProc = NULL;
  673. tclWinProcs->getVolumeNameForVMPProc = 
  674.   (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, 
  675.   DWORD)) GetProcAddress(hInstance, 
  676.   "GetVolumeNameForVolumeMountPointA");
  677. FreeLibrary(hInstance);
  678.     }
  679. }
  680.     }
  681. }
  682. /*
  683.  *---------------------------------------------------------------------------
  684.  *
  685.  * TclWinResetInterfaceEncodings --
  686.  *
  687.  * Called during finalization to free up any encodings we use.
  688.  * The tclWinProcs-> look up table is still ok to use after
  689.  * this call, provided no encoding conversion is required.
  690.  *
  691.  *      We also clean up any memory allocated in our mount point
  692.  *      map which is used to follow certain kinds of symlinks.
  693.  *      That code should never be used once encodings are taken
  694.  *      down.
  695.  *      
  696.  * Results:
  697.  * None.
  698.  *
  699.  * Side effects:
  700.  * None.
  701.  *
  702.  *---------------------------------------------------------------------------
  703.  */
  704. void
  705. TclWinResetInterfaceEncodings()
  706. {
  707.     MountPointMap *dlIter, *dlIter2;
  708.     if (tclWinTCharEncoding != NULL) {
  709. Tcl_FreeEncoding(tclWinTCharEncoding);
  710. tclWinTCharEncoding = NULL;
  711.     }
  712.     /* Clean up the mount point map */
  713.     Tcl_MutexLock(&mountPointMap);
  714.     dlIter = driveLetterLookup; 
  715.     while (dlIter != NULL) {
  716. dlIter2 = dlIter->nextPtr;
  717. ckfree((char*)dlIter->volumeName);
  718. ckfree((char*)dlIter);
  719. dlIter = dlIter2;
  720.     }
  721.     Tcl_MutexUnlock(&mountPointMap);
  722. }
  723. /*
  724.  *---------------------------------------------------------------------------
  725.  *
  726.  * TclWinResetInterfaces --
  727.  *
  728.  * Called during finalization to reset us to a safe state for reuse.
  729.  * After this call, it is best not to use the tclWinProcs-> look
  730.  * up table since it is likely to be different to what is expected.
  731.  *
  732.  * Results:
  733.  * None.
  734.  *
  735.  * Side effects:
  736.  * None.
  737.  *
  738.  *---------------------------------------------------------------------------
  739.  */
  740. void
  741. TclWinResetInterfaces()
  742. {
  743.     tclWinProcs = &asciiProcs;
  744. }
  745. /*
  746.  *--------------------------------------------------------------------
  747.  *
  748.  * TclWinDriveLetterForVolMountPoint
  749.  *
  750.  * Unfortunately, Windows provides no easy way at all to get hold
  751.  * of the drive letter for a volume mount point, but we need that
  752.  * information to understand paths correctly.  So, we have to 
  753.  * build an associated array to find these correctly, and allow
  754.  * quick and easy lookup from volume mount points to drive letters.
  755.  * 
  756.  * We assume here that we are running on a system for which the wide
  757.  * character interfaces are used, which is valid for Win 2000 and WinXP
  758.  * which are the only systems on which this function will ever be called.
  759.  * 
  760.  * Result: the drive letter, or -1 if no drive letter corresponds to
  761.  * the given mount point.
  762.  * 
  763.  *--------------------------------------------------------------------
  764.  */
  765. char 
  766. TclWinDriveLetterForVolMountPoint(CONST WCHAR *mountPoint)
  767. {
  768.     MountPointMap *dlIter, *dlPtr2;
  769.     WCHAR Target[55];         /* Target of mount at mount point */
  770.     WCHAR drive[4] = { L'A', L':', L'\', L'' };
  771.     
  772.     /* 
  773.      * Detect the volume mounted there.  Unfortunately, there is no
  774.      * simple way to map a unique volume name to a DOS drive letter.  
  775.      * So, we have to build an associative array.
  776.      */
  777.     
  778.     Tcl_MutexLock(&mountPointMap);
  779.     dlIter = driveLetterLookup; 
  780.     while (dlIter != NULL) {
  781. if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
  782.     /* 
  783.      * We need to check whether this information is
  784.      * still valid, since either the user or various
  785.      * programs could have adjusted the mount points on
  786.      * the fly.
  787.      */
  788.     drive[0] = L'A' + (dlIter->driveLetter - 'A');
  789.     /* Try to read the volume mount point and see where it points */
  790.     if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, 
  791.        (TCHAR*)Target, 55) != 0) {
  792. if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
  793.     /* Nothing has changed */
  794.     Tcl_MutexUnlock(&mountPointMap);
  795.     return dlIter->driveLetter;
  796. }
  797.     }
  798.     /* 
  799.      * If we reach here, unfortunately, this mount point is
  800.      * no longer valid at all
  801.      */
  802.     if (driveLetterLookup == dlIter) {
  803. dlPtr2 = dlIter;
  804. driveLetterLookup = dlIter->nextPtr;
  805.     } else {
  806. for (dlPtr2 = driveLetterLookup; 
  807.      dlPtr2 != NULL; dlPtr2 = dlPtr2->nextPtr) {
  808.     if (dlPtr2->nextPtr == dlIter) {
  809. dlPtr2->nextPtr = dlIter->nextPtr;
  810. dlPtr2 = dlIter;
  811. break;
  812.     }
  813. }
  814.     }
  815.     /* Now dlPtr2 points to the structure to free */
  816.     ckfree((char*)dlPtr2->volumeName);
  817.     ckfree((char*)dlPtr2);
  818.     /* 
  819.      * Restart the loop --- we could try to be clever
  820.      * and continue half way through, but the logic is a 
  821.      * bit messy, so it's cleanest just to restart
  822.      */
  823.     dlIter = driveLetterLookup;
  824.     continue;
  825. }
  826. dlIter = dlIter->nextPtr;
  827.     }
  828.    
  829.     /* We couldn't find it, so we must iterate over the letters */
  830.     
  831.     for (drive[0] = L'A'; drive[0] <= L'Z'; drive[0]++) {
  832. /* Try to read the volume mount point and see where it points */
  833. if ((*tclWinProcs->getVolumeNameForVMPProc)((TCHAR*)drive, 
  834.    (TCHAR*)Target, 55) != 0) {
  835.     int alreadyStored = 0;
  836.     for (dlIter = driveLetterLookup; dlIter != NULL; 
  837.  dlIter = dlIter->nextPtr) {
  838. if (wcscmp((WCHAR*)dlIter->volumeName, Target) == 0) {
  839.     alreadyStored = 1;
  840.     break;
  841. }
  842.     }
  843.     if (!alreadyStored) {
  844. dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
  845. dlPtr2->volumeName = TclNativeDupInternalRep(Target);
  846. dlPtr2->driveLetter = 'A' + (drive[0] - L'A');
  847. dlPtr2->nextPtr = driveLetterLookup;
  848. driveLetterLookup  = dlPtr2;
  849.     }
  850. }
  851.     }
  852.     /* Try again */
  853.     for (dlIter = driveLetterLookup; dlIter != NULL; 
  854. dlIter = dlIter->nextPtr) {
  855. if (wcscmp(dlIter->volumeName, mountPoint) == 0) {
  856.     Tcl_MutexUnlock(&mountPointMap);
  857.     return dlIter->driveLetter;
  858. }
  859.     }
  860.     /* 
  861.      * The volume doesn't appear to correspond to a drive letter -- we
  862.      * remember that fact and store '-1' so we don't have to look it
  863.      * up each time.
  864.      */
  865.     dlPtr2 = (MountPointMap*) ckalloc(sizeof(MountPointMap));
  866.     dlPtr2->volumeName = TclNativeDupInternalRep((ClientData)mountPoint);
  867.     dlPtr2->driveLetter = -1;
  868.     dlPtr2->nextPtr = driveLetterLookup;
  869.     driveLetterLookup  = dlPtr2;
  870.     Tcl_MutexUnlock(&mountPointMap);
  871.     return -1;
  872. }
  873. /*
  874.  *---------------------------------------------------------------------------
  875.  *
  876.  * Tcl_WinUtfToTChar, Tcl_WinTCharToUtf --
  877.  *
  878.  * Convert between UTF-8 and Unicode when running Windows NT or 
  879.  * the current ANSI code page when running Windows 95.
  880.  *
  881.  * On Mac, Unix, and Windows 95, all strings exchanged between Tcl
  882.  * and the OS are "char" oriented.  We need only one Tcl_Encoding to
  883.  * convert between UTF-8 and the system's native encoding.  We use
  884.  * NULL to represent that encoding.
  885.  *
  886.  * On NT, some strings exchanged between Tcl and the OS are "char"
  887.  * oriented, while others are in Unicode.  We need two Tcl_Encoding
  888.  * APIs depending on whether we are targeting a "char" or Unicode
  889.  * interface.  
  890.  *
  891.  * Calling Tcl_UtfToExternal() or Tcl_ExternalToUtf() with an
  892.  * encoding of NULL should always used to convert between UTF-8
  893.  * and the system's "char" oriented encoding.  The following two
  894.  * functions are used in Windows-specific code to convert between
  895.  * UTF-8 and Unicode strings (NT) or "char" strings(95).  This saves
  896.  * you the trouble of writing the following type of fragment over and
  897.  * over:
  898.  *
  899.  * if (running NT) {
  900.  *     encoding <- Tcl_GetEncoding("unicode");
  901.  *     nativeBuffer <- UtfToExternal(encoding, utfBuffer);
  902.  *     Tcl_FreeEncoding(encoding);
  903.  * } else {
  904.  *     nativeBuffer <- UtfToExternal(NULL, utfBuffer);
  905.  * }
  906.  *
  907.  * By convention, in Windows a TCHAR is a character in the ANSI code
  908.  * page on Windows 95, a Unicode character on Windows NT.  If you
  909.  * plan on targeting a Unicode interfaces when running on NT and a
  910.  * "char" oriented interface while running on 95, these functions
  911.  * should be used.  If you plan on targetting the same "char"
  912.  * oriented function on both 95 and NT, use Tcl_UtfToExternal()
  913.  * with an encoding of NULL.
  914.  *
  915.  * Results:
  916.  * The result is a pointer to the string in the desired target
  917.  * encoding.  Storage for the result string is allocated in
  918.  * dsPtr; the caller must call Tcl_DStringFree() when the result
  919.  * is no longer needed.
  920.  *
  921.  * Side effects:
  922.  * None.
  923.  *
  924.  *---------------------------------------------------------------------------
  925.  */
  926. TCHAR *
  927. Tcl_WinUtfToTChar(string, len, dsPtr)
  928.     CONST char *string; /* Source string in UTF-8. */
  929.     int len; /* Source string length in bytes, or < 0 for
  930.  * strlen(). */
  931.     Tcl_DString *dsPtr; /* Uninitialized or free DString in which 
  932.  * the converted string is stored. */
  933. {
  934.     return (TCHAR *) Tcl_UtfToExternalDString(tclWinTCharEncoding, 
  935.     string, len, dsPtr);
  936. }
  937. char *
  938. Tcl_WinTCharToUtf(string, len, dsPtr)
  939.     CONST TCHAR *string; /* Source string in Unicode when running
  940.  * NT, ANSI when running 95. */
  941.     int len; /* Source string length in bytes, or < 0 for
  942.  * platform-specific string length. */
  943.     Tcl_DString *dsPtr; /* Uninitialized or free DString in which 
  944.  * the converted string is stored. */
  945. {
  946.     return Tcl_ExternalToUtfDString(tclWinTCharEncoding, 
  947.     (CONST char *) string, len, dsPtr);
  948. }
  949. /*
  950.  *------------------------------------------------------------------------
  951.  *
  952.  * TclWinCPUID --
  953.  *
  954.  * Get CPU ID information on an Intel box under Windows
  955.  *
  956.  * Results:
  957.  * Returns TCL_OK if successful, TCL_ERROR if CPUID is not
  958.  * supported or fails.
  959.  *
  960.  * Side effects:
  961.  * If successful, stores EAX, EBX, ECX and EDX registers after 
  962.  *      the CPUID instruction in the four integers designated by 'regsPtr'
  963.  *
  964.  *----------------------------------------------------------------------
  965.  */
  966. int
  967. TclWinCPUID( unsigned int index, /* Which CPUID value to retrieve */
  968.      unsigned int * regsPtr ) /* Registers after the CPUID */
  969. {
  970. #ifdef HAVE_NO_SEH
  971.     EXCEPTION_REGISTRATION registration;
  972. #endif
  973.     int status = TCL_ERROR;
  974. #if defined(__GNUC__) && !defined(_WIN64)
  975.     /* 
  976.      * Execute the CPUID instruction with the given index, and
  977.      * store results off 'regPtr'.
  978.      */
  979.     
  980.     __asm__ __volatile__ (
  981.         /*
  982.          * Construct an EXCEPTION_REGISTRATION to protect the
  983.          * CPUID instruction (early 486's don't have CPUID)
  984.          */
  985.         "leal   %[registration], %%edx"         "nt"
  986.         "movl   %%fs:0,         %%eax"          "nt"
  987.         "movl   %%eax,          0x0(%%edx)"     "nt" /* link */
  988.         "leal   1f,             %%eax"          "nt"
  989.         "movl   %%eax,          0x4(%%edx)"     "nt" /* handler */
  990.         "movl   %%ebp,          0x8(%%edx)"     "nt" /* ebp */
  991.         "movl   %%esp,          0xc(%%edx)"     "nt" /* esp */
  992.         "movl   %[error],       0x10(%%edx)"    "nt" /* status */
  993.         
  994.         /*
  995.          * Link the EXCEPTION_REGISTRATION on the chain
  996.          */
  997.         "movl   %%edx,          %%fs:0"         "nt"
  998.         /*
  999.          * Do the CPUID instruction, and save the results in
  1000.          * the 'regsPtr' area
  1001.          */
  1002.         "movl   %[rptr],        %%edi"          "nt"
  1003.         "movl   %[index],       %%eax"          "nt"
  1004.         "cpuid"                                 "nt"
  1005.         "movl   %%eax,          0x0(%%edi)"     "nt"
  1006.         "movl   %%ebx,          0x4(%%edi)"     "nt"
  1007.         "movl   %%ecx,          0x8(%%edi)"     "nt"
  1008.         "movl   %%edx,          0xc(%%edi)"     "nt"
  1009.         /*
  1010.          * Come here on a normal exit. Recover the EXCEPTION_REGISTRATION
  1011.          * and store a TCL_OK status
  1012.          */
  1013.         "movl   %%fs:0,         %%edx"          "nt"
  1014.         "movl   %[ok],          %%eax"          "nt"
  1015.         "movl   %%eax,          0x10(%%edx)"    "nt"
  1016.         "jmp    2f"                             "n"
  1017.         /*
  1018.          * Come here on an exception. Get the EXCEPTION_REGISTRATION
  1019.          * that we previously put on the chain.
  1020.          */
  1021.         "1:"                                    "t"
  1022.         "movl   %%fs:0,         %%edx"          "nt"
  1023.         "movl   0x8(%%edx),     %%edx"          "nt"
  1024.         
  1025.         /* 
  1026.          * Come here however we exited.  Restore context from the
  1027.          * EXCEPTION_REGISTRATION in case the stack is unbalanced.
  1028.          */
  1029.         
  1030.         "2:"                                    "t"
  1031.         "movl   0xc(%%edx),     %%esp"          "nt"
  1032.         "movl   0x8(%%edx),     %%ebp"          "nt"
  1033.         "movl   0x0(%%edx),     %%eax"          "nt"
  1034.         "movl   %%eax,          %%fs:0"         "nt"
  1035.         : 
  1036.         /* No outputs */
  1037.         : 
  1038.         [index]         "m"     (index),
  1039.         [rptr]          "m"     (regsPtr),
  1040.         [registration]  "m"     (registration),
  1041.         [ok]            "i"     (TCL_OK),
  1042.         [error]         "i"     (TCL_ERROR)
  1043.         :
  1044.         "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory" );
  1045.     status = registration.status;
  1046. #elif defined(_MSC_VER) && !defined(_WIN64)
  1047.     /* Define a structure in the stack frame to hold the registers */
  1048.     struct {
  1049. DWORD dw0;
  1050. DWORD dw1;
  1051. DWORD dw2;
  1052. DWORD dw3;
  1053.     } regs;
  1054.     regs.dw0 = index;
  1055.     
  1056.     /* Execute the CPUID instruction and save regs in the stack frame */
  1057.     _try {
  1058. _asm {
  1059.     push    ebx
  1060.     push    ecx
  1061.     push    edx
  1062.     mov     eax, regs.dw0
  1063.     cpuid
  1064.     mov     regs.dw0, eax
  1065.     mov     regs.dw1, ebx
  1066.     mov     regs.dw2, ecx
  1067.     mov     regs.dw3, edx
  1068.             pop     edx
  1069.             pop     ecx
  1070.             pop     ebx
  1071. }
  1072. /* Copy regs back out to the caller */
  1073. regsPtr[0]=regs.dw0;
  1074. regsPtr[1]=regs.dw1;
  1075. regsPtr[2]=regs.dw2;
  1076. regsPtr[3]=regs.dw3;
  1077. status = TCL_OK;
  1078.     } __except( EXCEPTION_EXECUTE_HANDLER ) {
  1079.     }
  1080. #else
  1081. /* Don't know how to do assembly code for
  1082.  * this compiler and/or architecture */
  1083. #endif
  1084.     return status;
  1085. }