Index: ChangeLog.win32 ================================================================== --- ChangeLog.win32 +++ ChangeLog.win32 @@ -1,5 +1,261 @@ +2002-06-28 davygrvy + * win/expWinInjectorIPC.hpp: + fixed comments. + + * win/Mcl/Mcl.dsp: + exceptions truned off. + + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinMessage.hpp: + * win/expWinSlaveMain.cpp: + * win/expWinSlaveTrapDbg.cpp: + * win/expWinTestClient.hpp: + * win/expWinTestClientConio.cpp: + * win/expWinTestClientInteract.cpp: + * win/expWinTestClientStdio.cpp: + The ClientInteract class has been created. It's empty, though. + +2002-06-27 davygrvy + * win/expWinClientTransport.hpp: + * win/expWinClientTransportConio.cpp: + * win/expWinClientTransportStdio.cpp: + * win/expWinSlave.hpp: + * win/expWinSlaveMain.cpp: + * win/expWinTestClient.hpp: + * win/expWinTestClientConio.cpp: + * win/expWinTestClientStdio.cpp: + * win/slavedrv.dsp: + renamed ClientTransport* to be TestClient* as the name is more + descriptive. + + * win/expWinConsoleDebugger.cpp: + * win/expWinInjectorIPC.hpp: + * win/expWinInjectorMain.cpp: + * win/injector.dsp: + * win/slavedrv.dsp: + slot and slot sizes are shared on both sides. This ensures there won't be + any errors from different info. + + * win/expWinClientTransport.hpp: + * win/expWinClientTransportConio.cpp: + * win/expWinConsoleDebugger.cpp: + * win/expWinSlaveMain.cpp: + * win/expWinSlaveTrap.hpp: + closing of the test application is more thorough and controlled. + +2002-06-26 davygrvy + * win/expWinConsoleDebugger.cpp: + small stuff + +2002-06-25 davygrvy + * win/expWinClientTransport.hpp: + * win/expWinClientTransportConio.cpp: + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinInjectorMain.cpp: + * win/expWinSlaveMain.cpp: + * win/test1.dsp: + We can now write to the slave console. Debugged and working. + slavedrv1.1 was released today from the code of this commit. + + * win/Mcl/Mcl.dsp: + Changed all builds to not throw C++ exceptions. there's some exe size + savings for doing this. I would prefer to check the Status() member after + the constructor instead. + + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/slavedrvmc.mc: + Added RIP events to the debugger and better error reporting for bad trap + and transport methods on the commandline. + + * win/Mcl/include/CMclGlobal.h: + another bug squashed. + +2002-06-24 davygrvy + * win/Mcl/src/CMclMailbox.cpp: + Nasty bug found and fixed. Talked to Mike Woodring about it + yesterday. + +2002-06-23 davygrvy + * win/expWinSlaveMain.cpp: + small variable naming changes to help the reader. + + * win/expWinInjectorMain.cpp: + Upped the mailbox size to 80 slots from 10. An INPUT_RECORD can't be + too much more that 24 bytes, so this shouldn't hurt active memory. + + * win/expWinConsoleKeyMap.cpp: + more good stuff + + * win/expWinClientStdio.cpp: + * win/expWinClientTransport.hpp: + * win/expWinClientTransportConio.cpp: + * win/expWinClientTransportStdio.cpp: + * win/slavedrv.dsp: + yet more filename changes. + + * win/expWinMessage.cpp: + Changed the destructor to use the array modifier. I don't know if it serves a + purpose, though. + + * win/expWinClientTransport.hpp: + * win/expWinSpawnClient.hpp: + * win/slavedrv.dsp: + filename changed to be more obvious/meaningful. + + * win/expWinSlaveMain.cpp: + matches the class name changes + + * win/expWinSlave.hpp: + matches the class name changes and added a proto for the new + MapToKeys() function. + + * win/expWinConsoleDebugger.cpp: + hMasterConsole now properly closed in destructor. + + * win/expWinClientStdio.cpp: + * win/expWinSpawnStdioClient.cpp: + * win/slavedrv.dsp: + another filename changed to be more obvious/meaningful. + +2002-06-22 davygrvy + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinConsoleDebuggerBreakPoints.cpp: + * win/expWinInjectorMain.cpp: + * win/expWinMessage.cpp: + * win/expWinMessage.hpp: + * win/expWinSlave.hpp: + * win/expWinSlaveMain.cpp: + * win/expWinSlaveTrap.hpp: + * win/expWinSlaveTrapDbg.cpp: + * win/expWinSpawnStdioClient.cpp: + More new good stuff. + + * win/expWinConsoleKeyMap.cpp: + New file. Contains the mapping routines for converting characters into + keypress events. + + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + IPC connection to the injector dll, done. Write() added, but does nothing yet. + I have to think this through... + + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinInjectorMain.cpp: + * win/expWinSlaveMain.cpp: + * win/expWinSpawnStdioClient.cpp: + * win/injector.dsp: + Big crash big fixed. I was restarting the thread AFTER the breakpoint rather + than on top of it. OutputDebugString() is now passing through, too. No + connection has been made yet to the IPC server the injector dll is providing. + +2002-06-21 davygrvy + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinConsoleDebuggerBreakPoints.cpp: + * win/expWinInjectorMain.cpp: + * win/expWinMessage.cpp: + * win/expWinMessage.hpp: + * win/expWinSlaveTrapDbg.cpp: + * win/expWinSpawnClient.hpp: + * win/expWinSpawnStdioClient.cpp: + Injector code hook-in, but doesn't yet work. I don't know why. + The opcodes for loading the DLL are correct. The opcodes are + written to the sub process memory and run. I just don't know. + + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinInjectorMain.cpp: + The injector DLL is now loading into the process. That's the good news. + The bad news is that it's crashing the process. I decided to commit the + changes anyways with the hope someone can assist. Even with the + injector doing nothing, we still crash for some unknown reason. + +2002-06-20 davygrvy + * win/expWinInjectorMain.cpp: + better error handling. I think I'll use OutputDebugString() + for sending warnings back to the ConsoleDebugger class. + + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinInjectorMain.cpp: + * win/expWinMessage.hpp: + * win/expWinSpawnStdioClient.cpp: + Added OnXDebugString() to the ConsoleDebugger class to handle the + OUTPUT_DEBUG_STRING_EVENT debugger event. This sends a new + message type called TYPE_WARNING to the output client. Changed the + stdio client to just send this out on stderr. + + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/slavedrv.dsp: + small refactoring. + + * win/expWinInjectorMain.cpp: + one must open the console INPUT buffer to write console events + to it, not the SCREEN buffer. + + * win/expWinInjectorMain.cpp: + small changes, but still untested. + +2002-06-19 davygrvy + * win/slavedrv.rc: + small app type error fixed. I had been calling this a dll. + Oops. + + * win/expWinInjectorMain.cpp: + * win/injector.dsp: + * win/injector.dsw: + minimal starting point for the console event injector dll (the + write portion of the ConsoleDebugger class) + + * win/expWinInjectorMain.cpp: + * win/inject.rc: + * win/injector.dsp: + added an RC script for version info. + + * win/expWinInjectorMain.cpp: + * win/injector.dsp: + * win/injector.dsw: + Injector idea more formalized from thought into some code. + +2002-06-18 davygrvy + * generic/exp.h: + * generic/expDecls.h: + * generic/expIntDecls.h: + * generic/expIntPlatDecls.h: + * win/expWinConsoleDebugger.cpp: + * win/expWinConsoleDebugger.hpp: + * win/expWinConsoleDebuggerBreakPoints.cpp: + * win/expWinSlaveMain.cpp: + * win/expWinUtils.cpp: + * win/expWinUtils.hpp: + * win/expect.rc: + * win/slavedrv.rc: + * win/slavedrvmc.mc: + * win/test1.cpp: + these changes perfect the debugger code under Win98 and have + been sitting in my workspace for quite some time now. + + * win/expWinConsoleDebugger.cpp: + oops. fixed a compiling bug. + +2002-03-22 davygrvy + * win/slavedrv.dsp: + * win/slavedrv.dsw: + * win/test1.cpp: + * win/test1.dsp: + new "follow the mouse" test case. + + * win/TclHash.hpp: + new Extract() functions. + 2002-03-16 davygrvy * win/expWinConsoleDebugger.cpp: * win/expWinConsoleDebugger.hpp: * win/expWinMessage.cpp: * win/expWinMessage.hpp: Index: generic/exp.h ================================================================== --- generic/exp.h +++ generic/exp.h @@ -20,11 +20,11 @@ * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: exp.h,v 1.1.4.8 2002/03/06 02:18:20 davygrvy Exp $ + * RCS: @(#) $Id: exp.h,v 1.1.4.9 2002/03/07 02:49:36 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef _EXP #define _EXP @@ -65,11 +65,11 @@ JOIN(JOIN(EXP_MAJOR_VERSION, \ JOIN(., EXP_MINOR_VERSION)), \ JOIN(., EXP_RELEASE_SERIAL))) #else -# include "bad/release/level/used" +# error bad release level used. #endif /* * The windows resource compiler defines this by default. Skip the rest of this * file when included from an rc script. @@ -93,34 +93,41 @@ /* Fix the Borland bug in tcl.h */ #ifndef TCL_EXTERN # undef DLLIMPORT # undef DLLEXPORT -# if (defined(__WIN32__) && (defined(_MSC_VER) || (__BORLANDC__ >= 0x0550) \ +# if (defined(__WIN32__) && \ + (defined(_MSC_VER) || (__BORLANDC__ >= 0x0550) \ || (defined(__GNUC__) && defined(__DECLSPEC_SUPPORTED)))) \ || (defined(MAC_TCL) && FUNCTION_DECLSPEC) # define DLLIMPORT __declspec(dllimport) # define DLLEXPORT __declspec(dllexport) # elif defined(__BORLANDC__) + /* Pre 5.5 Borland */ # define OLD_BORLAND 1 # define DLLIMPORT __import # define DLLEXPORT __export # else + /* Systems that don't support keywords for exporting/importing + * functions from dynamic libraries. */ # define DLLIMPORT # define DLLEXPORT # endif - /* Avoid name mangling. */ + /* Avoid C++ name mangling. */ # ifdef __cplusplus # define TCL_CPP "C" # else # define TCL_CPP # endif - /* Pre 5.5 Borland requires the attributes be placed after the return type. */ + /* Pre 5.5 Borland requires the attributes be placed after the return + * type. */ # if OLD_BORLAND -# define TCL_EXTERN(rtnType) extern TCL_CPP rtnType TCL_STORAGE_CLASS +# define TCL_EXTERN(rtnType) \ + extern TCL_CPP rtnType TCL_STORAGE_CLASS # else -# define TCL_EXTERN(rtnType) extern TCL_CPP TCL_STORAGE_CLASS rtnType +# define TCL_EXTERN(rtnType) \ + extern TCL_CPP TCL_STORAGE_CLASS rtnType # endif #endif /* needed by some exports */ Index: generic/expDecls.h ================================================================== --- generic/expDecls.h +++ generic/expDecls.h @@ -21,11 +21,11 @@ * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expDecls.h,v 1.1.4.2 2002/02/10 12:04:22 davygrvy Exp $ + * RCS: @(#) $Id: expDecls.h,v 1.1.4.3 2002/02/10 13:40:47 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef _EXPDECLS #define _EXPDECLS @@ -41,117 +41,117 @@ /* * Exported function declarations: */ /* 0 */ -TCL_EXTERN(int) Expect_Init _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN int Expect_Init _ANSI_ARGS_((Tcl_Interp * interp)); /* Slot 1 is reserved */ /* Slot 2 is reserved */ /* 3 */ -TCL_EXTERN(int) Exp_ExpInternalCmd _ANSI_ARGS_(( +EXTERN int Exp_ExpInternalCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* Slot 4 is reserved */ /* 5 */ -TCL_EXTERN(int) Exp_ExitCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_ExitCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 6 */ -TCL_EXTERN(int) Exp_ExpContinueCmd _ANSI_ARGS_(( +EXTERN int Exp_ExpContinueCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* Slot 7 is reserved */ /* 8 */ -TCL_EXTERN(int) Exp_ExpPidCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_ExpPidCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 9 */ -TCL_EXTERN(int) Exp_GetpidDeprecatedCmd _ANSI_ARGS_(( +EXTERN int Exp_GetpidDeprecatedCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* Slot 10 is reserved */ /* 11 */ -TCL_EXTERN(int) Exp_LogFileCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_LogFileCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 12 */ -TCL_EXTERN(int) Exp_LogUserCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_LogUserCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 13 */ -TCL_EXTERN(int) Exp_OpenCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_OpenCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* Slot 14 is reserved */ /* Slot 15 is reserved */ /* Slot 16 is reserved */ /* 17 */ -TCL_EXTERN(int) Exp_SendLogCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_SendLogCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 18 */ -TCL_EXTERN(int) Exp_SleepCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_SleepCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 19 */ -TCL_EXTERN(int) Exp_SpawnCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_SpawnCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 20 */ -TCL_EXTERN(int) Exp_StraceCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_StraceCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 21 */ -TCL_EXTERN(int) Exp_WaitCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_WaitCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 22 */ -TCL_EXTERN(int) Exp_ExpVersionCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_ExpVersionCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 23 */ -TCL_EXTERN(int) Exp_Prompt1Cmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_Prompt1Cmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 24 */ -TCL_EXTERN(int) Exp_Prompt2Cmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_Prompt2Cmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 25 */ -TCL_EXTERN(int) Exp_TrapCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_TrapCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 26 */ -TCL_EXTERN(int) Exp_SttyCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_SttyCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 27 */ -TCL_EXTERN(int) Exp_SystemCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_SystemCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 28 */ -TCL_EXTERN(int) Exp_ExpectCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_ExpectCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int objc, Tcl_Obj *CONST objv[])); /* 29 */ -TCL_EXTERN(int) Exp_ExpectGlobalCmd _ANSI_ARGS_(( +EXTERN int Exp_ExpectGlobalCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp * interp, int argc, Tcl_Obj *CONST objv[])); /* 30 */ -TCL_EXTERN(int) Exp_MatchMaxCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_MatchMaxCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 31 */ -TCL_EXTERN(int) Exp_RemoveNullsCmd _ANSI_ARGS_(( +EXTERN int Exp_RemoveNullsCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 32 */ -TCL_EXTERN(int) Exp_ParityCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_ParityCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 33 */ -TCL_EXTERN(int) Exp_TimestampCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_TimestampCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 34 */ -TCL_EXTERN(int) Exp_CloseCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_CloseCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 35 */ -TCL_EXTERN(int) Exp_InterpreterCmd _ANSI_ARGS_(( +EXTERN int Exp_InterpreterCmd _ANSI_ARGS_(( ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 36 */ -TCL_EXTERN(int) Exp_SendCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_SendCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* 37 */ -TCL_EXTERN(int) Exp_KillCmd _ANSI_ARGS_((ClientData clientData, +EXTERN int Exp_KillCmd _ANSI_ARGS_((ClientData clientData, Tcl_Interp * interp, int argc, char * argv[])); /* Slot 38 is reserved */ /* Slot 39 is reserved */ /* 40 */ -TCL_EXTERN(char *) exp_printify _ANSI_ARGS_((char * s)); +EXTERN char * exp_printify _ANSI_ARGS_((char * s)); /* Slot 41 is reserved */ /* Slot 42 is reserved */ /* Slot 43 is reserved */ /* Slot 44 is reserved */ /* Slot 45 is reserved */ @@ -158,108 +158,108 @@ /* Slot 46 is reserved */ /* Slot 47 is reserved */ /* Slot 48 is reserved */ /* Slot 49 is reserved */ /* 50 */ -TCL_EXTERN(void) exp_errorlog _ANSI_ARGS_(TCL_VARARGS(char *,fmt)); +EXTERN void exp_errorlog _ANSI_ARGS_(TCL_VARARGS(char *,fmt)); /* 51 */ -TCL_EXTERN(void) exp_log _ANSI_ARGS_(TCL_VARARGS(int,force_stdout)); +EXTERN void exp_log _ANSI_ARGS_(TCL_VARARGS(int,force_stdout)); /* 52 */ -TCL_EXTERN(void) exp_debuglog _ANSI_ARGS_(TCL_VARARGS(char *,fmt)); +EXTERN void exp_debuglog _ANSI_ARGS_(TCL_VARARGS(char *,fmt)); /* 53 */ -TCL_EXTERN(void) exp_nflog _ANSI_ARGS_((char * buf, int force_stdout)); +EXTERN void exp_nflog _ANSI_ARGS_((char * buf, int force_stdout)); /* 54 */ -TCL_EXTERN(void) exp_nferrorlog _ANSI_ARGS_((char * buf, +EXTERN void exp_nferrorlog _ANSI_ARGS_((char * buf, int force_stdout)); /* 55 */ -TCL_EXTERN(void) exp_error _ANSI_ARGS_(TCL_VARARGS(Tcl_Interp *,interp)); +EXTERN void exp_error _ANSI_ARGS_(TCL_VARARGS(Tcl_Interp *,interp)); /* Slot 56 is reserved */ /* Slot 57 is reserved */ /* Slot 58 is reserved */ /* Slot 59 is reserved */ /* 60 */ -TCL_EXTERN(void) exp_parse_argv _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN void exp_parse_argv _ANSI_ARGS_((Tcl_Interp * interp, int argc, char ** argv)); /* 61 */ -TCL_EXTERN(int) exp_interpreter _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN int exp_interpreter _ANSI_ARGS_((Tcl_Interp * interp)); /* 62 */ -TCL_EXTERN(int) exp_interpret_cmdfile _ANSI_ARGS_(( +EXTERN int exp_interpret_cmdfile _ANSI_ARGS_(( Tcl_Interp * interp, Tcl_Channel cmdfile)); /* 63 */ -TCL_EXTERN(int) exp_interpret_cmdfilename _ANSI_ARGS_(( +EXTERN int exp_interpret_cmdfilename _ANSI_ARGS_(( Tcl_Interp * interp, char * filename)); /* 64 */ -TCL_EXTERN(void) exp_interpret_rcfiles _ANSI_ARGS_(( +EXTERN void exp_interpret_rcfiles _ANSI_ARGS_(( Tcl_Interp * interp, int my_rc, int sys_rc)); /* 65 */ -TCL_EXTERN(char *) exp_cook _ANSI_ARGS_((CONST char * s, int * len)); +EXTERN char * exp_cook _ANSI_ARGS_((CONST char * s, int * len)); /* Slot 66 is reserved */ /* 67 */ -TCL_EXTERN(int) exp_getpidproc _ANSI_ARGS_((void)); +EXTERN int exp_getpidproc _ANSI_ARGS_((void)); /* 68 */ -TCL_EXTERN(Tcl_Channel) ExpCreateSpawnChannel _ANSI_ARGS_(( +EXTERN Tcl_Channel ExpCreateSpawnChannel _ANSI_ARGS_(( Tcl_Interp * interp, Tcl_Channel chan)); /* 69 */ -TCL_EXTERN(int) ExpPlatformSpawnOutput _ANSI_ARGS_(( +EXTERN int ExpPlatformSpawnOutput _ANSI_ARGS_(( ClientData instanceData, CONST char * bufPtr, int toWrite, int * errorPtr)); /* 70 */ -TCL_EXTERN(void) exp_init_main_cmds _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN void exp_init_main_cmds _ANSI_ARGS_((Tcl_Interp * interp)); /* 71 */ -TCL_EXTERN(void) exp_init_expect_cmds _ANSI_ARGS_(( +EXTERN void exp_init_expect_cmds _ANSI_ARGS_(( Tcl_Interp * interp)); /* 72 */ -TCL_EXTERN(void) exp_init_most_cmds _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN void exp_init_most_cmds _ANSI_ARGS_((Tcl_Interp * interp)); /* 73 */ -TCL_EXTERN(void) exp_init_trap_cmds _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN void exp_init_trap_cmds _ANSI_ARGS_((Tcl_Interp * interp)); /* 74 */ -TCL_EXTERN(void) exp_init_interact_cmds _ANSI_ARGS_(( +EXTERN void exp_init_interact_cmds _ANSI_ARGS_(( Tcl_Interp * interp)); /* 75 */ -TCL_EXTERN(int) exp_init_tty_cmds _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN int exp_init_tty_cmds _ANSI_ARGS_((Tcl_Interp * interp)); /* Slot 76 is reserved */ /* Slot 77 is reserved */ /* 78 */ -TCL_EXTERN(Tcl_Channel) ExpCreatePairChannel _ANSI_ARGS_(( +EXTERN Tcl_Channel ExpCreatePairChannel _ANSI_ARGS_(( Tcl_Interp * interp, CONST char * chanInId, CONST char * chanOutId, CONST char * chanName)); /* 79 */ -TCL_EXTERN(int) ExpSpawnOpen _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN int ExpSpawnOpen _ANSI_ARGS_((Tcl_Interp * interp, char * chanId, int leaveopen)); /* 80 */ -TCL_EXTERN(struct exp_f *) exp_update_master _ANSI_ARGS_(( - Tcl_Interp * interp, int opened, int adjust)); +EXTERN struct exp_f * exp_update_master _ANSI_ARGS_((Tcl_Interp * interp, + int opened, int adjust)); /* 81 */ -TCL_EXTERN(CONST char *) exp_get_var _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN CONST char * exp_get_var _ANSI_ARGS_((Tcl_Interp * interp, char * var)); /* 82 */ -TCL_EXTERN(void) exp_exit _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN void exp_exit _ANSI_ARGS_((Tcl_Interp * interp, int status)); /* 83 */ -TCL_EXTERN(int) exp_dsleep _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN int exp_dsleep _ANSI_ARGS_((Tcl_Interp * interp, double sec)); /* 84 */ -TCL_EXTERN(void) exp_init_event _ANSI_ARGS_((void)); +EXTERN void exp_init_event _ANSI_ARGS_((void)); /* Slot 85 is reserved */ /* 86 */ -TCL_EXTERN(void) exp_background_filehandler _ANSI_ARGS_(( +EXTERN void exp_background_filehandler _ANSI_ARGS_(( ClientData clientData, int mask)); /* 87 */ -TCL_EXTERN(void) exp_exit_handlers _ANSI_ARGS_((ClientData clientData)); +EXTERN void exp_exit_handlers _ANSI_ARGS_((ClientData clientData)); /* 88 */ -TCL_EXTERN(void) exp_close_on_exec _ANSI_ARGS_((int fd)); +EXTERN void exp_close_on_exec _ANSI_ARGS_((int fd)); /* 89 */ -TCL_EXTERN(int) exp_flageq_code _ANSI_ARGS_((char * flag, +EXTERN int exp_flageq_code _ANSI_ARGS_((char * flag, char * string, int minlen)); /* 90 */ -TCL_EXTERN(void) exp_close_tcl_files _ANSI_ARGS_((void)); +EXTERN void exp_close_tcl_files _ANSI_ARGS_((void)); /* 91 */ -TCL_EXTERN(void) exp_lowmemcpy _ANSI_ARGS_((char * dest, +EXTERN void exp_lowmemcpy _ANSI_ARGS_((char * dest, CONST char * src, int n)); /* 92 */ -TCL_EXTERN(void) exp_timestamp _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN void exp_timestamp _ANSI_ARGS_((Tcl_Interp * interp, time_t * timeval, char * array)); typedef struct ExpStubHooks { struct ExpPlatStubs *expPlatStubs; struct ExpIntStubs *expIntStubs; Index: generic/expIntDecls.h ================================================================== --- generic/expIntDecls.h +++ generic/expIntDecls.h @@ -21,11 +21,11 @@ * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expIntDecls.h,v 1.1.4.4 2002/02/10 13:40:47 davygrvy Exp $ + * RCS: @(#) $Id: expIntDecls.h,v 1.1.4.5 2002/02/13 02:39:41 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef _EXPINTDECLS #define _EXPINTDECLS @@ -42,126 +42,126 @@ * Exported function declarations: */ /* Slot 0 is reserved */ /* 1 */ -TCL_EXTERN(int) Exp_StringMatch _ANSI_ARGS_((CONST char * string, +EXTERN int Exp_StringMatch _ANSI_ARGS_((CONST char * string, CONST char * pattern, int * offset)); /* 2 */ -TCL_EXTERN(int) Exp_StringMatch2 _ANSI_ARGS_((CONST char * string, +EXTERN int Exp_StringMatch2 _ANSI_ARGS_((CONST char * string, CONST char * pattern)); /* Slot 3 is reserved */ /* 4 */ -TCL_EXTERN(struct exp_i *) exp_new_i_complex _ANSI_ARGS_(( - Tcl_Interp * interp, char * arg, - int duration, Tcl_VarTraceProc * updateproc, +EXTERN struct exp_i * exp_new_i_complex _ANSI_ARGS_((Tcl_Interp * interp, + char * arg, int duration, + Tcl_VarTraceProc * updateproc, CONST char * msg)); /* 5 */ -TCL_EXTERN(struct exp_i *) exp_new_i_simple _ANSI_ARGS_((struct exp_f * fd, +EXTERN struct exp_i * exp_new_i_simple _ANSI_ARGS_((struct exp_f * fd, int duration)); /* 6 */ -TCL_EXTERN(struct exp_fs_list *) exp_new_fs _ANSI_ARGS_((struct exp_f * f)); +EXTERN struct exp_fs_list * exp_new_fs _ANSI_ARGS_((struct exp_f * f)); /* 7 */ -TCL_EXTERN(void) exp_free_i _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN void exp_free_i _ANSI_ARGS_((Tcl_Interp * interp, struct exp_i * i, Tcl_VarTraceProc * updateproc)); /* 8 */ -TCL_EXTERN(void) exp_free_fs _ANSI_ARGS_(( +EXTERN void exp_free_fs _ANSI_ARGS_(( struct exp_fs_list * fs_first)); /* 9 */ -TCL_EXTERN(void) exp_free_fs_single _ANSI_ARGS_(( +EXTERN void exp_free_fs_single _ANSI_ARGS_(( struct exp_fs_list * fs)); /* 10 */ -TCL_EXTERN(void) exp_i_update _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN void exp_i_update _ANSI_ARGS_((Tcl_Interp * interp, struct exp_i * i)); /* 11 */ -TCL_EXTERN(void) exp_pty_exit _ANSI_ARGS_((void)); +EXTERN void exp_pty_exit _ANSI_ARGS_((void)); /* 12 */ -TCL_EXTERN(void) exp_init_spawn_ids _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN void exp_init_spawn_ids _ANSI_ARGS_((Tcl_Interp * interp)); /* 13 */ -TCL_EXTERN(void) exp_init_pty _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN void exp_init_pty _ANSI_ARGS_((Tcl_Interp * interp)); /* 14 */ -TCL_EXTERN(void) exp_init_tty _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN void exp_init_tty _ANSI_ARGS_((Tcl_Interp * interp)); /* 15 */ -TCL_EXTERN(void) exp_init_stdio _ANSI_ARGS_((void)); +EXTERN void exp_init_stdio _ANSI_ARGS_((void)); /* 16 */ -TCL_EXTERN(void) exp_init_sig _ANSI_ARGS_((void)); +EXTERN void exp_init_sig _ANSI_ARGS_((void)); /* 17 */ -TCL_EXTERN(void) exp_init_trap _ANSI_ARGS_((void)); +EXTERN void exp_init_trap _ANSI_ARGS_((void)); /* 18 */ -TCL_EXTERN(void) exp_init_unit_random _ANSI_ARGS_((void)); +EXTERN void exp_init_unit_random _ANSI_ARGS_((void)); /* 19 */ -TCL_EXTERN(void) exp_init_spawn_id_vars _ANSI_ARGS_(( +EXTERN void exp_init_spawn_id_vars _ANSI_ARGS_(( Tcl_Interp * interp)); /* 20 */ -TCL_EXTERN(void) exp_adjust _ANSI_ARGS_((struct exp_f * f)); +EXTERN void exp_adjust _ANSI_ARGS_((struct exp_f * f)); /* 21 */ -TCL_EXTERN(void) exp_ecmd_remove_f_direct_and_indirect _ANSI_ARGS_(( +EXTERN void exp_ecmd_remove_f_direct_and_indirect _ANSI_ARGS_(( Tcl_Interp * interp, struct exp_f * f)); /* 22 */ -TCL_EXTERN(void) exp_rearm_sigchld _ANSI_ARGS_((Tcl_Interp * interp)); +EXTERN void exp_rearm_sigchld _ANSI_ARGS_((Tcl_Interp * interp)); /* 23 */ -TCL_EXTERN(struct exp_f *) exp_chan2f _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN struct exp_f * exp_chan2f _ANSI_ARGS_((Tcl_Interp * interp, CONST char * chan, int opened, int adjust, CONST char * msg)); /* 24 */ -TCL_EXTERN(int) exp_fcheck _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN int exp_fcheck _ANSI_ARGS_((Tcl_Interp * interp, struct exp_f * f, int opened, int adjust, CONST char * msg)); /* 25 */ -TCL_EXTERN(int) exp_close _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN int exp_close _ANSI_ARGS_((Tcl_Interp * interp, struct exp_f * f)); /* 26 */ -TCL_EXTERN(void) exp_strftime _ANSI_ARGS_((char * format, +EXTERN void exp_strftime _ANSI_ARGS_((char * format, const struct tm * timeptr, Tcl_DString * dstring)); /* 27 */ -TCL_EXTERN(void) exp_create_commands _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN void exp_create_commands _ANSI_ARGS_((Tcl_Interp * interp, struct exp_cmd_data * c)); /* 28 */ -TCL_EXTERN(void) exp_tty_break _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN void exp_tty_break _ANSI_ARGS_((Tcl_Interp * interp, struct exp_f * f)); /* 29 */ -TCL_EXTERN(void) exp_event_disarm _ANSI_ARGS_((struct exp_f * f)); +EXTERN void exp_event_disarm _ANSI_ARGS_((struct exp_f * f)); /* 30 */ -TCL_EXTERN(void) exp_arm_background_filehandler _ANSI_ARGS_(( +EXTERN void exp_arm_background_filehandler _ANSI_ARGS_(( struct exp_f * f)); /* 31 */ -TCL_EXTERN(void) exp_disarm_background_filehandler _ANSI_ARGS_(( +EXTERN void exp_disarm_background_filehandler _ANSI_ARGS_(( struct exp_f * f)); /* 32 */ -TCL_EXTERN(void) exp_disarm_background_filehandler_force _ANSI_ARGS_(( +EXTERN void exp_disarm_background_filehandler_force _ANSI_ARGS_(( struct exp_f * f)); /* 33 */ -TCL_EXTERN(void) exp_unblock_background_filehandler _ANSI_ARGS_(( +EXTERN void exp_unblock_background_filehandler _ANSI_ARGS_(( struct exp_f * f)); /* 34 */ -TCL_EXTERN(void) exp_block_background_filehandler _ANSI_ARGS_(( +EXTERN void exp_block_background_filehandler _ANSI_ARGS_(( struct exp_f * f)); /* 35 */ -TCL_EXTERN(int) exp_get_next_event _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN int exp_get_next_event _ANSI_ARGS_((Tcl_Interp * interp, struct exp_f ** masters, int n, struct exp_f ** master_out, int timeout, int key)); /* 36 */ -TCL_EXTERN(int) exp_get_next_event_info _ANSI_ARGS_(( +EXTERN int exp_get_next_event_info _ANSI_ARGS_(( Tcl_Interp * interp, struct exp_f * fd, int ready_mask)); /* 37 */ -TCL_EXTERN(struct exp_f *) exp_f_find _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN struct exp_f * exp_f_find _ANSI_ARGS_((Tcl_Interp * interp, char * spawnId)); /* 38 */ -TCL_EXTERN(struct exp_f *) exp_f_new _ANSI_ARGS_((Tcl_Interp * interp, +EXTERN struct exp_f * exp_f_new _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Channel chan, char * spawnId, int pid)); /* 39 */ -TCL_EXTERN(int) exp_f_new_platform _ANSI_ARGS_((struct exp_f * f)); +EXTERN int exp_f_new_platform _ANSI_ARGS_((struct exp_f * f)); /* 40 */ -TCL_EXTERN(void) exp_f_free _ANSI_ARGS_((struct exp_f * f)); +EXTERN void exp_f_free _ANSI_ARGS_((struct exp_f * f)); /* 41 */ -TCL_EXTERN(void) exp_f_free_platform _ANSI_ARGS_((struct exp_f * f)); +EXTERN void exp_f_free_platform _ANSI_ARGS_((struct exp_f * f)); /* 42 */ -TCL_EXTERN(int) exp_exact_write _ANSI_ARGS_((struct exp_f * f, +EXTERN int exp_exact_write _ANSI_ARGS_((struct exp_f * f, char * buffer, int rembytes)); typedef struct ExpIntStubs { int magic; struct ExpIntStubHooks *hooks; Index: generic/expIntPlatDecls.h ================================================================== --- generic/expIntPlatDecls.h +++ generic/expIntPlatDecls.h @@ -20,11 +20,11 @@ * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expIntPlatDecls.h,v 1.1.4.4 2002/03/07 02:49:36 davygrvy Exp $ + * RCS: @(#) $Id: expIntPlatDecls.h,v 1.1.4.5 2002/03/11 06:52:53 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef _EXPPLATINTDECLS #define _EXPPLATINTDECLS @@ -35,33 +35,33 @@ * Exported function declarations: */ #ifdef __WIN32__ /* 0 */ -TCL_EXTERN(DWORD) ExpWinApplicationType _ANSI_ARGS_(( +EXTERN DWORD ExpWinApplicationType _ANSI_ARGS_(( const char * originalName, Tcl_DString * fullPath)); /* 1 */ -TCL_EXTERN(DWORD) ExpWinCreateProcess _ANSI_ARGS_((int argc, +EXTERN DWORD ExpWinCreateProcess _ANSI_ARGS_((int argc, char *const * argv, HANDLE inputHandle, HANDLE outputHandle, HANDLE errorHandle, int allocConsole, int hideConsole, int debug, int newProcessGroup, HANDLE * processPtr, PDWORD globalPidPtr)); /* 2 */ -TCL_EXTERN(void) ExpWinSyslog _ANSI_ARGS_(TCL_VARARGS(DWORD,errId)); +EXTERN void ExpWinSyslog _ANSI_ARGS_(TCL_VARARGS(DWORD,errId)); /* 3 */ -TCL_EXTERN(char *) ExpSyslogGetSysMsg _ANSI_ARGS_((DWORD errId)); +EXTERN char * ExpSyslogGetSysMsg _ANSI_ARGS_((DWORD errId)); /* 4 */ -TCL_EXTERN(Tcl_Pid) Exp_WaitPid _ANSI_ARGS_((Tcl_Pid pid, int * statPtr, +EXTERN Tcl_Pid Exp_WaitPid _ANSI_ARGS_((Tcl_Pid pid, int * statPtr, int options)); /* 5 */ -TCL_EXTERN(void) Exp_KillProcess _ANSI_ARGS_((Tcl_Pid pid)); +EXTERN void Exp_KillProcess _ANSI_ARGS_((Tcl_Pid pid)); /* 6 */ -TCL_EXTERN(void) ExpWinInit _ANSI_ARGS_((void)); +EXTERN void ExpWinInit _ANSI_ARGS_((void)); /* 7 */ -TCL_EXTERN(void) BuildCommandLine _ANSI_ARGS_(( +EXTERN void BuildCommandLine _ANSI_ARGS_(( CONST char * executable, int argc, char *const * argv, Tcl_DString * linePtr)); #endif /* __WIN32__ */ typedef struct ExpIntPlatStubs { Index: win/.gitignore ================================================================== --- win/.gitignore +++ win/.gitignore @@ -1,7 +1,6 @@ *.ncb *.opt *.plg Debug -DebugU Release -ReleaseU +Detours Index: win/Mcl/ChangeLog ================================================================== --- win/Mcl/ChangeLog +++ win/Mcl/ChangeLog @@ -1,5 +1,10 @@ +2002-06-24 David Gravereaux + + * src/CMclMailbox.cpp: A nasty bug found and fixed. Author knows + of it, too. + 2001-11-18 David Gravereaux * src/CMclMailbox.cpp: 2001-11-07 eratta change. See http://www.bearcanyon.com/mtbook/errata.htm#source Index: win/Mcl/Mcl.dsp ================================================================== --- win/Mcl/Mcl.dsp +++ win/Mcl/Mcl.dsp @@ -43,11 +43,11 @@ # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\lib" # PROP Intermediate_Dir ".\ReleaseA" # PROP Target_Dir "" # ADD BASE CPP /nologo /MD /W3 /GX /O2 /I ".\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I ".\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX- /O2 /I ".\include" /D "NDEBUG" /D "_MBCS" /D __CMCL_THROW_EXCEPTIONS__=0 /D "WIN32" /D "_WINDOWS" /YX /FD /c # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo @@ -66,11 +66,12 @@ # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\lib" # PROP Intermediate_Dir ".\DebugA" # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I ".\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I ".\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX- /Z7 /Od /I ".\include" /D "_DEBUG" /D "_MBCS" /D __CMCL_THROW_EXCEPTIONS__=0 /D "WIN32" /D "_WINDOWS" /YX /FD /c +# SUBTRACT CPP /Fr # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo @@ -89,11 +90,11 @@ # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\lib" # PROP Intermediate_Dir ".\DebugU" # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I ".\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "UNICODE" /D "_UNICODE" /YX /FD /c -# ADD CPP /nologo /MDd /W3 /GX /Z7 /Od /I ".\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "UNICODE" /D "_UNICODE" /YX /FD /c +# ADD CPP /nologo /MDd /W3 /GX- /Z7 /Od /I ".\include" /D "_DEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D __CMCL_THROW_EXCEPTIONS__=0 /YX /FD /c # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo @@ -112,11 +113,11 @@ # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\lib" # PROP Intermediate_Dir ".\ReleaseU" # PROP Target_Dir "" # ADD BASE CPP /nologo /MD /W3 /GX /O2 /I ".\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "UNICODE" /D "_UNICODE" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I ".\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "UNICODE" /D "_UNICODE" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX- /O2 /I ".\include" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D __CMCL_THROW_EXCEPTIONS__=0 /YX /FD /c # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo @@ -135,11 +136,11 @@ # PROP Use_Debug_Libraries 0 # PROP Output_Dir ".\lib" # PROP Intermediate_Dir ".\ReleaseAS" # PROP Target_Dir "" # ADD BASE CPP /nologo /MD /W3 /GX /O2 /I ".\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G5 /MT /W3 /GX /O2 /I ".\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G5 /MT /W3 /GX- /O2 /I ".\include" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D __CMCL_THROW_EXCEPTIONS__=0 /YX /FD /c # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo @@ -158,11 +159,11 @@ # PROP Use_Debug_Libraries 1 # PROP Output_Dir ".\lib" # PROP Intermediate_Dir ".\DebugAS" # PROP Target_Dir "" # ADD BASE CPP /nologo /MDd /W3 /GX /Z7 /Od /I ".\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /G5 /MTd /W3 /GX /Z7 /Od /I ".\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G5 /MTd /W3 /GX- /Z7 /Od /I ".\include" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D __CMCL_THROW_EXCEPTIONS__=0 /YX /FD /c # ADD BASE RSC /l 0x409 # ADD RSC /l 0x409 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo Index: win/Mcl/include/CMclGlobal.h ================================================================== --- win/Mcl/include/CMclGlobal.h +++ win/Mcl/include/CMclGlobal.h @@ -48,11 +48,11 @@ #endif // SCODE is the return value to check, // STATUS is the variable in which to store an error code if an error is detected... #if __CMCL_THROW_EXCEPTIONS__ -#define CMCL_CHECK_CREATION_STATUS(SCODE,STATUS) {} +#define CMCL_CHECK_CREATION_STATUS(SCODE,STATUS) if (((SCODE)!=NO_ERROR)&&((SCODE)!=ERROR_ALREADY_EXISTS)) { CMclThrowError(SCODE); } #else #define CMCL_CHECK_CREATION_STATUS(SCODE,STATUS) if (((SCODE)!=NO_ERROR)&&((SCODE)!=ERROR_ALREADY_EXISTS)) { STATUS = (SCODE); return; } #endif // error handling macro and function... Index: win/Mcl/src/CMclMailbox.cpp ================================================================== --- win/Mcl/src/CMclMailbox.cpp +++ win/Mcl/src/CMclMailbox.cpp @@ -232,11 +232,11 @@ BOOL CMclMailbox::PostAlertable( const void *lpMsg, CMclEvent *pInterrupt, DWORD dwTimeout) { BOOL bStatus = FALSE; DWORD dwStatus = pInterrupt->WaitForTwo( *m_cFreeCountSemaphoreAPtr, FALSE, dwTimeout); if (CMclWaitSucceeded( dwStatus, 2) - && (CMclWaitSucceededIndex(dwStatus) == (WAIT_OBJECT_0 + 1))) { + && (CMclWaitSucceededIndex(dwStatus) == 1)) { dwStatus = m_cGuardMutexAPtr->Wait(dwTimeout); if (CMclWaitSucceeded(dwStatus, 1) || CMclWaitAbandoned(dwStatus, 1)) { CopyMemory( GetTailPtr(), lpMsg, m_pHdr->cbMsgSize); IncrementTail(); m_cGuardMutexAPtr->Release(); @@ -258,11 +258,11 @@ BOOL CMclMailbox::GetAlertable( void *lpMsg, CMclEvent *pInterrupt, DWORD dwTimeout) { BOOL bStatus = FALSE; DWORD dwStatus = pInterrupt->WaitForTwo( *m_cPendingCountSemaphoreAPtr, FALSE, dwTimeout); if (CMclWaitSucceeded( dwStatus, 2) - && (CMclWaitSucceededIndex(dwStatus) == (WAIT_OBJECT_0 + 1))) { + && (CMclWaitSucceededIndex(dwStatus) == 1)) { dwStatus = m_cGuardMutexAPtr->Wait(dwTimeout); if (CMclWaitSucceeded(dwStatus, 1) || CMclWaitAbandoned(dwStatus, 1)) { CopyMemory( lpMsg, GetHeadPtr(), m_pHdr->cbMsgSize); IncrementHead(); m_cGuardMutexAPtr->Release(); @@ -290,11 +290,11 @@ int nObjects = cCollection.GetCount(); DWORD dwStatus = cCollection.Wait( FALSE, dwTimeout); if (CMclWaitSucceeded( dwStatus, nObjects) - && (CMclWaitSucceededIndex(dwStatus) == WAIT_OBJECT_0)) { + && (CMclWaitSucceededIndex(dwStatus) == 0)) { dwStatus = m_cGuardMutexAPtr->Wait(dwTimeout); if (CMclWaitSucceeded(dwStatus, 1) || CMclWaitAbandoned(dwStatus, 1)) { CopyMemory( GetTailPtr(), lpMsg, m_pHdr->cbMsgSize); IncrementTail(); m_cGuardMutexAPtr->Release(); @@ -323,11 +323,11 @@ int nObjects = cCollection.GetCount(); DWORD dwStatus = cCollection.Wait( FALSE, dwTimeout); if (CMclWaitSucceeded( dwStatus, nObjects) - && (CMclWaitSucceededIndex(dwStatus) == WAIT_OBJECT_0)) { + && (CMclWaitSucceededIndex(dwStatus) == 0)) { dwStatus = m_cGuardMutexAPtr->Wait(dwTimeout); if (CMclWaitSucceeded(dwStatus, 1) || CMclWaitAbandoned(dwStatus, 1)) { CopyMemory( lpMsg, GetHeadPtr(), m_pHdr->cbMsgSize); IncrementHead(); m_cGuardMutexAPtr->Release(); Index: win/MsvcDbgControl.cpp ================================================================== --- win/MsvcDbgControl.cpp +++ win/MsvcDbgControl.cpp @@ -21,18 +21,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.sf.net/ * http://expect.nist.gov/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: MsvcDbgControl.cpp,v 1.1.2.6 2002/03/12 04:37:39 davygrvy Exp $ + * RCS: @(#) $Id: MsvcDbgControl.cpp,v 1.1.2.7 2002/03/12 23:12:59 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include extern CComModule _Module; Index: win/MsvcDbgControl.h ================================================================== --- win/MsvcDbgControl.h +++ win/MsvcDbgControl.h @@ -18,24 +18,25 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: MsvcDbgControl.h,v 1.1.2.4 2002/03/09 01:17:29 davygrvy Exp $ + * RCS: @(#) $Id: MsvcDbgControl.h,v 1.1.2.6 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef INC_MsvcDbgControl_h__ #define INC_MsvcDbgControl_h__ #include -extern TCL_CPP int MsvcDbg_Launch(const CHAR *wrkspace, Tcl_DString *cmdline, +TCL_EXTRNC int MsvcDbg_Launch(const CHAR *wrkspace, Tcl_DString *cmdline, void **token); #endif DELETED win/TclAdapter.hpp Index: win/TclAdapter.hpp ================================================================== --- win/TclAdapter.hpp +++ /dev/null @@ -1,164 +0,0 @@ -/* - ------------------------------------------------------------------------------ - * TclAdapter.hpp -- - * - * Defines one templated class for doing the grunt work for making - * C++ extensions. - * - * Copyright (c) 1999-2001 TomaSoft Engineering - * - * See the file "license.txt" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: TclAdapter.hpp,v 1.1.2.1 2002/03/11 00:31:56 davygrvy Exp $ - ------------------------------------------------------------------------------ - */ -#ifndef INC_TclAdapter_hpp__ -#define INC_TclAdapter_hpp__ - -#include "tcl.h" - -// We need at least the Tcl_Obj interface that was started in 8.0 -#if TCL_MAJOR_VERSION < 8 -# error "we need Tcl 8.0 or greater to build this" - -// Check for Stubs compatibility when asked for it. -#elif defined(USE_TCL_STUBS) && TCL_MAJOR_VERSION == 8 && \ - (TCL_MINOR_VERSION == 0 || \ - (TCL_MINOR_VERSION == 1 && TCL_RELEASE_LEVEL != TCL_FINAL_RELEASE)) -# error "Stubs interface doesn't work in 8.0 and alpha/beta 8.1; only 8.1.0+" -#endif - -#ifdef _MSC_VER - // Only do this when MSVC++ is compiling us. -# ifdef USE_TCL_STUBS - // Mark this .obj as needing tcl's Stubs library. -# pragma comment(lib, "tclstub" \ - STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) ".lib") -# if !defined(_MT) || !defined(_DLL) || defined(_DEBUG) - // This fixes a bug with how the Stubs library was compiled. - // The requirement for msvcrt.lib from tclstubXX.lib should - // be removed. -# pragma comment(linker, "-nodefaultlib:msvcrt.lib") -# endif -# else - // Mark this .obj needing the import library -# pragma comment(lib, "tcl" \ - STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) ".lib") -# endif -#endif - -// We only need one Win32 API in here so we can be super defensive -// with the destructor. -#ifdef __WIN32__ -# include -# ifdef _MSC_VER -# pragma comment (lib, "kernel32.lib") -# endif -#endif - - -// short cut -#define NewTclCmd(a,b,c) \ - Tcl_CreateObjCommand((a), (b), CmdDemux, CmdInfo((c), this), CmdDelete) - - -namespace Tcl { - template - class Adapter - { - typedef struct { - T *ext; - int (T::*cmd)(int, struct Tcl_Obj * CONST []); - } MPLEXDATA, *LPMPLEXDATA; - - protected: - Adapter(Tcl_Interp *_interp); - ~Adapter(); - - Tcl_Interp *interp; - - virtual void DoCleanup(void) = 0; - - // Create the multiplexor data that we save in the ClientData portion - // of the Tcl command. - ClientData CmdInfo(int (T::*cmd)(int, struct Tcl_Obj * CONST []), T *that) - { - LPMPLEXDATA mplex = new MPLEXDATA; - - mplex->ext = that; - mplex->cmd = cmd; - return static_cast (mplex); - } - static Tcl_InterpDeleteProc InterpDeleting; - static Tcl_ExitProc Exiting; - static Tcl_ObjCmdProc CmdDemux; - static Tcl_CmdDeleteProc CmdDelete; - }; - - - template - Adapter::Adapter(Tcl_Interp *_interp) - : interp(_interp) - { - Tcl_CallWhenDeleted(interp, InterpDeleting, this); - Tcl_CreateExitHandler(Exiting, this); - } - - - template - Adapter::~Adapter() - { - Tcl_DeleteExitHandler(Exiting, this); - } - - - template void - Adapter::InterpDeleting (ClientData clientData, Tcl_Interp *) - { - T *adapt = static_cast (clientData); - adapt->DoCleanup(); - delete adapt; - } - - - template void - Adapter::Exiting (ClientData clientData) - { -#ifdef __WIN32__ - // It can happen that the HEAP could have already been unloaded from an - // awkward teardown caused by a Ctrl+C or other. Win32 seems to do a - // teardown in reverse order and by the time Tcl knows what's going on - // and Tcl_Finalize calls the exit handlers, this extension's data has - // already been unloaded by the OS. Do a quick legal check on the - // pointer first. - if (IsBadReadPtr(clientData, sizeof(T *))) return; -#endif - delete static_cast (clientData); - } - - - template int - Adapter::CmdDemux (ClientData clientData, Tcl_Interp *, int objc, - struct Tcl_Obj * CONST objv[]) - { - LPMPLEXDATA demux = static_cast (clientData); - // We aleady know what the interp pointer is (saved in the class - // instance), so don't bother with it here. Call the member function - // of the extension instance as saved in the MPLEXDATA struct when we - // created this command using the somewhat obscure C++ pointer-to- - // member method. - // - // This is a demultiplexor or 'demux' for short. - return ((demux->ext) ->* (demux->cmd)) (objc,objv); - } - - - template void - Adapter::CmdDelete (ClientData clientData) - { - // clean-up the MPLEXDATA structure from the commands. - delete static_cast (clientData); - } -} -#endif ADDED win/TclAdaptor.hpp Index: win/TclAdaptor.hpp ================================================================== --- /dev/null +++ win/TclAdaptor.hpp @@ -0,0 +1,204 @@ +/* + ------------------------------------------------------------------------------ + * TclAdaptor.hpp -- + * + * Defines one templated class for doing the grunt work of making + * C++ extensions for Tcl. + * + * Copyright (c) 1999-2001 TomaSoft Engineering + * + * See the file "license.txt" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: TclAdaptor.hpp,v 1.6 2002/08/26 23:48:20 davygrvy Exp $ + ------------------------------------------------------------------------------ + */ +#ifndef INC_TclAdaptor_hpp__ +#define INC_TclAdaptor_hpp__ + +#ifndef INC_config_hpp__ +# include "config.hpp" +#endif + +#include "tcl.h" + +// We need at least the Tcl_Obj interface that was started in 8.0 +#if TCL_MAJOR_VERSION < 8 +# error "we need Tcl 8.0 or greater to build this" + +// Check for Stubs compatibility when asked for it. +#elif defined(USE_TCL_STUBS) && TCL_MAJOR_VERSION == 8 && \ + (TCL_MINOR_VERSION == 0 || \ + (TCL_MINOR_VERSION == 1 && TCL_RELEASE_LEVEL != TCL_FINAL_RELEASE)) +# error "Stubs interface doesn't work in 8.0 and alpha/beta 8.1; only 8.1.0+" +#endif + +#ifdef _MSC_VER + // Only do this when MSVC++ is compiling us. +# ifdef USE_TCL_STUBS + // Mark this .obj as needing tcl's Stubs library. +# pragma comment(lib, "tclstub" \ + STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) ".lib") +# if !defined(_MT) || !defined(_DLL) || defined(_DEBUG) + // This fixes a bug with how the Stubs library was compiled. + // The requirement for msvcrt.lib from tclstubXX.lib should + // be removed. +# pragma comment(linker, "-nodefaultlib:msvcrt.lib") +# endif +# else + // Mark this .obj needing the import library +# pragma comment(lib, "tcl" \ + STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) ".lib") +# endif +#endif + +// We only need one Win32 API in here so we can be super defensive +// with the destructor. +#ifdef __WIN32__ +# include +# ifdef _MSC_VER +# pragma comment (lib, "kernel32.lib") +# endif +#endif + + +// short cut +#define NewTclCmd(a,b) \ + Tcl_CreateObjCommand(interp, (a), CmdDemux, CmdInfo((b), this), CmdDelete) + + +CPPTCL_BEGIN_NAMESPACE(Tcl) + +template + class Adaptor +{ + typedef struct { + T *ext; + int (T::*cmd)(int, struct Tcl_Obj * const []); + } MPLEXDATA, *LPMPLEXDATA; + +public: + Tcl_Interp *interp; + +protected: + Adaptor(Tcl_Interp *_interp); + Adaptor(); + virtual ~Adaptor(); + + virtual void DoInterpDataCleanup(void) {}; + virtual void DoCommandCleanup(void) {}; + + void InitBase(); // delay start entry when the interp isn't + // known for the constructor. + + // Create the multiplexor data that we save in the ClientData + // portion of the Tcl command. + // + ClientData CmdInfo(int (T::*cmd)(int, struct Tcl_Obj * const []), T *that) + { + LPMPLEXDATA mplex = new MPLEXDATA; + + mplex->ext = that; + mplex->cmd = cmd; + return static_cast (mplex); + } + static Tcl_InterpDeleteProc InterpDeleting; + static Tcl_ExitProc Exiting; + static Tcl_ObjCmdProc CmdDemux; + static Tcl_CmdDeleteProc CmdDelete; +}; + + +template + Adaptor::Adaptor(Tcl_Interp *_interp) + : interp(_interp) +{ + InitBase(); +} + +template + Adaptor::Adaptor() + : interp(0L) +{ +} + +template void + Adaptor::InitBase() +{ + Tcl_CallWhenDeleted(interp, InterpDeleting, this); + Tcl_CreateExitHandler(Exiting, this); +} + +template + Adaptor::~Adaptor() +{ + if (interp != 0L) DoCommandCleanup(); + Tcl_DeleteExitHandler(Exiting, this); +} + + +template void + Adaptor::InterpDeleting (ClientData clientData, Tcl_Interp *) +{ + T *adapt = reinterpret_cast (clientData); + adapt->DoInterpDataCleanup(); + + // The use of the interp* is not allowed from the context of the + // destructor. Ensure that it can't be used by removing it now. + // + adapt->interp = 0L; + delete adapt; +} + + +template void + Adaptor::Exiting (ClientData clientData) +{ + T *adapt = reinterpret_cast (clientData); +#ifdef __WIN32__ + // It can happen that the HEAP could have already been unloaded + // from an awkward teardown caused by a Ctrl+C or other. Win32 + // seems to do a teardown in reverse order and by the time Tcl + // knows what's going on and Tcl_Finalize calls the exit + // handlers, this extension's data (heap?) has already been + // unloaded by the OS. Do a quick legal check on the pointer + // first. + // + if (IsBadReadPtr(adapt, sizeof(T *))) return; +#endif + // The use of the interp* is not allowed from the context of an + // exit handler, so make sure it can't be used by removing it. + // + adapt->interp = 0L; + delete adapt; +} + + +template int + Adaptor::CmdDemux (ClientData clientData, Tcl_Interp *, int objc, + struct Tcl_Obj * const objv[]) +{ + LPMPLEXDATA demux = static_cast (clientData); + // We aleady know what the interp pointer is (saved in the class + // instance), so don't bother with it here. Call the member function + // of the extension instance as saved in the MPLEXDATA struct when we + // created this command using the somewhat obscure C++ pointer-to- + // member method. + // + // This is a demultiplexor or 'demux' for short. + // + return ((demux->ext) ->* (demux->cmd)) (objc,objv); +} + + +template void + Adaptor::CmdDelete (ClientData clientData) +{ + // clean-up the MPLEXDATA structure from the commands. + // + delete static_cast (clientData); +} + +CPPTCL_END_NAMESPACE + +#endif Index: win/TclHash.hpp ================================================================== --- win/TclHash.hpp +++ win/TclHash.hpp @@ -2,128 +2,156 @@ ------------------------------------------------------------------------------ * TclHash.hpp -- * * Tcl's hash table done as a template. * - * Copyright (c) 1999-2001 David Gravereaux + * Copyright (c) 1999-2001 TomaSoft Engineering * * See the file "license.txt" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: TclHash.hpp,v 1.1.2.1 2002/03/12 16:42:07 davygrvy Exp $ + * RCS: @(#) $Id: TclHash.hpp,v 1.15 2002/08/27 01:27:44 davygrvy Exp $ ------------------------------------------------------------------------------ */ #ifndef INC_tclhash_hpp__ #define INC_tclhash_hpp__ + +#ifndef INC_config_hpp__ +# include "config.hpp" +#endif #include "tcl.h" -namespace Tcl { - - template - class Hash - { - public: - Hash () { Tcl_InitHashTable(&HashTbl, keytype); } - ~Hash () { Tcl_DeleteHashTable(&HashTbl); } - Tcl_Obj *Stats (); - int Add (void *key, T result); - int Find (void *key, T *result); - int Delete (void *key); - int Top (T *result); - int Next (T *result); - - protected: - Tcl_HashSearch HashSrch; - Tcl_HashTable HashTbl; - }; - - template - Tcl_Obj *Hash::Stats () - { - char *stats; - Tcl_Obj *oStats; - - stats = Tcl_HashStats(&HashTbl); - oStats = Tcl_NewStringObj(stats, -1); - ckfree(stats); - return oStats; - } - - template - int Hash::Add (void *key, T result) - { - int created; - Tcl_HashEntry *entryPtr; - - entryPtr = Tcl_CreateHashEntry(&HashTbl, static_cast(key), - &created); - - if (!created) { - return TCL_ERROR; - } - Tcl_SetHashValue(entryPtr, result); - return TCL_OK; - } - - template - int Hash::Find (void *key, T *result) - { - Tcl_HashEntry *entryPtr; - - entryPtr = Tcl_FindHashEntry(&HashTbl, static_cast(key)); - if (entryPtr == 0L) { - return TCL_ERROR; - } - if (result != 0L) { - *result = static_cast(Tcl_GetHashValue(entryPtr)); - } - return TCL_OK; - } - - template - int Hash::Delete (void *key) - { - Tcl_HashEntry *entryPtr; - - entryPtr = Tcl_FindHashEntry(&HashTbl, static_cast(key)); - if (entryPtr == 0L) { - return TCL_ERROR; - } - Tcl_DeleteHashEntry(entryPtr); - return TCL_OK; - } - - template - int Hash::Top (T *result) - { - Tcl_HashEntry *entryPtr; - - entryPtr = Tcl_FirstHashEntry(&HashTbl, &HashSrch); - if (entryPtr == 0L) { - return TCL_ERROR; - } - if (result != 0L) { - *result = static_cast(Tcl_GetHashValue(entryPtr)); - } - return TCL_OK; - } - - template - int Hash::Next (T *result) - { - Tcl_HashEntry *entryPtr; - - entryPtr = Tcl_NextHashEntry(&HashSrch); - if (entryPtr == 0L) { - return TCL_ERROR; - } - if (result != 0L) { - *result = static_cast(Tcl_GetHashValue(entryPtr)); - } - return TCL_OK; - } - -}; // namespace Tcl +CPPTCL_BEGIN_NAMESPACE(Tcl) + +template + class Hash +{ +public: + Hash () { Tcl_InitHashTable(&HashTbl, keytype); } + ~Hash () { Tcl_DeleteHashTable(&HashTbl); } + Tcl_Obj *Stats (); + int Add (const void *key, T result); + int Find (const void *key, T *result); + int Extract (const void *key, T *result); + int Delete (const void *key); + int Top (T *result, const void **key = 0L); + int Next (T *result, const void **key = 0L); + +protected: + Tcl_HashSearch HashSrch; + Tcl_HashTable HashTbl; +}; + +template + Tcl_Obj *Hash::Stats () +{ + const char *stats; + Tcl_Obj *oStats; + + stats = Tcl_HashStats(&HashTbl); + oStats = Tcl_NewStringObj(stats, -1); + ckfree((char *)stats); + return oStats; +} + +template + int Hash::Add (const void *key, T result) +{ + int created; + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_CreateHashEntry(&HashTbl, static_cast(key), + &created); + + if (!created) { + return TCL_ERROR; + } + Tcl_SetHashValue(entryPtr, result); + return TCL_OK; +} + +template + int Hash::Find (const void *key, T *result) +{ + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FindHashEntry(&HashTbl, static_cast(key)); + if (entryPtr == 0L) { + return TCL_ERROR; + } + if (result != 0L) { + *result = reinterpret_cast(Tcl_GetHashValue(entryPtr)); + } + return TCL_OK; +} + +template + int Hash::Delete (const void *key) +{ + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FindHashEntry(&HashTbl, static_cast(key)); + if (entryPtr == 0L) { + return TCL_ERROR; + } + Tcl_DeleteHashEntry(entryPtr); + return TCL_OK; +} + +template + int Hash::Top (T *result, const void **key) +{ + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FirstHashEntry(&HashTbl, &HashSrch); + if (entryPtr == 0L) { + return TCL_ERROR; + } + if (result != 0L) { + *result = reinterpret_cast(Tcl_GetHashValue(entryPtr)); + } + if (key != 0L) { + *key = Tcl_GetHashKey(&HashTbl, entryPtr); + } + return TCL_OK; +} + +template + int Hash::Next (T *result, const void **key) +{ + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_NextHashEntry(&HashSrch); + if (entryPtr == 0L) { + return TCL_ERROR; + } + if (result != 0L) { + *result = reinterpret_cast(Tcl_GetHashValue(entryPtr)); + } + if (key != 0L) { + *key = Tcl_GetHashKey(&HashTbl, entryPtr); + } + return TCL_OK; +} + +template + int Hash::Extract (const void *key, T *result) +{ + Tcl_HashEntry *entryPtr; + + entryPtr = Tcl_FindHashEntry(&HashTbl, static_cast(key)); + if (entryPtr == 0L) { + return TCL_ERROR; + } + if (result != 0L) { + *result = reinterpret_cast(Tcl_GetHashValue(entryPtr)); + } + Tcl_DeleteHashEntry(entryPtr); + return TCL_OK; +} + +CPPTCL_END_NAMESPACE + #endif // #ifndef INC_tclhash_hpp__ ADDED win/config.hpp Index: win/config.hpp ================================================================== --- /dev/null +++ win/config.hpp @@ -0,0 +1,101 @@ +#ifndef INC_config_hpp__ +#define INC_config_hpp__ + +// Just a simple configuration file to adjust between +// various compiler quirks. + + +/******************************************* + * Microsoft Visual C++ + *******************************************/ +#if defined(_MSC_VER) && !defined(__ICL) && !defined(__MWERKS__) + // we don't care to know about name trucation in the debug data. +# pragma warning (disable:4786) +#endif + + +/******************************************* + * Intel C++ Compiler + *******************************************/ +#if defined(__ICL) +#endif + + +/******************************************* + * Mingw32 (gcc) + * (egcs compiler using the M$ C runtime) + *******************************************/ +#if defined(__MINGW32__) +#endif + + +/******************************************* + * Cygwin32 (gcc) + * (egcs cross-compiler on M$ Windows) + *******************************************/ +#if defined(__CYGWIN__) +#endif + + +#if defined(__sgi) && !defined(__GNUC__) +# if (_COMPILER_VERSION >= 721) && !defined(_NAMESPACES) +# define CPPTCL_NO_NAMESPACES +# endif +#endif + +/******************************************* + * SunPro Compiler + * (Using OBJECTSPACE STL) + *******************************************/ +#ifdef __SUNPRO_CC +# if (__SUNPRO_CC == 0x420) +# define CPPTCL_NO_NAMESPACES +# endif +#endif + + +/******************************************* + * SCO UDK 7 compiler + * (UnixWare 7x, OSR 5, UnixWare 2x) + *******************************************/ +#if defined(__USLC__) +#endif + + +/******************************************* + * Inprise (Borland) C++ Builder 3.0 + *******************************************/ +#ifdef __BCPLUSPLUS__ +#endif + + +/******************************************* + * IBM VisualAge C++ + * ( uses the Dinkumware C++ Library ) + *******************************************/ +#ifdef __IBMCPP__ +#endif + + +/******************************************* + * Metrowerks Codewarrior + *******************************************/ +#ifdef __MWERKS__ +#endif + + + +#if !defined(CPPTCL_NO_NAMESPACES) +# define CPPTCL_USE_NAMESPACE(_x_) _x_:: +# define CPPTCL_USING_NAMESPACE(_x_) using namespace _x_; +# define CPPTCL_BEGIN_NAMESPACE(_x_) namespace _x_ { +# define CPPTCL_END_NAMESPACE } +#else +# define CPPTCL_USE_NAMESPACE(_x_) +# define CPPTCL_USING_NAMESPACE(_x_) +# define CPPTCL_BEGIN_NAMESPACE(_x_) +# define CPPTCL_END_NAMESPACE +#endif + + +#endif // #ifndef INC_config_hpp__ Index: win/expWinCommand.c ================================================================== --- win/expWinCommand.c +++ win/expWinCommand.c @@ -13,18 +13,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinCommand.c,v 1.1.2.1.2.10 2002/02/10 12:03:30 davygrvy Exp $ + * RCS: @(#) $Id: expWinCommand.c,v 1.1.2.1.2.12 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinInt.h" @@ -175,20 +176,20 @@ */ /* arguments are passed verbatim to execvp() */ /*ARGSUSED*/ int -Exp_SpawnCmd(ClientData clientData,Tcl_Interp *interp,int argc,char **argv) +Exp_SpawnCmd(ClientData clientData,Tcl_Interp *interp,int argc, CONST char **argv) { HANDLE hSlaveDrv = INVALID_HANDLE_VALUE; /* Handle to communicate with slave driver */ Tcl_Pid slaveDrvPid; /* Process id of the slave */ BOOL bRet; DWORD dwRet; DWORD count; int echo = TRUE; - char **a; - char *argv0 = argv[0]; + CONST char **a; + CONST char *argv0 = argv[0]; char slaveName[50]; /* Used to set 'spawn_out(slave,name)' */ static int slaveId = 1; /* Start at one because console0 is expect's */ UCHAR buf[8]; /* enough space for child status info */ WCHAR execPath[MAX_PATH]; /* needed for unicode space. */ Tcl_DString slavePath; @@ -200,16 +201,16 @@ Tcl_Channel channel = NULL; Tcl_Channel channel2 = NULL; Tcl_Channel spawnChan = NULL; TclFile masterRFile; TclFile masterWFile; - char *openarg = NULL; + CONST char *openarg = NULL; int leaveopen = 0; CONST char *val; int hide; int debug; - char **nargv = NULL; + CONST char **nargv = NULL; int i, j; int usePipes = 0; int useSocket = 0; char pipeName[100]; @@ -639,15 +640,15 @@ */ /*ARGSUSED*/ int -Exp_KillCmd(ClientData clientData,Tcl_Interp *interp,int argc,char **argv) +Exp_KillCmd(ClientData clientData,Tcl_Interp *interp,int argc, CONST char **argv) { struct exp_f *f; - char *chanId = NULL; - char *argv0 = argv[0]; + CONST char *chanId = NULL; + CONST char *argv0 = argv[0]; int signal = 9; char buf[2]; int msg; argc--; argv++; Index: win/expWinConsoleDebugger.cpp ================================================================== --- win/expWinConsoleDebugger.cpp +++ win/expWinConsoleDebugger.cpp @@ -13,33 +13,84 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinConsoleDebugger.cpp,v 1.1.2.13 2002/03/15 07:51:56 davygrvy Exp $ + * RCS: @(#) $Id: expWinConsoleDebugger.cpp,v 1.1.2.33 2003/08/26 00:14:38 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include #include #include "expWinConsoleDebugger.hpp" +#include "expWinInjectorIPC.hpp" +#include +#pragma comment (lib, "vdmdbg.lib") + #ifdef _MSC_VER # pragma comment (lib, "imagehlp.lib") #endif + +#ifdef _M_IX86 + // Breakpoint opcode on i386 +# define BRK_OPCODE 0xCC + // Single step flag +# define SINGLE_STEP_BIT 0x100 +#else +# error need opcodes for this hardware. +#endif + + // Constructor. -ConsoleDebugger::ConsoleDebugger (int _argc, char * const *_argv, CMclQueue &_mQ) +ConsoleDebugger::ConsoleDebugger ( + int _argc, + char * const *_argv, + CMclQueue &_mQ + ) : argc(_argc), argv(_argv), ProcessList(0L), CursorKnown(FALSE), - ShowExceptionBacktraces(FALSE), SymbolPath(0L), mQ(_mQ) + ConsoleOutputCP(0), ConsoleCP(0), mQ(_mQ), pStartAddress(0L), + originalExeEntryPointOpcode(0), pInjectorStub(0), injectorIPC(0L), + interacting(false), interactingConsole(0L) { + OSVERSIONINFO osvi; + DWORD n, i; + + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + dwPlatformId = osvi.dwPlatformId; + + if (dwPlatformId == VER_PLATFORM_WIN32_NT) { + pfnVirtualAllocEx = (PFNVIRTUALALLOCEX) GetProcAddress( + GetModuleHandle("KERNEL32.DLL"),"VirtualAllocEx"); + pfnVirtualFreeEx = (PFNVIRTUALFREEEX) GetProcAddress( + GetModuleHandle("KERNEL32.DLL"),"VirtualFreeEx"); + } + + n = GetEnvironmentVariable("Path", NULL, 0); + n += GetEnvironmentVariable("_NT_SYMBOL_PATH", NULL, 0) + 1; + n += GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", NULL, 0) + 1; + n += GetEnvironmentVariable("SystemRoot", NULL, 0) + 1; + + SymbolPath = new char [n]; + + i = GetEnvironmentVariable("Path", SymbolPath, n); + SymbolPath[i++] = ';'; + i += GetEnvironmentVariable("_NT_SYMBOL_PATH", &SymbolPath[i], n-i); + SymbolPath[i++] = ';'; + i += GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", &SymbolPath[i], n-i); + SymbolPath[i++] = ';'; + i += GetEnvironmentVariable("SystemRoot", &SymbolPath[i], n-i); + // Until further notice, assume this. // ConsoleSize.X = 80; ConsoleSize.Y = 25; @@ -47,113 +98,152 @@ // CursorPosition.X = 0; CursorPosition.Y = 0; // Set all our breakpoint info. We have to do this the long way, here in - // the constructor, because we need to have the this pointer already + // the constructor, because we need to have the 'this' pointer already // set because we refer to ourselves by needing the address to member // functions. // - BreakArrayKernel32[0].funcName = "Beep"; - BreakArrayKernel32[0].nargs = 2; - BreakArrayKernel32[0].breakProc = OnBeep; - BreakArrayKernel32[0].dwFlags = BREAK_OUT|BREAK_IN; - - BreakArrayKernel32[1].funcName = "FillConsoleOutputCharacterA"; - BreakArrayKernel32[1].nargs = 5; - BreakArrayKernel32[1].breakProc = OnFillConsoleOutputCharacter; - BreakArrayKernel32[1].dwFlags = BREAK_OUT; - - BreakArrayKernel32[2].funcName = "FillConsoleOutputCharacterW"; + + // interesting ones I might want to add: + // DuplicateConsoleHandle + + BreakArrayKernel32[0].funcName = "AllocConsole"; + BreakArrayKernel32[0].nargs = 0; + BreakArrayKernel32[0].breakProc = OnAllocConsole; + BreakArrayKernel32[0].dwFlags = BREAK_OUT; + + BreakArrayKernel32[1].funcName = "Beep"; + BreakArrayKernel32[1].nargs = 2; + BreakArrayKernel32[1].breakProc = OnBeep; + BreakArrayKernel32[1].dwFlags = BREAK_OUT|BREAK_IN; + + BreakArrayKernel32[2].funcName = "CreateConsoleScreenBuffer"; BreakArrayKernel32[2].nargs = 5; - BreakArrayKernel32[2].breakProc = OnFillConsoleOutputCharacter; + BreakArrayKernel32[2].breakProc = OnCreateConsoleScreenBuffer; BreakArrayKernel32[2].dwFlags = BREAK_OUT; - BreakArrayKernel32[3].funcName = "GetStdHandle"; - BreakArrayKernel32[3].nargs = 1; - BreakArrayKernel32[3].breakProc = OnGetStdHandle; + BreakArrayKernel32[3].funcName = "FillConsoleOutputAttribute"; + BreakArrayKernel32[3].nargs = 5; + BreakArrayKernel32[3].breakProc = OnFillConsoleOutputAttribute; BreakArrayKernel32[3].dwFlags = BREAK_OUT; - BreakArrayKernel32[4].funcName = "OpenConsoleW"; - BreakArrayKernel32[4].nargs = 4; - BreakArrayKernel32[4].breakProc = OnOpenConsoleW; + BreakArrayKernel32[4].funcName = "FillConsoleOutputCharacterA"; + BreakArrayKernel32[4].nargs = 5; + BreakArrayKernel32[4].breakProc = OnFillConsoleOutputCharacterA; BreakArrayKernel32[4].dwFlags = BREAK_OUT; - BreakArrayKernel32[5].funcName = "ReadConsoleInputA"; - BreakArrayKernel32[5].nargs = 4; - BreakArrayKernel32[5].breakProc = OnReadConsoleInput; + BreakArrayKernel32[5].funcName = "FillConsoleOutputCharacterW"; + BreakArrayKernel32[5].nargs = 5; + BreakArrayKernel32[5].breakProc = OnFillConsoleOutputCharacterW; BreakArrayKernel32[5].dwFlags = BREAK_OUT; - BreakArrayKernel32[6].funcName = "ReadConsoleInputW"; - BreakArrayKernel32[6].nargs = 4; - BreakArrayKernel32[6].breakProc = OnReadConsoleInput; + BreakArrayKernel32[6].funcName = "FreeConsole"; + BreakArrayKernel32[6].nargs = 0; + BreakArrayKernel32[6].breakProc = OnFreeConsole; BreakArrayKernel32[6].dwFlags = BREAK_OUT; - BreakArrayKernel32[7].funcName = "ScrollConsoleScreenBufferA"; - BreakArrayKernel32[7].nargs = 5; - BreakArrayKernel32[7].breakProc = OnScrollConsoleScreenBuffer; + BreakArrayKernel32[7].funcName = "GetStdHandle"; + BreakArrayKernel32[7].nargs = 1; + BreakArrayKernel32[7].breakProc = OnGetStdHandle; BreakArrayKernel32[7].dwFlags = BREAK_OUT; - BreakArrayKernel32[8].funcName = "ScrollConsoleScreenBufferW"; - BreakArrayKernel32[8].nargs = 5; - BreakArrayKernel32[8].breakProc = OnScrollConsoleScreenBuffer; + BreakArrayKernel32[8].funcName = "OpenConsoleW"; + BreakArrayKernel32[8].nargs = 4; + BreakArrayKernel32[8].breakProc = OnOpenConsoleW; BreakArrayKernel32[8].dwFlags = BREAK_OUT; - BreakArrayKernel32[9].funcName = "SetConsoleMode"; - BreakArrayKernel32[9].nargs = 2; - BreakArrayKernel32[9].breakProc = OnSetConsoleMode; + BreakArrayKernel32[9].funcName = "ScrollConsoleScreenBufferA"; + BreakArrayKernel32[9].nargs = 5; + BreakArrayKernel32[9].breakProc = OnScrollConsoleScreenBuffer; BreakArrayKernel32[9].dwFlags = BREAK_OUT; - BreakArrayKernel32[10].funcName = "SetConsoleActiveScreenBuffer"; - BreakArrayKernel32[10].nargs = 1; - BreakArrayKernel32[10].breakProc = OnSetConsoleActiveScreenBuffer; + BreakArrayKernel32[10].funcName = "ScrollConsoleScreenBufferW"; + BreakArrayKernel32[10].nargs = 5; + BreakArrayKernel32[10].breakProc = OnScrollConsoleScreenBuffer; BreakArrayKernel32[10].dwFlags = BREAK_OUT; - BreakArrayKernel32[11].funcName = "SetConsoleCursorPosition"; - BreakArrayKernel32[11].nargs = 2; - BreakArrayKernel32[11].breakProc = OnSetConsoleCursorPosition; + BreakArrayKernel32[11].funcName = "SetConsoleActiveScreenBuffer"; + BreakArrayKernel32[11].nargs = 1; + BreakArrayKernel32[11].breakProc = OnSetConsoleActiveScreenBuffer; BreakArrayKernel32[11].dwFlags = BREAK_OUT; - BreakArrayKernel32[12].funcName = "SetConsoleWindowInfo"; - BreakArrayKernel32[12].nargs = 2; - BreakArrayKernel32[12].breakProc = OnSetConsoleWindowInfo; + BreakArrayKernel32[12].funcName = "SetConsoleCP"; + BreakArrayKernel32[12].nargs = 1; + BreakArrayKernel32[12].breakProc = OnSetConsoleCP; BreakArrayKernel32[12].dwFlags = BREAK_OUT; - BreakArrayKernel32[13].funcName = "WriteConsoleA"; - BreakArrayKernel32[13].nargs = 5; - BreakArrayKernel32[13].breakProc = OnWriteConsoleA; + BreakArrayKernel32[13].funcName = "SetConsoleCursorInfo"; + BreakArrayKernel32[13].nargs = 2; + BreakArrayKernel32[13].breakProc = OnSetConsoleCursorInfo; BreakArrayKernel32[13].dwFlags = BREAK_OUT; - BreakArrayKernel32[14].funcName = "WriteConsoleW"; - BreakArrayKernel32[14].nargs = 5; - BreakArrayKernel32[14].breakProc = OnWriteConsoleW; + BreakArrayKernel32[14].funcName = "SetConsoleCursorPosition"; + BreakArrayKernel32[14].nargs = 2; + BreakArrayKernel32[14].breakProc = OnSetConsoleCursorPosition; BreakArrayKernel32[14].dwFlags = BREAK_OUT; - BreakArrayKernel32[15].funcName = "WriteConsoleOutputA"; - BreakArrayKernel32[15].nargs = 5; - BreakArrayKernel32[15].breakProc = OnWriteConsoleOutputA; + BreakArrayKernel32[15].funcName = "SetConsoleMode"; + BreakArrayKernel32[15].nargs = 2; + BreakArrayKernel32[15].breakProc = OnSetConsoleMode; BreakArrayKernel32[15].dwFlags = BREAK_OUT; - BreakArrayKernel32[16].funcName = "WriteConsoleOutputW"; - BreakArrayKernel32[16].nargs = 5; - BreakArrayKernel32[16].breakProc = OnWriteConsoleOutputW; + BreakArrayKernel32[16].funcName = "SetConsoleOutputCP"; + BreakArrayKernel32[16].nargs = 1; + BreakArrayKernel32[16].breakProc = OnSetConsoleOutputCP; BreakArrayKernel32[16].dwFlags = BREAK_OUT; - BreakArrayKernel32[17].funcName = "WriteConsoleOutputCharacterA"; - BreakArrayKernel32[17].nargs = 5; - BreakArrayKernel32[17].breakProc = OnWriteConsoleOutputCharacterA; + BreakArrayKernel32[17].funcName = "SetConsoleTextAttribute"; + BreakArrayKernel32[17].nargs = 2; + BreakArrayKernel32[17].breakProc = OnSetConsoleTextAttribute; BreakArrayKernel32[17].dwFlags = BREAK_OUT; - BreakArrayKernel32[18].funcName = "WriteConsoleOutputCharacterW"; - BreakArrayKernel32[18].nargs = 5; - BreakArrayKernel32[18].breakProc = OnWriteConsoleOutputCharacterW; + BreakArrayKernel32[18].funcName = "SetConsoleWindowInfo"; + BreakArrayKernel32[18].nargs = 3; + BreakArrayKernel32[18].breakProc = OnSetConsoleWindowInfo; BreakArrayKernel32[18].dwFlags = BREAK_OUT; - BreakArrayKernel32[19].funcName = 0L; - BreakArrayKernel32[19].nargs = 0; - BreakArrayKernel32[19].breakProc = 0L; - BreakArrayKernel32[19].dwFlags = 0; + BreakArrayKernel32[19].funcName = "WriteConsoleA"; + BreakArrayKernel32[19].nargs = 5; + BreakArrayKernel32[19].breakProc = OnWriteConsoleA; + BreakArrayKernel32[19].dwFlags = BREAK_OUT; + + BreakArrayKernel32[20].funcName = "WriteConsoleW"; + BreakArrayKernel32[20].nargs = 5; + BreakArrayKernel32[20].breakProc = OnWriteConsoleW; + BreakArrayKernel32[20].dwFlags = BREAK_OUT; + + BreakArrayKernel32[21].funcName = "WriteConsoleOutputA"; + BreakArrayKernel32[21].nargs = 5; + BreakArrayKernel32[21].breakProc = OnWriteConsoleOutputA; + BreakArrayKernel32[21].dwFlags = BREAK_OUT; + + BreakArrayKernel32[22].funcName = "WriteConsoleOutputW"; + BreakArrayKernel32[22].nargs = 5; + BreakArrayKernel32[22].breakProc = OnWriteConsoleOutputW; + BreakArrayKernel32[22].dwFlags = BREAK_OUT; + + BreakArrayKernel32[23].funcName = "WriteConsoleOutputCharacterA"; + BreakArrayKernel32[23].nargs = 5; + BreakArrayKernel32[23].breakProc = OnWriteConsoleOutputCharacterA; + BreakArrayKernel32[23].dwFlags = BREAK_OUT; + + BreakArrayKernel32[24].funcName = "WriteConsoleOutputCharacterW"; + BreakArrayKernel32[24].nargs = 5; + BreakArrayKernel32[24].breakProc = OnWriteConsoleOutputCharacterW; + BreakArrayKernel32[24].dwFlags = BREAK_OUT; + + BreakArrayKernel32[25].funcName = "WriteFile"; + BreakArrayKernel32[25].nargs = 5; + BreakArrayKernel32[25].breakProc = OnWriteFile; + BreakArrayKernel32[25].dwFlags = BREAK_OUT; + + BreakArrayKernel32[26].funcName = 0L; + BreakArrayKernel32[26].nargs = 0; + BreakArrayKernel32[26].breakProc = 0L; + BreakArrayKernel32[26].dwFlags = 0; BreakArrayUser32[0].funcName = "IsWindowVisible"; BreakArrayUser32[0].nargs = 1; BreakArrayUser32[0].breakProc = OnIsWindowVisible; BreakArrayUser32[0].dwFlags = BREAK_OUT; @@ -176,153 +266,63 @@ FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); } ConsoleDebugger::~ConsoleDebugger() { - if (SymbolPath) delete [] SymbolPath; + delete [] SymbolPath; + if (injectorIPC) delete injectorIPC; + CloseHandle(hMasterConsole); } unsigned ConsoleDebugger::ThreadHandlerProc(void) { - Process *proc; - DWORD ok; + DWORD ok, exitcode; STARTUPINFO si; PROCESS_INFORMATION pi; char *cmdline; ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); - si.wShowWindow = SW_SHOWDEFAULT; + si.dwXCountChars = 80; + si.dwYCountChars = 25; + si.wShowWindow = SW_SHOWNOACTIVATE; + si.dwFlags = STARTF_FORCEONFEEDBACK | STARTF_USESHOWWINDOW | + STARTF_USECOUNTCHARS; cmdline = ArgMaker::BuildCommandLine(argc, argv); - // Make sure the master does not ignore Ctrl-C - SetConsoleCtrlHandler(0L, FALSE); - - ok = CreateProcess ( + ok = CreateProcess( 0L, // Module name (not needed). cmdline, // Command line. 0L, // Process handle will not be inheritable. 0L, // Thread handle will not be inheritable. FALSE, // No handle inheritance. - DEBUG_PROCESS|CREATE_NEW_CONSOLE|CREATE_DEFAULT_ERROR_MODE, + DEBUG_PROCESS | + CREATE_NEW_CONSOLE | + CREATE_DEFAULT_ERROR_MODE | + CREATE_SEPARATE_WOW_VDM | + 0, // Creation flags. 0L, // Use parent's environment block. 0L, // Use parent's starting directory. &si, // Pointer to STARTUPINFO structure. &pi); // Pointer to PROCESS_INFORMATION structure. - delete [] cmdline; - if (!ok) { - //arg->lastError = GetLastError(); + EXP_LOG2(MSG_DT_BADDEBUGGEE, cmdline, GetSysMsg(GetLastError())); } + delete [] cmdline; WaitForInputIdle(pi.hProcess, 5000); CloseHandle(pi.hThread); - - // Make sure we now ignore Ctrl-C - SetConsoleCtrlHandler(0L, TRUE); - - proc = ProcessNew(); - //CloseHandle(pi.hProcess); - proc->hProcess = pi.hProcess; - proc->pid = pi.dwProcessId; - - CommonDebugger(); - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleDebugger::ProcessNew -- - * - * Allocates a new structure for debugging a process and - * initializes it. - * - * Results: - * A new structure - * - * Side Effects: - * Memory is allocated, an event is created. - * - *---------------------------------------------------------------------- - */ - -ConsoleDebugger::Process * -ConsoleDebugger::ProcessNew(void) -{ - Process *proc; - proc = new Process; - proc->threadList = 0L; - proc->threadCount = 0; - proc->brkptList = 0L; - proc->lastBrkpt = 0L; - proc->offset = 0; - proc->nBreakCount = 0; - proc->consoleHandlesMax = 0; - proc->isConsoleApp = FALSE; - proc->isShell = FALSE; - proc->hProcess = 0L; - proc->pSubprocessMemory = 0; - proc->pSubprocessBuffer = 0; - proc->pMemoryCacheBase = 0; - proc->exeModule = 0L; - proc->nextPtr = ProcessList; - ProcessList = proc; - return proc; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleDebugger::ProcessFree -- - * - * Frees all allocated memory for a process and closes any - * open handles - * - * Results: - * None - * - *---------------------------------------------------------------------- - */ - -void -ConsoleDebugger::ProcessFree(Process *proc) -{ - ThreadInfo *tcurr, *tnext; - Breakpoint *bcurr, *bnext; - Process *pcurr, *pprev; - - for (tcurr = proc->threadList; tcurr != 0L; tcurr = tnext) { - tnext = tcurr->nextPtr; - proc->threadCount--; - CloseHandle(tcurr->hThread); - delete tcurr; - } - for (bcurr = proc->brkptList; bcurr != 0L; bcurr = bnext) { - bnext = bcurr->nextPtr; - delete bcurr; - } - for (pprev = 0L, pcurr = ProcessList; pcurr != 0L; - pcurr = pcurr->nextPtr) - { - if (pcurr == proc) { - if (pprev == 0L) { - ProcessList = pcurr->nextPtr; - } else { - pprev->nextPtr = pcurr->nextPtr; - } - break; - } - } - CloseHandle(proc->hProcess); - - delete proc; + CloseHandle(pi.hProcess); + + exitcode = CommonDebugger(); + NotifyDone(); + return exitcode; } /* *---------------------------------------------------------------------- * @@ -337,166 +337,147 @@ * Adds the process to the things being waited for by * WaitForMultipleObjects * *---------------------------------------------------------------------- */ -void +DWORD ConsoleDebugger::CommonDebugger() { DEBUG_EVENT debEvent; // debugging event info. DWORD dwContinueStatus; // exception continuation. - DWORD err; Process *proc; - DWORD n, i; - - n = GetEnvironmentVariable("Path", 0L, 0); - n += GetEnvironmentVariable("_NT_SYMBOL_PATH", 0L, 0) + 1; - n += GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", 0L, 0) + 1; - n += GetEnvironmentVariable("SystemRoot", 0L, 0) + 1; - - SymbolPath = new char [n]; - - i = GetEnvironmentVariable("Path", SymbolPath, n); - SymbolPath[i++] = ';'; - i += GetEnvironmentVariable("_NT_SYMBOL_PATH", &SymbolPath[i], n-i); - SymbolPath[i++] = ';'; - i += GetEnvironmentVariable("_NT_ALT_SYMBOL_PATH", &SymbolPath[i], n-i); - SymbolPath[i++] = ';'; - i += GetEnvironmentVariable("SystemRoot", &SymbolPath[i], n-i); - - for(;;) { - dwContinueStatus = DBG_CONTINUE; - - // Wait for a debugging event to occur. The second parameter - // indicates that the function does not return until - // a debugging event occurs. - // - if (WaitForDebugEvent(&debEvent, INFINITE) == FALSE) { - err = GetLastError(); - *((char *) 0L) = 0; // cause an exception. - } - - // Find the process that is responsible for this event. - // - for (proc = ProcessList; proc; proc = proc->nextPtr) { - if (proc->pid == debEvent.dwProcessId) { - break; - } - } - - if (!proc && debEvent.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { - char buf[50]; - wsprintf(buf, "%d/%d (%d)", - debEvent.dwProcessId, debEvent.dwThreadId, - debEvent.dwDebugEventCode); - EXP_LOG1(MSG_DT_UNEXPECTEDDBGEVENT, buf); - if (debEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { - char buf[50]; - wsprintf(buf, "0x%08x", debEvent.u.Exception.ExceptionRecord.ExceptionCode); - EXP_LOG1(MSG_DT_EXCEPTIONDBGEVENT, buf); - dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; - } - goto skip; - } - - // Process the debugging event code. - // - switch (debEvent.dwDebugEventCode) { - case EXCEPTION_DEBUG_EVENT: - // Process the exception code. When handling - // exceptions, remember to set the continuation - // status parameter (dwContinueStatus). This value - // is used by the ContinueDebugEvent function. - // - switch (debEvent.u.Exception.ExceptionRecord.ExceptionCode) { - case EXCEPTION_BREAKPOINT: - { - if (proc->nBreakCount < 1000) { - proc->nBreakCount++; - } - if (proc->nBreakCount == 1) { - OnXFirstBreakpoint(proc, &debEvent); - } else if (proc->nBreakCount == 2) { - OnXSecondBreakpoint(proc, &debEvent); - } else { - OnXBreakpoint(proc, &debEvent); - } - break; - } - - case EXCEPTION_SINGLE_STEP: - OnXSingleStep(proc, &debEvent); - break; - - case DBG_CONTROL_C: - dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; - break; - - case DBG_CONTROL_BREAK: - dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; - break; - - case EXCEPTION_DATATYPE_MISALIGNMENT: - case EXCEPTION_ACCESS_VIOLATION: - default: + int breakCount = 0; + +again: + dwContinueStatus = DBG_CONTINUE; + + // Wait (forever) for a debugging event to occur. + // + if (WaitForDebugEvent(&debEvent, INFINITE) == FALSE) { + return GetLastError(); + } + + // Find the process that is responsible for this event. + // + for (proc = ProcessList; proc; proc = proc->nextPtr) { + if (proc->pid == debEvent.dwProcessId) { + break; + } + } + + if (!proc && debEvent.dwDebugEventCode != CREATE_PROCESS_DEBUG_EVENT) { +/* char buf[50]; + wsprintf(buf, "%d/%d (%d)", + debEvent.dwProcessId, debEvent.dwThreadId, + debEvent.dwDebugEventCode); + EXP_LOG1(MSG_DT_UNEXPECTEDDBGEVENT, buf);*/ + if (debEvent.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) { + /*char buf[50]; + wsprintf(buf, "0x%08x", debEvent.u.Exception.ExceptionRecord.ExceptionCode); + EXP_LOG1(MSG_DT_EXCEPTIONDBGEVENT, buf);*/ + dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; + } + goto skip; + } + + bpCritSec.Enter(); + + // Process the debugging event code. + // + switch (debEvent.dwDebugEventCode) { + case EXCEPTION_DEBUG_EVENT: + switch (debEvent.u.Exception.ExceptionRecord.ExceptionCode) { + case EXCEPTION_BREAKPOINT: + { + // only the first three get special attention. + switch (breakCount < 4 ? ++breakCount : 4) { + case 1: + OnXFirstBreakpoint(proc, &debEvent); break; + case 2: + OnXSecondBreakpoint(proc, &debEvent); break; + case 3: + OnXThirdBreakpoint(proc, &debEvent); break; + case 4: + OnXBreakpoint(proc, &debEvent); + } + break; + } + + case EXCEPTION_SINGLE_STEP: + OnXSingleStep(proc, &debEvent); + break; + + case DBG_CONTROL_C: + case DBG_CONTROL_BREAK: + dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; + break; + + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + // we die here. + return EXCEPTION_NONCONTINUABLE_EXCEPTION; + + case STATUS_VDM_EVENT: + OnXVDMException(proc, &debEvent); + break; + + default: + if (!debEvent.u.Exception.dwFirstChance) { // An exception was hit and it was not handled by the program. - // Now it is time to get a backtrace. - if (! debEvent.u.Exception.dwFirstChance) { - OnXSecondChanceException(proc, &debEvent); - } - dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; - } - break; - - case CREATE_THREAD_DEBUG_EVENT: - OnXCreateThread(proc, &debEvent); - break; - - case CREATE_PROCESS_DEBUG_EVENT: - OnXCreateProcess(proc, &debEvent); - break; - - case EXIT_THREAD_DEBUG_EVENT: - OnXDeleteThread(proc, &debEvent); - break; - - case EXIT_PROCESS_DEBUG_EVENT: - // XXX: This is really screwed up, but we get breakpoints - // for processes that are already dead. So we cannot remove - // and cleanup a process until some later (How much later?) - // point. This really, really sucks.... + // Now it is time to get a backtrace before it's death. + // + OnXSecondChanceException(proc, &debEvent); + } + dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; + } + break; + + case CREATE_THREAD_DEBUG_EVENT: + OnXCreateThread(proc, &debEvent); + break; + + case CREATE_PROCESS_DEBUG_EVENT: + OnXCreateProcess(proc, &debEvent); + break; + + case EXIT_THREAD_DEBUG_EVENT: + OnXDeleteThread(proc, &debEvent); + break; + + case EXIT_PROCESS_DEBUG_EVENT: + ProcessFree(proc); + if (ProcessList == 0L) { + // When the last process exits, we exit. // -#if 0 /* This gets closed in WaitQueueThread */ - CloseHandle(proc->hProcess); -#endif - err = debEvent.u.ExitProcess.dwExitCode; - ProcessFree(proc); - if (ProcessList == 0L) { - // When the last process exits, we exit. - NotifyDone(); - return; - } - break; - - case LOAD_DLL_DEBUG_EVENT: - OnXLoadDll(proc, &debEvent); - break; - - case UNLOAD_DLL_DEBUG_EVENT: - OnXUnloadDll(proc, &debEvent); - break; - - case OUTPUT_DEBUG_STRING_EVENT: - // Display the output debugging string. - break; - } - - skip: - // Resume executing the thread that reported the debugging event. - ContinueDebugEvent(debEvent.dwProcessId, debEvent.dwThreadId, - dwContinueStatus); - } + return debEvent.u.ExitProcess.dwExitCode; + } + break; + + case LOAD_DLL_DEBUG_EVENT: + OnXLoadDll(proc, &debEvent); + break; + + case UNLOAD_DLL_DEBUG_EVENT: + OnXUnloadDll(proc, &debEvent); + break; + + case OUTPUT_DEBUG_STRING_EVENT: + OnXDebugString(proc, &debEvent); + break; + + case RIP_EVENT: + OnXRip(proc, &debEvent); + break; + } + + bpCritSec.Leave(); + +skip: + // Resume executing the thread that reported the debugging event. + // + ContinueDebugEvent(debEvent.dwProcessId, debEvent.dwThreadId, + dwContinueStatus); + goto again; } /* *---------------------------------------------------------------------- * @@ -512,93 +493,47 @@ * None * *---------------------------------------------------------------------- */ -static CONTEXT FirstContext; -static UCHAR FirstPage[PAGESIZE]; -static HANDLE FirstThread; -#include -typedef struct _InjectCode { - UCHAR instPush1; - DWORD argMemProtect; - UCHAR instPush2; - DWORD argMemType; - UCHAR instPush3; - DWORD argMemSize; - UCHAR instPush4; - DWORD argMemAddr; - UCHAR instCall; - DWORD argCallAddr; - DWORD instIntr; -} InjectCode; -#include void ConsoleDebugger::OnXFirstBreakpoint(Process *proc, LPDEBUG_EVENT pDebEvent) { - DWORD base; ThreadInfo *tinfo; for (tinfo = proc->threadList; tinfo != 0L; tinfo = tinfo->nextPtr) { if (pDebEvent->dwThreadId == tinfo->dwThreadId) { break; } } - // Set up the memory that will serve as the place for our - // intercepted function return points. - - { - InjectCode code; - DWORD addr; - - FirstThread = tinfo->hThread; - FirstContext.ContextFlags = CONTEXT_FULL; - GetThreadContext(FirstThread, &FirstContext); - - if (proc->funcTable.Find("VirtualAlloc", - reinterpret_cast(&addr)) != TCL_OK) - { - proc->nBreakCount++; // Don't stop at second breakpoint - EXP_LOG0(MSG_DT_NOVIRT); - return; - } - - code.instPush1 = 0x68; - code.argMemProtect = PAGE_EXECUTE_READWRITE; - code.instPush2 = 0x68; - code.argMemType = MEM_COMMIT; - code.instPush3 = 0x68; - code.argMemSize = 2048; - code.instPush4 = 0x68; - code.argMemAddr = 0; - code.instCall = 0xe8; - code.argCallAddr = addr - FirstContext.Eip - offsetof(InjectCode, instCall) - 5; - code.instIntr = 0xCC; - - base = FirstContext.Eip; - if (!ReadSubprocessMemory(proc, (PVOID) base, FirstPage, sizeof(InjectCode))) { - EXP_LOG0(MSG_DT_CANTREADSPMEM); - } - if (!WriteSubprocessMemory(proc, (PVOID) base, &code, sizeof(InjectCode))) { - EXP_LOG0(MSG_DT_CANTWRITESPMEM); - } - } + // Install our entry breakpoint. We can't run the injector Stub now + // as the process heap hasn't been created. (it was some memory related + // error and I don't know exactly why, but moving the stub run later + // solved it). It seems that the first breakpoint naturally fired is + // much too early in the creation of the initial process for much of + // anything to be ready. + // + ReadSubprocessMemory(proc, pStartAddress, + &originalExeEntryPointOpcode, sizeof(BYTE)); + + BYTE bpOpcode = BRK_OPCODE; + WriteSubprocessMemory(proc, pStartAddress, &bpOpcode, sizeof(BYTE)); + return; } /* *---------------------------------------------------------------------- * * ConsoleDebugger::OnXSecondBreakpoint -- * * This routine is called when the second breakpoint is hit. - * The second breakpoint is at the end of our call to GlobalAlloc(). - * Save the returned pointer from GlobalAlloc, then restore the - * first page of memory and put everything back the way it was. - * Finally, we can start. + * The processes' entry-point is getting called. We intercept this + * and make our injector.dll load first before the entry-point is + * called. * * Results: * None * *---------------------------------------------------------------------- @@ -605,40 +540,218 @@ */ void ConsoleDebugger::OnXSecondBreakpoint(Process *proc, LPDEBUG_EVENT pDebEvent) { - CONTEXT context; - BYTE retbuf[2048]; - DWORD base; - LPEXCEPTION_DEBUG_INFO exceptInfo; - BreakInfo *info; + ThreadInfo *tinfo; + + for (tinfo = proc->threadList; tinfo != 0L; tinfo = tinfo->nextPtr) { + if (pDebEvent->dwThreadId == tinfo->dwThreadId) { + break; + } + } + + // Put the first opcode at the entry point back in place. + WriteSubprocessMemory(proc, pStartAddress, + &originalExeEntryPointOpcode, sizeof(BYTE)); + + // Make some memory for our stub that we place into the processes' address + // space. This stub (or set of opcodes) calls LoadLibrary() to bring in our + // injector dll that acts as the receiver for "injecting" console events. + // + MakeSubprocessMemory(proc, sizeof(LOADLIBRARY_STUB), &pInjectorStub, + PAGE_EXECUTE_READWRITE); + injectorStub.operand_PUSH_value = (DWORD) pInjectorStub + + offsetof(LOADLIBRARY_STUB, data_DllName); + injectorStub.operand_MOV_EAX = (DWORD) GetProcAddress(GetModuleHandle( + "KERNEL32.DLL"), "LoadLibraryA"); + WriteSubprocessMemory(proc, pInjectorStub, &injectorStub, + sizeof(LOADLIBRARY_STUB)); + FlushInstructionCache(proc->hProcess, pInjectorStub, sizeof(LOADLIBRARY_STUB)); + + + // Save the instruction pointer so we can restore it later. + // + preStubContext.ContextFlags = CONTEXT_FULL; + GetThreadContext(tinfo->hThread, &preStubContext); + + // Set instruction pointer to run the Stub instead of continuing + // from where we are (which is the app's entry point). + // + CONTEXT stubContext = preStubContext; + stubContext.Eip = (DWORD) pInjectorStub; + SetThreadContext(tinfo->hThread, &stubContext); +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::OnXThirdBreakpoint -- + * + * This routine is called when the third breakpoint is hit and + * our stub has run and our injector is loaded. + * + * Results: + * None + * + *---------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnXThirdBreakpoint(Process *proc, LPDEBUG_EVENT pDebEvent) +{ + ThreadInfo *tinfo; + CHAR boxName[50]; + DWORD err; +# define RETBUF_SIZE 2048 + BYTE retbuf[RETBUF_SIZE]; + BreakInfo *binfo; int i; - exceptInfo = &pDebEvent->u.Exception; - - context.ContextFlags = CONTEXT_FULL; - GetThreadContext(FirstThread, &context); - proc->pSubprocessMemory = context.Eax; - - memset(retbuf, 0xcc, sizeof(retbuf)); // All breakpoints - WriteSubprocessMemory(proc, (PVOID) proc->pSubprocessMemory, - retbuf, sizeof(retbuf)); - - base = FirstContext.Eip; - if (!WriteSubprocessMemory(proc, (PVOID) base, FirstPage, sizeof(InjectCode))) { - EXP_LOG0(MSG_DT_CANTWRITESPMEM); - } - SetThreadContext(FirstThread, &FirstContext); - - // Set all breakpoints + for (tinfo = proc->threadList; tinfo != 0L; tinfo = tinfo->nextPtr) { + if (pDebEvent->dwThreadId == tinfo->dwThreadId) { + break; + } + } + + // Create the IPC connection to our loaded injector.dll + // + wsprintf(boxName, "ExpectInjector_pid%d", proc->pid); + injectorIPC = new CMclMailbox(IPC_NUMSLOTS, IPC_SLOTSIZE, boxName); + + // Check status. + err = injectorIPC->Status(); + if (err != NO_ERROR && err != ERROR_ALREADY_EXISTS) { + char *error = new char [512]; + strcpy(error, "IPC connection to injector.dll could not be made: "); + strcat(error, GetSysMsg(err)); + strcat(error, "\n"); + WriteMasterError(error, strlen(error)); + delete injectorIPC; + injectorIPC = 0L; + } + + // Set our thread to run the entry point, now, starting the + // application once we return from this breakpoint. + preStubContext.Eip -= sizeof(BYTE); + SetThreadContext(tinfo->hThread, &preStubContext); + + + // We should now remove the memory allocated in the sub process for + // our injector stub. The dll is already loaded and there's no sense + // hogging a virtual memory page. + // + RemoveSubprocessMemory(proc, pInjectorStub); + + + ///////////////////////////////////////////////////////////////////// + // Now create our breakpoints on all calls to the OS console API. + ///////////////////////////////////////////////////////////////////// + + + // Set up the memory that will serve as the place for our + // intercepted function return points. + // + MakeSubprocessMemory(proc, RETBUF_SIZE, &(proc->pSubprocessMemory)); + + // Fill the buffer with all breakpoint opcodes. + // + memset(retbuf, BRK_OPCODE, RETBUF_SIZE); + + // Write it out to our buffer space in the other process. + // + WriteSubprocessMemory(proc, proc->pSubprocessMemory, retbuf, RETBUF_SIZE); + + // Set all Console API breakpoints. // for (i = 0; BreakPoints[i].dllName; i++) { - for (info = BreakPoints[i].breakInfo; info->funcName; info++) { - SetBreakpoint(proc, info); + for (binfo = BreakPoints[i].breakInfo; binfo->funcName; binfo++) { + SetBreakpoint(proc, binfo); } } + +# undef RETBUF_SIZE + return; +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::SetBreakpoint -- + * + * Inserts a single breakpoint + * + * Results: + * TRUE if successful, FALSE if unsuccessful. + * + *---------------------------------------------------------------------- + */ + +BOOL +ConsoleDebugger::SetBreakpoint(Process *process, BreakInfo *info) +{ + PVOID funcPtr; + + if (process->funcTable.Find(info->funcName, &funcPtr) == TCL_ERROR) + { +// PCHAR buffer; +// DWORD len; +// +// buffer = new CHAR [128]; +// len = wsprintf(buffer, "Unable to set breakpoint at %s", info->funcName); +// WriteMasterError(buffer, len); + return FALSE; + } + + // Set a breakpoint at the function start in the subprocess and + // save the original code at the function start. + // + return SetBreakpointAtAddr(process, info, funcPtr); +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::SetBreakpointAtAddr -- + * + * Inserts a single breakpoint at the given address + * + * Results: + * The new BreakPoint instance. + * + *---------------------------------------------------------------------- + */ + +BOOL +ConsoleDebugger::SetBreakpointAtAddr(Process *proc, BreakInfo *info, PVOID funcPtr) +{ + Breakpoint *bpt, *lastBpt; + BYTE code; + BOOL ok; + + bpt = new Breakpoint; + bpt->codePtr = funcPtr; + bpt->codeReturnPtr = (PVOID) (proc->offset + (DWORD) proc->pSubprocessMemory); + bpt->breakInfo = info; + proc->offset += 2; + bpt->nextPtr = lastBpt = proc->brkptList; + proc->brkptList = bpt; + + if ((ok = ReadSubprocessMemory(proc, funcPtr, &bpt->code, sizeof(BYTE))) + == TRUE) { + code = BRK_OPCODE; + ok = WriteSubprocessMemory(proc, funcPtr, &code, sizeof(BYTE)); + } + + if (!ok) { + // unsplice it. + proc->brkptList = lastBpt; + delete bpt; + bpt = 0L; + } + + return ok; } /* *---------------------------------------------------------------------- * @@ -658,11 +771,11 @@ { BYTE code; // Now, we need to restore the breakpoint that we had removed. // - code = 0xcc; + code = BRK_OPCODE; WriteSubprocessMemory(proc, proc->lastBrkpt->codePtr, &code, sizeof(BYTE)); } /* *---------------------------------------------------------------------- @@ -685,60 +798,63 @@ Module *modPtr; DWORD displacement; BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL) + 512]; PIMAGEHLP_SYMBOL pSymbol = (PIMAGEHLP_SYMBOL)symbolBuffer; char *s; + int result; + unsigned int level = 0; - if (!ShowExceptionBacktraces) { - return; - } - - for (tinfo = proc->threadList; tinfo != 0L; tinfo = tinfo->nextPtr) { + for (tinfo = proc->threadList; tinfo != NULL; tinfo = tinfo->nextPtr) { if (pDebEvent->dwThreadId == tinfo->dwThreadId) { break; } } - assert(tinfo != 0L); context.ContextFlags = CONTEXT_FULL; GetThreadContext(tinfo->hThread, &context); - // XXX: From what I can tell, SymInitialize is broken on Windows NT 4.0 - // if you try to have it iterate the modules in a process. It always - // returns an object mismatch error. Instead, initialize without iterating - // the modules. Contrary to what MSDN documentation says, - // Microsoft debuggers do not exclusively use the imagehlp API. In - // fact, the only thing VC 5.0 uses is the StackWalk function. - // Windbg uses a few more functions, but it doesn't use SymInitialize. - // We will then do the hard work of finding all the - // modules and doing the right thing. - // - if (! SymInitialize(proc->hProcess, SymbolPath, FALSE)){ - fprintf(stderr, "Unable to get backtrace (Debug 1): 0x%08x\n", - GetLastError()); + /* + * XXX: From what I can tell, SymInitialize is broken on Windows NT 4.0 + * if you try to have it iterate the modules in a process. It always + * returns an object mismatch error. Instead, initialize without iterating + * the modules. Contrary to what MSDN documentation says, + * Microsoft debuggers do not exclusively use the imagehlp API. In + * fact, the only thing VC 5.0 uses is the StackWalk function. + * Windbg uses a few more functions, but it doesn't use SymInitialize. + * We will then do the hard work of finding all the + * modules and doing the right thing. + */ + + if (!SymInitialize(proc->hProcess, SymbolPath, FALSE)) + { + CHAR *buffer = new CHAR [512]; + DWORD len; + len = wsprintf(buffer, "Unable to get backtrace: %s\n", + GetSysMsg(GetLastError())); + WriteMasterError(buffer, len); return; } -#ifdef _M_IX86 +#ifdef _X86_ memset(&frame, 0, sizeof(frame)); frame.AddrPC.Mode = AddrModeFlat; frame.AddrPC.Segment = 0; frame.AddrPC.Offset = context.Eip; frame.AddrReturn.Mode = AddrModeFlat; frame.AddrReturn.Segment = 0; - frame.AddrReturn.Offset = context.Ebp; // I think this is correct + frame.AddrReturn.Offset = context.Ebp; /* I think this is correct */ frame.AddrFrame.Mode = AddrModeFlat; frame.AddrFrame.Segment = 0; frame.AddrFrame.Offset = context.Ebp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrStack.Segment = 0; frame.AddrStack.Offset = context.Esp; - frame.FuncTableEntry = 0L; + frame.FuncTableEntry = NULL; frame.Params[0] = context.Eax; frame.Params[1] = context.Ecx; frame.Params[2] = context.Edx; frame.Params[3] = context.Ebx; frame.Far = FALSE; @@ -746,74 +862,135 @@ frame.Reserved[0] = 0; frame.Reserved[1] = 0; frame.Reserved[2] = 0; /* frame.KdHelp.* is not set */ - // Iterate through the loaded modules and load symbols for each one. - // - proc->moduleTable.Top(&modPtr); - do { - if (! modPtr->loaded) { + /* + * Iterate through the loaded modules and load symbols for each one. + */ + for ( + result = proc->moduleTable.Top(&modPtr); + result == TCL_OK; + result = proc->moduleTable.Next(&modPtr) + ) { + if (!modPtr->loaded) { modPtr->dbgInfo = MapDebugInformation(modPtr->hFile, 0L, SymbolPath, (DWORD)modPtr->baseAddr); SymLoadModule(proc->hProcess, modPtr->hFile, 0L, 0L, (DWORD) modPtr->baseAddr, 0); modPtr->loaded = TRUE; } - } while (proc->moduleTable.Next(&modPtr) != TCL_ERROR); + } if (proc->exeModule && proc->exeModule->dbgInfo && proc->exeModule->dbgInfo->ImageFileName) { s = proc->exeModule->dbgInfo->ImageFileName; } else { s = ""; } -// fprintf(stderr, "Backtrace for %s\n", s); -// fprintf(stderr, "-------------------------------------\n"); -// EXP_LOG("Backtrace for %s", s); + + { + DWORD len; + CHAR *buffer = new CHAR [MAX_PATH+600]; + DWORD exCode = pDebEvent->u.Exception.ExceptionRecord.ExceptionCode; + len = wsprintf(buffer, + "\nA fatal, second-chance exception has occured in \"%s\".\n" + "(0x%X) -- %s\n" + "This is the backtrace:\n" + "-------------------------------------\n", s, exCode, + GetExceptionCodeString(exCode)); + WriteMasterError(buffer, len); + } + while (1) { pSymbol->SizeOfStruct = sizeof(symbolBuffer); pSymbol->MaxNameLength = 512; - b = StackWalk(IMAGE_FILE_MACHINE_I386, proc->hProcess, + b = StackWalk( +#ifdef _WIN64 + IMAGE_FILE_MACHINE_IA64, +#else + IMAGE_FILE_MACHINE_I386, +#endif + proc->hProcess, tinfo->hThread, &frame, &context, 0L, SymFunctionTableAccess, SymGetModuleBase, 0L); if (b == FALSE || frame.AddrPC.Offset == 0) { break; } + + level++; if (SymGetSymFromAddr(proc->hProcess, frame.AddrPC.Offset, &displacement, pSymbol) ) { - DWORD base; - char buf[1024]; + DWORD base, len; + CHAR *buffer = new CHAR [128]; base = SymGetModuleBase(proc->hProcess, frame.AddrPC.Offset); - proc->moduleTable.Find(reinterpret_cast(base), &modPtr); - if (modPtr->dbgInfo && modPtr->dbgInfo->ImageFileName) { - s = modPtr->dbgInfo->ImageFileName; + if (proc->moduleTable.Find((void *)base, &modPtr) != TCL_ERROR) { + if (modPtr->dbgInfo && modPtr->dbgInfo->ImageFileName) { + s = modPtr->dbgInfo->ImageFileName; + } else { + s = ""; + } } else { s = ""; } -// fprintf(stderr, "%.20s %08x\t%s+%X\n", s, frame.AddrPC.Offset, -// pSymbol->Name, displacement); - sprintf(buf, "%.20s %08x\t%s+%X", s, frame.AddrPC.Offset, - pSymbol->Name, displacement); -// EXP_LOG("%s", buf); + len = wsprintf(buffer, "%u) %.20s 0x%08.8x\t%s+%X\n", level, s, frame.AddrPC.Offset, + pSymbol->Name, displacement); + WriteMasterError(buffer, len); } else { -// fprintf(stderr, "%08x\n", frame.AddrPC.Offset); -// EXP_LOG("%08x\t", frame.AddrPC.Offset); + DWORD len; + CHAR *buffer = new CHAR [33]; + len = wsprintf(buffer, "%08.8x\n", frame.AddrPC.Offset); + WriteMasterError(buffer, len); } } + + SymCleanup(proc->hProcess); #else -# error "Unsupported architecture" +# error Unsupported architecture #endif } + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::GetExceptionCodeString -- + * + * Returns a string about the exception code. Much more can + * be added. + * + *---------------------------------------------------------------------- + */ + +PCSTR +ConsoleDebugger::GetExceptionCodeString (DWORD exCode) +{ + switch (exCode) + { + case EXCEPTION_ACCESS_VIOLATION: + return "Access Violation."; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "Array access was out-of-bounds."; + case EXCEPTION_INT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + return "Divide by zero."; + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_PRIV_INSTRUCTION: + return "Illegal opcode."; + case EXCEPTION_STACK_OVERFLOW: + return "Stack overflow."; + default: + return "exception unknown."; + } +} /* *---------------------------------------------------------------------- * * ConsoleDebugger::OnXCreateThread -- @@ -828,15 +1005,10 @@ */ void ConsoleDebugger::OnXCreateThread(Process *proc, LPDEBUG_EVENT pDebEvent) { - // As needed, examine or change the thread's registers - // with the GetThreadContext and SetThreadContext functions; - // and suspend and resume thread execution with the - // SuspendThread and ResumeThread functions. - // ThreadInfo *threadInfo; threadInfo = new ThreadInfo; threadInfo->dwThreadId = pDebEvent->dwThreadId; threadInfo->hThread = pDebEvent->u.CreateThread.hThread; @@ -860,15 +1032,10 @@ */ void ConsoleDebugger::OnXDeleteThread(Process *proc, LPDEBUG_EVENT pDebEvent) { - // As needed, examine or change the thread's registers - // with the GetThreadContext and SetThreadContext functions; - // and suspend and resume thread execution with the - // SuspendThread and ResumeThread functions. - // ThreadInfo *threadInfo; ThreadInfo *prev; prev = 0L; for (threadInfo = proc->threadList; threadInfo; @@ -907,38 +1074,23 @@ { ThreadInfo *threadInfo; CREATE_PROCESS_DEBUG_INFO *info = &pDebEvent->u.CreateProcessInfo; int known; + // Save the first processes' start address. + if (!pStartAddress) + pStartAddress = info->lpStartAddress; + if (proc == 0L) { proc = ProcessNew(); -// proc->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - if (!DuplicateHandle(GetCurrentProcess(), - info->hProcess, - GetCurrentProcess(), - &proc->hProcess, PROCESS_ALL_ACCESS, - FALSE, 0)) { - fprintf(stderr, "Unable to duplicate handle\n"); - } + proc->hProcess = info->hProcess; proc->pid = pDebEvent->dwProcessId; - -// ExpAddToWaitQueue(proc->hProcess); - } - - known = LoadedModule(proc, info->hFile, info->lpImageName, - info->fUnicode, info->lpBaseOfImage, - info->dwDebugInfoFileOffset); - - // As needed, examine or change the registers of the - // process's initial thread with the GetThreadContext and - // SetThreadContext functions; read from and write to the - // process's virtual memory with the ReadProcessMemory and - // WriteProcessMemory functions; and suspend and resume - // thread execution with the SuspendThread and ResumeThread - // functions. - // + } + + known = LoadedModule(proc, info->hFile, info->lpImageName, info->fUnicode, + info->lpBaseOfImage, info->dwDebugInfoFileOffset); + threadInfo = new ThreadInfo; threadInfo->dwThreadId = pDebEvent->dwThreadId; threadInfo->hThread = info->hThread; threadInfo->nextPtr = proc->threadList; proc->threadCount++; @@ -946,11 +1098,11 @@ } /* *---------------------------------------------------------------------- * - * OnXLoadDll -- + * ConsoleDebugger::OnXLoadDll -- * * This routine is called when a LOAD_DLL_DEBUG_EVENT is seen * * Results: * None @@ -1041,10 +1193,26 @@ // ptr = &ped->Name; ReadSubprocessMemory(proc, ptr, &dw, sizeof(DWORD)); ptr = (PVOID) (base + dw); ReadSubprocessStringA(proc, ptr, dllname, sizeof(dllname)); + + { + int len; + CHAR msg[256]; + + if (dllname[0] == '\0') { + // image has no export section, so get the name another way. + // TODO: How?? + + } else { + strcpy(msg, dllname); + strcat(msg, " has loaded.\n"); + len = strlen(msg); + } + WriteMasterWarning(strdup(msg), len); + } bFound = FALSE; for (n = 0; BreakPoints[n].dllName; n++) { if (stricmp(dllname, BreakPoints[n].dllName) == 0) { bFound = TRUE; @@ -1086,11 +1254,11 @@ } /* *---------------------------------------------------------------------- * - * OnXUnloadDll -- + * ConsoleDebugger::OnXUnloadDll -- * * This routine is called when a UNLOAD_DLL_DEBUG_EVENT is seen * * Results: * None @@ -1104,274 +1272,258 @@ void ConsoleDebugger::OnXUnloadDll(Process *proc, LPDEBUG_EVENT pDebEvent) { Module *modPtr; - if (proc->moduleTable.Find(pDebEvent->u.UnloadDll.lpBaseOfDll, &modPtr) + if (proc->moduleTable.Extract(pDebEvent->u.UnloadDll.lpBaseOfDll, &modPtr) != TCL_ERROR) { if (modPtr->hFile) { CloseHandle(modPtr->hFile); } if (modPtr->modName) { - free(modPtr->modName); + delete [] modPtr->modName; } if (modPtr->dbgInfo) { UnmapDebugInformation(modPtr->dbgInfo); } delete modPtr; - proc->moduleTable.Delete(pDebEvent->u.UnloadDll.lpBaseOfDll); - } -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleDebugger::SetBreakpoint -- - * - * Inserts a single breakpoint - * - * Results: - * TRUE if successful, FALSE if unsuccessful. - * - *---------------------------------------------------------------------- - */ - -BOOL -ConsoleDebugger::SetBreakpoint(Process *proc, BreakInfo *info) -{ - PVOID funcPtr; - - if (proc->funcTable.Find((void *)info->funcName, &funcPtr) == TCL_ERROR) - { -// EXP_LOG("Unable to set breakpoint at %s", info->funcName); - return FALSE; - } - - // Set a breakpoint at the function start in the subprocess and - // save the original code at the function start. - // - SetBreakpointAtAddr(proc, info, funcPtr); - return TRUE; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleDebugger::SetBreakpointAtAddr -- - * - * Inserts a single breakpoint at the given address - * - * Results: - * TRUE if successful, FALSE if unsuccessful. - * - *---------------------------------------------------------------------- - */ - -ConsoleDebugger::Breakpoint * -ConsoleDebugger::SetBreakpointAtAddr(Process *proc, BreakInfo *info, PVOID funcPtr) -{ - Breakpoint *bpt; - BYTE code; - - bpt = new Breakpoint; - bpt->returning = FALSE; - bpt->codePtr = funcPtr; - bpt->codeReturnPtr = (PVOID) (proc->offset + (DWORD) proc->pSubprocessMemory); - bpt->origRetAddr = 0; - bpt->breakInfo = info; - bpt->threadInfo = 0L; - proc->offset += 2; - bpt->nextPtr = proc->brkptList; - proc->brkptList = bpt; - - ReadSubprocessMemory(proc, funcPtr, &bpt->code, sizeof(BYTE)); -#ifdef _M_IX86 - // Breakpoint opcode on i386 - code = 0xcc; -#else -# error "need breakpoint opcode for this hardware" -#endif - WriteSubprocessMemory(proc, funcPtr, &code, sizeof(BYTE)); - return bpt; -} - -/* - *---------------------------------------------------------------------- - * - * ConsoleDebugger::ReadSubprocessMemory -- - * - * Reads memory from the subprocess. Takes care of all the - * issues with page protection. - * - * Results: - * FALSE if unsuccessful, TRUE if successful. - * - * Notes: - * The efficient memory reading routine is disabled here - * because it doesn't quite work right. I don't see the - * problem in the code, but there must be something there - * since the test suite fails when run with this code - * enabled. When it works, it should be much faster than - * the current safe but slow implementation. - * - *---------------------------------------------------------------------- - */ - -#if 0 -BOOL -ConsoleDebugger::ReadSubprocessMemory(ExpProcess *proc, LPVOID addr, LPVOID buf, DWORD len) -{ - DWORD oldProtection = 0; - MEMORY_BASIC_INFORMATION mbi; - BOOL ret = TRUE; - DWORD offset; - DWORD base, curr, end, n; - HANDLE hProcess; - PBYTE bufpos = buf; - - hProcess = proc->hProcess; - - end = len + (DWORD) addr; - for (curr = (DWORD) addr; curr < end; ) { - base = curr & (~PAGEMASK); - offset = curr & PAGEMASK; - if (offset + len > PAGESIZE) { - n = PAGESIZE - offset; - } else { - n = len; - } - if (proc->pMemoryCacheBase != (curr & PAGEMASK)) { - /* if not committed memory abort */ - if (!VirtualQueryEx(hProcess, (LPVOID) base, &mbi, sizeof(mbi)) || - (mbi.State != MEM_COMMIT)) - { - return FALSE; - } - - /* if guarded memory, change protection temporarily */ - if (!(mbi.Protect & PAGE_READONLY) && - !(mbi.Protect & PAGE_READWRITE)) - { - VirtualProtectEx(hProcess, (LPVOID) base, PAGESIZE, - PAGE_READONLY, &oldProtection); - } - - if (!ReadProcessMemory(hProcess, (LPVOID) base, proc->pMemoryCache, - PAGESIZE, 0L)) { - ret = FALSE; - } - - /* reset protection if changed */ - if (oldProtection) { - VirtualProtectEx(hProcess, (LPVOID) base, PAGESIZE, - oldProtection, &oldProtection); - } - if (ret == FALSE) { - return FALSE; - } - proc->pMemoryCacheBase = base; - } - - memcpy(bufpos, &proc->pMemoryCache[offset], n); - bufpos += n; - curr += n; - } - - return ret; -} - -#else -BOOL -ConsoleDebugger::ReadSubprocessMemory(Process *proc, LPVOID addr, LPVOID buf, DWORD len) -{ - DWORD oldProtection = 0; - MEMORY_BASIC_INFORMATION mbi; - BOOL ret; - LONG error; - - // if not committed memory abort - if (!VirtualQueryEx(proc->hProcess, addr, &mbi, sizeof(mbi)) || - mbi.State != MEM_COMMIT) - { - return FALSE; - } - - // if guarded memory, change protection temporarily - if (!(mbi.Protect & PAGE_READONLY) && !(mbi.Protect & PAGE_READWRITE)) { - VirtualProtectEx(proc->hProcess, addr, len, PAGE_READONLY, &oldProtection); - } - - ret = ReadProcessMemory(proc->hProcess, addr, buf, len, 0L); - if (ret == FALSE) { - error = GetLastError(); - } - - // reset protection if changed - if (oldProtection) { - VirtualProtectEx(proc->hProcess, addr, len, oldProtection, &oldProtection); - SetLastError(error); - } - return ret; -} -#endif /* XXX */ - -/* - *---------------------------------------------------------------------- - * - * ConsoleDebugger::WriteSubprocessMemory -- - * - * Writes memory from the subprocess. Takes care of all the - * issues with page protection. - * - * Results: - * 0 if unsuccessful, 1 if successful. - * - *---------------------------------------------------------------------- - */ - -BOOL -ConsoleDebugger::WriteSubprocessMemory(Process *proc, LPVOID addr, LPVOID buf, DWORD len) -{ - DWORD oldProtection = 0; - MEMORY_BASIC_INFORMATION mbi; - BOOL ret = TRUE; - DWORD err; - HANDLE hProcess; - - hProcess = proc->hProcess; - - // Flush the read cache. - proc->pMemoryCacheBase = 0; - - // if not committed memory abort - if (!VirtualQueryEx(hProcess, addr, &mbi, sizeof(mbi)) || - mbi.State != MEM_COMMIT) - { - ret = FALSE; - // assert(ret != FALSE); - return ret; - } - - // if guarded memory, change protection temporarily. - if (!(mbi.Protect & PAGE_READWRITE)) { - if (!VirtualProtectEx(hProcess, addr, len, PAGE_READWRITE, - &oldProtection)) { - err = GetLastError(); - } - } - - if (!WriteProcessMemory(hProcess, addr, buf, len, 0L)) { - ret = FALSE; - err = GetLastError(); - } - - // reset protection if changed - if (oldProtection) { - VirtualProtectEx(hProcess, addr, len, oldProtection, &oldProtection); - } - return ret; + } +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::OnXDebugString -- + * + * This routine is called when a OUTPUT_DEBUG_STRING_EVENT + * happens. + * + * Results: + * None + * + * Side Effects: + * Allocates a buffer for the string that is not cleared *here*. + * + *---------------------------------------------------------------------- + */ +void +ConsoleDebugger::OnXDebugString(Process *proc, LPDEBUG_EVENT pDebEvent) +{ + CHAR *buffer; + DWORD len; + + if (pDebEvent->u.DebugString.fUnicode) { + int wlen = pDebEvent->u.DebugString.nDebugStringLength; + WCHAR *wbuffer = new WCHAR [wlen]; + ReadSubprocessStringW(proc, + pDebEvent->u.DebugString.lpDebugStringData, + wbuffer, wlen); + len = WideCharToMultiByte(CP_ACP, 0, wbuffer, wlen, 0L, 0, 0L, 0L); + buffer = new CHAR [len+1]; + WideCharToMultiByte(CP_ACP, 0, wbuffer, wlen, buffer, len, 0L, 0L); + } else { + len = pDebEvent->u.DebugString.nDebugStringLength; + buffer = new CHAR [len+1]; + ReadSubprocessStringA(proc, + pDebEvent->u.DebugString.lpDebugStringData, + buffer, len); + } + +// buffer[len] = '\0'; // Oops, Win9x forgets this. + WriteMasterWarning(buffer, len-1); +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::OnXVDMException -- + * + * Exceptions raised by the NTVDM (Virtual Dos Machine). We only + * get here when a DOS or Win16 (not likely for us, though) + * application is the slave or a child of the slave. + * + * Results: + * None + * + * Side Effects: + * . + * + *---------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnXVDMException(Process *proc, LPDEBUG_EVENT pDebEvent) +{ + EXCEPTION_RECORD &exrec = pDebEvent->u.Exception.ExceptionRecord; + USHORT exCode = W1(exrec); + VDMProcessException(pDebEvent); + + switch (exCode) { + case DBG_SEGLOAD: + __asm nop; + break; + + case DBG_SEGMOVE: + __asm nop; + break; + + case DBG_SEGFREE: + __asm nop; + break; + + case DBG_MODFREE: + case DBG_MODLOAD: + { + SEGMENT_NOTE segNote; + char *buffer; + DWORD len; + const char *verb; + + switch (exCode) + { + case DBG_MODLOAD: + verb = "loaded into"; break; + case DBG_MODFREE: + verb = "unloaded from"; break; + } + + + ReadSubprocessMemory(proc, (PVOID)DW3(exrec), &segNote, sizeof(segNote)); + len = strlen(segNote.FileName) + 25; + buffer = new char [len]; + len = wsprintf(buffer, "%s %s the VDM.\n", segNote.FileName, verb); + WriteMasterWarning(buffer, len); + } + break; + + case DBG_SINGLESTEP: + __asm nop; + break; + + case DBG_BREAK: + __asm nop; + break; + + case DBG_GPFAULT: + __asm nop; + break; + + case DBG_DIVOVERFLOW: + __asm nop; + break; + + case DBG_INSTRFAULT: + __asm nop; + break; + + case DBG_TASKSTART: + case DBG_TASKSTOP: + case DBG_DLLSTART: + case DBG_DLLSTOP: + { + IMAGE_NOTE imgNote; + char *buffer; + DWORD len; + const char *verb; + + switch (exCode) + { + case DBG_TASKSTART: + verb = "started in"; break; + case DBG_DLLSTART: + verb = "started in"; break; + case DBG_DLLSTOP: + verb = "stopped in"; break; + case DBG_TASKSTOP: + verb = "stopped in"; break; + } + + ReadSubprocessMemory(proc, (PVOID)DW3(exrec), &imgNote, sizeof(IMAGE_NOTE)); + len = strlen(imgNote.FileName) + 25; + buffer = new char [len]; + len = wsprintf(buffer, "%s %s the VDM.\n", imgNote.FileName, verb); + WriteMasterWarning(buffer, len); + } + break; + + case DBG_ATTACH: + __asm nop; + break; + + case DBG_TOOLHELP: + __asm nop; + break; + + case DBG_STACKFAULT: + __asm nop; + break; + + case DBG_WOWINIT: + __asm nop; + break; + + case DBG_TEMPBP: + __asm nop; + break; + + case DBG_MODMOVE: + __asm nop; + break; + + case DBG_INIT: + VDMSetDbgFlags(proc->hProcess, +// VDMDBG_BREAK_DOSTASK | // <- seems to cause a non-continueable exception on it's own. +// VDMDBG_BREAK_WOWTASK | + VDMDBG_BREAK_LOADDLL | + VDMDBG_BREAK_EXCEPTIONS | + VDMDBG_BREAK_DEBUGGER | +// VDMDBG_TRACE_HISTORY | + 0); + break; + + case DBG_GPFAULT2: + __asm nop; + break; + + default: + __asm nop; + break; + } +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::OnXRip -- + * + * Catches and reports RIP events (system error messages). + * Is RIP short for Rest-In-Peace?? + * + * Results: + * None + * + * Side Effects: + * allocates memory that is freed by the Message destructor. + * + *---------------------------------------------------------------------- + */ +void +ConsoleDebugger::OnXRip(Process *proc, LPDEBUG_EVENT pDebEvent) +{ + char *errorMsg = new CHAR [512]; + DWORD len; + + if (pDebEvent->u.RipInfo.dwType == SLE_ERROR) { + len = wsprintf(errorMsg, "A fatal RIP error was caught: %s", + GetSysMsg(pDebEvent->u.RipInfo.dwError)); + WriteMasterError(errorMsg, len); + } else { + len = wsprintf(errorMsg, "A non-fatal RIP error was caught: %s", + GetSysMsg(pDebEvent->u.RipInfo.dwError)); + WriteMasterWarning(errorMsg, len); + } } /* *---------------------------------------------------------------------- * @@ -1416,15 +1568,21 @@ if (brkpt->threadInfo == tinfo) { break; } } } + + if (brkpt == 0L) { + // shouldn't happen, but does.. + // ask td32 for a new OS shell in a seperate console and this happens. + return; + } context.ContextFlags = CONTEXT_FULL; GetThreadContext(tinfo->hThread, &context); - if (! brkpt->returning) { + if (!brkpt->returning) { Breakpoint *bpt; // Get the arguments to the function and store them in the thread // specific data structure. for (pdw = tinfo->args, i=0; i < brkpt->breakInfo->nargs; i++, pdw++) { ReadSubprocessMemory(proc, (PVOID) (context.Esp+(4*(i+1))), @@ -1484,11 +1642,133 @@ } /* *---------------------------------------------------------------------- * - * ReadSubprocessStringA -- + * ConsoleDebugger::ReadSubprocessMemory -- + * + * Reads memory from the subprocess. Takes care of all the + * issues with page protection. + * + * Results: + * FALSE if unsuccessful, TRUE if successful. + * + * Notes: + * Currently safe, but slow. + * + *---------------------------------------------------------------------- + */ + +BOOL +ConsoleDebugger::ReadSubprocessMemory(Process *proc, LPVOID addr, LPVOID buf, DWORD len) +{ + DWORD oldProtection = 0; + MEMORY_BASIC_INFORMATION mbi; + BOOL ret = TRUE; + DWORD err = ERROR_SUCCESS; + + // if inaccessible or not committed memory, abort + // + if (!VirtualQueryEx(proc->hProcess, addr, &mbi, + sizeof(MEMORY_BASIC_INFORMATION)) || mbi.State != MEM_COMMIT) + { + return FALSE; + } + + // On Win9x, special ranges can't have their protection changed. + // + if (dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + && addr >= (LPVOID) 0x80000000 && addr <= (LPVOID) 0xBFFFFFFF) { + ret = ReadProcessMemory(proc->hProcess, addr, buf, len, 0L); + } else { + // if guarded memory, change protection temporarily. + // + if (!(mbi.Protect & PAGE_READONLY) && !(mbi.Protect & PAGE_READWRITE)) { + VirtualProtectEx(proc->hProcess, addr, len, PAGE_READONLY, + &oldProtection); + } + + if (!ReadProcessMemory(proc->hProcess, addr, buf, len, 0L)) { + err = GetLastError(); + ret = FALSE; + } + + // reset protection if changed. + // + if (oldProtection) { + VirtualProtectEx(proc->hProcess, addr, len, oldProtection, + &oldProtection); + SetLastError(err); + } + } + return ret; +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::WriteSubprocessMemory -- + * + * Writes memory from the subprocess. Takes care of all the + * issues with page protection. + * + * Results: + * zero if unsuccessful, non-zero if successful. + * + *---------------------------------------------------------------------- + */ + +BOOL +ConsoleDebugger::WriteSubprocessMemory(Process *proc, LPVOID addr, LPVOID buf, DWORD len) +{ + DWORD oldProtection = 0; + MEMORY_BASIC_INFORMATION mbi; + BOOL ret = TRUE; + DWORD err = ERROR_SUCCESS; + + // if inaccessible or not committed memory, abort + if (!VirtualQueryEx(proc->hProcess, addr, &mbi, + sizeof(MEMORY_BASIC_INFORMATION)) || mbi.State != MEM_COMMIT) + { + return FALSE; + } + + // On Win9x, special ranges can't have their protection changed. + // + if (dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + && addr >= (LPVOID) 0x80000000 && addr <= (LPVOID) 0xBFFFFFFF) { + ret = WriteProcessMemory(proc->hProcess, addr, buf, len, 0L); + } else { + // if guarded memory, change protection temporarily. + // + if (!(mbi.Protect & PAGE_READWRITE || mbi.Protect & PAGE_EXECUTE_READWRITE)) { + if (!VirtualProtectEx(proc->hProcess, addr, len, PAGE_READWRITE, + &oldProtection)) { + return FALSE; + } + } + + if (!WriteProcessMemory(proc->hProcess, addr, buf, len, 0L)) { + ret = FALSE; + err = GetLastError(); + } + + // reset protection if changed. + // + if (oldProtection) { + VirtualProtectEx(proc->hProcess, addr, len, oldProtection, + &oldProtection); + SetLastError(err); + } + } + return ret; +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::ReadSubprocessStringA -- * * Read a character string from the subprocess * * Results: * The length of the string @@ -1580,18 +1860,21 @@ // This modname is a pointer to the name of the // DLL in the process space of the subprocess // if (ReadSubprocessMemory(proc, modname, &ptr, sizeof(PVOID)) && ptr) { if (isUnicode) { - WCHAR name[512]; + WCHAR name[MAX_PATH]; + int len; ReadSubprocessStringW(proc, ptr, name, 512); - wcstombs(mbstr, name, sizeof(mbstr)); + len = WideCharToMultiByte(CP_ACP, 0, name, -1, 0L, 0, 0L, 0L); + s = new char [len]; + WideCharToMultiByte(CP_ACP, 0, name, -1, s, len, 0L, 0L); } else { ReadSubprocessStringA(proc, ptr, mbstr, sizeof(mbstr)); + s = new char [strlen(mbstr)]; + strcpy(s, mbstr); } - s = strdup(mbstr); - } else { known = 0; } } @@ -1609,17 +1892,251 @@ return known; } void -ConsoleDebugger::WriteMaster(CHAR *buf, DWORD len) +ConsoleDebugger::MakeSubprocessMemory(Process *proc, SIZE_T amount, + LPVOID *pBuff, DWORD access) +{ + if (dwPlatformId == VER_PLATFORM_WIN32_NT) { + if (!(*pBuff = pfnVirtualAllocEx(proc->hProcess, 0, amount, MEM_COMMIT, + access))) { + EXP_LOG1(MSG_DT_CANTMAKENTSPMEM, GetSysMsg(GetLastError())); + } + } else { + // In Windows 9X, create a small memory mapped file. On this + // platform, memory mapped files are above 2GB, and thus are + // accessible to all processes. + // + HANDLE hFileMapping = CreateFileMapping(INVALID_HANDLE_VALUE, 0, + access | SEC_COMMIT, 0, amount, 0); + + if (!hFileMapping) { + EXP_LOG1(MSG_DT_CANTMAKE95SPMEM, GetSysMsg(GetLastError())); + } + + LPVOID buffer = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, + amount); + + if (!buffer) { + EXP_LOG1(MSG_DT_CANTMAKE95SPMEM, GetSysMsg(GetLastError())); + } + + // Save the association + // + spMemMapping.Add(buffer, hFileMapping); + *pBuff = buffer; + } +} + +BOOL +ConsoleDebugger::RemoveSubprocessMemory(Process *proc, LPVOID buff) +{ + BOOL ret; + + if (dwPlatformId == VER_PLATFORM_WIN32_NT) { + ret = pfnVirtualFreeEx(proc->hProcess, buff, 0, MEM_RELEASE); + } else { + HANDLE hFileMapping; + if (spMemMapping.Extract(buff, &hFileMapping) != TCL_OK) { + SetLastError(ERROR_FILE_NOT_FOUND); + return FALSE; + } + ret = UnmapViewOfFile(buff); + CloseHandle(hFileMapping); + } + return ret; +} + +/* + *---------------------------------------------------------------------- + * + * RefreshScreen -- + * + * Redraw the entire screen + * + * Results: + * None + * + *---------------------------------------------------------------------- + */ +/* +void +ConsoleDebugger::RefreshScreen(void) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + CHAR buf[4096]; + DWORD bufpos = 0; + CHAR_INFO consoleBuf[4096]; + COORD size = {ConsoleSize.X, ConsoleSize.Y}; + COORD begin = {0, 0}; + SMALL_RECT rect = {0, 0, ConsoleSize.X-1, ConsoleSize.Y-1}; + int x, y, prespaces, postspaces, offset; + + // Clear the screen + bufpos += wsprintf(&buf[bufpos], "\033[2J"); + bufpos += wsprintf(&buf[bufpos], "\033[%d;%dH", CursorPosition.Y+1, + CursorPosition.X+1); + CursorKnown = TRUE; + + WriteMasterCopy(buf, bufpos); + bufpos = 0; + +// if (GetConsoleScreenBufferInfo(HConsole, &info) != FALSE) { +// return; +// } + + CursorPosition = info.dwCursorPosition; + +// if (! ReadConsoleOutput(HConsole, consoleBuf, size, begin, &rect)) { +// return; +// } + + offset = 0; + for (y = 0; y < ConsoleSize.Y; y++) { + offset += ConsoleSize.X; + for (x = 0; x < ConsoleSize.X; x++) { + if (consoleBuf[offset+x].Char.AsciiChar != ' ') { + break; + } + } + prespaces = x; + if (prespaces == ConsoleSize.X) { + continue; + } + + for (x = ConsoleSize.X-1; x >= 0; x--) { + if (consoleBuf[offset+x].Char.AsciiChar != ' ') { + break; + } + } + postspaces = x; + bufpos += wsprintf(&buf[bufpos], "\033[%d;%dH", y+1, prespaces+1); + + for (x = prespaces; x < postspaces; x++) { + buf[bufpos++] = consoleBuf[offset+x].Char.AsciiChar; + } + } + + bufpos += wsprintf(&buf[bufpos], "\033[%d;%dH", CursorPosition.Y+1, + CursorPosition.X+1); + CursorKnown = TRUE; + WriteMasterCopy(buf, bufpos); +} +*/ + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::ProcessNew -- + * + * Allocates a new structure for debugging a process and + * initializes it. + * + * Results: + * A new structure + * + * Side Effects: + * Memory is allocated, an event is created. + * + *---------------------------------------------------------------------- + */ + +ConsoleDebugger::Process * +ConsoleDebugger::ProcessNew(void) +{ + Process *proc; + proc = new Process; + proc->nextPtr = ProcessList; + ProcessList = proc; + return proc; +} + +/* + *---------------------------------------------------------------------- + * + * ConsoleDebugger::ProcessFree -- + * + * Frees all allocated memory for a process and closes any + * open handles + * + * Results: + * None + * + *---------------------------------------------------------------------- + */ + +void +ConsoleDebugger::ProcessFree(Process *proc) +{ + ThreadInfo *tcurr, *tnext; + Breakpoint *bcurr, *bnext; + Process *pcurr, *pprev; + + for (tcurr = proc->threadList; tcurr != 0L; tcurr = tnext) { + tnext = tcurr->nextPtr; + proc->threadCount--; + CloseHandle(tcurr->hThread); + delete tcurr; + } + for (bcurr = proc->brkptList; bcurr != 0L; bcurr = bnext) { + bnext = bcurr->nextPtr; + delete bcurr; + } + for (pprev = 0L, pcurr = ProcessList; pcurr != 0L; + pcurr = pcurr->nextPtr) + { + if (pcurr == proc) { + if (pprev == 0L) { + ProcessList = pcurr->nextPtr; + } else { + pprev->nextPtr = pcurr->nextPtr; + } + break; + } + } + CloseHandle(proc->hProcess); + + delete proc; +} + +void +ConsoleDebugger::WriteMasterCopy(CHAR *buf, DWORD len) +{ + Message *msg; + DWORD i; + + msg = new Message; + msg->bytes = new CHAR [len]; + for (i = 0; i < len; i++) + ((PCHAR)msg->bytes)[i] = buf[i]; + msg->length = len; + msg->type = Message::TYPE_NORMAL; + mQ.Put(msg); +} + +/* doesn't copy! */ +void +ConsoleDebugger::WriteMasterWarning(CHAR *buf, DWORD len) +{ + Message *msg; + msg = new Message; + msg->bytes = buf; + msg->length = len; + msg->type = Message::TYPE_WARNING; + mQ.Put(msg); +} + +/* doesn't copy! */ +void +ConsoleDebugger::WriteMasterError(CHAR *buf, DWORD len) { Message *msg; msg = new Message; - msg->bytes = (BYTE *) _strdup(buf); + msg->bytes = buf; msg->length = len; - msg->type = Message::TYPE_NORMAL; + msg->type = Message::TYPE_ERROR; mQ.Put(msg); } void ConsoleDebugger::NotifyDone() @@ -1627,5 +2144,36 @@ Message *msg; msg = new Message; msg->type = Message::TYPE_SLAVEDONE; mQ.Put(msg); } + +void +ConsoleDebugger::WriteRecord (INPUT_RECORD *ir) +{ + if (injectorIPC != 0L) { + injectorIPC->Post(ir); + } +} + +void +ConsoleDebugger::EnterInteract (HANDLE OutConsole) +{ + bpCritSec.Enter(); + + interactingConsole = OutConsole; + + // More stuff to do here... What? + // Copy entire screen contents, how? + // Set interactingConsole to the proper size? + // more ??? help! + + interacting = true; + bpCritSec.Leave(); +} + +void +ConsoleDebugger::ExitInteract () +{ + interactingConsole = 0L; + interacting = false; +} Index: win/expWinConsoleDebugger.hpp ================================================================== --- win/expWinConsoleDebugger.hpp +++ win/expWinConsoleDebugger.hpp @@ -13,90 +13,64 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinConsoleDebugger.hpp,v 1.1.2.16 2002/03/15 07:51:56 davygrvy Exp $ + * RCS: @(#) $Id: expWinConsoleDebugger.hpp,v 1.1.2.30 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef INC_expWinConsoleDebugger_hpp__ #define INC_expWinConsoleDebugger_hpp__ -#include "expWinSlave.hpp" +#include "CMcl.h" +#include "slavedrvmc.h" +#include "expWinUtils.hpp" +#include "expWinMessage.hpp" #include "TclHash.hpp" // for the hash table template. #include - -#ifdef _M_IX86 - // 4096 is for ix86 only -# define PAGESIZE 0x1000 - // This only works on ix86 -# define SINGLE_STEP_BIT 0x100; -#else -# error "need platform page size" -#endif -#define PAGEMASK (PAGESIZE-1) - // This is our debugger. We run it in a thread. // class ConsoleDebugger : public CMclThreadHandler, ArgMaker { public: - ConsoleDebugger(int argc, char * const *argv, CMclQueue &_mQ); + ConsoleDebugger(int _argc, char * const *_argv, CMclQueue &_mQ); ~ConsoleDebugger(); + + void WriteRecord (INPUT_RECORD *ir); + void EnterInteract (HANDLE OutConsole); + void ExitInteract (void); private: virtual unsigned ThreadHandlerProc(void); - // forward reference. - class Process; - class Breakpoint; - - class CreateProcessInfo { - friend class ConsoleDebugger; - TCHAR appName[8192]; - TCHAR cmdLine[8192]; - SECURITY_ATTRIBUTES procAttrs; - SECURITY_ATTRIBUTES threadAttrs; - BOOL bInheritHandles; - DWORD dwCreationFlags; - LPVOID lpEnvironment; - TCHAR currDir[8192]; - STARTUPINFO si; - PROCESS_INFORMATION pi; - PVOID piPtr; // Pointer to PROCESS_INFORMATION in slave. - DWORD flags; - }; - - class CreateProcessThreadArgs { - friend class ConsoleDebugger; - CreateProcessInfo *cp; - Process *proc; - }; - class ThreadInfo { friend class ConsoleDebugger; HANDLE hThread; DWORD dwThreadId; DWORD nargs; DWORD args[16]; // Space for saving 16 args. We need this // space while we are waiting for the return // value for the function. LPCONTEXT context; // Current context. - CreateProcessInfo *createProcess; // Create process pointer. ThreadInfo *nextPtr; // Linked list. }; + + // forward reference. + class Process; + class Breakpoint; class BreakInfo { friend class ConsoleDebugger; const char *funcName; // Name of function to intercept. DWORD nargs; // Number of arguments. @@ -103,11 +77,11 @@ void (ConsoleDebugger::*breakProc)(Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); // Function to call when the breakpoint is hit. # define BREAK_IN 1 // Call handler on the way in. # define BREAK_OUT 2 // Call handler on the way out. - DWORD dwFlags; // Bits for direction to call handler in. + DWORD dwFlags; // Bits for direction to call handler in. }; class DllBreakpoints { friend class ConsoleDebugger; const char *dllName; @@ -114,17 +88,19 @@ BreakInfo *breakInfo; }; class Breakpoint { friend class ConsoleDebugger; + Breakpoint() : returning(FALSE), origRetAddr(0), threadInfo(0L) {} BOOL returning; // Is this a returning breakpoint? BYTE code; // Original code. PVOID codePtr; // Address of original code. PVOID codeReturnPtr; // Address of return breakpoint. DWORD origRetAddr; // Original return address. BreakInfo *breakInfo; // Information about the breakpoint. - ThreadInfo *threadInfo; // If this breakpoint is for a specific thread. + ThreadInfo *threadInfo; // If this breakpoint is for a specific + // thread. Breakpoint *nextPtr; // Linked list. }; class Module { friend class ConsoleDebugger; @@ -133,112 +109,198 @@ LPVOID baseAddr; PCHAR modName; PIMAGE_DEBUG_INFORMATION dbgInfo; }; - typedef Tcl::Hash STRING2PTR; - typedef Tcl::Hash PTR2MODULE; + typedef Tcl::Hash STRING2PTR; + typedef Tcl::Hash PTR2MODULE; - // There is one of these instances for each subprocess that we are + // There is one of these instances for each process that we are // controlling. // class Process { friend class ConsoleDebugger; + Process() : threadList(0L), threadCount(0), brkptList(0L), + lastBrkpt(0L), offset(0), nBreakCount(0), consoleHandlesMax(0), + hProcess(0L), pSubprocessMemory(0), exeModule(0L) {} ThreadInfo *threadList; // List of threads in the subprocess. Breakpoint *brkptList; // List of breakpoints in the subprocess. Breakpoint *lastBrkpt; // Last breakpoint hit. DWORD offset; // Breakpoint offset in allocated mem. DWORD nBreakCount; // Number of breakpoints hit. DWORD consoleHandles[100];// A list of input console handles. DWORD consoleHandlesMax; - BOOL isConsoleApp; // Is this a console app? - BOOL isShell; // Is this some sort of console shell? - HANDLE hProcess; // handle to subprocess. + HANDLE hProcess; // Handle of process. DWORD pid; // Global process id. DWORD threadCount; // Number of threads in process. - DWORD pSubprocessMemory; // Pointer to allocated memory in subprocess. - DWORD pSubprocessBuffer; // Pointer to buffer memory in subprocess. - DWORD pMemoryCacheBase; // Base address of memory cache. - BYTE pMemoryCache[PAGESIZE];// Subprocess memory cache. + PVOID pSubprocessMemory; // Pointer to allocated memory in subprocess. STRING2PTR funcTable; // Function table name to address mapping. PTR2MODULE moduleTable; // Win32 modules that have been loaded. Module *exeModule; // Executable module info. Process *nextPtr; // Linked list. }; + +# include +# ifdef _M_IX86 + struct LOADLIBRARY_STUB + { + BYTE instr_PUSH; + DWORD operand_PUSH_value; + BYTE instr_MOV_EAX; + DWORD operand_MOV_EAX; + WORD instr_CALL_EAX; + BYTE instr_INT_3; + char data_DllName[MAX_PATH]; + + LOADLIBRARY_STUB() : + instr_PUSH(0x68), instr_MOV_EAX(0xB8), + instr_CALL_EAX(0xD0FF), instr_INT_3(0xCC) + { + // Just a temporary hack.. just ignore for now. +# ifdef _DEBUG + strcpy(data_DllName, "D:\\expect_wslive\\expect_win32_take2\\win\\Debug\\injector.dll"); +# else + strcpy(data_DllName, "injector.dll"); +# endif + } + }; +# else +# error "need correct stub loader opcodes for this hardware." +# endif +# include // Direct debug event handlers. // void OnXFirstBreakpoint (Process *, LPDEBUG_EVENT); void OnXSecondBreakpoint (Process *, LPDEBUG_EVENT); + void OnXThirdBreakpoint (Process *, LPDEBUG_EVENT); void OnXBreakpoint (Process *, LPDEBUG_EVENT); void OnXCreateProcess (Process *, LPDEBUG_EVENT); void OnXCreateThread (Process *, LPDEBUG_EVENT); void OnXDeleteThread (Process *, LPDEBUG_EVENT); void OnXLoadDll (Process *, LPDEBUG_EVENT); void OnXUnloadDll (Process *, LPDEBUG_EVENT); + void OnXDebugString (Process *, LPDEBUG_EVENT); + void OnXRip (Process *, LPDEBUG_EVENT); + void OnXVDMException (Process *, LPDEBUG_EVENT); void OnXSecondChanceException (Process *, LPDEBUG_EVENT); void OnXSingleStep (Process *, LPDEBUG_EVENT); // Our breakpoint handlers (indirect). Called from OnXBreakpoint(). // + void OnAllocConsole (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnBeep (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); - void OnFillConsoleOutputCharacter (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnCreateConsoleScreenBuffer (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnFillConsoleOutputAttribute (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnFillConsoleOutputCharacterA (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnFillConsoleOutputCharacterW (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnFreeConsole (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnGetStdHandle (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnIsWindowVisible (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnOpenConsoleW (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); - void OnReadConsoleInput (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnSetConsoleActiveScreenBuffer (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnSetConsoleCP (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnSetConsoleCursorInfo (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnSetConsoleCursorPosition (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnSetConsoleMode (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnSetConsoleOutputCP (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnSetConsoleTextAttribute (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnSetConsoleWindowInfo (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnScrollConsoleScreenBuffer (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnWriteConsoleA (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnWriteConsoleW (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnWriteConsoleOutputA (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnWriteConsoleOutputW (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnWriteConsoleOutputCharacterA (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); void OnWriteConsoleOutputCharacterW (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); + void OnWriteFile (Process *, ThreadInfo *, Breakpoint *, PDWORD, DWORD); // Internal utilities // Process *ProcessNew (); void ProcessFree (Process *); - void CommonDebugger (); + DWORD CommonDebugger (); BOOL SetBreakpoint (Process *, BreakInfo *); - Breakpoint *SetBreakpointAtAddr (Process *, BreakInfo *, PVOID); + BOOL SetBreakpointAtAddr (Process *, BreakInfo *, PVOID); int LoadedModule (Process *, HANDLE, LPVOID, int, LPVOID, DWORD); BOOL ReadSubprocessMemory (Process *, LPVOID, LPVOID, DWORD); BOOL WriteSubprocessMemory (Process *, LPVOID, LPVOID, DWORD); + void MakeSubprocessMemory (Process *, SIZE_T, LPVOID *, DWORD = PAGE_READWRITE); + BOOL RemoveSubprocessMemory (Process *, LPVOID); int ReadSubprocessStringA (Process *, PVOID, PCHAR, int); int ReadSubprocessStringW (Process *, PVOID, PWCHAR, int); void CreateVtSequence (Process *, COORD, DWORD); + void OnFillCOC_Finish (CHAR, DWORD, COORD); + DWORD lastBeepDuration; + PCSTR GetExceptionCodeString (DWORD); + +// void RefreshScreen (void); // send info back to the parent - void WriteMaster (CHAR *, DWORD); + void WriteMasterCopy (CHAR *, DWORD); + void WriteMasterWarning (CHAR *, DWORD); + void WriteMasterError (CHAR *, DWORD); + // announce we are done. void NotifyDone (); // The arrays of functions where we set breakpoints // - BreakInfo BreakArrayKernel32[20]; + BreakInfo BreakArrayKernel32[27]; BreakInfo BreakArrayUser32[2]; DllBreakpoints BreakPoints[3]; // private vars // Process *ProcessList; // Top of linked list of Process instances. HANDLE hMasterConsole; // Master console handle (us). - DWORD MasterConsoleInputMode;// Current flags for the master console. + DWORD dwPlatformId; // what OS are we under? + DWORD ConsoleInputMode;// Current flags for the master console. COORD ConsoleSize; // Size of the console in the slave. COORD CursorPosition; // Coordinates of the cursor in the slave. + char *SymbolPath; + UINT ConsoleCP; // console input code page of the slave. + UINT ConsoleOutputCP;// console output code page of the slave. BOOL CursorKnown; // Do we know where the slave's cursor is? - char *SymbolPath; // Storage for setting OS kernel symbols path. - BOOL ShowExceptionBacktraces;// print exception info from debuggee? + CONSOLE_CURSOR_INFO CursorInfo;// Cursor info structure that is a copy of + // the slave's. int argc; // Debugee process commandline count char * const * argv; // Debugee process commandline args // Thread-safe message queue used for communication back to the parent. + // CMclQueue &mQ; + + // This critical section is set when breakpoints are running. + // + CMclCritSec bpCritSec; + + LPVOID pStartAddress; // Start address of the top process. + BYTE originalExeEntryPointOpcode; + + LOADLIBRARY_STUB injectorStub;// opcodes we use to force load our injector + // dll. + PVOID pInjectorStub; // Pointer to memory in sub process used + // for the injector's loader. + CONTEXT preStubContext; // Thread context info before switching to run + // the stub. + + typedef Tcl::Hash PTR2HANDLE; + PTR2HANDLE spMemMapping; // Used on Win9x to associate the file mapping + // handle to the memory address it provides. + + // A couple NT routines we'll might need when running + // on NT/2K/XP + typedef LPVOID (__stdcall *PFNVIRTUALALLOCEX)(HANDLE,LPVOID,SIZE_T,DWORD,DWORD); + typedef BOOL (__stdcall *PFNVIRTUALFREEEX)(HANDLE,LPVOID,SIZE_T,DWORD); + + PFNVIRTUALALLOCEX pfnVirtualAllocEx; + PFNVIRTUALFREEEX pfnVirtualFreeEx; + + CMclMailbox *injectorIPC; // IPC transfer mechanism to the injector dll. + + bool interacting; + HANDLE interactingConsole; }; #endif // INC_expWinConsoleDebugger_hpp__ Index: win/expWinConsoleDebuggerBreakPoints.cpp ================================================================== --- win/expWinConsoleDebuggerBreakPoints.cpp +++ win/expWinConsoleDebuggerBreakPoints.cpp @@ -15,24 +15,27 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinConsoleDebuggerBreakPoints.cpp,v 1.1.2.9 2002/03/13 03:52:57 davygrvy Exp $ + * RCS: @(#) $Id: expWinConsoleDebuggerBreakPoints.cpp,v 1.1.2.16 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinConsoleDebugger.hpp" -// NOTE: black magic abounds... be warry young padwon... +///////////////////////////////////////////////////////////// +// NOTE: black magic abounds... be warry young padwon... // +///////////////////////////////////////////////////////////// /* *---------------------------------------------------------------------- * * ConsoleDebugger::CreateVtSequence -- @@ -73,11 +76,34 @@ } newPos.X += (SHORT) (n % ConsoleSize.X); newPos.Y += (SHORT) (n / ConsoleSize.X); CursorPosition = newPos; - WriteMaster(buf, count); + WriteMasterCopy(buf, count); +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnAllocConsole -- + * + * Results: + * None + * + * Notes: + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnAllocConsole(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + if (*returnValue == FALSE) { + return; + } + __asm nop; } /* *----------------------------------------------------------------------------- * @@ -103,27 +129,125 @@ Breakpoint *brkpt, PDWORD returnValue, DWORD direction) { CHAR buf[2] = {0,0}; if (direction == BREAK_IN) { + lastBeepDuration = threadInfo->args[1]; // Modify the arguments so a beep doesn't sound in the slave. threadInfo->args[1] = 0; } else if (direction == BREAK_OUT) { if (*returnValue == 0) { buf[0] = 7; // ASCII beep - WriteMaster(buf, 1); + WriteMasterCopy(buf, 1); + if (interacting) { + Beep(threadInfo->args[0], lastBeepDuration); + } } } } /* *----------------------------------------------------------------------------- * - * ConsoleDebugger::OnFillConsoleOutputCharacter -- + * ConsoleDebugger::OnCreateConsoleScreenBuffer -- + * + * This function gets called when a CreateConsoleScreenBuffer + * breakpoint is hit. + * + * Results: + * None + * + * Side Effects: + * unknown. + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnCreateConsoleScreenBuffer(Process *proc, + ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, + DWORD direction) +{ + if (*returnValue == FALSE) { + return; + } + // TODO: what to do here? + __asm nop; +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnFillConsoleOutputAttribute -- + * + * Results: + * None + * + * Notes: + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnFillConsoleOutputAttribute(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + if (*returnValue == FALSE) { + return; + } + __asm nop; +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnFillConsoleOutputCharacterA -- * * This function gets called when an FillConsoleOutputCharacterA - * or FillConsoleOutputCharacterW breakpoint is hit. + * breakpoint is hit. + * + * Results: + * None + * + * Side Effects: + * Prints some output. + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnFillConsoleOutputCharacterA(Process *proc, + ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, + DWORD direction) +{ + CHAR cCharacter; + DWORD nLength; + COORD dwWriteCoord; + PVOID ptr; + + if (*returnValue == 0) { + return; + } + + cCharacter = (CHAR) threadInfo->args[1]; + nLength = threadInfo->args[2]; + dwWriteCoord = *((PCOORD) &(threadInfo->args[3])); + ptr = (PVOID) threadInfo->args[4]; + if (ptr) { + ReadSubprocessMemory(proc, ptr, &nLength, sizeof(DWORD)); + } + + OnFillCOC_Finish(cCharacter, nLength, dwWriteCoord); +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnFillConsoleOutputCharacterW -- + * + * This function gets called when an FillConsoleOutputCharacterW + * breakpoint is hit. * * Results: * None * * Side Effects: @@ -131,142 +255,183 @@ * *----------------------------------------------------------------------------- */ void -ConsoleDebugger::OnFillConsoleOutputCharacter(Process *proc, +ConsoleDebugger::OnFillConsoleOutputCharacterW(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, DWORD direction) { + CHAR cCharacter; + WCHAR cWCharacter; + DWORD nLength; + COORD dwWriteCoord; + PVOID ptr; + + if (*returnValue == 0) { + return; + } + + cWCharacter = (WCHAR) threadInfo->args[1]; + nLength = threadInfo->args[2]; + dwWriteCoord = *((PCOORD) &(threadInfo->args[3])); + ptr = (PVOID) threadInfo->args[4]; + if (ptr) { + ReadSubprocessMemory(proc, ptr, &nLength, sizeof(DWORD)); + } + + // For now, just truncated it. + // TODO: fix me! + // + cCharacter = (cWCharacter & 0xff); + + OnFillCOC_Finish(cCharacter, nLength, dwWriteCoord); +} + +void +ConsoleDebugger::OnFillCOC_Finish(CHAR cCharacter, DWORD nLength, COORD dwWriteCoord) +{ CHAR buf[4096]; int bufpos; - UCHAR c; - PVOID ptr; DWORD i; - DWORD len; - COORD coord; DWORD lines, preCols, postCols; BOOL eol, bol; // Needs clearing to end, beginning of line CONSOLE_SCREEN_BUFFER_INFO info; - if (*returnValue == 0) { - return; - } - - c = (UCHAR) threadInfo->args[1]; - len = threadInfo->args[2]; - coord = *((PCOORD) &(threadInfo->args[3])); - ptr = (PVOID) threadInfo->args[4]; - if (ptr) { - ReadSubprocessMemory(proc, ptr, &len, sizeof(DWORD)); + if (interacting) { + DWORD dwWritten; + FillConsoleOutputCharacter(interactingConsole, cCharacter, nLength, dwWriteCoord, &dwWritten); } preCols = 0; bufpos = 0; eol = bol = FALSE; - if (coord.X) { - preCols = ConsoleSize.X - coord.X; - if (len <= preCols) { - preCols = len; - len = 0; - if (len == preCols) { + if (dwWriteCoord.X) { + preCols = ConsoleSize.X - dwWriteCoord.X; + if (nLength <= preCols) { + preCols = nLength; + nLength = 0; + if (nLength == preCols) { eol = TRUE; } } else { eol = TRUE; - len -= preCols; + nLength -= preCols; } - } else if (len < (DWORD) ConsoleSize.X) { + } else if (nLength < (DWORD) ConsoleSize.X) { bol = TRUE; - preCols = len; - len = 0; + preCols = nLength; + nLength = 0; } - lines = len / ConsoleSize.X; - postCols = len % ConsoleSize.X; + lines = nLength / ConsoleSize.X; + postCols = nLength % ConsoleSize.X; if (preCols) { if (bol) { // Beginning of line to before end of line - if (c == ' ') { + if (cCharacter == ' ') { wsprintfA(&buf[bufpos], "\033[%d;%dH\033[1K", - coord.Y+1, preCols+coord.X); + dwWriteCoord.Y+1, preCols+dwWriteCoord.X); bufpos += strlen(&buf[bufpos]); } else { wsprintfA(&buf[bufpos], "\033[%d;%dH", - coord.Y+1, coord.X+1); + dwWriteCoord.Y+1, dwWriteCoord.X+1); bufpos += strlen(&buf[bufpos]); - memset(&buf[bufpos], c, preCols); + memset(&buf[bufpos], cCharacter, preCols); bufpos += preCols; } } else { // After beginning of line to end of line - wsprintfA(&buf[bufpos], "\033[%d;%dH", coord.Y+1, coord.X+1); + wsprintfA(&buf[bufpos], "\033[%d;%dH", dwWriteCoord.Y+1, dwWriteCoord.X+1); bufpos += strlen(&buf[bufpos]); - if (eol && c == ' ') { + if (eol && cCharacter == ' ') { wsprintfA(&buf[bufpos], "\033[K"); bufpos += strlen(&buf[bufpos]); } else { - memset(&buf[bufpos], c, preCols); + memset(&buf[bufpos], cCharacter, preCols); bufpos += preCols; } } - coord.X = 0; - coord.Y++; + dwWriteCoord.X = 0; + dwWriteCoord.Y++; } if (lines) { - if ((c == ' ') && ((lines + coord.Y) >= (DWORD) ConsoleSize.Y)) { + if ((cCharacter == ' ') && ((lines + dwWriteCoord.Y) >= (DWORD) ConsoleSize.Y)) { // Clear to end of screen wsprintfA(&buf[bufpos], "\033[%d;%dH\033[J", - coord.Y+1, coord.X+1); + dwWriteCoord.Y+1, dwWriteCoord.X+1); bufpos += strlen(&buf[bufpos]); - } else if ((c == ' ') && (coord.Y == 0) && (lines > 0)) { + } else if ((cCharacter == ' ') && (dwWriteCoord.Y == 0) && (lines > 0)) { // Clear to top of screen wsprintfA(&buf[bufpos], "\033[%d;%dH\033[1J", lines, 1); bufpos += strlen(&buf[bufpos]); } else { for (i = 0; i < lines; i++) { wsprintfA(&buf[bufpos], "\033[%d;%dH", - coord.Y+i+1, coord.X+1); + dwWriteCoord.Y+i+1, dwWriteCoord.X+1); bufpos += strlen(&buf[bufpos]); - if (c == ' ') { + if (cCharacter == ' ') { wsprintfA(&buf[bufpos], "\033[2K"); bufpos += strlen(&buf[bufpos]); } else { - memset(&buf[bufpos], c, ConsoleSize.X); + memset(&buf[bufpos], cCharacter, ConsoleSize.X); bufpos += ConsoleSize.X; } } } - coord.Y += (SHORT) lines; + dwWriteCoord.Y += (SHORT) lines; } if (postCols) { - if (c == ' ') { + if (cCharacter == ' ') { // Clear to beginning of line wsprintfA(&buf[bufpos], "\033[%d;%dH\033[1K", - coord.Y+1, postCols+coord.X); + dwWriteCoord.Y+1, postCols+dwWriteCoord.X); bufpos += strlen(&buf[bufpos]); } else { - wsprintfA(&buf[bufpos], "\033[%d;%dH", coord.X+1, coord.Y+1); + wsprintfA(&buf[bufpos], "\033[%d;%dH", dwWriteCoord.X+1, dwWriteCoord.Y+1); bufpos += strlen(&buf[bufpos]); - memset(&buf[bufpos], c, postCols); + memset(&buf[bufpos], cCharacter, postCols); bufpos += postCols; } } if (GetConsoleScreenBufferInfo(hMasterConsole, &info) == FALSE) { char errbuf[200]; wsprintfA(errbuf, "handle=0x%08x", hMasterConsole); - EXP_LOG2(MSG_DT_SCREENBUF, errbuf, ExpSyslogGetSysMsg(GetLastError())); + EXP_LOG2(MSG_DT_SCREENBUF, errbuf, GetSysMsg(GetLastError())); } else { CursorPosition = info.dwCursorPosition; wsprintfA(&buf[bufpos], "\033[%d;%dH", CursorPosition.Y+1, CursorPosition.X+1); bufpos += strlen(&buf[bufpos]); CursorKnown = TRUE; } - WriteMaster(buf, bufpos); + WriteMasterCopy(buf, bufpos); +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnFreeConsole -- + * + * Results: + * None + * + * Notes: + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnFreeConsole(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + if (*returnValue == FALSE) { + return; + } + __asm nop; } /* *----------------------------------------------------------------------------- * @@ -372,34 +537,10 @@ } /* *---------------------------------------------------------------------- * - * ConsoleDebugger::OnReadConsoleInput -- - * - * This function gets called when a ReadConsoleInput breakpoint - * is hit. - * - * Results: - * None - * - * Notes: - * If this is ever used for real, there need to be ASCII - * and UNICODE versions. - * - *---------------------------------------------------------------------- - */ - -void -ConsoleDebugger::OnReadConsoleInput(Process *proc, ThreadInfo *threadInfo, - Breakpoint *brkpt, PDWORD returnValue, DWORD direction) -{ -} - -/* - *---------------------------------------------------------------------- - * * ConsoleDebugger::OnScrollConsoleScreenBuffer -- * * This funtions gets called when a ScrollConsoleScreenBuffer * breakpoint is hit. * @@ -461,56 +602,16 @@ dest.Y - scroll.Top); } count = strlen(&buf[count]); wsprintf(&buf[count], "\033[%d;%dr", 1, ConsoleSize.Y); count += strlen(&buf[count]); - WriteMaster(buf, count); + WriteMasterCopy(buf, count); } else { // RefreshScreen(&proc->overlapped); } } -/* - *---------------------------------------------------------------------- - * - * ConsoleDebugger::OnSetConsoleMode -- - * - * This function gets called when a SetConsoleMode breakpoint - * is hit. - * - * Results: - * None - * - * Side Effects: - * Sets some flags that are used in determining echoing - * characteristics of the slave driver. - * - *---------------------------------------------------------------------- - */ - -void -ConsoleDebugger::OnSetConsoleMode(Process *proc, ThreadInfo *threadInfo, - Breakpoint *brkpt, PDWORD returnValue, DWORD direction) -{ - DWORD i; - BOOL found; - - // The console mode seems to get set even if the return value is FALSE - if (*returnValue == FALSE) { - return; - } - for (found = FALSE, i = 0; i < proc->consoleHandlesMax; i++) { - if (threadInfo->args[0] == proc->consoleHandles[i]) { - found = TRUE; - break; - } - } - if (found) { - MasterConsoleInputMode = threadInfo->args[1]; - } -} - /* *---------------------------------------------------------------------- * * ConsoleDebugger::OnSetConsoleActiveScreenBuffer -- * @@ -534,15 +635,74 @@ { if (*returnValue == FALSE) { return; } + __asm nop; // RefreshScreen(&proc->overlapped); } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnSetConsoleCP -- + * + * Results: + * None + * + * Notes: + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnSetConsoleCP(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + if (*returnValue == FALSE) { + return; + } + ConsoleCP = (UINT) threadInfo->args[0]; + + if (interacting) { + SetConsoleCP(ConsoleCP); + } +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnSetConsoleCursorInfo -- + * + * Results: + * None + * + * Notes: + * Updates the current console's cursor info. + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnSetConsoleCursorInfo(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + PVOID ptr; + + if (*returnValue == FALSE) { + return; + } + ptr = (PVOID) threadInfo->args[1]; + ReadSubprocessMemory(proc, ptr, &CursorInfo, sizeof(CONSOLE_CURSOR_INFO)); + + if (interacting) { + SetConsoleCursorInfo(interactingConsole, &CursorInfo); + } +} + +/* + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnSetConsoleCursorPosition -- * * This function gets called when a SetConsoleCursorPosition breakpoint * is hit. @@ -549,35 +709,140 @@ * * Results: * None * * Side Effects: - * Updates the current console cursor position + * Updates the current console's cursor position * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnSetConsoleCursorPosition(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, DWORD direction) { - CHAR buf[50]; + static CHAR buf[50]; DWORD count; if (*returnValue == FALSE) { return; } CursorPosition = *((PCOORD) &threadInfo->args[1]); - wsprintfA(buf, "\033[%d;%dH", CursorPosition.Y+1, CursorPosition.X+1); - count = strlen(buf); - WriteMaster(buf, count); + count = wsprintf(buf, "\033[%d;%dH", CursorPosition.Y+1, CursorPosition.X+1); + WriteMasterCopy(buf, count); + + if (interacting) { + SetConsoleCursorPosition(interactingConsole, CursorPosition); + } +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnSetConsoleMode -- + * + * This function gets called when a SetConsoleMode breakpoint + * is hit. + * + * Results: + * None + * + * Side Effects: + * Sets some flags that are used in determining echoing + * characteristics of the slave driver. + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnSetConsoleMode(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + DWORD i; + BOOL found; + + // The console mode seems to get set even if the return value is FALSE + if (*returnValue == FALSE) { + return; + } + for (found = FALSE, i = 0; i < proc->consoleHandlesMax; i++) { + if (threadInfo->args[0] == proc->consoleHandles[i]) { + found = TRUE; + break; + } + } + if (found) { + ConsoleInputMode = threadInfo->args[1]; + } + + if (interacting) { + SetConsoleMode(interactingConsole, ConsoleInputMode); + } +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnSetConsoleOutputCP -- + * + * Results: + * None + * + * Notes: + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnSetConsoleOutputCP(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + if (*returnValue == FALSE) { + return; + } + ConsoleOutputCP = (UINT) threadInfo->args[0]; + + if (interacting) { + SetConsoleOutputCP(ConsoleOutputCP); + } +} + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnSetConsoleTextAttribute -- + * + * Results: + * None + * + * Notes: + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnSetConsoleTextAttribute(Process *proc, ThreadInfo *threadInfo, + Breakpoint *brkpt, PDWORD returnValue, DWORD direction) +{ + WORD wAttributes; + + wAttributes = (WORD) threadInfo->args[1]; + + // TODO: fix me! + // + __asm nop; + + if (interacting) { + SetConsoleTextAttribute(interactingConsole, wAttributes); + } + } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnSetConsoleWindowInfo -- * * This function gets called when a SetConsoleWindowInfo breakpoint * is hit. @@ -586,22 +851,41 @@ * None * * Side Effects: * Updates the current console cursor position * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnSetConsoleWindowInfo(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, DWORD direction) { + HANDLE hConsoleOutput; + BOOL bAbsolute; + SMALL_RECT ConsoleWindowRect; + PVOID ptr; + + if (*returnValue == FALSE) { + return; + } + + hConsoleOutput = (HANDLE) threadInfo->args[0]; + bAbsolute = threadInfo->args[1]; + ptr = (PVOID) threadInfo->args[2]; + if (ptr) { + ReadSubprocessMemory(proc, ptr, &ConsoleWindowRect, sizeof(SMALL_RECT)); + } + + // TODO: fix me! What do we do here? + // + __asm nop; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnWriteConsoleA -- * * This function gets called when an WriteConsoleA breakpoint * is hit. The data is also redirected to expect since expect @@ -611,11 +895,11 @@ * None * * Side Effects: * Prints some output. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnWriteConsoleA(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, DWORD direction) @@ -641,21 +925,25 @@ p = buf; } ptr = (PVOID) threadInfo->args[1]; ReadSubprocessMemory(proc, ptr, p, n * sizeof(CHAR)); -// ResetEvent(proc->overlapped.hEvent); - WriteMaster(p, n); + WriteMasterCopy(p, n); + + if (interacting) { + DWORD x; + WriteConsole(interactingConsole, p, n, &x, 0L); + } if (p != buf) { delete [] p; } CursorKnown = FALSE; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnWriteConsoleW -- * * This function gets called when an WriteConsoleW breakpoint * is hit. @@ -664,11 +952,11 @@ * None * * Side Effects: * Prints some output. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnWriteConsoleW(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, DWORD direction) @@ -697,25 +985,29 @@ p = buf; a = ansi; asize = sizeof(ansi); } ReadSubprocessMemory(proc, ptr, p, n * sizeof(WCHAR)); -// ResetEvent(proc->overlapped.hEvent); - // Convert to ASCII and write the intercepted data to the pipe. + // Convert to ASCII and write-out the intercepted data. // w = WideCharToMultiByte(CP_ACP, 0, p, n, a, asize, 0L, 0L); - WriteMaster(a, w); + WriteMasterCopy(a, w); + + if (interacting) { + DWORD x; + WriteConsole(interactingConsole, a, w, &x, 0L); + } if (p != buf) { delete [] p, a; } CursorKnown = FALSE; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnWriteConsoleOutputA -- * * This function gets called when an WriteConsoleOutputA breakpoint * is hit. The data is also redirected to expect since expect @@ -725,11 +1017,11 @@ * None * * Side Effects: * Prints some output. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnWriteConsoleOutputA(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, @@ -753,11 +1045,11 @@ bufferSize = *((PCOORD) &threadInfo->args[2]); bufferCoord = *((PCOORD) &threadInfo->args[3]); ptr = (PVOID) threadInfo->args[4]; // Get the rectangle written if (ptr == 0L) return; - ReadSubprocessMemory(proc, ptr, &writeRegion,sizeof(SMALL_RECT)); + ReadSubprocessMemory(proc, ptr, &writeRegion, sizeof(SMALL_RECT)); ptr = (PVOID) threadInfo->args[1]; // Get character array if (ptr == 0L) return; n = bufferSize.X * bufferSize.Y * sizeof(CHAR_INFO); @@ -779,31 +1071,33 @@ maxbuf = sizeof(buf); end = buf + maxbuf; for (x = 0; x <= writeRegion.Right - writeRegion.Left; x++, pcb++) { *p++ = pcb->Char.AsciiChar; if (p == end) { -// ResetEvent(proc->overlapped.hEvent); - WriteMaster(buf, maxbuf); + WriteMasterCopy(buf, maxbuf); p = buf; } } curr.X = writeRegion.Left; curr.Y = writeRegion.Top + y; n = writeRegion.Right - writeRegion.Left; CreateVtSequence(proc, curr, n); -// ResetEvent(proc->overlapped.hEvent); maxbuf = p - buf; - WriteMaster(buf, maxbuf); + WriteMasterCopy(buf, maxbuf); buf[maxbuf] = 0; } + + if (interacting) { + WriteConsoleOutput(interactingConsole, charBuf, bufferSize, bufferCoord, &writeRegion); + } delete [] charBuf; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnWriteConsoleOutputW -- * * This function gets called when an WriteConsoleOutputW breakpoint * is hit. The data is also redirected to expect since expect @@ -813,11 +1107,11 @@ * None * * Side Effects: * Prints some output. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnWriteConsoleOutputW(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, @@ -867,31 +1161,33 @@ maxbuf = sizeof(buf); end = buf + maxbuf; for (x = 0; x <= writeRegion.Right - writeRegion.Left; x++, pcb++) { *p++ = (CHAR) (pcb->Char.UnicodeChar & 0xff); if (p == end) { -// ResetEvent(proc->overlapped.hEvent); - WriteMaster((char *)buf, maxbuf); + WriteMasterCopy((char *)buf, maxbuf); p = buf; } } curr.X = writeRegion.Left; curr.Y = writeRegion.Top + y; n = writeRegion.Right - writeRegion.Left; CreateVtSequence(proc, curr, n); -// ResetEvent(proc->overlapped.hEvent); maxbuf = p - buf; - WriteMaster((char *)buf, maxbuf); + WriteMasterCopy((char *)buf, maxbuf); buf[maxbuf] = 0; } + + if (interacting) { + WriteConsoleOutput(interactingConsole, charBuf, bufferSize, bufferCoord, &writeRegion); + } delete [] charBuf; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnWriteConsoleOutputCharacterA -- * * This function gets called when an WriteConsoleOutputCharacterA breakpoint * is hit. The data is also redirected to expect since expect @@ -901,55 +1197,60 @@ * None * * Side Effects: * Prints some output. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnWriteConsoleOutputCharacterA(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, DWORD direction) { static CHAR buf[1024]; PVOID ptr; - DWORD n; - PCHAR p; + DWORD nLength; + PCHAR lpCharacter; + COORD dwWriteCoord; if (*returnValue == 0) { return; } // Get number of bytes written ptr = (PVOID) threadInfo->args[4]; if (ptr == 0L) { - n = threadInfo->args[2]; - } else { - ReadSubprocessMemory(proc, ptr, &n, sizeof(DWORD)); - } - - CreateVtSequence(proc, *((PCOORD) &threadInfo->args[3]), n); - - if (n > 1024) { - p = new CHAR [n]; - } else { - p = buf; + nLength = threadInfo->args[2]; + } else { + ReadSubprocessMemory(proc, ptr, &nLength, sizeof(DWORD)); + } + + dwWriteCoord = *((PCOORD) &threadInfo->args[3]); + CreateVtSequence(proc, dwWriteCoord, nLength); + + if (nLength > 1024) { + lpCharacter = new CHAR [nLength]; + } else { + lpCharacter = buf; } ptr = (PVOID) threadInfo->args[1]; - ReadSubprocessMemory(proc, ptr, p, n * sizeof(CHAR)); -// ResetEvent(proc->overlapped.hEvent); + ReadSubprocessMemory(proc, ptr, lpCharacter, nLength * sizeof(CHAR)); + WriteMasterCopy(lpCharacter, nLength); - WriteMaster(p, n); + if (interacting) { + DWORD dwWritten; + WriteConsoleOutputCharacter(interactingConsole, lpCharacter, nLength, dwWriteCoord, &dwWritten); + } - if (p != buf) { - delete [] p; + if (lpCharacter != buf) { + delete [] lpCharacter; } CursorKnown = FALSE; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnWriteConsoleOutputCharacterW -- * * This function gets called when an WriteConsoleOutputCharacterW * breakpoint is hit. @@ -958,11 +1259,11 @@ * None * * Side Effects: * Prints some output. * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnWriteConsoleOutputCharacterW(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, @@ -969,55 +1270,60 @@ DWORD direction) { static WCHAR buf[1024]; static CHAR ansi[2048]; PVOID ptr; - DWORD n; + DWORD nLength; PWCHAR p; - PCHAR a; + PCHAR lpCharacter; + COORD dwWriteCoord; int asize; - int w; if (*returnValue == 0) { return; } // Get number of bytes written ptr = (PVOID) threadInfo->args[4]; if (ptr == 0L) { - n = threadInfo->args[2]; + nLength = threadInfo->args[2]; } else { - ReadSubprocessMemory(proc, ptr, &n, sizeof(DWORD)); + ReadSubprocessMemory(proc, ptr, &nLength, sizeof(DWORD)); } - CreateVtSequence(proc, *((PCOORD) &threadInfo->args[3]), n); + dwWriteCoord = *((PCOORD) &threadInfo->args[3]); + CreateVtSequence(proc, dwWriteCoord, nLength); - if (n > 1024) { - p = new WCHAR [n]; - asize = n * 2 * sizeof(CHAR); - a = new CHAR [n * 2]; + if (nLength > 1024) { + p = new WCHAR [nLength]; + asize = nLength * 2 * sizeof(CHAR); + lpCharacter = new CHAR [nLength * 2]; } else { p = buf; - a = ansi; + lpCharacter = ansi; asize = sizeof(ansi); } ptr = (PVOID) threadInfo->args[1]; - ReadSubprocessMemory(proc, ptr, p, n * sizeof(WCHAR)); -// ResetEvent(proc->overlapped.hEvent); + ReadSubprocessMemory(proc, ptr, p, nLength * sizeof(WCHAR)); // Convert to ASCI and Write the intercepted data to the pipe. - w = WideCharToMultiByte(CP_ACP, 0, p, n, a, asize, 0L, 0L); - WriteMaster(a, w); + nLength = WideCharToMultiByte(CP_ACP, 0, p, nLength, lpCharacter, asize, 0L, 0L); + WriteMasterCopy(lpCharacter, nLength); + + if (interacting) { + DWORD dwWritten; + WriteConsoleOutputCharacter(interactingConsole, lpCharacter, nLength, dwWriteCoord, &dwWritten); + } if (p != buf) { - delete [] p, a; + delete [] p, lpCharacter; } CursorKnown = FALSE; } /* - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- * * ConsoleDebugger::OnIsWindowVisible -- * * This routine gets called when IsWindowVisible is called. * The MKS Korn shell uses this as an indication of a window @@ -1028,14 +1334,62 @@ * return FALSE given that nobody is ever going to see anything. * * Results: * None * - *---------------------------------------------------------------------- + *----------------------------------------------------------------------------- */ void ConsoleDebugger::OnIsWindowVisible(Process *proc, ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, DWORD direction) { *returnValue = TRUE; } + +/* + *----------------------------------------------------------------------------- + * + * ConsoleDebugger::OnWriteFile -- + * + * This function gets called when a WriteFile + * breakpoint is hit. + * + * Results: + * None + * + * Side Effects: + * none yet.. + * + *----------------------------------------------------------------------------- + */ + +void +ConsoleDebugger::OnWriteFile(Process *proc, + ThreadInfo *threadInfo, Breakpoint *brkpt, PDWORD returnValue, + DWORD direction) +{ + HANDLE hFile; // handle to file + PCHAR lpBuffer; // data buffer + DWORD nNumberOfBytesToWrite; // number of bytes to write +// LPOVERLAPPED lpOverlapped; // overlapped buffer + PVOID ptr; + + hFile = (HANDLE) threadInfo->args[0]; + + // TODO: is this a console handle in the slave? + return; + + // Get number of bytes written, if available. + ptr = (PVOID) threadInfo->args[4]; + if (ptr == 0L) { + nNumberOfBytesToWrite = threadInfo->args[2]; + } else { + ReadSubprocessMemory(proc, ptr, &nNumberOfBytesToWrite, sizeof(DWORD)); + } + + ptr = (PVOID) threadInfo->args[1]; + lpBuffer = new CHAR [nNumberOfBytesToWrite]; + ReadSubprocessMemory(proc, ptr, lpBuffer, nNumberOfBytesToWrite); + + delete lpBuffer; +} ADDED win/expWinConsoleKeyMap.cpp Index: win/expWinConsoleKeyMap.cpp ================================================================== --- /dev/null +++ win/expWinConsoleKeyMap.cpp @@ -0,0 +1,366 @@ +/* ---------------------------------------------------------------------------- + * expWinConsoleKeyMap.cpp -- + * + * Routines for recomposing a string into a series of keypress events. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: expWinConsoleKeyMap.cpp,v 1.1.2.2 2002/06/23 09:26:28 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#include "expWinSlave.hpp" + +struct KEY_MATRIX { + WORD wVirtualKeyCode; + WORD wVirtualScanCode; + DWORD dwControlKeyState; +}; + +static const KEY_MATRIX ModifierKeyArray[] = { +/* Control */ { 17, 29, 0}, +/* LShift */ { 16, 42, 0}, +/* RShift */ { 16, 54, 0}, +/* Alt */ { 18, 56, 0}, +}; + +static const KEY_MATRIX AsciiToKeyArray[] = { +/* 0 */ { 50, 3, RIGHT_CTRL_PRESSED|SHIFT_PRESSED}, +/* 1 */ { 65, 30, RIGHT_CTRL_PRESSED}, +/* 2 */ { 66, 48, RIGHT_CTRL_PRESSED}, +/* 3 */ { 67, 46, RIGHT_CTRL_PRESSED}, +/* 4 */ { 68, 32, RIGHT_CTRL_PRESSED}, +/* 5 */ { 69, 18, RIGHT_CTRL_PRESSED}, +/* 6 */ { 70, 33, RIGHT_CTRL_PRESSED}, +/* 7 */ { 71, 34, RIGHT_CTRL_PRESSED}, +/* 8 */ { 72, 35, RIGHT_CTRL_PRESSED}, +/* 9 */ { 9, 15, RIGHT_CTRL_PRESSED}, +/* 10 */ { 74, 36, RIGHT_CTRL_PRESSED}, +/* 11 */ { 75, 37, RIGHT_CTRL_PRESSED}, +/* 12 */ { 76, 38, RIGHT_CTRL_PRESSED}, +/* 13 */ { 13, 28, 0}, +/* 14 */ { 78, 49, RIGHT_CTRL_PRESSED}, +/* 15 */ { 79, 24, RIGHT_CTRL_PRESSED}, +/* 16 */ { 80, 25, RIGHT_CTRL_PRESSED}, +/* 17 */ { 81, 16, RIGHT_CTRL_PRESSED}, +/* 18 */ { 82, 19, RIGHT_CTRL_PRESSED}, +/* 19 */ { 83, 31, RIGHT_CTRL_PRESSED}, +/* 20 */ { 84, 20, RIGHT_CTRL_PRESSED}, +/* 21 */ { 85, 22, RIGHT_CTRL_PRESSED}, +/* 22 */ { 86, 47, RIGHT_CTRL_PRESSED}, +/* 23 */ { 87, 17, RIGHT_CTRL_PRESSED}, +/* 24 */ { 88, 45, RIGHT_CTRL_PRESSED}, +/* 25 */ { 89, 21, RIGHT_CTRL_PRESSED}, +/* 26 */ { 90, 44, RIGHT_CTRL_PRESSED}, +/* 27 */ {219, 219, RIGHT_CTRL_PRESSED|SHIFT_PRESSED}, +/* 28 */ {220, 220, RIGHT_CTRL_PRESSED|SHIFT_PRESSED}, +/* 29 */ {221, 221, RIGHT_CTRL_PRESSED|SHIFT_PRESSED}, +/* 30 */ { 54, 54, RIGHT_CTRL_PRESSED|SHIFT_PRESSED}, +/* 31 */ {189, 189, RIGHT_CTRL_PRESSED|SHIFT_PRESSED}, +/* 32 */ { 32, 32, 0}, +/* 33 */ { 49, 49, SHIFT_PRESSED}, +/* 34 */ {222, 222, SHIFT_PRESSED}, +/* 35 */ { 51, 51, SHIFT_PRESSED}, +/* 36 */ { 52, 52, SHIFT_PRESSED}, +/* 37 */ { 53, 53, SHIFT_PRESSED}, +/* 38 */ { 55, 55, SHIFT_PRESSED}, +/* 39 */ {222, 222, 0}, +/* 40 */ { 57, 57, SHIFT_PRESSED}, +/* 41 */ { 48, 48, SHIFT_PRESSED}, +/* 42 */ { 56, 56, SHIFT_PRESSED}, +/* 43 */ {187, 187, SHIFT_PRESSED}, +/* 44 */ {188, 188, 0}, +/* 45 */ {189, 189, SHIFT_PRESSED}, +/* 46 */ {190, 190, 0}, +/* 47 */ {191, 191, 0}, +/* 48 */ { 48, 48, 0}, +/* 49 */ { 49, 49, 0}, +/* 50 */ { 50, 3, 0}, +/* 51 */ { 51, 51, 0}, +/* 52 */ { 52, 52, 0}, +/* 53 */ { 53, 53, 0}, +/* 54 */ { 54, 54, 0}, +/* 55 */ { 55, 55, 0}, +/* 56 */ { 56, 56, 0}, +/* 57 */ { 57, 57, 0}, +/* 58 */ {186, 186, SHIFT_PRESSED}, +/* 59 */ {186, 186, 0}, +/* 60 */ {188, 188, SHIFT_PRESSED}, +/* 61 */ {187, 187, SHIFT_PRESSED}, +/* 62 */ {190, 190, SHIFT_PRESSED}, +/* 63 */ {191, 191, SHIFT_PRESSED}, +/* 64 */ { 50, 3, 0}, +/* 65 */ { 65, 30, SHIFT_PRESSED}, +/* 66 */ { 66, 48, SHIFT_PRESSED}, +/* 67 */ { 67, 46, SHIFT_PRESSED}, +/* 68 */ { 68, 32, SHIFT_PRESSED}, +/* 69 */ { 69, 18, SHIFT_PRESSED}, +/* 70 */ { 70, 33, SHIFT_PRESSED}, +/* 71 */ { 71, 34, SHIFT_PRESSED}, +/* 72 */ { 72, 35, SHIFT_PRESSED}, +/* 73 */ { 73, 23, SHIFT_PRESSED}, +/* 74 */ { 74, 36, SHIFT_PRESSED}, +/* 75 */ { 75, 37, SHIFT_PRESSED}, +/* 76 */ { 76, 38, SHIFT_PRESSED}, +/* 77 */ { 77, 50, SHIFT_PRESSED}, +/* 78 */ { 78, 49, SHIFT_PRESSED}, +/* 79 */ { 79, 24, SHIFT_PRESSED}, +/* 80 */ { 80, 25, SHIFT_PRESSED}, +/* 81 */ { 81, 16, SHIFT_PRESSED}, +/* 82 */ { 82, 19, SHIFT_PRESSED}, +/* 83 */ { 83, 31, SHIFT_PRESSED}, +/* 84 */ { 84, 20, SHIFT_PRESSED}, +/* 85 */ { 85, 22, SHIFT_PRESSED}, +/* 86 */ { 86, 47, SHIFT_PRESSED}, +/* 87 */ { 87, 17, SHIFT_PRESSED}, +/* 88 */ { 88, 45, SHIFT_PRESSED}, +/* 89 */ { 89, 21, SHIFT_PRESSED}, +/* 90 */ { 90, 44, SHIFT_PRESSED}, +/* 91 */ {219, 219, 0}, +/* 92 */ {220, 220, 0}, +/* 93 */ {221, 221, 0}, +/* 94 */ { 54, 54, SHIFT_PRESSED}, +/* 95 */ {189, 189, SHIFT_PRESSED}, +/* 96 */ {192, 192, 0}, +/* 97 */ { 65, 30, 0}, +/* 98 */ { 66, 48, 0}, +/* 99 */ { 67, 46, 0}, +/* 100 */ { 68, 32, 0}, +/* 101 */ { 69, 18, 0}, +/* 102 */ { 70, 33, 0}, +/* 103 */ { 71, 34, 0}, +/* 104 */ { 72, 35, 0}, +/* 105 */ { 73, 23, 0}, +/* 106 */ { 74, 36, 0}, +/* 107 */ { 75, 37, 0}, +/* 108 */ { 76, 38, 0}, +/* 109 */ { 77, 50, 0}, +/* 110 */ { 78, 49, 0}, +/* 111 */ { 79, 24, 0}, +/* 112 */ { 80, 25, 0}, +/* 113 */ { 81, 16, 0}, +/* 114 */ { 82, 19, 0}, +/* 115 */ { 83, 31, 0}, +/* 116 */ { 84, 20, 0}, +/* 117 */ { 85, 22, 0}, +/* 118 */ { 86, 47, 0}, +/* 119 */ { 87, 17, 0}, +/* 120 */ { 88, 45, 0}, +/* 121 */ { 89, 21, 0}, +/* 122 */ { 90, 44, 0}, +/* 123 */ {219, 219, SHIFT_PRESSED}, +/* 124 */ {220, 220, SHIFT_PRESSED}, +/* 125 */ {221, 221, SHIFT_PRESSED}, +/* 126 */ {192, 192, SHIFT_PRESSED}, +#if 0 +/* 127 */ { 8, 14, RIGHT_CTRL_PRESSED}, +#else +/* Delete */ { VK_DELETE, 83, 0}, +#endif +}; + +static const KEY_MATRIX FunctionToKeyArray[] = { +/* Cursor Up */ {VK_UP, 72, 0}, +/* Cursor Down */ {VK_DOWN, 80, 0}, +/* Cursor Right */ {VK_RIGHT, 77, 0}, +/* Cursor Left */ {VK_LEFT, 75, 0}, +/* End */ {VK_END, 79, 0}, +/* Home */ {VK_HOME, 71, 0}, +/* PageUp */ {VK_PRIOR, 73, 0}, +/* PageDown */ {VK_NEXT, 81, 0}, +/* Insert */ {VK_INSERT, 82, 0}, +/* Delete */ {VK_DELETE, 83, 0}, +/* Select */ {VK_SELECT, 0, 0}, +/* F1 */ {VK_F1, 59, 0}, +/* F2 */ {VK_F2, 60, 0}, +/* F3 */ {VK_F3, 61, 0}, +/* F4 */ {VK_F4, 62, 0}, +/* F5 */ {VK_F5, 63, 0}, +/* F6 */ {VK_F6, 64, 0}, +/* F7 */ {VK_F7, 65, 0}, +/* F8 */ {VK_F8, 66, 0}, +/* F9 */ {VK_F9, 67, 0}, +/* F10 */ {VK_F10, 68, 0}, +/* F11 */ {VK_F11, 87, 0}, +/* F12 */ {VK_F12, 88, 0}, +/* F13 */ {VK_F13, 0, 0}, +/* F14 */ {VK_F14, 0, 0}, +/* F15 */ {VK_F15, 0, 0}, +/* F16 */ {VK_F16, 0, 0}, +/* F17 */ {VK_F17, 0, 0}, +/* F18 */ {VK_F18, 0, 0}, +/* F19 */ {VK_F19, 0, 0}, +/* F20 */ {VK_F20, 0, 0}, +}; + +const DWORD KEY_CONTROL = 0; +const DWORD KEY_SHIFT = 1; +const DWORD KEY_LSHIFT = 1; +const DWORD KEY_RSHIFT = 2; +const DWORD KEY_ALT = 3; + +static void +SendIR(INPUT_RECORD *ir, CMclQueue &mQ) +{ + Message *msg = new Message; + msg->type = Message::TYPE_INRECORD; + msg->length = sizeof(INPUT_RECORD); // not needed + msg->bytes = ir; + mQ.Put(msg); +} + +static void +MapCharToIRs (UCHAR c, CMclQueue &mQ) +{ + UCHAR lc; + DWORD mods; + INPUT_RECORD *ir; + + lc = c < 128 ? c : c - 128; + mods = AsciiToKeyArray[lc].dwControlKeyState; + +#if 0 + if (mods & RIGHT_CTRL_PRESSED) { + /* First, generate a control key press */ + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = TRUE; + ir->Event.KeyEvent.wRepeatCount = 1; + ir->Event.KeyEvent.wVirtualKeyCode = + ModifierKeyArray[KEY_CONTROL].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + ModifierKeyArray[KEY_CONTROL].wVirtualScanCode; + ir->Event.KeyEvent.uChar.AsciiChar = 0; + ir->Event.KeyEvent.dwControlKeyState = RIGHT_CTRL_PRESSED; + SendIR(ir, mQ); + } + if (mods & SHIFT_PRESSED) { + /* First, generate a control key press */ + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = TRUE; + ir->Event.KeyEvent.wVirtualKeyCode = + ModifierKeyArray[KEY_SHIFT].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + ModifierKeyArray[KEY_SHIFT].wVirtualScanCode; + ir->Event.KeyEvent.uChar.AsciiChar = 0; + ir->Event.KeyEvent.dwControlKeyState = mods; + injectorIPC->Post(&ir); + } +#endif + + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = TRUE; + ir->Event.KeyEvent.wRepeatCount = 1; + ir->Event.KeyEvent.wVirtualKeyCode = + AsciiToKeyArray[lc].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + AsciiToKeyArray[lc].wVirtualScanCode; + ir->Event.KeyEvent.dwControlKeyState = + AsciiToKeyArray[lc].dwControlKeyState; + ir->Event.KeyEvent.uChar.AsciiChar = c; + SendIR(ir, mQ); + + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = FALSE; + ir->Event.KeyEvent.wRepeatCount = 1; + ir->Event.KeyEvent.wVirtualKeyCode = + AsciiToKeyArray[lc].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + AsciiToKeyArray[lc].wVirtualScanCode; + ir->Event.KeyEvent.dwControlKeyState = + AsciiToKeyArray[lc].dwControlKeyState; + ir->Event.KeyEvent.uChar.AsciiChar = c; + SendIR(ir, mQ); + +#if 0 + if (mods & SHIFT_PRESSED) { + /* First, generate a control key press */ + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = FALSE; + ir->Event.KeyEvent.wVirtualKeyCode = + ModifierKeyArray[KEY_SHIFT].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + ModifierKeyArray[KEY_SHIFT].wVirtualScanCode; + ir->Event.KeyEvent.uChar.AsciiChar = 0; + ir->Event.KeyEvent.dwControlKeyState = mods & ~SHIFT_PRESSED; + SendIR(ir, mQ); + } + if (mods & RIGHT_CTRL_PRESSED) { + /* First, generate a control key press */ + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = FALSE; + ir->Event.KeyEvent.wVirtualKeyCode = + ModifierKeyArray[KEY_CONTROL].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + ModifierKeyArray[KEY_CONTROL].wVirtualScanCode; + ir->Event.KeyEvent.uChar.AsciiChar = 0; + ir->Event.KeyEvent.dwControlKeyState = 0; + SendIR(ir, mQ); + } +#endif +} + +void +MapToKeys (Message *msg, CMclQueue &mQ) +{ + size_t i; + for (i = 0; i < msg->length; i++) { + MapCharToIRs(((PUCHAR)msg->bytes)[i], mQ); + } + delete msg; +} + +void +MapFKeyToIRs(DWORD fk, CMclQueue &mQ) +{ + INPUT_RECORD *ir; + + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = TRUE; + ir->Event.KeyEvent.wRepeatCount = 1; + ir->Event.KeyEvent.wVirtualKeyCode = + FunctionToKeyArray[fk].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + FunctionToKeyArray[fk].wVirtualScanCode; + ir->Event.KeyEvent.dwControlKeyState = + FunctionToKeyArray[fk].dwControlKeyState; + ir->Event.KeyEvent.uChar.AsciiChar = 0; + SendIR(ir, mQ); + + ir = new INPUT_RECORD; + ir->EventType = KEY_EVENT; + ir->Event.KeyEvent.bKeyDown = FALSE; + ir->Event.KeyEvent.wRepeatCount = 1; + ir->Event.KeyEvent.wVirtualKeyCode = + FunctionToKeyArray[fk].wVirtualKeyCode; + ir->Event.KeyEvent.wVirtualScanCode = + FunctionToKeyArray[fk].wVirtualScanCode; + ir->Event.KeyEvent.dwControlKeyState = + FunctionToKeyArray[fk].dwControlKeyState; + ir->Event.KeyEvent.uChar.AsciiChar = 0; + SendIR(ir, mQ); +} Index: win/expWinDynloadTclStubs.cpp ================================================================== --- win/expWinDynloadTclStubs.cpp +++ win/expWinDynloadTclStubs.cpp @@ -13,18 +13,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.sf.net/ * http://expect.nist.gov/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinDynloadTclStubs.cpp,v 1.1.2.1 2002/03/12 18:41:38 davygrvy Exp $ + * RCS: @(#) $Id: expWinDynloadTclStubs.cpp,v 1.1.2.2 2002/03/12 21:06:51 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "tcl.h" Index: win/expWinInit.c ================================================================== --- win/expWinInit.c +++ win/expWinInit.c @@ -13,18 +13,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinInit.c,v 1.1.4.3 2002/02/11 09:56:00 davygrvy Exp $ + * RCS: @(#) $Id: expWinInit.c,v 1.1.4.4 2002/02/16 03:16:59 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinInt.h" ADDED win/expWinInjectorIPC.hpp Index: win/expWinInjectorIPC.hpp ================================================================== --- /dev/null +++ win/expWinInjectorIPC.hpp @@ -0,0 +1,38 @@ +/* ---------------------------------------------------------------------------- + * expWinInjectorIPC.hpp -- + * + * CMclMailbox values saved to a common include file to avoid + * differences in the constructor calls on either end of the IPC + * connection phase. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: expWinInjectorIPC.hpp,v 1.1.2.2 2002/06/28 02:00:56 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#ifndef INC_expWinInjectorIPC_hpp__ +#define INC_expWinInjectorIPC_hpp__ + +#define IPC_NUMSLOTS 80 +#define IPC_SLOTSIZE sizeof(INPUT_RECORD) + +#endif ADDED win/expWinInjectorMain.cpp Index: win/expWinInjectorMain.cpp ================================================================== --- /dev/null +++ win/expWinInjectorMain.cpp @@ -0,0 +1,126 @@ +/* ---------------------------------------------------------------------------- + * expWinInjectorMain.cpp -- + * + * Console event injector DLL that's loaded into the slave's address space + * used by the ConsoleDebugger class for "writing" to the slave. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: expWinInjectorMain.cpp,v 1.1.2.15 2003/08/25 23:17:49 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#include "CMcl.h" +#include "expWinInjectorIPC.hpp" + +class Injector : public CMclThreadHandler +{ + CMclMailbox *ConsoleDebuggerIPC; + HANDLE console; + CMclEvent *interrupt; + char sysMsgSpace[512]; + +public: + + Injector(HANDLE _console, CMclEvent *_interrupt) + : console(_console), interrupt(_interrupt), ConsoleDebuggerIPC(0L) + {} + + ~Injector() {} + +private: + + virtual unsigned ThreadHandlerProc(void) + { + CHAR boxName[50]; + DWORD err, dwWritten; + INPUT_RECORD ir; + + wsprintf(boxName, "ExpectInjector_pid%d", GetCurrentProcessId()); + + // Create the shared memory IPC transfer mechanism by name + // (a mailbox). + ConsoleDebuggerIPC = + new CMclMailbox(IPC_NUMSLOTS, IPC_SLOTSIZE, boxName); + + // Check status. + err = ConsoleDebuggerIPC->Status(); + if (err != NO_ERROR && err != ERROR_ALREADY_EXISTS) { + OutputDebugString(GetSysMsg(err)); + delete ConsoleDebuggerIPC; + return 0x666; + } + + OutputDebugString("Expect's injector DLL loaded and ready.\n"); + + // forever loop receiving INPUT_RECORDs over IPC. + while (ConsoleDebuggerIPC->GetAlertable(&ir, interrupt)) { + // Stuff it into our slave console as if it had been entered + // by the user. + WriteConsoleInput(console, &ir, 1, &dwWritten); + } + + delete ConsoleDebuggerIPC; + return 0; + } + + const char *GetSysMsg(DWORD id) + { + int chars; + + chars = wsprintf(sysMsgSpace, + "Expect's injector DLL could not start IPC: [%u] ", id); + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, id, 0, + sysMsgSpace+chars, (512-chars), 0); + return sysMsgSpace; + } +}; + +CMclEvent *interrupt; +CMclThread *injectorThread; +Injector *inject; +HANDLE console; + +BOOL WINAPI +DllMain (HINSTANCE hInst, ULONG ulReason, LPVOID lpReserved) +{ + switch (ulReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hInst); + console = CreateFile("CONIN$", GENERIC_WRITE, + FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); + interrupt = new CMclEvent(); + inject = new Injector(console, interrupt); + injectorThread = new CMclThread(inject); + break; + case DLL_PROCESS_DETACH: + interrupt->Set(); + injectorThread->Wait(INFINITE); + CloseHandle(console); + delete interrupt; + delete injectorThread; + delete inject; + break; + } + return TRUE; +} Index: win/expWinInt.h ================================================================== --- win/expWinInt.h +++ win/expWinInt.h @@ -13,18 +13,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinInt.h,v 1.1.4.5 2002/03/09 01:17:29 davygrvy Exp $ + * RCS: @(#) $Id: expWinInt.h,v 1.1.4.7 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef _EXPWININT #define _EXPWININT @@ -46,18 +47,15 @@ # include "expPort.h" #endif #undef TCL_STORAGE_CLASS #if defined(BUILD_slavedriver) -# define TCL_STORAGE_CLASS -# include "expWinSlave.hpp" -# ifdef _DEBUG -# include "MsvcDbgControl.h" -# endif -# include "slavedrvmc.h" +//# define TCL_STORAGE_CLASS +//# include "expWinSlave.hpp" #elif defined(BUILD_exp) # define TCL_STORAGE_CLASS DLLEXPORT +# include "slavedrvmc.h" /* error code constants */ #else # ifdef USE_EXP_STUBS # define TCL_STORAGE_CLASS # else # define TCL_STORAGE_CLASS DLLIMPORT @@ -129,14 +127,14 @@ BOOL (WINAPI *getEnvironmentVariableProc)(LPCTSTR, LPTSTR, DWORD); LONG (WINAPI *regSetValueExProc)(HKEY, LPCTSTR, DWORD, DWORD, CONST BYTE *, DWORD); } ExpWinProcs; -extern TCL_CPP ExpWinProcs *expWinProcs; +TCL_EXTRNC ExpWinProcs *expWinProcs; #include "expIntPlatDecls.h" #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLIMPORT #endif /* _EXPWININT */ Index: win/expWinLog.c ================================================================== --- win/expWinLog.c +++ win/expWinLog.c @@ -15,18 +15,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinLog.c,v 1.1.2.1.2.2 2002/02/10 12:03:30 davygrvy Exp $ + * RCS: @(#) $Id: expWinLog.c,v 1.1.2.1.2.3 2002/03/09 05:48:51 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinInt.h" Index: win/expWinMessage.cpp ================================================================== --- win/expWinMessage.cpp +++ win/expWinMessage.cpp @@ -14,27 +14,39 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinMessage.cpp,v 1.1.2.4 2002/03/15 07:41:45 davygrvy Exp $ + * RCS: @(#) $Id: expWinMessage.cpp,v 1.1.2.8 2002/06/23 09:24:03 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinMessage.hpp" Message::Message() : bytes(0L), length(0), type(TYPE_BLANK) { } + +Message::~Message() +{ + switch (type) { + case TYPE_NORMAL: + case TYPE_ERROR: + case TYPE_WARNING: + case TYPE_INRECORD: + delete [] bytes; + } +} Message::Message(Message &other) { type = other.type; bytes = other.bytes; Index: win/expWinMessage.hpp ================================================================== --- win/expWinMessage.hpp +++ win/expWinMessage.hpp @@ -14,18 +14,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinMessage.hpp,v 1.1.2.4 2002/03/15 07:41:45 davygrvy Exp $ + * RCS: @(#) $Id: expWinMessage.hpp,v 1.1.2.9 2002/06/28 01:26:57 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef INC_expWinMessage_hpp__ #define INC_expWinMessage_hpp__ @@ -34,14 +35,26 @@ class Message { public: Message(); + ~Message(); Message(Message &); - enum Mode {TYPE_BLANK, TYPE_NORMAL, TYPE_ERROR, TYPE_INSTREAM, TYPE_FUNCTION, TYPE_SLAVEDONE}; + enum Mode { + TYPE_BLANK, + TYPE_NORMAL, + TYPE_ERROR, + TYPE_WARNING, + TYPE_INSTREAM, + TYPE_INRECORD, + TYPE_ENTERINTERACT, + TYPE_EXITINTERACT, + TYPE_SLAVEDONE + }; + Mode type; size_t length; - unsigned char *bytes; + void *bytes; }; #endif Index: win/expWinPort.h ================================================================== --- win/expWinPort.h +++ win/expWinPort.h @@ -14,18 +14,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinPort.h,v 1.1.2.1.2.4 2002/02/11 09:56:00 davygrvy Exp $ + * RCS: @(#) $Id: expWinPort.h,v 1.1.2.1.2.5 2002/03/08 23:33:13 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef _EXPWINPORT #define _EXPWINPORT Index: win/expWinProcess.c ================================================================== --- win/expWinProcess.c +++ win/expWinProcess.c @@ -14,18 +14,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinProcess.c,v 1.1.2.1.2.7 2002/03/08 23:31:18 davygrvy Exp $ + * RCS: @(#) $Id: expWinProcess.c,v 1.1.2.1.2.8 2002/03/09 05:48:51 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinInt.h" Index: win/expWinSlave.hpp ================================================================== --- win/expWinSlave.hpp +++ win/expWinSlave.hpp @@ -14,18 +14,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinSlave.hpp,v 1.1.4.9 2002/03/12 21:07:00 davygrvy Exp $ + * RCS: @(#) $Id: expWinSlave.hpp,v 1.1.4.15 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef INC_expWinSlave_hpp__ #define INC_expWinSlave_hpp__ @@ -33,13 +34,18 @@ void DynloadTclStubs (void); void ShutdownTcl (void); -#include "Mcl/include/CMcl.h" +#include "CMcl.h" #include "slavedrvmc.h" #include "expWinUtils.hpp" #include "expWinMessage.hpp" -#include "expWinSpawnClient.hpp" +#include "expWinTestClient.hpp" +#include "expWinConsoleDebugger.hpp" +//#include "expWinConsoleDetour.hpp" #include "expWinSlaveTrap.hpp" + +void MapToKeys (Message *msg, CMclQueue &mQ); + #endif // INC_expWinSlave_hpp__ Index: win/expWinSlaveMain.cpp ================================================================== --- win/expWinSlaveMain.cpp +++ win/expWinSlaveMain.cpp @@ -1,9 +1,9 @@ /* ---------------------------------------------------------------------------- * expWinSlaveMain.cpp -- * - * Program entry for the Win32 slave driver helper application. + * Program entry for the Win32 slave tester application. * * ---------------------------------------------------------------------------- * * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 * @@ -13,28 +13,29 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinSlaveMain.cpp,v 1.1.4.16 2002/03/15 07:41:45 davygrvy Exp $ + * RCS: @(#) $Id: expWinSlaveMain.cpp,v 1.1.4.28 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinSlave.hpp" // local protos -static SpawnClientTransport *SpawnOpenClientTransport(const char *, CMclQueue &); +static TestClient *OpenTestClient(const char *, CMclQueue &); static SlaveTrap *SlaveOpenTrap(const char *, int, char * const *, CMclQueue &); -static int DoEvents(SpawnClientTransport *, SlaveTrap *, CMclQueue &, CMclEvent &); +static int DoEvents(TestClient *, SlaveTrap *, CMclQueue &); static char *OurGetCmdLine(); // Turns on/off special debugger hooks used in development. // #ifndef IDE_LATCHED @@ -45,14 +46,13 @@ int main (void) { int argc; // Number of command-line arguments. char **argv; // Values of command-line arguments. - SpawnClientTransport *transport;// class pointer of transport client. - SlaveTrap *slaveCtrl; // trap method class pointer. + TestClient *client; // class pointer of transport client. + SlaveTrap *slave; // trap method class pointer. CMclQueue messageQ; // Our message Queue we hand off to everyone. - CMclEvent Shutdown; // global shutdown for the event queue. int code; // exitcode. CHAR *cmdLine; // commandline to use. // We need a few Tcl APIs in here. Load it now. // @@ -73,30 +73,30 @@ } // Open the client side of our IPC transport that connects us back // to the parent (ie. the Expect extension). // - transport = SpawnOpenClientTransport(argv[1], messageQ); + client = OpenTestClient(argv[1], messageQ); // Start the process to be intercepted within the trap method requested // on the commandline (ie. run telnet in a debugger and trap OS calls). // - slaveCtrl = SlaveOpenTrap(argv[2], argc-3, &argv[3], messageQ); + slave = SlaveOpenTrap(argv[2], argc-3, &argv[3], messageQ); // Process messages. // - code = DoEvents(transport, slaveCtrl, messageQ, Shutdown); + code = DoEvents(client, slave, messageQ); // Close up. // ShutdownTcl(); return code; } /* *---------------------------------------------------------------------- - * SpawnOpenTransport -- + * OpenTestClient -- * * The factory method for creating the client IPC transport from * the name asked of it. * * Returns: @@ -103,15 +103,21 @@ * a polymorphed SpawnClientTransport pointer or die. * *---------------------------------------------------------------------- */ -SpawnClientTransport * -SpawnOpenClientTransport(const char *method, CMclQueue &mQ) +TestClient * +OpenTestClient(const char *method, CMclQueue &mQ) { if (!strcmp(method, "stdio")) { - return new SpawnStdioClient(method, mQ); + return new ClientStdio(mQ); + } + else if (!strcmp(method, "conio")) { + return new ClientConio(mQ); + } + else if (!strcmp(method, "interact")) { + return new ClientInteract(mQ); } else EXP_LOG1(MSG_IO_TRANSPRTARGSBAD, method); // not reached. return 0L; @@ -122,11 +128,11 @@ * SlaveOpenTrap -- * * The factory method for creating the trap class instance. * * Returns: - * a polymorphed SpawnTrap pointer or die. + * a polymorphed SlaveTrap pointer or die. * *---------------------------------------------------------------------- */ SlaveTrap * @@ -134,10 +140,13 @@ CMclQueue &mQ) { if (!strcmp(method, "dbg")) { return new SlaveTrapDbg(argc, argv, mQ); } +// else if (!strcmp(method, "detour")) { +// return new SlaveTrapDetour(argc, argv, mQ); +// } else EXP_LOG1(MSG_IO_TRAPARGSBAD, method); // not reached. return 0L; } @@ -154,42 +163,47 @@ * *---------------------------------------------------------------------- */ int -DoEvents(SpawnClientTransport *transport, SlaveTrap *slaveCtrl, - CMclQueue &mQ, CMclEvent &sd) +DoEvents(TestClient *client, SlaveTrap *slave, CMclQueue &msgQ) { Message *msg; - while (mQ.Get(msg, INFINITE)) { + while (msgQ.Get(msg, INFINITE)) { switch (msg->type) { case Message::TYPE_NORMAL: + case Message::TYPE_WARNING: case Message::TYPE_ERROR: // Send stuff back to the parent. // - transport->Write(msg); + client->Write(msg); + break; + + case Message::TYPE_INRECORD: + case Message::TYPE_ENTERINTERACT: + case Message::TYPE_EXITINTERACT: + // Send stuff to the slave. + // + slave->Write(msg); break; case Message::TYPE_INSTREAM: - // Send stuff to the slave. - // - slaveCtrl->Write(msg); - break; - - case Message::TYPE_FUNCTION: - // Internal mode switching and info gathering. - // + // Do char to keypress conversion here. + // These get reposted back as TYPE_INRECORD messages. + // + MapToKeys(msg, msgQ); break; case Message::TYPE_SLAVEDONE: - //delete slaveCtrl; - Sleep(500); // bad hack, please ignore for now. + delete slave; + delete client; + // Returning the exitcode of the slave is not yet supported. + // return 0; } } - //delete transport, slaveCtrl; return 0; } /* *---------------------------------------------------------------------- @@ -250,12 +264,12 @@ itoa(pid, pidChar, 10); RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Tomasoft\\MsDevDbgCtrl", 0, KEY_ALL_ACCESS, &root); RegQueryValueEx(root, pidChar, 0, &type, 0L, &size); - buf = (CHAR *) HeapAlloc(GetProcessHeap(), 0, size); + buf = new CHAR [size]; RegQueryValueEx(root, pidChar, 0, &type, (LPBYTE) buf, &size); RegDeleteValue(root, pidChar); RegCloseKey(root); return buf; } #endif // _DEBUG && _MSC_VER && IDE_LATCHED Index: win/expWinSlaveTrap.hpp ================================================================== --- win/expWinSlaveTrap.hpp +++ win/expWinSlaveTrap.hpp @@ -1,9 +1,10 @@ /* ---------------------------------------------------------------------------- * expWinSlaveTrap.hpp -- * - * Declares the SlaveTrap classes. + * Declares the SlaveTrap classes which are our "invokation + * managers" of the trap method we run in a thread. * * ---------------------------------------------------------------------------- * * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 * @@ -13,38 +14,61 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinSlaveTrap.hpp,v 1.1.2.1 2002/03/12 07:09:36 davygrvy Exp $ + * RCS: @(#) $Id: expWinSlaveTrap.hpp,v 1.1.2.5 2002/07/03 02:47:44 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #ifndef INC_expWinSlaveTrap_hpp__ #define INC_expWinSlaveTrap_hpp__ -#include "expWinMessage.hpp" -#include "Mcl/include/CMcl.h" - class SlaveTrap { public: + virtual ~SlaveTrap() {}; virtual void Write(Message *) = 0; }; - -class SlaveTrapDbg : public SlaveTrap { +// This uses the debugger method by setting breakpoints on all calls the +// process makes to the console API and running the process within the +// native OS debugger. See expWinConsoleDebugger.hpp for the details of +// what we run in the thread. +// +class SlaveTrapDbg : public SlaveTrap +{ public: SlaveTrapDbg(int argc, char * const argv[], CMclQueue &_mQ); + virtual ~SlaveTrapDbg(); + virtual void Write(Message *); + +private: + ConsoleDebugger *debugger; + CMclQueue &mQ; + CMclThread *debuggerThread; +}; + +// This uses the detour method by rewriting the import directory of the +// processes' image (in memory) so as to pass though us. This method +// doesn't require the debugger APIs. See expWinConsoleDetour.hpp for +// more detials. +// +class SlaveTrapDetour : public SlaveTrap +{ +public: + SlaveTrapDetour(int argc, char * const argv[], CMclQueue &_mQ); + virtual ~SlaveTrapDetour(); virtual void Write(Message *); + private: CMclQueue &mQ; - CMclThreadAutoPtr debuggerThread; }; #endif Index: win/expWinSlaveTrapDbg.cpp ================================================================== --- win/expWinSlaveTrapDbg.cpp +++ win/expWinSlaveTrapDbg.cpp @@ -20,31 +20,55 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinSlaveTrapDbg.cpp,v 1.1.4.9 2002/03/13 03:52:57 davygrvy Exp $ + * RCS: @(#) $Id: expWinSlaveTrapDbg.cpp,v 1.1.4.13 2002/06/28 01:26:57 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinSlave.hpp" -#include "expWinConsoleDebugger.hpp" SlaveTrapDbg::SlaveTrapDbg(int argc, char * const argv[], CMclQueue &_mQ) : mQ(_mQ) { - debuggerThread = new CMclThread(new ConsoleDebugger(argc, argv, _mQ)); + debugger = new ConsoleDebugger(argc, argv, _mQ); + debuggerThread = new CMclThread(debugger); +} + +SlaveTrapDbg::~SlaveTrapDbg() +{ + DWORD exitCode; + + debuggerThread->GetExitCode(&exitCode); + if (exitCode == STILL_ACTIVE) { + debuggerThread->Terminate(128); + } + delete debuggerThread, debugger; } void SlaveTrapDbg::Write(Message *msg) { - // inject it from here.. how? - delete [] msg->bytes; + switch (msg->type) { + case Message::TYPE_ENTERINTERACT: + debugger->EnterInteract(static_cast(msg->bytes)); + break; + + case Message::TYPE_EXITINTERACT: + debugger->ExitInteract(); + break; + + case Message::TYPE_INRECORD: + debugger->WriteRecord(static_cast(msg->bytes)); + break; + } + delete msg; } Index: win/expWinSpawnChan.c ================================================================== --- win/expWinSpawnChan.c +++ win/expWinSpawnChan.c @@ -14,18 +14,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: exp.h,v 1.1.4.4 2002/02/10 10:17:04 davygrvy Exp $ + * RCS: @(#) $Id: expWinSpawnChan.c,v 1.1.2.1.2.3 2002/02/10 12:03:30 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinInt.h" DELETED win/expWinSpawnClient.hpp Index: win/expWinSpawnClient.hpp ================================================================== --- win/expWinSpawnClient.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/* ---------------------------------------------------------------------------- - * expWinSpawnClient.hpp -- - * - * Declares the SpawnClient classes. - * - * ---------------------------------------------------------------------------- - * - * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 - * - * Design and implementation of this program was paid for by U.S. tax - * dollars. Therefore it is public domain. However, the author and NIST - * would appreciate credit if this program or parts of it are used. - * - * Copyright (c) 1997 Mitel Corporation - * work by Gordon Chaffee for the WinNT port. - * - * Copyright (c) 2001-2002 Telindustrie, LLC - * work by David Gravereaux for any Win32 OS. - * - * ---------------------------------------------------------------------------- - * URLs: http://expect.nist.gov/ - * http://expect.sf.net/ - * http://bmrc.berkeley.edu/people/chaffee/expectnt.html - * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinSpawnClient.hpp,v 1.1.2.2 2002/03/12 21:34:16 davygrvy Exp $ - * ---------------------------------------------------------------------------- - */ - -#include "expWinMessage.hpp" -#include "Mcl/include/CMcl.h" - -class SpawnClientTransport -{ -public: - virtual void Write(Message *) = 0; -}; - -class SpawnMailboxClient : public SpawnClientTransport -{ -public: - SpawnMailboxClient(const char *name, CMclQueue &_mQ); - virtual void Write(Message *); -private: - CMclMailbox *MasterToExpect; - CMclMailbox *MasterFromExpect; - CMclQueue &mQ; -}; - -class ReadPipe : public CMclThreadHandler -{ -public: - ReadPipe(CMclQueue &_mQ); -private: - virtual unsigned ThreadHandlerProc(void); - CMclQueue &mQ; - HANDLE hStdIn; -}; - -class SpawnStdioClient : public SpawnClientTransport -{ -public: - SpawnStdioClient(const char *name, CMclQueue &_mQ); - ~SpawnStdioClient(); - virtual void Write(Message *); -private: - CMclQueue &mQ; - HANDLE hStdOut; - HANDLE hStdErr; - ReadPipe *reader; - CMclThreadAutoPtr readThread; -}; DELETED win/expWinSpawnStdioClient.cpp Index: win/expWinSpawnStdioClient.cpp ================================================================== --- win/expWinSpawnStdioClient.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* ---------------------------------------------------------------------------- - * expWinSpawnStdioClient.cpp -- - * - * Simple standard IO as our IPC mechanism. - * - * ---------------------------------------------------------------------------- - * - * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 - * - * Design and implementation of this program was paid for by U.S. tax - * dollars. Therefore it is public domain. However, the author and NIST - * would appreciate credit if this program or parts of it are used. - * - * Copyright (c) 1997 Mitel Corporation - * work by Gordon Chaffee for the WinNT port. - * - * Copyright (c) 2001-2002 Telindustrie, LLC - * work by David Gravereaux for any Win32 OS. - * - * ---------------------------------------------------------------------------- - * URLs: http://expect.nist.gov/ - * http://expect.sf.net/ - * http://bmrc.berkeley.edu/people/chaffee/expectnt.html - * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinSpawnStdioClient.cpp,v 1.1.2.1 2002/03/12 21:33:26 davygrvy Exp $ - * ---------------------------------------------------------------------------- - */ - -#include "expWinSpawnClient.hpp" - - - -SpawnStdioClient::SpawnStdioClient(const char *name, CMclQueue &_mQ) - : mQ(_mQ) -{ - hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - hStdErr = GetStdHandle(STD_ERROR_HANDLE); - reader = new ReadPipe(_mQ); - readThread = new CMclThread(reader); -} - -SpawnStdioClient::~SpawnStdioClient() -{ - DWORD dwExit; - - readThread->GetExitCode(&dwExit); - if (dwExit == STILL_ACTIVE) { - // by cute convention, terminate threads with a 666. - // - readThread->Terminate(666); - } - delete reader; -} - -void -SpawnStdioClient::Write(Message *what) -{ - DWORD dwWritten; - HANDLE where; - - switch (what->type) { - case Message::TYPE_NORMAL: - where = hStdOut; - case Message::TYPE_ERROR: - where = hStdErr; - } - WriteFile(where, what->bytes, what->length, &dwWritten, 0L); -} - -ReadPipe::ReadPipe(CMclQueue &_mQ) - : mQ(_mQ) -{ - hStdIn = GetStdHandle(STD_INPUT_HANDLE); -} - -#define READ_BUFFER_SIZE 128 - -unsigned ReadPipe::ThreadHandlerProc(void) -{ - BOOL ok; - DWORD dwRead; - Message *msg; - BYTE *readBuf; - -again: - readBuf = new BYTE [READ_BUFFER_SIZE]; - ok = ReadFile(hStdIn, readBuf, READ_BUFFER_SIZE, &dwRead, 0L); - if (!ok || dwRead == 0) { - CloseHandle(hStdIn); // <- should this be here? - delete [] readBuf; - goto done; - } - msg = new Message; - msg->bytes = readBuf; - msg->length = dwRead; - msg->type = Message::TYPE_INSTREAM; - mQ.Put(msg); - goto again; - -done: - return 0; -} Index: win/expWinTest.cpp ================================================================== --- win/expWinTest.cpp +++ win/expWinTest.cpp @@ -1,22 +1,23 @@ -#include "TclAdapter.hpp" +#include "TclAdaptor.hpp" #include "expWinUtils.hpp" -class Test1 : protected Tcl::Adapter, ArgMaker -{ -public: - Test1(Tcl_Interp *_interp) : Tcl::Adapter(_interp) { - NewTclCmd(interp, "test_buildcmdline", TestCmdLineCmd); - NewTclCmd(interp, "test_passthru", TestPassThruCmd); - }; - virtual void DoCleanup () { - // The adapter base class is telling us we are about to go away and it is - // safe to use the interp pointer to do any needed cleanup. - }; +class Test1 : protected Tcl::Adaptor, ArgMaker +{ + friend Tcl::Adaptor; + +public: + Test1(Tcl_Interp *_interp) + : Tcl::Adaptor(_interp) + { + NewTclCmd("test_buildcmdline", TestCmdLineCmd); + NewTclCmd("test_passthru", TestPassThruCmd); + } ~Test1() { // can't use interp pointer in here. - }; + } + private: // Test the ArgMaker::BuildCommandLine() function. // int TestCmdLineCmd (int objc, struct Tcl_Obj * CONST objv[]) { @@ -28,10 +29,11 @@ line = BuildCommandLine(objc-1, argv); Tcl_SetObjResult(interp, Tcl_NewStringObj(line, -1)); delete [] line; return TCL_OK; } + // Test the full pass-thru // int TestPassThruCmd (int objc, struct Tcl_Obj * CONST objv[]) { char **argvIn = new char * [objc-1]; @@ -48,10 +50,15 @@ oobjv = new Tcl_Obj * [argc]; for (i = 0; i < argc; i++) oobjv[i] = Tcl_NewStringObj(argv[i], -1); Tcl_SetObjResult(interp, Tcl_NewListObj(argc, oobjv)); return TCL_OK; } + + virtual void DoCleanup () { + // The adapter base class is telling us we are about to go away and it is + // safe to use the interp pointer to do any needed cleanup. + }; }; // tell the EXTERN macro we want to declare functions for export. #undef TCL_STORAGE_CLASS #define TCL_STORAGE_CLASS DLLEXPORT ADDED win/expWinTestClient.hpp Index: win/expWinTestClient.hpp ================================================================== --- /dev/null +++ win/expWinTestClient.hpp @@ -0,0 +1,86 @@ +/* ---------------------------------------------------------------------------- + * expWinTestClient.hpp -- + * + * Declares all the TestClient classes. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: expWinTestClient.hpp,v 1.1.2.4 2003/08/25 23:17:49 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#include "expWinMessage.hpp" +#include "CMcl.h" + +class TestClient +{ +public: + virtual ~TestClient() {}; + virtual void Write(Message *) = 0; +}; + + +// Forward reference. +class ReadPipe; +class ReadCon; +class ReadConWithSwitching; + +class ClientStdio : public TestClient +{ +public: + ClientStdio(CMclQueue &_mQ); + virtual ~ClientStdio(); + virtual void Write(Message *); +private: + CMclQueue &mQ; + HANDLE hStdOut; + HANDLE hStdErr; + ReadPipe *reader; + CMclThreadAutoPtr readThread; +}; + +class ClientConio : public TestClient +{ +public: + ClientConio(CMclQueue &_mQ); + virtual ~ClientConio(); + virtual void Write(Message *); +private: + CMclQueue &mQ; + HANDLE ConOut, ConIn, oldBuffer; + ReadCon *reader; + CMclEvent Stop; + CMclThread *readThread; +}; + +class ClientInteract : public TestClient +{ +public: + ClientInteract(CMclQueue &_mQ); + virtual ~ClientInteract(); + virtual void Write(Message *); +private: + CMclQueue &mQ; + HANDLE ConOut, ConIn, ConInteract, oldBuffer; + ReadConWithSwitching *reader; + CMclEvent Stop; + CMclThread *readThread; +}; ADDED win/expWinTestClientConio.cpp Index: win/expWinTestClientConio.cpp ================================================================== --- /dev/null +++ win/expWinTestClientConio.cpp @@ -0,0 +1,190 @@ +/* ---------------------------------------------------------------------------- + * expWinTestClientConio.cpp -- + * + * Simple console I/O as our client. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: expWinTestClientConio.cpp,v 1.1.2.3 2002/06/29 00:44:36 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#include "expWinTestClient.hpp" + +class ReadCon : public CMclThreadHandler +{ + CMclQueue &mQ; + CMclEvent &Stop; + HANDLE ConIn; + CMclWaitableCollection groupedHandles; +# define RECORD_SIZE 15 + +public: + ReadCon(CMclQueue &_mQ, CMclEvent &_Stop, HANDLE _ConIn) + : mQ(_mQ), Stop(_Stop), ConIn(_ConIn) + { + // Turn on mouse and window events, too. + SetConsoleMode(ConIn, ENABLE_MOUSE_INPUT); + } + + ~ReadCon() + { + } + +private: + virtual unsigned ThreadHandlerProc(void) + { + DWORD dwRet, dwRead, i; + INPUT_RECORD Records[RECORD_SIZE], *record; + MOUSE_EVENT_RECORD lastMouse; + Message *msg; + + // Index 0, highest priority goes first. + groupedHandles.AddObject(Stop); + + // Console handles are waitable objects. + // Index 1 + groupedHandles.AddObject(ConIn); + + again: + // Wait for any (either) to signal. + dwRet = groupedHandles.Wait(FALSE, INFINITE); + + if (!CMclWaitSucceeded(dwRet, 2) || + CMclWaitSucceeded(dwRet, 2) && CMclWaitSucceededIndex(dwRet) == 0) { + // stop event or some other error, so die. + return 0; + } + + ReadConsoleInput(ConIn, Records, RECORD_SIZE, &dwRead); + for (i = 0; i < dwRead; i++) { + switch (Records[i].EventType) { + case FOCUS_EVENT: + case MENU_EVENT: + // ignore these. + continue; + + case MOUSE_EVENT: + // only send a mouse event if it's different then the last one. + if (!isDiff(&lastMouse, &Records[i].Event.MouseEvent)) { + continue; + } + lastMouse = Records[i].Event.MouseEvent; + break; + } + msg = new Message; + msg->type = Message::TYPE_INRECORD; + msg->length = sizeof(INPUT_RECORD); + record = new INPUT_RECORD; + memcpy(record, &Records[i], sizeof(INPUT_RECORD)); + msg->bytes = (BYTE *)record; + mQ.Put(msg); + } + goto again; + } + + BOOL + isDiff(MOUSE_EVENT_RECORD *mer1, MOUSE_EVENT_RECORD *mer2) + { + if ( + mer1->dwMousePosition.X ^ mer2->dwMousePosition.X || + mer1->dwMousePosition.Y ^ mer2->dwMousePosition.Y || + mer1->dwButtonState ^ mer2->dwButtonState || + mer1->dwControlKeyState ^ mer2->dwControlKeyState || + mer1->dwEventFlags ^ mer2->dwEventFlags + ) { + return TRUE; + } else { + return FALSE; + } + + } +}; + + +ClientConio::ClientConio(CMclQueue &_mQ) + : mQ(_mQ), Stop() +{ + COORD Size = {80, 500}; + + ConIn = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); + + reader = new ReadCon(_mQ, Stop, ConIn); + readThread = new CMclThread(reader); + + oldBuffer = CreateFile("CONOUT$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); + ConOut = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, CONSOLE_TEXTMODE_BUFFER, 0L); +// SetConsoleCtrlHandler(ConsoleHandler, TRUE); + SetConsoleActiveScreenBuffer(ConOut); + SetConsoleScreenBufferSize(ConOut, Size); +} + +ClientConio::~ClientConio() +{ + DWORD dwRead; + INPUT_RECORD record; + + Stop.Set(); + readThread->Wait(INFINITE); + delete reader, readThread; + + SetConsoleTextAttribute(ConOut, FOREGROUND_BLUE | FOREGROUND_INTENSITY); + WriteConsole(ConOut, "\nPress any key to exit...\n", 26, &dwRead, 0L); + FlushConsoleInputBuffer(ConIn); + +again: + ReadConsoleInput(ConIn, &record, 1, &dwRead); + if (record.EventType != KEY_EVENT) { + goto again; + } + + SetConsoleActiveScreenBuffer(oldBuffer); + CloseHandle(ConOut); + CloseHandle(ConIn); +} + +void +ClientConio::Write(Message *what) +{ + WORD color; + DWORD dwWritten; + + switch (what->type) { + case Message::TYPE_NORMAL: + // grey + color = FOREGROUND_BLUE |FOREGROUND_GREEN | FOREGROUND_RED; + break; + case Message::TYPE_WARNING: + // bright yellow + color = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + case Message::TYPE_ERROR: + // bright red + color = FOREGROUND_RED | FOREGROUND_INTENSITY; + break; + } + SetConsoleTextAttribute(ConOut, color); + WriteConsole(ConOut, what->bytes, what->length, &dwWritten, 0L); + delete what; +} ADDED win/expWinTestClientInteract.cpp Index: win/expWinTestClientInteract.cpp ================================================================== --- /dev/null +++ win/expWinTestClientInteract.cpp @@ -0,0 +1,153 @@ +/* ---------------------------------------------------------------------------- + * expWinTestClientInteract.cpp -- + * + * This tests the interact capabilities. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: expWinTestClientInteract.cpp,v 1.1.2.3 2002/07/03 02:48:22 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#include "expWinTestClient.hpp" + +class ReadConWithSwitching : public CMclThreadHandler +{ + CMclQueue &mQ; + CMclEvent &Stop; + HANDLE ConIn; + CMclWaitableCollection groupedHandles; +# define RECORD_SIZE 15 + +public: + ReadConWithSwitching(CMclQueue &_mQ, CMclEvent &_Stop, HANDLE _ConIn) + : mQ(_mQ), Stop(_Stop), ConIn(_ConIn) + { + // Turn on mouse and window events, too. + SetConsoleMode(ConIn, ENABLE_MOUSE_INPUT); + } + + ~ReadConWithSwitching() + { + } + +private: + virtual unsigned ThreadHandlerProc(void) + { + DWORD dwRet, dwRead, i; + INPUT_RECORD Records[RECORD_SIZE], *record; + MOUSE_EVENT_RECORD lastMouse; + Message *msg; + + // Index 0, highest priority goes first. + groupedHandles.AddObject(Stop); + + // Console handles are waitable objects. + // Index 1 + groupedHandles.AddObject(ConIn); + + again: + // Wait for any (either) to signal. + dwRet = groupedHandles.Wait(FALSE, INFINITE); + + if (!CMclWaitSucceeded(dwRet, 2) || + CMclWaitSucceeded(dwRet, 2) && CMclWaitSucceededIndex(dwRet) == 0) { + // stop event or some other error, so die. + return 0; + } + + ReadConsoleInput(ConIn, Records, RECORD_SIZE, &dwRead); + for (i = 0; i < dwRead; i++) { + switch (Records[i].EventType) { + case FOCUS_EVENT: + case MENU_EVENT: + case WINDOW_BUFFER_SIZE_EVENT: + // ignore these. + continue; + + case MOUSE_EVENT: + // only send a mouse event if it's different then the last one. + if (!isDiff(&lastMouse, &Records[i].Event.MouseEvent)) { + continue; + } + lastMouse = Records[i].Event.MouseEvent; + break; + + case KEY_EVENT: + break; + } + msg = new Message; + msg->type = Message::TYPE_INRECORD; + msg->length = sizeof(INPUT_RECORD); + record = new INPUT_RECORD; + memcpy(record, &Records[i], sizeof(INPUT_RECORD)); + msg->bytes = record; + mQ.Put(msg); + } + goto again; + } + + BOOL + isDiff(MOUSE_EVENT_RECORD *mer1, MOUSE_EVENT_RECORD *mer2) + { + if ( + mer1->dwMousePosition.X ^ mer2->dwMousePosition.X || + mer1->dwMousePosition.Y ^ mer2->dwMousePosition.Y || + mer1->dwButtonState ^ mer2->dwButtonState || + mer1->dwControlKeyState ^ mer2->dwControlKeyState || + mer1->dwEventFlags ^ mer2->dwEventFlags + ) { + return TRUE; + } else { + return FALSE; + } + + } +}; + + +ClientInteract::ClientInteract(CMclQueue &_mQ) + : mQ(_mQ), ConOut(0L), ConIn(0L), ConInteract(0L), oldBuffer(0L) +{ + COORD Size = {80, 500}; + + ConIn = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); + + reader = new ReadConWithSwitching(mQ, Stop, ConIn); + readThread = new CMclThread(reader); + + oldBuffer = CreateFile("CONOUT$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); + ConOut = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, CONSOLE_TEXTMODE_BUFFER, 0L); +// SetConsoleCtrlHandler(ConsoleHandler, TRUE); + SetConsoleActiveScreenBuffer(ConOut); + SetConsoleScreenBufferSize(ConOut, Size); +} + +ClientInteract::~ClientInteract() +{ +} + +void ClientInteract::Write(Message *) +{ +} ADDED win/expWinTestClientStdio.cpp Index: win/expWinTestClientStdio.cpp ================================================================== --- /dev/null +++ win/expWinTestClientStdio.cpp @@ -0,0 +1,108 @@ +/* ---------------------------------------------------------------------------- + * expWinTestClientStdio.cpp -- + * + * Simple standard I/O as our client. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: expWinTestClientStdio.cpp,v 1.1.2.2 2002/06/28 01:26:57 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#include "expWinTestClient.hpp" + + +class ReadPipe : public CMclThreadHandler +{ +public: + ReadPipe(CMclQueue &_mQ) : mQ(_mQ) + { + hStdIn = GetStdHandle(STD_INPUT_HANDLE); + } + +private: + +# define READ_BUFFER_SIZE 128 + virtual unsigned ThreadHandlerProc(void) + { + BOOL ok; + DWORD dwRead; + Message *msg; + BYTE *readBuf; + + again: + readBuf = new BYTE [READ_BUFFER_SIZE]; + ok = ReadFile(hStdIn, readBuf, READ_BUFFER_SIZE, &dwRead, 0L); + if (!ok || dwRead == 0) { + CloseHandle(hStdIn); // <- should this be here? + delete [] readBuf; + goto done; + } + msg = new Message; + msg->bytes = (CHAR *) readBuf; + msg->length = dwRead; + msg->type = Message::TYPE_INSTREAM; + mQ.Put(msg); + goto again; + + done: + return 0; + } + + CMclQueue &mQ; + HANDLE hStdIn; +}; + +ClientStdio::ClientStdio(CMclQueue &_mQ) + : mQ(_mQ) +{ + hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + hStdErr = GetStdHandle(STD_ERROR_HANDLE); + reader = new ReadPipe(_mQ); + readThread = new CMclThread(reader); +} + +ClientStdio::~ClientStdio() +{ + DWORD dwExit; + + readThread->GetExitCode(&dwExit); + if (dwExit == STILL_ACTIVE) { + readThread->Terminate(128); + } +} + +void +ClientStdio::Write(Message *what) +{ + DWORD dwWritten; + HANDLE where; + + switch (what->type) { + case Message::TYPE_NORMAL: + where = hStdOut; break; + case Message::TYPE_WARNING: + case Message::TYPE_ERROR: + where = hStdErr; + } + WriteFile(where, what->bytes, what->length, &dwWritten, 0L); + delete what; +} Index: win/expWinTty.c ================================================================== --- win/expWinTty.c +++ win/expWinTty.c @@ -14,18 +14,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: exp.h,v 1.1.4.4 2002/02/10 10:17:04 davygrvy Exp $ + * RCS: @(#) $Id: expWinTty.c,v 1.1.2.1.2.4 2003/08/25 23:17:49 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinInt.h" @@ -229,11 +230,11 @@ static int Exp_SttyCmd(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; - char **argv; + CONST char **argv; { #if 1 /* redirection symbol is not counted as a stty arg in terms */ /* of recognition. */ int saw_unknown_stty_arg = FALSE; @@ -242,11 +243,11 @@ int rc = TCL_OK; int cooked = FALSE; int was_raw, was_echo; - char **argv0 = argv; + CONST char **argv0 = argv; for (argv=argv0+1;*argv;argv++) { if (argv[0][0] == '<') { Tcl_AppendResult(interp, argv0, ": redirection not supported on Windows NT", NULL); @@ -320,11 +321,11 @@ static int Exp_SystemCmd(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; int argc; - char **argv; + CONST char **argv; { Tcl_AppendResult(interp, argv[0], ": not implemented", NULL); return TCL_ERROR; } Index: win/expWinUtils.cpp ================================================================== --- win/expWinUtils.cpp +++ win/expWinUtils.cpp @@ -13,18 +13,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: expWinUtils.cpp,v 1.1.2.5 2002/03/12 07:59:14 davygrvy Exp $ + * RCS: @(#) $Id: expWinUtils.cpp,v 1.1.2.8 2002/07/03 02:50:05 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "expWinUtils.hpp" #include "slavedrvmc.h" @@ -326,15 +327,15 @@ } LocalFree(errMsg); } -char *ExpSyslogGetSysMsg (DWORD id) +char *GetSysMsg (DWORD id) { int chars; - chars = wsprintf(sysMsgSpace, "[%d] ", id); + chars = wsprintf(sysMsgSpace, "[%u] ", id); FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, Index: win/expWinUtils.hpp ================================================================== --- win/expWinUtils.hpp +++ win/expWinUtils.hpp @@ -11,11 +11,11 @@ #define EXP_LOG0(errCode) ExpWinSyslog(errCode, __FILE__, (int)__LINE__, 0) #define EXP_LOG1(errCode, arg1) ExpWinSyslog(errCode, __FILE__, (int)__LINE__, arg1, 0) #define EXP_LOG2(errCode, arg1, arg2) ExpWinSyslog(errCode, __FILE__, (int)__LINE__, arg1, arg2, 0) void ExpWinSyslog (DWORD errCode, ...); -char *ExpSyslogGetSysMsg (DWORD id); +char *GetSysMsg (DWORD id); class ArgMaker { public: char *BuildCommandLine (int, char * const *); Index: win/expect.dsp ================================================================== --- win/expect.dsp +++ win/expect.dsp @@ -41,15 +41,15 @@ # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release\expect" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPECT_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\generic" /I "d:\tcl_workspace\tcl_head\generic" /D "NDEBUG" /D "WIN32" /D "BUILD_exp" /D TCL_THREADS=1 /D "USE_TCL_STUBS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\generic" /I "d:\tcl_workspace\tcl_head_stock\generic" /I "$(IntDir)" /D "NDEBUG" /D "WIN32" /D "BUILD_exp" /D TCL_THREADS=1 /D "USE_TCL_STUBS" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head\generic" /d "NDEBUG" +# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head_stock\generic" /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 @@ -67,21 +67,21 @@ # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug\expect" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPECT_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /GB /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\generic" /I "d:\tcl_workspace\tcl_head\generic" /D "_DEBUG" /D "WIN32" /D "BUILD_exp" /D TCL_THREADS=1 /D "USE_TCL_STUBS" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\generic" /I "d:\tcl_workspace\tcl_head_stock\generic" /I "$(IntDir)" /D "_DEBUG" /D "WIN32" /D "BUILD_exp" /D TCL_THREADS=1 /D "USE_TCL_STUBS" /FR /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head\generic" /d "DEBUG" +# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head_stock\generic" /d "DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 advapi32.lib user32.lib /nologo /dll /debug /machine:I386 /out:"Debug/expect60d.dll" /pdbtype:sept /libpath:"d:\tcl_workspace\tcl_head\win\Debug" +# ADD LINK32 advapi32.lib user32.lib /nologo /dll /debug /machine:I386 /out:"Debug/expect60d.dll" /pdbtype:sept /libpath:"d:\tcl_workspace\tcl_head_stock\win\Debug" !ENDIF # Begin Target @@ -152,11 +152,11 @@ # Begin Custom Build - Rebuilding the Stubs table... InputDir=\expect_wslive\expect_win32_take2\generic InputPath=..\generic\exp.decls BuildCmds= \ - c:\progra~1\tcl\bin\tclsh84 d:/tcl_workspace/tcl_head/tools/genStubs.tcl $(InputDir) $(InputPath) + c:\progra~1\tcl\bin\tclsh84 d:/tcl_workspace/tcl_head_stock/tools/genStubs.tcl $(InputDir) $(InputPath) "$(InputDir)\expDecls.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" $(BuildCmds) "$(InputDir)\expPlatDecls.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" @@ -241,20 +241,32 @@ # PROP Default_Filter "" # Begin Group "winheaders" # PROP Default_Filter "" # Begin Source File + +SOURCE=.\expWinConsoleDebugger.hpp +# End Source File +# Begin Source File + +SOURCE=.\expWinInjectorIPC.hpp +# End Source File +# Begin Source File SOURCE=.\expWinInt.h # End Source File # Begin Source File + +SOURCE=.\expWinMessage.hpp +# End Source File +# Begin Source File SOURCE=.\expWinPort.h # End Source File # Begin Source File -SOURCE=.\MsvcDbgControl.h +SOURCE=.\expWinUtils.hpp # End Source File # End Group # Begin Source File SOURCE=.\expect.rc @@ -272,20 +284,28 @@ # Begin Source File SOURCE=.\expWinCommand.c # End Source File # Begin Source File + +SOURCE=.\expWinConsoleDebugger.cpp +# End Source File +# Begin Source File + +SOURCE=.\expWinConsoleDebuggerBreakPoints.cpp +# End Source File +# Begin Source File SOURCE=.\expWinInit.c # End Source File # Begin Source File SOURCE=.\expWinLog.c # End Source File # Begin Source File -SOURCE=.\expWinProcess.c +SOURCE=.\expWinMessage.cpp # End Source File # Begin Source File SOURCE=.\expWinSpawnChan.c # End Source File @@ -293,17 +313,53 @@ SOURCE=.\expWinTty.c # End Source File # Begin Source File -SOURCE=.\MsvcDbgControl.cpp +SOURCE=.\expWinUtils.cpp +# End Source File +# Begin Source File + +SOURCE=.\slavedrvmc.mc !IF "$(CFG)" == "expect - Win32 Release" -# PROP Exclude_From_Build 1 +# Begin Custom Build - Compiling message catalog... +IntDir=.\Release\expect +InputPath=.\slavedrvmc.mc + +BuildCmds= \ + mc -w -h "$(IntDir)" -r "$(IntDir)" $(InputPath) + +"$(IntDir)\slavedrvmc.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(IntDir)\slavedrvmc.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(IntDir)\MSG00409.bin" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) +# End Custom Build !ELSEIF "$(CFG)" == "expect - Win32 Debug" + +# Begin Custom Build - Compiling message catalog... +IntDir=.\Debug\expect +InputPath=.\slavedrvmc.mc + +BuildCmds= \ + mc -w -h "$(IntDir)" -r "$(IntDir)" $(InputPath) + +"$(IntDir)\slavedrvmc.rc" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(IntDir)\slavedrvmc.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) + +"$(IntDir)\MSG00409.bin" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + $(BuildCmds) +# End Custom Build !ENDIF # End Source File # Begin Source File Index: win/expect.dsw ================================================================== --- win/expect.dsw +++ win/expect.dsw @@ -1,18 +1,33 @@ Microsoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### +Project: "Mcl"=.\Mcl\Mcl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + Project: "expect"=.\expect.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ + Begin Project Dependency + Project_Dep_Name Mcl + End Project Dependency }}} ############################################################################### Global: Index: win/expect.rc ================================================================== --- win/expect.rc +++ win/expect.rc @@ -13,25 +13,24 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: exp.h,v 1.1.4.4 2002/02/10 10:17:04 davygrvy Exp $ + * RCS: @(#) $Id: expect.rc,v 1.1.2.1.2.5 2002/06/18 22:51:31 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include #include - -#define RESOURCE_INCLUDED /* needed for tcl.h, only */ #include "exp.h" #ifdef DEBUG #define SUFFIX_DEBUG "d" #else @@ -60,20 +59,20 @@ BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ BEGIN - VALUE "FileDescription", "Expect DLL\0" - VALUE "OriginalFilename", "expect" STRINGIFY(EXP_MAJOR_VERSION) STRINGIFY(EXP_MINOR_VERSION) SUFFIX ".dll\0" - VALUE "CompanyName", "Teleindustrie, LLC\0" - VALUE "FileVersion", EXP_PATCH_LEVEL - VALUE "LegalCopyright", "Copyright \251 Teleindustrie, LLC 2002\0" - VALUE "ProductName", "Expect " EXP_VERSION " for Win32\0" - VALUE "ProductVersion", EXP_PATCH_LEVEL - VALUE "Comments", "Expect was written for Unix by Don Libes at NIST. This is the Win32 port.\0" + VALUE "FileDescription", "Expect Tcl extension DLL\0" + VALUE "OriginalFilename", "expect" EXP_VERSION SUFFIX ".dll\0" + VALUE "CompanyName", "Teleindustrie, LLC\0" + VALUE "FileVersion", EXP_PATCH_LEVEL + VALUE "LegalCopyright", "Copyright \251 Teleindustrie, LLC 2002\r\nCopyright \251 2003 by ActiveState Corporation\0" + VALUE "ProductName", "Expect " EXP_VERSION " for Win32\0" + VALUE "ProductVersion", EXP_PATCH_LEVEL + VALUE "Comments", "Expect was written for Unix by Don Libes at NIST.\r\n" "Gordon Chaffee ported it to WinNT for Mitel Corporation in 1997.\r\n" "David Gravereaux merged Gordon's port back into the official sources for Telindustrie LLC in Oct. 2001.\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END ADDED win/inject.rc Index: win/inject.rc ================================================================== --- /dev/null +++ win/inject.rc @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------------- + * inject.rc -- + * + * Resource script for use with the resource compiler. + * + * ---------------------------------------------------------------------------- + * + * Written by: Don Libes, libes@cme.nist.gov, NIST, 12/3/90 + * + * Design and implementation of this program was paid for by U.S. tax + * dollars. Therefore it is public domain. However, the author and NIST + * would appreciate credit if this program or parts of it are used. + * + * Copyright (c) 1997 Mitel Corporation + * work by Gordon Chaffee for the WinNT port. + * + * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation + * work by David Gravereaux for any Win32 OS. + * + * ---------------------------------------------------------------------------- + * URLs: http://expect.nist.gov/ + * http://expect.sf.net/ + * http://bmrc.berkeley.edu/people/chaffee/expectnt.html + * ---------------------------------------------------------------------------- + * RCS: @(#) $Id: inject.rc,v 1.1.2.1 2002/06/19 06:42:45 davygrvy Exp $ + * ---------------------------------------------------------------------------- + */ + +#include +#include "exp.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION EXP_MAJOR_VERSION,EXP_MINOR_VERSION,EXP_RELEASE_LEVEL,EXP_RELEASE_SERIAL + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + +#if defined(_DEBUG) + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 /* open to all */ + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ + BEGIN + VALUE "FileDescription", "Expect's console event injector tool that sits inside the slave process\0" + VALUE "OriginalFilename", "inject.dll\0" + VALUE "CompanyName", "Telindustrie, LLC\0" + VALUE "FileVersion", "1.0a0" "\0" + VALUE "LegalCopyright", "Copyright \251 Telindustrie, LLC 2002\r\nCopyright \251 2003 by ActiveState Corporation\0" + VALUE "ProductName", "Expect " EXP_VERSION " for Win32\0" + VALUE "ProductVersion", EXP_PATCH_LEVEL "\0" + VALUE "Comments", "Expect was written for Unix by Don Libes at NIST.\r\n" "Gordon Chaffee ported it to WinNT for Mitel Corporation in 1997.\r\n" "David Gravereaux merged Gordon's port back into the official sources for Telindustrie LLC in Oct. 2001.\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END ADDED win/injector.dsp Index: win/injector.dsp ================================================================== --- /dev/null +++ win/injector.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="injector" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=injector - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "injector.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "injector.mak" CFG="injector - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "injector - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "injector - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "injector - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "injector___Win32_Release" +# PROP BASE Intermediate_Dir "injector___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release\injector" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INJECTOR_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I ".\Mcl\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head_stock\generic" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /dll /machine:I386 /opt:nowin98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "injector - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "injector___Win32_Debug" +# PROP BASE Intermediate_Dir "injector___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug\injector" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INJECTOR_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I ".\Mcl\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head_stock\generic" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "injector - Win32 Release" +# Name "injector - Win32 Debug" +# Begin Source File + +SOURCE=.\expWinInjectorIPC.hpp +# End Source File +# Begin Source File + +SOURCE=.\expWinInjectorMain.cpp +# End Source File +# Begin Source File + +SOURCE=.\inject.rc +# End Source File +# End Target +# End Project ADDED win/injector.dsw Index: win/injector.dsw ================================================================== --- /dev/null +++ win/injector.dsw @@ -0,0 +1,44 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Mcl"=.\Mcl\Mcl.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "injector"=.\injector.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name Mcl + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + Index: win/slavedrv.dsp ================================================================== --- win/slavedrv.dsp +++ win/slavedrv.dsp @@ -40,19 +40,19 @@ # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release\slavedrv" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\generic" /I "d:\tcl_workspace\tcl_head\generic" /I "d:\tcl_workspace\tcl_head\win" /I "$(IntDir)" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "USE_TCL_STUBS" /D IDE_LATCHED=0 /YX /FD /c +# ADD CPP /nologo /G5 /MD /W3 /GX /O1 /I "." /I "..\generic" /I ".\Mcl\include" /I "c:\progra~1\tcl\include" /I "$(IntDir)" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "USE_TCL_STUBS" /D IDE_LATCHED=0 /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head\generic" /i "$(IntDir)" /d "NDEBUG" +# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head_stock\generic" /i "$(IntDir)" /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 -# ADD LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"d:\tcl_workspace\tcl_head\win\Release" /opt:nowin98 +# ADD LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib /nologo /subsystem:console /machine:I386 /libpath:"d:\tcl_workspace\tcl_head_stock\win\Release" /opt:nowin98 # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "slavedrv - Win32 Debug" # PROP BASE Use_MFC 0 @@ -65,19 +65,20 @@ # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug\slavedrv" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /GB /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\generic" /I "d:\tcl_workspace\tcl_head\generic" /I "d:\tcl_workspace\tcl_head\win" /I "$(IntDir)" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "USE_TCL_STUBS" /D "BUILD_slavedriver" /FR /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "." /I "..\generic" /I ".\Mcl\include" /I "d:\tcl_workspace\tcl_head_stock\generic" /I "$(IntDir)" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "USE_TCL_STUBS" /D "BUILD_slavedriver" /FR /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head\generic" /i "$(IntDir)" /d "_DEBUG" +# ADD RSC /l 0x409 /i "..\generic" /i "d:\tcl_workspace\tcl_head_stock\generic" /i "$(IntDir)" /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept -# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept /libpath:"d:\tcl_workspace\tcl_head\win\Release" +# ADD LINK32 kernel32.lib user32.lib advapi32.lib /nologo /subsystem:console /debug /machine:I386 /libpath:"d:\tcl_workspace\tcl_head_stock\win\Release" +# SUBTRACT LINK32 /profile /map !ENDIF # Begin Target @@ -102,14 +103,22 @@ # Begin Source File SOURCE=.\expWinConsoleDebuggerBreakPoints.cpp # End Source File # Begin Source File + +SOURCE=.\expWinConsoleKeyMap.cpp +# End Source File +# Begin Source File SOURCE=.\expWinDynloadTclStubs.cpp # End Source File # Begin Source File + +SOURCE=.\expWinInjectorIPC.hpp +# End Source File +# Begin Source File SOURCE=.\expWinMessage.cpp # End Source File # Begin Source File @@ -127,15 +136,23 @@ SOURCE=.\expWinSlaveTrapDbg.cpp # End Source File # Begin Source File -SOURCE=.\expWinSpawnClient.hpp +SOURCE=.\expWinTestClient.hpp +# End Source File +# Begin Source File + +SOURCE=.\expWinTestClientConio.cpp +# End Source File +# Begin Source File + +SOURCE=.\expWinTestClientInteract.cpp # End Source File # Begin Source File -SOURCE=.\expWinSpawnStdioClient.cpp +SOURCE=.\expWinTestClientStdio.cpp # End Source File # Begin Source File SOURCE=.\expWinUtils.cpp # End Source File Index: win/slavedrv.dsw ================================================================== --- win/slavedrv.dsw +++ win/slavedrv.dsw @@ -37,10 +37,25 @@ }}} Package=<4> {{{ }}} + +############################################################################### + +Project: "test1"=.\test1.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name Mcl + End Project Dependency +}}} ############################################################################### Global: Index: win/slavedrv.rc ================================================================== --- win/slavedrv.rc +++ win/slavedrv.rc @@ -20,42 +20,43 @@ * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: slavedrv.rc,v 1.1.2.1 2002/03/09 01:42:25 davygrvy Exp $ + * RCS: @(#) $Id: slavedrv.rc,v 1.1.2.3 2002/06/18 22:51:31 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include +#include "exp.h" VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,0,0,0 - PRODUCTVERSION 6,0,0,0 + FILEVERSION 1,0,0,0 + PRODUCTVERSION EXP_MAJOR_VERSION,EXP_MINOR_VERSION,EXP_RELEASE_LEVEL,EXP_RELEASE_SERIAL FILEFLAGSMASK VS_FFI_FILEFLAGSMASK #if defined(_DEBUG) FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS__WINDOWS32 /* open to all */ - FILETYPE VFT_DLL + FILETYPE VFT_APP FILESUBTYPE VFT2_UNKNOWN BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ BEGIN - VALUE "FileDescription", "Spawn Driver helper application for overseeing Win32 consoles.\0" - VALUE "OriginalFilename", "spawndrv.exe\0" - VALUE "CompanyName", "Telindustrie, LLC\0" - VALUE "FileVersion", "6.0a0" "\0" - VALUE "LegalCopyright", "Copyright \251 Telindustrie, LLC 2002\0" - VALUE "ProductName", "Expect " "6.0" " for Win32\0" - VALUE "ProductVersion", "6.0a0" "\0" - VALUE "Comments", "Expect was written for Unix by Don Libes at NIST.\r\n" "Gordon Chaffee ported it to WinNT for Mitel Corporation in 1997.\r\n" "David Gravereaux merged Gordon's port back into the official sources for Telindustrie LLC in Oct. 2001.\0" + VALUE "FileDescription", "Spawn Driver test application for overseeing Win32 consoles.\0" + VALUE "OriginalFilename", "spawndrv.exe\0" + VALUE "CompanyName", "Telindustrie, LLC\0" + VALUE "FileVersion", "1.0a0" "\0" + VALUE "LegalCopyright", "Copyright \251 Telindustrie, LLC 2002\0" + VALUE "ProductName", "Expect " EXP_VERSION " for Win32\0" + VALUE "ProductVersion", EXP_PATCH_LEVEL "\0" + VALUE "Comments", "Expect was written for Unix by Don Libes at NIST.\r\n" "Gordon Chaffee ported it to WinNT for Mitel Corporation in 1997.\r\n" "David Gravereaux merged Gordon's port back into the official sources for Telindustrie LLC in Oct. 2001.\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 @@ -63,6 +64,7 @@ END // Include the Message Table that lists the error codes and textual replies. // This is output from the message compiler and found in the temp build directory. + #include "slavedrvmc.rc" Index: win/slavedrv_test.dsp ================================================================== --- win/slavedrv_test.dsp +++ win/slavedrv_test.dsp @@ -67,11 +67,11 @@ # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug\slavedrv_test" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "SLAVEDRV_TEST_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "d:\tcl_workspace\tcl_head\generic" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "USE_TCL_STUBS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "d:\tcl_workspace\tcl_head_stock\generic" /I "$(OUTDIR)..\slavedrv" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "USE_TCL_STUBS" /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe @@ -92,10 +92,17 @@ SOURCE=.\expWinTest.cpp # End Source File # Begin Source File SOURCE=.\expWinUtils.cpp + +!IF "$(CFG)" == "slavedrv_test - Win32 Release" + +!ELSEIF "$(CFG)" == "slavedrv_test - Win32 Debug" + +!ENDIF + # End Source File # Begin Source File SOURCE=.\expWinUtils.hpp # End Source File ADDED win/slavedrv_test.dsw Index: win/slavedrv_test.dsw ================================================================== --- /dev/null +++ win/slavedrv_test.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "slavedrv_test"=.\slavedrv_test.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + Index: win/slavedrvmc.mc ================================================================== --- win/slavedrvmc.mc +++ win/slavedrvmc.mc @@ -20,11 +20,11 @@ ; * ---------------------------------------------------------------------------- ; * URLs: http://expect.nist.gov/ ; * http://expect.sf.net/ ; * http://bmrc.berkeley.edu/people/chaffee/expectnt.html ; * ---------------------------------------------------------------------------- -; * RCS: @(#) $Id: slavedrvmc.mc,v 1.1.2.1 2002/03/09 01:42:00 davygrvy Exp $ +; * RCS: @(#) $Id: slavedrvmc.mc,v 1.1.2.3 2002/06/18 22:51:31 davygrvy Exp $ ; * ---------------------------------------------------------------------------- ; */ MessageIdTypedef = DWORD OutputBase = 16 @@ -108,11 +108,11 @@ . MessageId=0x1 -Severity=Error +Severity=Fatal Facility=Io SymbolicName=MSG_IO_ARGSWRONG Language=English %1 : %2 (%3,%4): No commandline arguements to slavedrv.exe. No work to do. . @@ -124,11 +124,11 @@ Language=English %1 : %2 (%3,%4): Unclean shutdown: %5 . MessageId=0x2 -Severity=Error +Severity=Fatal Facility=Io SymbolicName=MSG_IO_UNEXPECTED Language=English %1 : %2 (%3,%4): Unexpected error: %5 . @@ -136,33 +136,33 @@ MessageId=0x3 Severity=Fatal Facility=Io SymbolicName=MSG_IO_TRANSPRTARGSBAD Language=English -%1 : %2 (%3,%4): Transport protocol bad: %5 +%1 : %2 (%3,%4): Transport protocol bad (must be 'conio' or 'stdio'): %5 . MessageId=0x4 Severity=Fatal Facility=Io SymbolicName=MSG_IO_TRAPARGSBAD Language=English -%1 : %2 (%3,%4): Trap method bad: %5 +%1 : %2 (%3,%4): Trap method bad (only 'dbg' is available): %5 . MessageId=0x0 -Severity=Error +Severity=Fatal Facility=Mailbox SymbolicName=MSG_MB_CANTOPENCLIENT1 Language=English %1 : %2 (%3,%4): Can't open client-side IPC mailbox for named mailbox "%5". . MessageId=0x1 -Severity=Error +Severity=Fatal Facility=Mailbox SymbolicName=MSG_MB_CANTOPENCLIENT2 Language=English %1 : %2 (%3,%4): Can't open client-side IPC mailbox for named mailbox "%5". Got system error %6 . @@ -211,11 +211,11 @@ Language=English %1 : %2 (%3,%4): Unable to write to slave: %5 . MessageId=0x2 -Severity=Error +Severity=Fatal Facility=MasterSlave_Protocol SymbolicName=MSG_MS_BADSTATE Language=English %1 : %2 (%3,%4): Unexpected state . @@ -222,52 +222,52 @@ MessageId=0x1 -Severity=Error +Severity=Fatal Facility=NamedPipe SymbolicName=MSG_NP_CANTOPEN Language=English %1 : %2 (%3,%4): Can't open argv[1], "%5", for read/write. CreateFile() returned: %6 . MessageId=0x2 -Severity=Error +Severity=Fatal Facility=NamedPipe SymbolicName=MSG_NP_BADTYPE Language=English %1 : %2 (%3,%4): NamedPipe specified as, "%5", was found not to be a pipe filetype. . MessageId=0x1 -Severity=Error +Severity=Fatal Facility=WinSock SymbolicName=MSG_WS_CANTSTART Language=English %1 : %2 (%3,%4): WinSock system was unable to start. slavedrv.exe requested version %5. WSAStartup() returned: %6 . MessageId=0x2 -Severity=Error +Severity=Fatal Facility=WinSock SymbolicName=MSG_WS_CANTCREATEMASTERSOCK Language=English %1 : %2 (%3,%4): Master socket was unable to be created. WSASocket() returned: %6 . MessageId=0x3 -Severity=Error +Severity=Fatal Facility=WinSock SymbolicName=MSG_WS_CANTCONNECTMASTERSOCK Language=English %1 : %2 (%3,%4): Can't connect to local loopback on port %5. connect() returned: %6 . MessageId=0x4 -Severity=Error +Severity=Fatal Facility=WinSock SymbolicName=MSG_WS_PORTOUTOFRANGE Language=English %1 : %2 (%3,%4): Local loopback port out-of-range at "%5". Must be greater than zero and less than 65536. . @@ -274,11 +274,11 @@ MessageId=0x1 -Severity=Error +Severity=Fatal Facility=DbgTrap SymbolicName=MSG_DT_CANTGETCONSOLEHANDLE Language=English %1 : %2 (%3,%4): Can't open the console handle. CreateFile("%5") returned: %6 . @@ -306,27 +306,51 @@ Language=English %1 : %2 (%3,%4): Unable to find entry for VirtualAlloc . MessageId=0x5 -Severity=Warning +Severity=Fatal Facility=DbgTrap SymbolicName=MSG_DT_CANTREADSPMEM Language=English -%1 : %2 (%3,%4): Error reading from subprocess memory +%1 : %2 (%3,%4): Error reading from subprocess memory, %5 . MessageId=0x6 -Severity=Warning +Severity=Fatal Facility=DbgTrap SymbolicName=MSG_DT_CANTWRITESPMEM Language=English -%1 : %2 (%3,%4): Error writing to subprocess memory +%1 : %2 (%3,%4): Error writing to subprocess memory, %5 . MessageId=0x7 +Severity=Fatal +Facility=DbgTrap +SymbolicName=MSG_DT_CANTMAKENTSPMEM +Language=English +%1 : %2 (%3,%4): Error creating subprocess memory. VirtualAllocEx() failed, %5 +. + +MessageId=0x8 +Severity=Fatal +Facility=DbgTrap +SymbolicName=MSG_DT_CANTMAKE95SPMEM +Language=English +%1 : %2 (%3,%4): Error creating subprocess memory, %5 +. + +MessageId=0x9 Severity=Warning Facility=DbgTrap SymbolicName=MSG_DT_SCREENBUF Language=English %1 : %2 (%3,%4): Call to GetConsoleScreenBufferInfo() failed with %5, %6 . + +MessageId=0xa +Severity=Fatal +Facility=DbgTrap +SymbolicName=MSG_DT_BADDEBUGGEE +Language=English +%1 : %2 (%3,%4): Unable to start debuggee from commandline: "%5", %6 +. ADDED win/test1.cpp Index: win/test1.cpp ================================================================== --- /dev/null +++ win/test1.cpp @@ -0,0 +1,132 @@ +/* + Follow the mouse. +*/ + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include "./Mcl/include/cmcl.h" + +#define RECORD_SIZE 15 +INPUT_RECORD Records[RECORD_SIZE]; +HANDLE ConIn, ConOut; +CMclEvent stop; + +void HandleKey(KEY_EVENT_RECORD *ker); +void HandleMouse(MOUSE_EVENT_RECORD *mer); +void HandleWindow(WINDOW_BUFFER_SIZE_RECORD *wbsr); +BOOL isDiff(MOUSE_EVENT_RECORD *mer1, MOUSE_EVENT_RECORD *mer2); +BOOL WINAPI ConsoleHandler(DWORD code); + +int main (void) +{ + DWORD dwRead, i; + CONSOLE_CURSOR_INFO cci = {100, 1}; + MOUSE_EVENT_RECORD lastMouse; + CMclWaitableCollection groupedHandles; + DWORD dwRet; + HANDLE oldBuffer; + + ConIn = CreateFile("CONIN$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); + oldBuffer = CreateFile("CONOUT$", GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, OPEN_EXISTING, 0, 0L); + ConOut = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, 0L, CONSOLE_TEXTMODE_BUFFER, 0L); + + if (!ConIn || !oldBuffer || !ConOut) { + WriteFile(GetStdHandle(STD_ERROR_HANDLE), "need console! die, die!\n", 24, &dwRet, 0L); + return -1; + } + + SetConsoleCtrlHandler(ConsoleHandler, TRUE); + SetConsoleActiveScreenBuffer(ConOut); + SetConsoleMode(ConIn, ENABLE_WINDOW_INPUT|ENABLE_MOUSE_INPUT); + SetConsoleCursorInfo(ConOut, &cci); + SetConsoleOutputCP(437); // us-ascii code page. + + // Index 0, highest priority goes first. + groupedHandles.AddObject(stop); + + // Console handles are waitable objects. + // Index 1 + groupedHandles.AddObject(ConIn); + +again: + // Wait for any (either) to signal. + dwRet = groupedHandles.Wait(FALSE, INFINITE); + + if (!CMclWaitSucceeded(dwRet, groupedHandles.GetCount()) || + CMclWaitSucceededIndex(dwRet) == 0) { + // stop event or some other error, so die. + CloseHandle(ConIn); + CloseHandle(ConOut); + SetConsoleActiveScreenBuffer(oldBuffer); + return 0; + } + + ReadConsoleInput(ConIn, Records, RECORD_SIZE, &dwRead); + for (i = 0; i < dwRead; i++) { + switch (Records[i].EventType) { + case KEY_EVENT: + HandleKey(&Records[i].Event.KeyEvent); + break; + case MOUSE_EVENT: + if (isDiff(&lastMouse, &Records[i].Event.MouseEvent)) { + lastMouse = Records[i].Event.MouseEvent; + HandleMouse(&Records[i].Event.MouseEvent); + } + break; + case WINDOW_BUFFER_SIZE_EVENT: + HandleWindow(&Records[i].Event.WindowBufferSizeEvent); + break; + } + } + goto again; +} + +void +HandleKey(KEY_EVENT_RECORD *ker) +{ + // exit on esc. + if (ker->wVirtualKeyCode == VK_ESCAPE && ker->bKeyDown) stop.Set(); +} + +void +HandleMouse(MOUSE_EVENT_RECORD *mer) +{ + // put the cursor where the mouse is. + SetConsoleCursorPosition(ConOut, mer->dwMousePosition); +} + +void +HandleWindow(WINDOW_BUFFER_SIZE_RECORD *wbsr) +{ +} + +BOOL +isDiff(MOUSE_EVENT_RECORD *mer1, MOUSE_EVENT_RECORD *mer2) +{ + if ( + mer1->dwMousePosition.X ^ mer2->dwMousePosition.X || + mer1->dwMousePosition.Y ^ mer2->dwMousePosition.Y || + mer1->dwButtonState ^ mer2->dwButtonState || + mer1->dwControlKeyState ^ mer2->dwControlKeyState || + mer1->dwEventFlags ^ mer2->dwEventFlags + ) { + return TRUE; + } else { + return FALSE; + } + +} + +BOOL WINAPI +ConsoleHandler (DWORD code) +{ + // this routine is called by a kernel supplied thread. + + // no matter what condition comes in, shutdown. + stop.Set(); + return TRUE; +} ADDED win/test1.dsp Index: win/test1.dsp ================================================================== --- /dev/null +++ win/test1.dsp @@ -0,0 +1,89 @@ +# Microsoft Developer Studio Project File - Name="test1" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=test1 - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "test1.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "test1.mak" CFG="test1 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "test1 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "test1 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "test1 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "test1___Win32_Release" +# PROP BASE Intermediate_Dir "test1___Win32_Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release\test1" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "test1 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "test1___Win32_Debug" +# PROP BASE Intermediate_Dir "test1___Win32_Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug\test1" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "test1 - Win32 Release" +# Name "test1 - Win32 Debug" +# Begin Source File + +SOURCE=.\test1.cpp +# End Source File +# End Target +# End Project Index: win/winDllMain.c ================================================================== --- win/winDllMain.c +++ win/winDllMain.c @@ -13,18 +13,19 @@ * * Copyright (c) 1997 Mitel Corporation * work by Gordon Chaffee for the WinNT port. * * Copyright (c) 2001-2002 Telindustrie, LLC + * Copyright (c) 2003 ActiveState Corporation * work by David Gravereaux for any Win32 OS. * * ---------------------------------------------------------------------------- * URLs: http://expect.nist.gov/ * http://expect.sf.net/ * http://bmrc.berkeley.edu/people/chaffee/expectnt.html * ---------------------------------------------------------------------------- - * RCS: @(#) $Id: winDllMain.c,v 1.1.2.4 2002/02/10 12:03:30 davygrvy Exp $ + * RCS: @(#) $Id: winDllMain.c,v 1.1.2.5 2002/02/16 03:17:00 davygrvy Exp $ * ---------------------------------------------------------------------------- */ #include "tcl.h" #define WIN32_LEAN_AND_MEAN @@ -42,11 +43,11 @@ # pragma comment(linker, "-nodefaultlib:msvcrt.lib") # endif # else # ifdef _DEBUG # pragma comment (lib, "tcl" \ - STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) "d.lib") + STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) "g.lib") # else # pragma comment (lib, "tcl" \ STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) ".lib") # endif # endif