/* * tclWin32Dll.c -- * * This file contains the DLL entry point which sets up the 32-to-16-bit * thunking code for SynchSpawn if the library is running under Win32s. * * Copyright (c) 1995-1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * SCCS: @(#) tclWin32Dll.c 1.15 96/09/12 15:10:59 */ #include #include "tcl.h" #include "tclPort.h" #include "tclWinInt.h" typedef DWORD (WINAPI * UT32PROC)(LPVOID lpBuff, DWORD dwUserDefined, LPVOID *lpTranslationList); typedef BOOL (WINAPI * PUTREGISTER)(HANDLE hModule, LPCSTR SixteenBitDLL, LPCSTR InitName, LPCSTR ProcName, UT32PROC* ThirtyTwoBitThunk, FARPROC UT32Callback, LPVOID Buff); typedef VOID (WINAPI * PUTUNREGISTER)(HANDLE hModule); static PUTUNREGISTER UTUnRegister = NULL; static int tclProcessesAttached = 0; /* * The following data structure is used to keep track of all of the DLL's * opened by Tcl so that they can be freed with the Tcl.dll is unloaded. */ typedef struct LibraryList { HINSTANCE handle; struct LibraryList *nextPtr; } LibraryList; static LibraryList *libraryList = NULL; /* List of currently loaded DLL's. */ static HINSTANCE tclInstance; /* Global library instance handle. */ /* * Declarations for functions that are only used in this file. */ static void UnloadLibraries _ANSI_ARGS_((void)); /* * The following declaration is for the VC++ DLL entry point. */ BOOL APIENTRY DllMain _ANSI_ARGS_((HINSTANCE hInst, DWORD reason, LPVOID reserved)); /* *---------------------------------------------------------------------- * * DllEntryPoint -- * * This wrapper function is used by Borland to invoke the * initialization code for Tcl. It simply calls the DllMain * routine. * * Results: * See DllMain. * * Side effects: * See DllMain. * *---------------------------------------------------------------------- */ BOOL APIENTRY DllEntryPoint(hInst, reason, reserved) HINSTANCE hInst; /* Library instance handle. */ DWORD reason; /* Reason this function is being called. */ LPVOID reserved; /* Not used. */ { return DllMain(hInst, reason, reserved); } /* *---------------------------------------------------------------------- * * DllMain -- * * This routine is called by the VC++ C run time library init * code, or the DllEntryPoint routine. It is responsible for * initializing various dynamically loaded libraries. * * Results: * TRUE on sucess, FALSE on failure. * * Side effects: * Establishes 32-to-16 bit thunk and initializes sockets library. * *---------------------------------------------------------------------- */ BOOL APIENTRY DllMain(hInst, reason, reserved) HINSTANCE hInst; /* Library instance handle. */ DWORD reason; /* Reason this function is being called. */ LPVOID reserved; /* Not used. */ { switch (reason) { case DLL_PROCESS_ATTACH: /* * Registration of UT need to be done only once for first * attaching process. At that time set the tclWin32s flag * to indicate if the DLL is executing under Win32s or not. */ if (tclProcessesAttached++) { return FALSE; /* Not the first initialization. */ } tclInstance = hInst; return TRUE; case DLL_PROCESS_DETACH: tclProcessesAttached--; if (tclProcessesAttached == 0) { /* * Unregister the Tcl thunk. */ if (UTUnRegister != NULL) { UTUnRegister(hInst); } /* * Cleanup any dynamically loaded libraries. */ UnloadLibraries(); } break; } return TRUE; } /* *---------------------------------------------------------------------- * * TclWinLoadLibrary -- * * This function is a wrapper for the system LoadLibrary. It is * responsible for adding library handles to the library list so * the libraries can be freed when tcl.dll is unloaded. * * Results: * Returns the handle of the newly loaded library, or NULL on * failure. * * Side effects: * Loads the specified library into the process. * *---------------------------------------------------------------------- */ HINSTANCE TclWinLoadLibrary(name) char *name; /* Library file to load. */ { HINSTANCE handle; LibraryList *ptr; handle = LoadLibrary(name); if (handle != NULL) { ptr = (LibraryList*) ckalloc(sizeof(LibraryList)); ptr->handle = handle; ptr->nextPtr = libraryList; libraryList = ptr; } else { TclWinConvertError(GetLastError()); } return handle; } /* *---------------------------------------------------------------------- * * UnloadLibraries -- * * Frees any dynamically allocated libraries loaded by Tcl. * * Results: * None. * * Side effects: * Frees the libraries on the library list as well as the list. * *---------------------------------------------------------------------- */ static void UnloadLibraries() { LibraryList *ptr; while (libraryList != NULL) { FreeLibrary(libraryList->handle); ptr = libraryList->nextPtr; ckfree(libraryList); libraryList = ptr; } } /* *---------------------------------------------------------------------- * * TclSynchSpawn -- * * 32-bit entry point to the 16-bit SynchSpawn code. * * Results: * 1 on success, 0 on failure. * * Side effects: * Spawns a command and waits for it to complete. * *---------------------------------------------------------------------- */ int TclSynchSpawn(void *args, int type, void **trans, int *pidPtr) { static UT32PROC UTProc = NULL; static int utErrorCode; if (UTUnRegister == NULL) { /* * Load the Universal Thunking routines from kernel32.dll. */ HINSTANCE hKernel; PUTREGISTER UTRegister; char buffer[] = "TCL16xx.DLL"; hKernel = TclWinLoadLibrary("Kernel32.Dll"); if (hKernel == NULL) { return 0; } UTRegister = (PUTREGISTER) GetProcAddress(hKernel, "UTRegister"); UTUnRegister = (PUTUNREGISTER) GetProcAddress(hKernel, "UTUnRegister"); if (!UTRegister || !UTUnRegister) { UnloadLibraries(); return 0; } /* * Construct the complete name of tcl16xx.dll. */ buffer[5] = '0' + TCL_MAJOR_VERSION; buffer[6] = '0' + TCL_MINOR_VERSION; /* * Register the Tcl thunk. */ if (UTRegister(tclInstance, buffer, NULL, "UTProc", &UTProc, NULL, NULL) == FALSE) { utErrorCode = GetLastError(); } } if (UTProc == NULL) { /* * The 16-bit thunking DLL wasn't found. Return error code that * indicates this problem. */ SetLastError(utErrorCode); return 0; } UTProc(args, type, trans); *pidPtr = 0; return 1; } /* *---------------------------------------------------------------------- * * TclWinGetTclInstance -- * * Retrieves the global library instance handle. * * Results: * Returns the global library instance handle. * * Side effects: * None. * *---------------------------------------------------------------------- */ HINSTANCE TclWinGetTclInstance() { return tclInstance; }