/* ** LOGGER - DLL to control logging of API trace information */ #define NOGDICAPMASKS #define NOVIRTUALKEYCODES #define NOWINSTYLES #define NOSYSMETRICS #define NOICONS #define NOKEYSTATES #define NOSYSCOMMANDS #define NORASTEROPS #define NOSHOWWINDOW #define NOATOM #define NOCLIPBOARD #define NOCOLOR #define NODRAWTEXT #define NOMB #define NOMEMMGR #define NOMETAFILE #define NOMINMAX #define NOMSG #define NOSCROLL #define NOSOUND #define NOTEXTMETRIC #define NOWINOFFSETS #define NOCOMM #define NOKANJI #define NOHELP #define NOPROFILER #define NODEFERWINDOWPOS #include #include #include #include #include #include #include #if !defined(WIN32) #define INT21H #include #endif #include "logger.h" #include "lintern.h" #include "saverest.h" #include "timing.h" // // by default OUTPUT.LOG is created in the current working directory unless: // there is any file ALT_LOG_FLAG(log.on) located in the ALTERNATE_PATH // #define OUTPUT_LOG "OUTPUT.LOG" #define OUTPUT_DAT "OUTPUT.DAT" #define ALT_LOG_DIR "x:\\log" // alt. dir to put log file in #define ALT_FLAG_FILE "log.on" // a flag to indicate "write output.log to al #ifdef LOGFILE_PATH #define ALTERNATE_PATH LOGFILE_PATH "\\" #define ALTERNATE_TEST ALTERNATE_PATH ALT_FLAG_FILE #else #define ALTERNATE_PATH ALT_LOG_DIR "\\" #define ALTERNATE_TEST ALTERNATE_PATH ALT_FLAG_FILE #endif // LOGFILE_PATH #define TIMING_ON_FLAG "time.on" // set timing on #define TIMING_ON_TEST ALTERNATE_PATH TIMING_ON_FLAG #if !defined( WIN32 ) int FAR PASCAL LibMain(HANDLE, WORD, WORD, LPSTR); DWORD far GetSetKernelDOSProc (DWORD); extern void _far __export _pascal _Int21_Handler (void); void DoInt21Init(void); void _loadds LogInt21Calls ( WORD wFlags, WORD wBP, WORD wSS, WORD wES, WORD wDS, WORD wSI, WORD wDI, WORD wDX, WORD wCX, WORD wBX, WORD wAX, WORD Dummy1, WORD Dummy2, WORD Dummy3, WORD Dummy4, WORD wIP, WORD wCS); void _loadds LogOut21Calls ( WORD wFlags, WORD wDS, WORD wES, WORD wSI, WORD wDI, WORD wDX, WORD wCX, WORD wBX, WORD wAX, WORD wIP, WORD wCS); DWORD dwTemp; UINT wSelData, uSel; UINT RegAX = 0; unsigned int cLogInInt21 = 0; // the above var. is required for the following reason: // it is possible that an API calls another API before // returning. So, before calling LogOut, another LogIn // might be called. If in the meanwhile, the write buffer // gets filled up, an Int21 will be issued (via a write // request. So, we log Int21s only when this var. is zero. // A counter is incremented and decremented at the beginning // & end of this function. unsigned int cInt21CallsByApp = 0; unsigned int cAllInt21Calls = 0; LPDWORD lpOrig; BOOL fLogIn = FALSE; // the above is a flag that is used for Int21 logging. This flag // is just set before exiting LogIn since this means that the app // has already made the first Windows API call. We use this to begin // counting the Int21 calls. // HTASK hTask; // STACKTRACEENTRY StackTrace; // MODULEENTRY ModuleEntry; #endif #define REST 0x99 #define MAX_INST_TABLE 30 #ifdef SHARED_MEM typedef struct _shared_mem_t { /* ** Global static variables */ int nLogIndent ; char achCurrentDirectory[_MAX_PATH]; int cDbg ; BOOL fLogInit ; BOOL cDbgPort ; BOOL fTiming ; BOOL fNotes ; BOOL fWOW ; BOOL fLogObjects ; BOOL fINT21H ; BOOL fAPIOnly ; BOOL fLogSync ; BOOL fDrvLog ; BOOL fElapsedTimes ; char szLogFileName[_MAX_PATH]; // output log file name char szDatFileName[_MAX_PATH]; // output dat file name } SHARED_MEMORY, *PSHARED_MEM; PSHARED_MEM pVars ; #define SHMEMSIZE sizeof(struct _shared_mem_t) #define ACCESS(varname) (pVars->varname) HANDLE hMapObject ; #else /* ** Global static variables */ int nLogIndent = 1; char achCurrentDirectory[_MAX_PATH]; int cDbg = REST; BOOL fLogInit = FALSE ; BOOL cDbgPort = FALSE ; BOOL fTiming = FALSE ; BOOL fNotes = FALSE ; BOOL fWOW = FALSE ; BOOL fLogObjects = FALSE ; BOOL fINT21H = FALSE ; BOOL fAPIOnly = FALSE ; BOOL fLogSync = FALSE ; BOOL fDrvLog = FALSE ; BOOL fElapsedTimes = TRUE ; // DEAFULT to elapsed times. static char szLogFileName[_MAX_PATH]; // output log file name static char szDatFileName[_MAX_PATH]; // output dat file name #define ACCESS(varname) varname #endif /* ** "Local" Global Data */ int WindowsVerRunning = 0; int hLogFile, hDataFile; int nLineLen = 0; long nLogLine = 0L; long nLogSpot = 0L; BOOL fInputHook; HHOOK hOldHook; FARPROC fpOldHook; FARPROC fpNewHook; #define MAX_BUFFER 1024 char chBuffer[MAX_BUFFER]; #define MAX_PATH_NAME_LEN _MAX_PATH /* ** For timing info ** Time only if compiled with this flag */ short TimerHandle [MAX_BUFFER]; BOOL fTimerCalibrated = FALSE; unsigned long ulOverhead = 0L; void CalibrateTimer (void); BOOL fDos3Call = FALSE; BOOL fAlias = FALSE ; /* ** Special HACK addresses so that we can determine whether there is ** a pending mouse movement message. */ int FAR *lpfMouseMoved = NULL; HANDLE hLibInstance = NULL; // for DialogBoxIndirectParam playback WORD hInstanceTable[MAX_INST_TABLE]; WORD hInstOfCaller = 0; #ifdef WIN32 BOOLEAN NtQueryPerformanceCounter ( PLARGE_INTEGER PerformanceCounter, PLARGE_INTEGER PerformanceFrequency ); #else typedef DWORD ULONG; typedef DWORD BOOLEAN; typedef struct large_integer { ULONG LowPart; LONG HighPart; } LARGE_INTEGER, FAR *PLARGE_INTEGER; #endif // This stuff can and will be local TYPEIO *typehash[256] = { NULL }; TYPEIO IoTypes[] = { #if defined( WIN32) // DRVLOG types - at the top so we don't slow down DDI anymore than necc. "PSURFOBJ", PrtPSURFOBJ, NULL, "PCLIPOBJ", PrtPCLIPOBJ, NULL, "PXLATEOBJ", PrtPXLATEOBJ, NULL, "PRECTL", PrtPRECTL, NULL, "PPOINTL", PrtPPOINTL, NULL, "POINTS", PrtPOINTS, NULL, "COORD", PrtPOINTS, NULL, "PBRUSHOBJ", PrtPBRUSHOBJ, NULL, "ROP4", PrtROP4, NULL, "FLONG", PrtLong, NULL, "PHSURF", PrtPHSURF, NULL, "HSURF", PrtHSURF, NULL, "DHSURF", PrtHSURF, NULL, "PIFIMETRICS", PrtPIFIMETRICS, NULL, "PDEVMODEW", PrtPDEVMODEW, NULL, "PDRVENABLEDATA", PrtPDRVENABLEDATA, NULL, "PDEVINFO", PrtPDEVINFO, NULL, "DHPDEV", PrtDHPDEV, NULL, "HDEV", PrtHDEV, NULL, "PSTROBJ", PrtPSTROBJ, NULL, "PFONTOBJ", PrtPFONTOBJ, NULL, "MIX", PrtMIX, NULL, "SIZE", PrtSIZE, NULL, "SIZEL", PrtSIZE, NULL, "LPWORD", PrtLPWORD, NULL, "PHANDLER_ROUTINE", PrtFARPROC, NULL, "PSMALL_RECT", PrtPSMALL_RECT, NULL, // Not implemented "PCONSOLE_SCREEN_BUFFER_INFO", PrtLong, NULL, "PCONSOLE_CURSOR_INFO", PrtLong, NULL, "PCHAR_INFO", PrtLong, NULL, "PINPUT_RECORD", PrtLong, NULL, "LPCPINFO", PrtLong, NULL, "LPSYSTEM_INFO", PrtLong, NULL, "LPKERNINGPAIR", PrtLong, NULL, #endif "UINT", PrtInt, NULL, "INT", PrtInt, NULL, "INT*", PrtLPINT, NULL, "const INT*", PrtLPINT, NULL, "INT *", PrtLPINT, NULL, "const INT *", PrtLPINT, NULL, "HDWP", PrtInt, NULL, "int", PrtInt, NULL, "HDWP", PrtHMEM, NULL, "short", PrtShort, NULL, "SHORT", PrtShort, NULL, "char", PrtInt, NULL, "CHAR", PrtInt, NULL, "BYTE", PrtInt, NULL, "long", PrtLong, NULL, "BOOL", PrtBool, NULL, "BOOL far*", PrtLPINT, NULL, "WORD", PrtInt, NULL, "WPARAM", PrtInt, NULL, "DWORD", PrtLong, NULL, "ULONG", PrtLong, NULL, "POINT", PrtLong, NULL, "LONG", PrtLong, NULL, "LPARAM", PrtLong, NULL, "LPVOID", PrtLong, NULL, "va_list", PrtLong, NULL, #ifdef WIN32 "PVOID", PrtLong, NULL, "const void*", PrtLong, NULL, "HSZ", PrtLong, NULL, "HDDEDATA", PrtLong, NULL, "HCONVLIST", PrtLong, NULL, "HCONV", PrtLong, NULL, "LCID", PrtLong, NULL, "PLCID", PrtLPDWORD, NULL, "LPLCID", PrtLPDWORD, NULL, "LCID *", PrtLPDWORD, NULL, "LCTYPE", PrtLong, NULL, "LPLCID", PrtLPDWORD, NULL, "LPCVOID", PrtLong, NULL, "REGSAM", PrtLong, NULL, "ACCESS_MASK", PrtLong, NULL, "PACCESS_MASK", PrtLPDWORD, NULL, "LPBYTE", PrtLPBYTE, NULL, "LANGID", PrtShort, NULL, "LPTHREAD_START_ROUTINE", PrtLong, NULL, "PTHREAD_START_ROUTINE", PrtLong, NULL, "LPWINDOWPLACEMENT", PrtLPWINDOWPLACEMENT, NULL, "PWINDOWPLACEMENT", PrtLPWINDOWPLACEMENT, NULL, "WINDOWPLACEMENT*", PrtLPWINDOWPLACEMENT, NULL, "const WINDOWPLACEMENT*", PrtLPWINDOWPLACEMENT, NULL, "LPCONVCONTEXT", PrtLPCONVCONTEXT, NULL, "PCONVCONTEXT", PrtLPCONVCONTEXT, NULL, "const CONVCONTEXT*", PrtLPCONVCONTEXT, NULL, "CONVCONTEXT*", PrtLPCONVCONTEXT, NULL, #endif "const BYTE*", PrtLong, NULL, "LRESULT", PrtLong, NULL, "COLORREF", PrtLong, NULL, "ATOM", PrtATOM, NULL, "LPINT", PrtLPINT, NULL, "int far*", PrtLPINT, NULL, "LPDWORD", PrtLPDWORD, NULL, "LPLONG", PrtLPDWORD, NULL, "LPBOOL", PrtLPDWORD, NULL, "const DWORD *", PrtLPDWORD, NULL, "const DWORD*", PrtLPDWORD, NULL, "DWORD *", PrtLPDWORD, NULL, "DWORD*", PrtLPDWORD, NULL, "PULONG", PrtLPDWORD, NULL, "PLONG", PrtLPDWORD, NULL, // Do we need to differentiate the sign? "ARRAYINT", PrtARRAYINT, NULL, "LPSTR", PrtLPSTR, NULL, "LPSTR*", PrtLPDWORD, NULL, "LPCSTR", PrtLPSTR, NULL, // Default these to pointers so we can see what is going on....mjr "HANDLETABLE far*", PrtLPINT, NULL, "METARECORD far*", PrtLPINT, NULL, #ifdef WIN32 "LPWSTR*", PrtPLPWSTR, NULL, "LPWSTR", PrtLPWSTR, NULL, "PWSTR", PrtLPWSTR, NULL, "LPCWSTR", PrtLPWSTR, NULL, "wchar near*", PrtLPSTR, NULL, "wchar far*", PrtLPSTR, NULL, "const wchar_t*", PrtLPSTR, NULL, "void*", PrtLong, NULL, "const char*", PrtLPSTR, NULL, "size_t", PrtInt, NULL, #endif "char near*", PrtLPSTR, NULL, "char far*", PrtLPSTR, NULL, "void far*", PrtLong, NULL, "const void far*", PrtLong, NULL, "const void *", PrtLong, NULL, "FixedString", PrtFixedString, NULL, "FineString", PrtFineString, NULL, "HMETAFILE", PrtHMETA, NULL, "const HANDLE*", PrtPHANDLE, NULL, "LPHANDLE", PrtPHANDLE, NULL, "HANDLE", PrtHMEM, NULL, "HLOCAL", PrtHMEM, NULL, "HINSTANCE", PrtHMEM, NULL, "HMODULE", PrtHMEM, NULL, "HGLOBAL", PrtHMEM, NULL, "HFILE", PrtHFILE, NULL, "HRSRC", PrtHRES, NULL, "HWND", PrtHWND, NULL, "HICON", PrtHICON, NULL, "HBITMAP", PrtHBITMAP, NULL, "HCURSOR", PrtHCURSOR, NULL, "HPEN", PrtHPEN, NULL, "HDC", PrtHDC, NULL, "HBRUSH", PrtHBRUSH, NULL, "HFONT", PrtHFONT, NULL, "HTASK", PrtHTASK, NULL, "HACCEL", PrtHACCEL, NULL, "HMENU", PrtHMENU, NULL, "HRGN", PrtHRGN, NULL, "HGDIOBJ", PrtHMEM, NULL, "HPALETTE", PrtHPALETTE, NULL, "LPLOGBRUSH", PrtLPLOGBRUSH, NULL, "LOGBRUSH *", PrtLPLOGBRUSH, NULL, "LOGBRUSH*", PrtLPLOGBRUSH, NULL, "const LOGBRUSH *", PrtLPLOGBRUSH, NULL, "const LOGBRUSH*", PrtLPLOGBRUSH, NULL, "LOGBRUSH far*", PrtLPLOGBRUSH, NULL, "LPDEVMODE", PrtLPDEVMODE, NULL, "DEVMODE far*", PrtLPDEVMODE, NULL, #ifdef WIN32 "LPLOGFONTA", PrtLPLOGFONTA, NULL, "LOGFONTA *", PrtLPLOGFONTA, NULL, "LOGFONTA*", PrtLPLOGFONTA, NULL, "const LOGFONTA *", PrtLPLOGFONTA, NULL, "const LOGFONTA*", PrtLPLOGFONTA, NULL, "LOGFONTA far*", PrtLPLOGFONTA, NULL, "const LOGFONTA*", PrtLPLOGFONTA, NULL, "LPLOGFONTW", PrtLPLOGFONTW, NULL, "LOGFONTW *", PrtLPLOGFONTW, NULL, "LOGFONTW*", PrtLPLOGFONTW, NULL, "const LOGFONTW *", PrtLPLOGFONTW, NULL, "const LOGFONTW*", PrtLPLOGFONTW, NULL, "LOGFONTW far*", PrtLPLOGFONTW, NULL, "const LOGFONTW*", PrtLPLOGFONTW, NULL, #else "LPLOGFONT", PrtLPLOGFONT, NULL, "LOGFONT *", PrtLPLOGFONT, NULL, "LOGFONT*", PrtLPLOGFONT, NULL, "const LOGFONT *", PrtLPLOGFONT, NULL, "const LOGFONT*", PrtLPLOGFONT, NULL, "LOGFONT far*", PrtLPLOGFONT, NULL, "const LOGFONTA*", PrtLPLOGFONT, NULL, #endif "LPLOGPEN", PrtLPLOGPEN, NULL, "LOGPEN far*", PrtLPLOGPEN, NULL, "LPLOGPALETTE", PrtLPLOGPALETTE, NULL, "LOGPALETTE far*", PrtLPLOGPALETTE, NULL, "LOGPALETTE*", PrtLPLOGPALETTE, NULL, "const LOGPALETTE*", PrtLPLOGPALETTE, NULL, "PALETTEENTRY far *", PrtLPPALETTEENTRY, NULL, "PALETTEENTRY far*", PrtLPPALETTEENTRY, NULL, "LPPALETTEENTRY", PrtLPPALETTEENTRY, NULL, "LPMSG", PrtLPMSG, NULL, "MSG far*", PrtLPMSG, NULL, "const MSG*", PrtLPMSG, NULL, "LPOFSTRUCT", PrtLPOFSTRUCT, NULL, "OFSTRUCT far*", PrtLPOFSTRUCT, NULL, "LPPOINT", PrtLPPOINT, NULL, "POINT far*", PrtLPPOINT, NULL, "const POINT *", PrtLPPOINT, NULL, "const POINT*", PrtLPPOINT, NULL, "POINT *", PrtLPPOINT, NULL, "POINT*", PrtLPPOINT, NULL, "LPSIZE", PrtLPPOINT, NULL, "LPRECT", PrtLPRECT, NULL, "LPTR", PrtLPTR, NULL, "RECT far*", PrtLPRECT, NULL, "const RECT*", PrtLPRECT, NULL, "LPPAINTSTRUCT", PrtLPPAINTSTRUCT, NULL, "PAINTSTRUCT far*", PrtLPPAINTSTRUCT, NULL, "const PAINTSTRUCT*", PrtLPPAINTSTRUCT, NULL, #ifdef WIN32 "LPWNDCLASSA", PrtLPWNDCLASSA, NULL, "WNDCLASSA far*", PrtLPWNDCLASSA, NULL, "const WNDCLASSA *", PrtLPWNDCLASSA, NULL, "LPWNDCLASSW", PrtLPWNDCLASSW, NULL, "WNDCLASSW far*", PrtLPWNDCLASSW, NULL, "const WNDCLASSW *", PrtLPWNDCLASSW, NULL, #else "LPWNDCLASS", PrtLPWNDCLASS, NULL, "WNDCLASS far*", PrtLPWNDCLASS, NULL, #endif "LPBITMAP", PrtLPBITMAP, NULL, "const BITMAP*", PrtLPBITMAP, NULL, "LPBITMAPINFOHEADER", PrtLPBMIH, NULL, "BITMAPINFOHEADER far*", PrtLPBMIH, NULL, "LPBITMAPINFO", PrtLPBMI, NULL, "BITMAPINFO far*", PrtLPBMI, NULL, "BITMAP far *", PrtLPBITMAP, NULL, "BITMAP far*", PrtLPBITMAP, NULL, "FARPROC far *", PrtLPFARPROC, NULL, "FARPROC far*", PrtLPFARPROC, NULL, "HOOKPROC", PrtFARPROC, NULL, "HOOKPROC far*", PrtLPFARPROC, NULL, "LNOTIFYPROC", PrtFARPROC, NULL, "DLGPROC", PrtFARPROC, NULL, "TIMERPROC", PrtFARPROC, NULL, "PROPENUMPROC", PrtFARPROC, NULL, "WNDENUMPROC", PrtFARPROC, NULL, "ABORTPROC", PrtFARPROC, NULL, "MFENUMPROC", PrtFARPROC, NULL, "FONTENUMPROC", PrtFARPROC, NULL, "GRAYSTRINGPROC", PrtFARPROC, NULL, "LINEDDAPROC", PrtFARPROC, NULL, "GOBJENUMPROC", PrtFARPROC, NULL, "RSRCHDLRPROC", PrtFARPROC, NULL, "GNOTIFYPROC", PrtFARPROC, NULL, "FARPROC", PrtFARPROC, NULL, "WNDPROC", PrtFARPROC, NULL, "PFNCALLBACK", PrtFARPROC, NULL, "HHOOK", PrtHHOOK, NULL, #ifdef WIN32 "LPTEXTMETRICA", PrtLPTEXTMETRICA, NULL, "TEXTMETRICA far*", PrtLPTEXTMETRICA, NULL, "TEXTMETRICA *", PrtLPTEXTMETRICA, NULL, "TEXTMETRICA*", PrtLPTEXTMETRICA, NULL, "LPTEXTMETRICW", PrtLPTEXTMETRICW, NULL, "TEXTMETRICW far*", PrtLPTEXTMETRICW, NULL, "TEXTMETRICW *", PrtLPTEXTMETRICW, NULL, "TEXTMETRICW*", PrtLPTEXTMETRICW, NULL, #else "LPTEXTMETRIC", PrtLPTEXTMETRIC, NULL, "TEXTMETRIC far*", PrtLPTEXTMETRIC, NULL, #endif "LPEVENTMSG", PrtLPEVENTMSG, NULL, "COMSTAT far*", PrtLPCOMSTAT, NULL, #if (WINVER >= 0x30a) #ifdef WIN32 "LPOUTLINETEXTMETRICA", PrtLPOUTLINETEXTMETRICA, NULL, "LPOUTLINETEXTMETRICW", PrtLPOUTLINETEXTMETRICW, NULL, #else "LPOUTLINETEXTMETRIC", PrtLPOUTLINETEXTMETRIC, NULL, #endif "LPGLYPHMETRICS", PrtLPGLYPHMETRICS, NULL, "LPMAT2", PrtLPMAT2, NULL, #endif #ifdef WIN32 "LPSTARTUPINFOA", PrtLPSTARTUPINFOA, NULL, "LPSTARTUPINFOW", PrtLPSTARTUPINFOW, NULL, "LPOVERLAPPED", PrtLPOVERLAPPED, NULL, "LPSECURITY_ATTRIBUTES", PrtLPSECURITY_ATTRIBUTES,NULL, "LPCRITICAL_SECTION", PrtLPCRITICAL_SECTION, NULL, "HEVENT", PrtHEVENT, NULL, "HKEY", PrtHKEY, NULL, "PHKEY", PrtPHKEY, NULL, "PMEMORY_BASIC_INFORMATION",PrtPMEMORY_BASIC_INFORMATION,NULL, "LPFILETIME", PrtLPFILETIME, NULL, "PFILETIME", PrtLPFILETIME, NULL, "const FILETIME *", PrtLPFILETIME, NULL, "const FILETIME*", PrtLPFILETIME, NULL, "LPSYSTEMTIME", PrtLPSYSTEMTIME, NULL, "PSYSTEMTIME", PrtLPSYSTEMTIME, NULL, "const SYSTEMTIME *", PrtLPSYSTEMTIME, NULL, "const SYSTEMTIME*", PrtLPSYSTEMTIME, NULL, "LPWIN32_FIND_DATAA", PrtLPWIN32_FIND_DATAA, NULL, "PWIN32_FIND_DATAA", PrtLPWIN32_FIND_DATAA, NULL, "LPWIN32_FIND_DATAW", PrtLPWIN32_FIND_DATAW, NULL, "PWIN32_FIND_DATAW", PrtLPWIN32_FIND_DATAW, NULL, "LPCDLGTEMPLATEA", PrtLPDLGTEMPLATEA, NULL, "LPCDLGTEMPLATEW", PrtLPDLGTEMPLATEW, NULL, "LPDLGTEMPLATEA", PrtLPDLGTEMPLATEA, NULL, "LPDLGTEMPLATEW", PrtLPDLGTEMPLATEW, NULL, "LPDLGITEMTEMPLATEA", PrtLPDLGITEMTEMPLATEA, NULL, "LPDLGITEMTEMPLATEW", PrtLPDLGITEMTEMPLATEW, NULL, #endif "LPNCB", PrtLPNCB, NULL }; int nIoTypes = sizeof(IoTypes)/sizeof(IoTypes[0]); SPECIAL SpecialCases[] = { #ifdef WIN32 "AppendMenuA", DoAppendMenu, "AppendMenuW", DoAppendMenuW, "ChangeMenuA", DoChangeMenu, "ChangeMenuW", DoChangeMenuW, "ModifyMenuA", DoModifyMenu, "ModifyMenuW", DoModifyMenuW, "SearchPathA", DoSearchPathA, "SearchPathW", DoSearchPathW, "GetStartupInfoA", DoGetStartupInfoA, "GetStartupInfoW", DoGetStartupInfoW, "CreateWindowExA", DoCreateWindow, "CreateWindowExW", DoCreateWindowW, "DefWindowProcA", DoMessageA, "DefWindowProcW", DoMessageW, "DefMDIChildProcA", DoMessageA, "DefMDIChildProcW", DoMessageW, "DefDlgProcA", DoMessageA, "DefDlgProcW", DoMessageW, "GetMessageA", DoGetMessage, "GetMessageW", DoGetMessage, "PeekMessageA", DoCallPeek, "PeekMessageW", DoCallPeek, "PostAppMessageA", DoMessageA, "PostAppMessageW", DoMessageW, "PostMessageA", DoMessageA, "PostMessageW", DoMessageW, "SendMessageA", DoMessageA, "SendMessageW", DoMessageW, "SendDlgItemMessageA", DoMessageA, "SendDlgItemMessageW", DoMessageW, "CallWindowProcA", DoMessageA, "CallWindowProcW", DoMessageW, "TextOutA", DoTextOut, "TextOutW", DoTextOutW, "GetTextExtentA", DoGetTextExtent, "GetTextExtentW", DoGetTextExtentW, #else "AppendMenu", DoAppendMenu, "ChangeMenu", DoChangeMenu, "ModifyMenu", DoModifyMenu, "CreateWindow", DoCreateWindow, "CreateWindowEx", DoCreateWindow, "DefWindowProc", DoMessage, "DefMDIChildProc", DoMessage, "DefDlgProc", DoMessage, "GetMessage", DoGetMessage, "PeekMessage", DoCallPeek, "PostAppMessage", DoMessage, "PostMessage", DoMessage, "SendMessage", DoMessage, "SendDlgItemMessage", DoMessage, "CallWindowProc", DoMessage, "TextOut", DoTextOut, "GetTextExtent", DoGetTextExtent, "CreateDialogIndirect", DoCreateDialogIndirect, #endif "DPtoLP", DoHDC_LPPOINT_int, "LPtoDP", DoHDC_LPPOINT_int, "Polygon", DoHDC_LPPOINT_int, "Polyline", DoHDC_LPPOINT_int, "_lread", Do_lreadwrite, "_lwrite", Do_lreadwrite, "SetKeyboardState", DoGetSetKeyboardState, "Escape", DoEscape, "CreateBitmap", DoCreateBitmap, "CreateDIBitmap", DoCreateDIBitmap, "SetBitmapBits", DoSetBitmapBits, "LoadModule", DoLoadModule, "CreatePolygonRgn", DoCreatePolygonRgn, "SetPaletteEntries", DoSetPaletteEntries, "SetClipboardData", DoSetClipboardData, } ; int nSpecialCases = sizeof(SpecialCases)/sizeof(SpecialCases[0]) ; SPECIAL RetSpecialCases[] = { #ifdef WIN32 "CreateWindowExA", DoCreateWindowRet, "CreateWindowExW", DoCreateWindowRet, "GetMessageA", DoGetMessageRet, "GetMessageW", DoGetMessageRet, "PeekMessageA", DoRetPeek, "PeekMessageW", DoRetPeek, #else "CreateWindow", DoCreateWindowRet, "CreateWindowEx", DoCreateWindowRet, "GetMessage", DoGetMessageRet, "PeekMessage", DoRetPeek, #endif "GlobalLock", DoRetSimpleLPSTR, "GlobalWire", DoRetSimpleLPSTR, "_lread", DoRet_lread, "GetKeyboardState", DoGetSetKeyboardState, "LockResource", DoRetSimpleLPSTR, "Escape", DoRetEscape, "GetPaletteEntries", DoRetPalettes, "GlobalHandle", DoRetGlobalHandle, "GetClipboardData", DoRetGetClipboardData, "GetSystemPaletteEntries", DoRetPalettes } ; int nRetSpecialCases = sizeof(RetSpecialCases)/sizeof(RetSpecialCases[0]) ; unsigned int nLogBuff = LOG_BUFF ; char LogBuffer[LOG_BUFF+1] = {0}; LPSTR LogPtr = (LPSTR)LogBuffer; unsigned int nLogSize; char far *SCP; WORD far *WCP; OFSTRUCT ofFileData, ofDataFile; BOOL fFlushed = FALSE; void CheckEntryForInstTable (WORD hInstanceCaller); VOID FAR LogInstanceIn(LPSTR lpstrFormat, ...); VOID FAR LogInstanceOut(LPSTR lpstrFormat,...); #ifdef WIN32 BOOL WINAPI Logger32SetType( DWORD dwFlags ) { if( dwFlags & LOGGER_DRVLOG ) { ACCESS(fDrvLog) = TRUE ; ACCESS(fLogSync) = TRUE ; } if( dwFlags & LOGGER_ENGLOG ) { ACCESS(fDrvLog) = TRUE ; ACCESS(fLogSync) = TRUE ; } return TRUE ; ; } #endif void FlushBuff( void ) { HANDLE hLogFile; fFlushed = TRUE; if ( nLogSize != 0 ) { switch( ACCESS(cDbgPort) ) { case TRUE: *LogPtr = '\0'; LogPtr = (LPSTR)LogBuffer; OutputDebugString(LogPtr); break; case FALSE: LogPtr = (LPSTR)LogBuffer; hLogFile = OpenFile( ACCESS(szLogFileName), (LPOFSTRUCT)&ofFileData, OF_READWRITE | OF_REOPEN | OF_SHARE_DENY_NONE ); if( hLogFile ) { _llseek( hLogFile, 0L, 2 ); nLogSize = _lwrite( hLogFile, LogPtr, nLogSize ); _lclose( hLogFile ); } break; case 2: LogPtr = (LPSTR)LogBuffer; break; } nLogSize = 0; } } void WriteBuff( LPSTR lpText ) { char ch; while ( (ch = *lpText++) != '\0' ) { if ( nLogSize == nLogBuff ) { FlushBuff(); } *LogPtr++ = ch; nLogSize++; nLogSpot++; } } void EndLineBuff( void ) { WriteBuff( (LPSTR)"\r\n" ); if ( !ACCESS(fTiming) ) { switch( ACCESS(cDbgPort) ) { case 2: case TRUE: FlushBuff(); break; case FALSE: break; } } else { if( ACCESS(fLogSync) ) FlushBuff() ; // Sync'd logs mean EOL flushes } } HWND WhereWindow( HWND hWnd, POINT pt, BOOL *lpfInClient ) { HWND hWndChild; RECT rect; POINT ptCoord; /* ** Search through the list of children of the passed in window ** If found a child that it is in, then recurse, otherwise return window */ hWndChild = GetWindow( hWnd, GW_CHILD ); while ( hWndChild ) { GetWindowRect( hWndChild, &rect ); if ( PtInRect(&rect, pt) ) { return( WhereWindow(hWndChild,pt,lpfInClient) ); } hWndChild = GetWindow( hWndChild, GW_HWNDNEXT ); } GetClientRect( hWnd, &rect ); ptCoord.x = rect.left; ptCoord.y = rect.top; ClientToScreen( hWnd, &ptCoord ); rect.left = ptCoord.x; rect.top = ptCoord.y; ptCoord.x = rect.right; ptCoord.y = rect.bottom; ClientToScreen( hWnd, &ptCoord ); rect.right = ptCoord.x; rect.bottom = ptCoord.y; *lpfInClient = PtInRect(&rect,pt); return( hWnd ); } void FAR PASCAL filterfunc( int nCode, WORD wParam, DWORD lParam ) { LPEVENTMSG msg; HWND hwndCapture; msg = (LPEVENTMSG)lParam; if ( msg != NULL ) { switch( msg->message ) { default: hwndCapture = GetCapture(); if( hwndCapture == NULL ) hwndCapture = GetFocus() ; break ; case WM_MOUSEMOVE: { POINT pt ; BOOL f; pt.x = msg->paramL ; pt.y = msg->paramH ; hwndCapture = WhereWindow( GetDesktopWindow(), pt, &f ); } break ; } wsprintf( chBuffer, "++|INPUT:x {%04X %04X %04X %08lX} %04X", msg->message, msg->paramL, msg->paramH, msg->time, hwndCapture ); WriteBuff( chBuffer ); EndLineBuff(); } if ( nCode < 0 ) { DefHookProc( nCode, wParam, lParam, &hOldHook ); } } void FAR PASCAL EvtLogHook( int nCode, WORD wParam, DWORD lParam ) { LPEVENTMSG msg; HWND hwndCapture; msg = (LPEVENTMSG)lParam; if ( msg != NULL ) { hwndCapture = GetCapture(); wsprintf( chBuffer, "++|INPUT:x {%04X %04X %04X %08lX} %04X ", msg->message, msg->paramL, msg->paramH, msg->time, hwndCapture ); WriteBuff( chBuffer ); EndLineBuff(); } } /* ** This function will be called by MS-TEST/WINPLAY tools if running */ BOOL fAutoDrive = FALSE ; DWORD FAR PASCAL InitLogger( void ) { DWORD dwRet ; fAutoDrive = TRUE ; dwRet = (DWORD)EvtLogHook ; return dwRet ; } void GlobalInitLib( BOOL fInit ) { char text[100]; if( fInit ) { /* ** Get Controlling information from the .INI file */ ACCESS(cDbgPort) = GetProfileInt( "Logger", "DbgPort", FALSE ); ACCESS(fTiming) = GetProfileInt( "Logger", "Timing", FALSE ); ACCESS(fNotes) = GetProfileInt( "Logger", "Notes", TRUE ); ACCESS(fINT21H) = GetProfileInt( "Logger", "Int21h", ACCESS(fINT21H) ) ; ACCESS(fAPIOnly) = GetProfileInt( "Logger", "APIOnly", FALSE ) ; ACCESS(fLogSync) = GetProfileInt( "Logger", "LogSync", FALSE ) ; ACCESS(fElapsedTimes)= GetProfileInt( "Logger", "TimerTicks", FALSE ) ? FALSE : TRUE ; #ifdef WIN32 if( !ACCESS(fLogSync) ) { GetProfileString( "LOGGER", "LogFile", "OUTPUT32.LOG", ACCESS(szLogFileName), sizeof(ACCESS(szLogFileName)) ); GetProfileString( "LOGGER", "DatFile", "OUTPUT32.DAT", ACCESS(szDatFileName), sizeof(ACCESS(szDatFileName)) ); } else #endif { GetProfileString( "LOGGER", "LogFile", "OUTPUT.LOG", ACCESS(szLogFileName), sizeof(ACCESS(szLogFileName)) ); GetProfileString( "LOGGER", "DatFile", "OUTPUT.DAT", ACCESS(szDatFileName), sizeof(ACCESS(szDatFileName)) ); } if ( ACCESS(fTiming) ) { ACCESS(fLogObjects) = GetProfileInt( "LOGGER", "LogObjects", FALSE ); } else { ACCESS(fLogObjects) = GetProfileInt( "LOGGER", "LogObjects", TRUE ); } ACCESS(nLogIndent) = 1; ACCESS(fLogInit) = TRUE; // Create/Truncate the the files #if !defined(WIN32) // Since Logger32 would be loaded first make sure that 16 bit Logger doesn't truncate // the log that Logger32 has already written to. if( ACCESS(fLogSync) ) { HANDLE hLogFile, hDataFile; hLogFile = OpenFile( ACCESS(szLogFileName), (LPOFSTRUCT)&ofFileData, OF_WRITE | OF_SHARE_DENY_NONE ); _lclose( hLogFile ); hDataFile = OpenFile( ACCESS(szDatFileName), (LPOFSTRUCT)&ofDataFile, OF_WRITE | OF_SHARE_DENY_NONE ); _lclose( hDataFile ); } else #endif { HANDLE hLogFile, hDataFile; hLogFile = OpenFile( ACCESS(szLogFileName), (LPOFSTRUCT)&ofFileData, OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE ); _lclose( hLogFile ); hDataFile = OpenFile( ACCESS(szDatFileName), (LPOFSTRUCT)&ofDataFile, OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE ); _lclose( hDataFile ); } // Do Header Info /* ** Determine the current directory */ #if !defined(WIN32) if( !ACCESS(fLogSync) ) #endif { int hTempFile; OFSTRUCT ofTemp; char *pch; char *pchLastDelimiter; hTempFile = OpenFile( "LOGGER.TMP", (LPOFSTRUCT)&ofTemp, OF_CREATE | OF_WRITE | OF_SHARE_DENY_NONE ); _lclose( hTempFile ); pch = ofTemp.szPathName; while ( *pch ) { if ( *pch == '\\' || *pch == '/' ) { pchLastDelimiter = pch; } pch++; } strcpy( ACCESS(achCurrentDirectory), ofTemp.szPathName ); ACCESS(achCurrentDirectory)[pchLastDelimiter - ofTemp.szPathName] = '\0'; wsprintf( text, "++|Current directory is [%s]", (LPSTR)ACCESS(achCurrentDirectory) ); WriteBuff( text ); EndLineBuff(); } #if !defined(WIN32) if( !ACCESS(fLogSync) ) #endif if ( fAlias ) { WriteBuff("++|Aliasing Enabled"); EndLineBuff(); } if ( ACCESS(fTiming) ) #if !defined(WIN32) if( !ACCESS(fLogSync) ) #endif { // Show that we think we are timing if( ACCESS(fElapsedTimes) ) { wsprintf( text,"++|Timing (Elapsed) Enabled" ) ; } else { wsprintf( text,"++|Timing (Ticks) Enabled" ) ; } WriteBuff(text); EndLineBuff(); } } else { // Logger is being inited for the second time. // Flush the current instance's buffers and go into LogSync mode. FlushBuff() ; ACCESS(fLogSync) = TRUE ; } } void LocalInitLib( void ) { int count; unsigned char hashvalue; DWORD version; WORD SpecialDS; BOOL fMouseHack; /* ** Determine which system we are on */ WindowsVerRunning = (int)GetVersion(); nLogBuff = GetProfileInt( "Logger", "FlushAfter", nLogBuff ) ; fAlias = GetProfileInt( "LOGGER", "Alias", FALSE ); /* ** Under WOW, default to no mousehack ** On Win 3.1, default to yes mousehack */ fMouseHack = GetProfileInt( "LOGGER", "MouseHack", !ACCESS(fWOW) ); /* ** Initialize the logging variables */ LogPtr = (LPSTR)LogBuffer; nLogSize = 0; /* ** Install a journal recording hook (input queue hook) so that ** we can watch the app being fed. */ fInputHook = GetProfileInt( "LOGGER", "InputHook", FALSE ); if ( fInputHook ) { fpNewHook = MakeProcInstance((FARPROC)filterfunc,hLibInstance); hOldHook = (HHOOK)SetWindowsHook( WH_JOURNALRECORD, (HOOKPROC)fpNewHook ); } /* ** Also initialize the type I/O hash table */ for ( count = 0; count < nIoTypes; count++ ) { /* ** Process this IoRtn */ hashvalue = (char)HASH_FUNC(IoTypes[count].name); IoTypes[count].next = typehash[hashvalue]; typehash[hashvalue] = &IoTypes[count]; } if ( fMouseHack ) { /* ** Initialize the special hack variables */ SCP = (char FAR *)SetCursorPos + 9; WCP = (WORD FAR *)SCP; version = GetVersion(); if ( version == 0x003 ) { SpecialDS = *WCP; lpfMouseMoved = (int FAR *)MAKELONG(0x0004,SpecialDS); } SCP += 5; WCP = (WORD far *)SCP; if ( version == 0xA03 ) { SpecialDS = *WCP; lpfMouseMoved = (int FAR *)MAKELONG(0x0002,SpecialDS); } } SetupCorrespondenceTables(); if( ACCESS(fTiming) && !ACCESS(fElapsedTimes) ) { // Open and init the global timer TimerOpen ((short far *)&TimerHandle[0], MICROSECONDS); TimerInit (TimerHandle[0]); CalibrateTimer() ; fTimerCalibrated = TRUE ; } } void InitLib( BOOL bInit ) { GlobalInitLib(bInit) ; LocalInitLib() ; } /*-------------------------------------------------------------------------- ** WEP() - Called when the DLL is unloaded. ** This routine closes the log file. **-------------------------------------------------------------------------- */ VOID FAR PASCAL WEP( int bSystemExit ) { // char lpText[60]; /* ** Unhook the journal recording hook */ if( fInputHook ) { UnhookWindowsHook( WH_JOURNALRECORD, (HOOKPROC)fpNewHook ); } /* ** Close the log file */ FlushBuff(); // Notify MS-TEST/WINPLAY that we are being unloaded if( fAutoDrive ) { void (FAR WINAPI *fp)( DWORD ); HANDLE hMod ; hMod = GetModuleHandle( "TESTEVNT.DLL" ) ; if( hMod == NULL ) { hMod = GetModuleHandle( "WATTEVNT.DLL" ) ; } if( hMod ) { fp = (void (FAR WINAPI *)(DWORD))GetProcAddress( hMod, "RegisterLogger" ) ; if( fp ) { (*fp)( (DWORD)NULL ) ; } } } #ifdef WIN32 #else // set the int21 handler to be handled by the original handler. if( fINT21H ) GetSetKernelDOSProc ((DWORD)OrigHandler); #endif return; } #ifdef WIN32 /*----------------------------------------------------------------------------- ** NT needs this to know when the DLL is going away (when to call the WEP). **----------------------------------------------------------------------------- */ BOOL APIENTRY LibMain(HANDLE hModule, DWORD fdwReason, PCONTEXT pContext) { BOOL fInit = TRUE ; #ifdef SHARED_MEM BOOL fIgnore; PSECURITY_DESCRIPTOR psd ; DWORD dwErr ; #endif /* ** We're just going to set them equal for now. This removes compiler ** warnings under NT. */ pContext = pContext; hModule = hModule; switch ( fdwReason ) { case DLL_PROCESS_ATTACH: #ifdef SHARED_MEM // Need a Security Descriptor to make sure ALL processes can get // to the shared memory psd = (PSECURITY_DESCRIPTOR)LocalAlloc( LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH ) ; if( !psd ) { OutputDebugString( "LOGGER32:LocalAlloc failed for security descriptor\n" ) ; return FALSE ; } if( !InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION) ) { OutputDebugString( "LOGGER32:Failed to init security descriptor\n" ) ; } if( !SetSecurityDescriptorDacl( psd, TRUE, (PACL)NULL, FALSE ) ) { OutputDebugString( "LOGGER32:Set DACL failed!\n" ) ; } hMapObject = CreateFileMapping( (HANDLE) 0xFFFFFFFF, /* use paging file */ psd, /* security attr. */ PAGE_READWRITE, /* read/write access */ 0, /* size: high 32-bits */ SHMEMSIZE, /* size: low 32-bits */ "LOGGER32MemoryMap"); /* name of map object */ dwErr = GetLastError() ; if (hMapObject == NULL) { OutputDebugString( "LOGGER32:CreateFileMapping Failed!\n" ) ; return FALSE; } /* The first process to attach initializes memory. */ fInit = (dwErr != ERROR_ALREADY_EXISTS); /* Get a pointer to file mapped shared memory. */ pVars = MapViewOfFile( hMapObject, /* object to map view of */ FILE_MAP_WRITE, /* read/write access */ 0, /* high offset: map from */ 0, /* low offset: beginning */ 0); /* default: map entire file */ if (pVars == NULL) { OutputDebugString( "LOGGER32:MapViewOfFile failed!\n" ) ; return FALSE; } /* Initialize memory if this is the first process. */ if (fInit) { if( !SetKernelObjectSecurity( hMapObject, DACL_SECURITY_INFORMATION, psd ) ) { OutputDebugString("LOGGER32:FAILED to set KernelObjSecurity\n" ) ; } } #endif InitLib(fInit) ; #ifdef SHARED_MEM if( psd ) LocalFree( (HLOCAL)psd ) ; #endif break; case DLL_PROCESS_DETACH: WEP(0) ; #ifdef SHARED_MEM /* Unmap shared memory from process' address space. */ fIgnore = UnmapViewOfFile(pVars); /* Close the process' handle to the file-mapping object. */ fIgnore = CloseHandle(hMapObject); #endif break; } return TRUE ; } #endif /*----------------------------------------------------------------------------- ** lpartial_strcpy() - Called to copy only part of a string. ** This routine copies an entire string, or the string up until some specified ** character into a destination string. This is used to help parse the format ** string passed to LogStuff(). **----------------------------------------------------------------------------- */ LPSTR lpartial_strcpy( LPSTR lpstrDest, LPSTR lpstrSource, char ch, int nMaxLen ) { char chOther; while ( (chOther=*lpstrSource) != '\0' ) { lpstrSource++; if ( chOther == ch ) { *lpstrDest = '\0'; return(lpstrSource); } *lpstrDest++ = chOther; --nMaxLen; if ( nMaxLen == 0 ) { *lpstrDest = '\0'; return(lpstrSource); } } return( lpstrSource ); } /*----------------------------------------------------------------------------- ** LogStuff() - Called when something needs to be logged. ** This routine logs the parameters (based on type) into the log file. **----------------------------------------------------------------------------- */ VOID LogStuff( LPSTR lpstrFormat, unsigned long ulTime, va_list marker ) { char chType[9] ; char chApi[MAX_BUFF+1]; char chBuff[MAX_BUFF+1]; LPSTR lpDest; int nLen; LPSTR lpSpot; LPSTR lpNext; short s; unsigned char hashvalue; TYPEIO *typeio; int count; nLogLine++; nLineLen = 0; /* ** Log the information */ lpDest = (LPSTR)chBuff; #ifdef WIN32 wsprintf( lpDest, (LPSTR)"%02X!", ACCESS(nLogIndent) ); #else wsprintf( lpDest, (LPSTR)"%02X|", ACCESS(nLogIndent) ); #endif WriteBuff( lpDest ); nLineLen += 3; if( ACCESS(fTiming) ) { wsprintf( lpDest, (LPSTR)" %08lX|", ulTime ); WriteBuff( (LPSTR)lpDest ); nLineLen += 10; } /* pull off the identifier */ lpSpot = lpartial_strcpy( chType, lpstrFormat, ':', MAX_BUFF ); WriteBuff( (LPSTR)chType ) ; WriteBuff( (LPSTR)":" ) ; nLineLen += lstrlen(chType) + 1; if ( chType[0] != 'M' ) { /* pull off API name */ lpDest = (LPSTR)chApi; lpSpot = lpartial_strcpy( lpDest, lpSpot, ' ', MAX_BUFF ); WriteBuff( lpDest ); if ( ACCESS(fTiming) == 2 || ACCESS(fAPIOnly) ) { EndLineBuff(); return; } // have to save and restore di & si registers while calling Dos3Call. // This is currently not done in the z Dlls. if (chApi[3] == '3') fDos3Call = TRUE; // WriteBuff( (LPSTR)" " ); nLineLen += lstrlen(lpDest) + 1; } else { if( ACCESS(fAPIOnly) ) { EndLineBuff() ; return ; } if ( ACCESS(fTiming) == 2 ) { WriteBuff( (LPSTR)"?" ); EndLineBuff(); return; } /* special MSGCALL/RET routine */ #ifdef WIN32 DoMessageA( (LPSTR)chType, lpSpot, marker ) ; #else DoMessage( (LPSTR)chType, lpSpot, marker ) ; #endif EndLineBuff() ; return ; } /* Do we need to call a special case ?? */ if ( chType[3] == 'C' ) /* CALL special cases */ { for( count = 0; count < nSpecialCases; count++ ) { if( lstrcmp( (LPSTR)chApi, (LPSTR)SpecialCases[count].name) == 0 ) { /* call special case and return */ (*SpecialCases[count].rtn)( (LPSTR)chApi, lpSpot, marker ) ; EndLineBuff() ; return ; } } } else { /* RET special cases */ for( count = 0; count < nRetSpecialCases; count++ ) { if( lstrcmp( (LPSTR)chApi, (LPSTR)RetSpecialCases[count].name) == 0 ) { /* call special case and return */ (*RetSpecialCases[count].rtn)( (LPSTR)chApi, lpSpot, marker ) ; EndLineBuff() ; return ; } } } lpDest = (LPSTR)chBuff; while ( TRUE ) { lpNext = lpartial_strcpy( lpDest, lpSpot, '+', MAX_BUFF ); if ( lpNext == lpSpot ) { break; } nLen = lstrlen( lpDest ); if ( nLen == 0 ) { /* ** Default is an unprintable short (really a 0) */ s = va_arg( marker, short ); lpSpot = lpNext; continue ; } else { hashvalue = HASH_FUNC( lpDest ); typeio = typehash[hashvalue]; while ( typeio ) { if ( lstrcmp(lpDest,(LPSTR)typeio->name) == 0 ) { marker = (* typeio->rtn)( (LPSTR)chApi, marker ); break; } typeio = typeio->next; } if ( typeio == NULL ) { for ( count = 0; count < nIoTypes; count++ ) { if ( lstrcmp(lpDest,(LPSTR)IoTypes[count].name) == 0 ) { WriteBuff( (LPSTR)"$Internal Logging Data Corrupted$" ); marker = (* IoTypes[count].rtn)( (LPSTR)chApi, marker ); typeio = &IoTypes[count]; break; } } } if ( typeio == NULL ) { /* ** These IFDEFs should be removed at some point. After we have most of the ** 32-bit structures being dumped. */ WriteBuff("\nUNKNOWN IOType:" ) ; //*** MJR MJR WriteBuff( lpDest ); WriteBuff("!!!!!\n" ) ; //*** MJR MJR FlushBuff() ; // Force write incase we fault nLineLen += lstrlen(lpDest); } } WriteBuff( (LPSTR)" " ); nLineLen++; lpSpot = lpNext; } EndLineBuff(); } /*----------------------------------------------------------------------------- ** LogIn() - Called when an API is about to be called with Input parameters ** This routine logs the input parameters to the log file. **----------------------------------------------------------------------------- */ VOID FAR LogIn( LPSTR lpstrFormat, ... ) { va_list marker; // NTWINT had moved this outside LogIn ULONG ulTime = 0 ; #ifdef WIN32 DWORD dwError = GetLastError() ; #endif #ifdef INT21H if( fINT21H ) { fLogIn = TRUE; ++cLogInInt21; } #endif if ( !ACCESS(fLogInit) ) { InitLib( TRUE ); } if( ACCESS(fTiming) && !ACCESS(fElapsedTimes) ) { ulTime = TimerRead(TimerHandle[0]) ; } switch( ACCESS(cDbg) ) { case REST: break; case 0: case 1: case 2: FlushBuff(); ACCESS(cDbgPort) = ACCESS(cDbg); ACCESS(cDbg) = REST; break; } switch( ACCESS(cDbgPort) ) { case 2: break; case TRUE: case FALSE: va_start( marker, lpstrFormat ); LogStuff( lpstrFormat, ulTime, marker ); va_end( marker ); break; } ACCESS(nLogIndent)++; #ifdef INT21H if( fINT21H ) --cLogInInt21; #endif if( ACCESS(fTiming) && ACCESS(fElapsedTimes) ) { // Time all calls, API, MSG etc. TimerOpen((short far *)&TimerHandle[ACCESS(nLogIndent)-1], MICROSECONDS); TimerInit(TimerHandle[ACCESS(nLogIndent)-1]); } #ifdef WIN32 SetLastError(dwError) ; #endif } /*----------------------------------------------------------------------------- ** LogData() - Called when someone wants to output some data. **--------------------------------------------------------------------------- */ VOID FAR LogData( LPSTR lpstrFormat, ... ) { va_list marker; if ( !ACCESS(fLogInit) ) { InitLib( TRUE ); } switch( ACCESS(cDbg) ) { case REST: break; case 0: case 1: case 2: FlushBuff(); ACCESS(cDbgPort) = ACCESS(cDbg) ; ACCESS(cDbg) = REST; break; } switch( ACCESS(cDbgPort) ) { case 2: break; case TRUE: case FALSE: va_start( marker, lpstrFormat ); LogStuff( lpstrFormat, 0, marker ); va_end( marker ); break; } } /*----------------------------------------------------------------------------- ** LogOut() - Called when an API has just returned with Output parameters and ** return code. This routine logs the output parameters to the log file. **----------------------------------------------------------------------------- */ // logging timing info char chType[9] ; char chIdent[9] ; char chApi[MAX_BUFF+1]; char chBuff[MAX_BUFF+1]; LPSTR lpDest, lpDestString, lpNew; int nLen; LPSTR lpSpot; unsigned long ulElapsedTime = 0L; VOID FAR LogOut( LPSTR lpstrFormat, ... ) { va_list marker; // Commented out in NTWINT version #ifdef WIN32 DWORD dwError = GetLastError() ; #endif if ( !ACCESS(fLogInit) ) { InitLib( TRUE ); } if( ACCESS(fTiming) ) { // get the time for the API, MSG etc. call // Dos3Call uses si and di. These two are not saved and // restored by the z dll's. Until that is done, we can have // fix in. - vaidy, June 8, 1992. //#if !defined(WIN32) // if (fDos3Call) { // _asm { // push di // push si // push es // push ds // push dx // push cx // push bx // push ax // }; // } //#endif if( ACCESS(fElapsedTimes) ) { ulElapsedTime = TimerRead (TimerHandle[ACCESS(nLogIndent) - 1]); } else { ulElapsedTime = TimerRead(TimerHandle[0]); } //#if !defined(WIN32) // if (fDos3Call) { // _asm { // pop ax // pop bx // pop cx // pop dx // pop ds // pop es // pop si // pop di // }; // // fDos3Call = FALSE; // reset to FALSE. // } //#endif #ifdef INT21H if( fINT21H ) ++cLogInInt21; #endif // calibrate the timer for overhead if not already done if (!fTimerCalibrated) { CalibrateTimer (); fTimerCalibrated = TRUE; } if( ACCESS(fElapsedTimes) ) { TimerClose (TimerHandle[ACCESS(nLogIndent)-1]); } } // fTiming --ACCESS(nLogIndent); switch( ACCESS(cDbgPort) ) { case 2: break; case TRUE: case FALSE: va_start( marker, lpstrFormat ); LogStuff( lpstrFormat, (unsigned long)(ulElapsedTime - ulOverhead),marker ); va_end( marker ); break; } switch( ACCESS(cDbg) ) { case REST: break; case 0: case 1: case 2: FlushBuff(); ACCESS(cDbgPort) = ACCESS(cDbg) ; ACCESS(cDbg) = REST; break; } #ifdef INT21H if( fINT21H ) --cLogInInt21; #endif #ifdef WIN32 // restore last error SetLastError(dwError) ; #endif } DWORD StoreData( LPCSTR lpstrData, DWORD dwCount) { DWORD dwEnd; HANDLE hDataFile; hDataFile = OpenFile( ACCESS(szDatFileName), (LPOFSTRUCT)&ofDataFile, OF_READWRITE | OF_REOPEN | OF_SHARE_DENY_NONE ); dwEnd = (DWORD) _llseek( hDataFile, 0L, 2 ); _lwrite( hDataFile, (LPSTR)&dwCount, sizeof(DWORD)); _lwrite( hDataFile, lpstrData, (int) dwCount); _lclose( hDataFile ); return dwEnd; } UINT FAR PASCAL GetLogInfo( UINT iInfoType ) { switch( iInfoType ) { case LOG_OBJECTS: return( (UINT)ACCESS(fLogObjects) ); default: return( (UINT)0 ); } } /*---------------------------------------------------------------------------- ** CalibrateTimer() - Calibrates the timer for overhead in saving and ** restoring registers. **---------------------------------------------------------------------------- */ #define MAX_REPEAT_FOR_CALIBRATION 250 unsigned long ulRepetitions = 0L; unsigned long ulLogIn [MAX_REPEAT_FOR_CALIBRATION]; unsigned long ulLogOut [MAX_REPEAT_FOR_CALIBRATION]; void CalibrateTimer(void) { short CalibrationHandle; unsigned long ulMinLogIn = 2000000L, ulMinLogOut = 2000000L; TimerOpen ((short far *) &CalibrationHandle, MICROSECONDS); while (ulRepetitions < MAX_REPEAT_FOR_CALIBRATION) { #if !defined(WIN32) SaveRegs(); // do not time this #endif TimerInit (CalibrationHandle); #if !defined(WIN32) RestoreRegs(); GrovelDS(); #endif ulLogIn[ulRepetitions] = TimerRead (CalibrationHandle); // login overhead done. Calibrate LogOut. TimerInit (CalibrationHandle); #if !defined(WIN32) UnGrovelDS(); SaveRegs(); #endif ulLogOut[ulRepetitions++] = TimerRead (CalibrationHandle); // do not time #if !defined(WIN32) RestoreRegs(); #endif } // end of while // grab the minimum of LogIn and LogOut overheads and sum them // for overall overhead. for (ulRepetitions = 0L; ulRepetitions < MAX_REPEAT_FOR_CALIBRATION; ulRepetitions++) { if (ulLogIn[ulRepetitions] < ulMinLogIn) ulMinLogIn = ulLogIn[ulRepetitions]; if (ulLogOut[ulRepetitions] < ulMinLogOut) ulMinLogOut = ulLogOut[ulRepetitions]; } ulOverhead = ulMinLogIn + ulMinLogOut; return; } #if !defined(WIN32) /********************************************************************* PURPOSE: Contains library routines for the logger FUNCTION: LibMain (HANDLE, WORD, WORD, LPSTR) PURPOSE: Is called by LibEntry. LibEntry is called by Windows when the DLL is loaded. The LibEntry routine is provided in the LIBENTRY.OBJ in the SDK Link Libraries disk. (The source LIBENTRY.ASM is also provided.) LibEntry initializes the DLL's heap, if a HEAPSIZE value is specified in the DLL's DEF file. Then LibEntry calls LibMain. The LibMain function below satisfies that call. The LibMain function should perform additional initialization tasks required by the DLL. LibMain should return a value of 1 if the initialization is successful. */ /*********************************************************************/ int FAR PASCAL LibMain(hModule, wDataSeg, cbHeapSize, lpszCmdLine) HANDLE hModule; WORD wDataSeg; WORD cbHeapSize; LPSTR lpszCmdLine; { #ifdef INT21H if( fINT21H ) DoInt21Init(); #endif return(1); } #endif #ifdef INT21H UINT WINAPI PrestoChangoSelector(UINT sourceSel, UINT destSel); UINT WINAPI AllocSelector(UINT); /* * DoInt21Init() - called by LibMain to install the new Int21 Handler * * Accepts and returns nothing */ void DoInt21Init () { // get the original handler and replace with the address of // the private handler. // lpOrig points to OrigHandler. lpOrig = &OrigHandler; uSel = AllocSelector (HIWORD(lpOrig)); // change the CS to a DS selector. This way, we can write // to OrigHandler. If we do not go thru' this, we will get // a GP fault when we try to get the original Int21 handler // & try to store it. wSelData = PrestoChangoSelector ((UINT)HIWORD(lpOrig), uSel); // we need to retain the LOWORD of lpOrig but get the // new DS selector into the HIWORD of lpOrig. dwTemp = wSelData; dwTemp <<= 16; lpOrig = (LPDWORD)((DWORD)lpOrig & 0xFFFF); lpOrig = (LPDWORD) (dwTemp | (DWORD)lpOrig); // call the kernel API to return the address of the // original Int21 Handler. *lpOrig = GetSetKernelDOSProc ((DWORD) _Int21_Handler); } #pragma pack (1) // pack on byte boundary for the MYFCB struct. /* * LogInt21Calls - gets called from the Int21 handler (handler.asm) * * Purpose is to log the params of the Int 21 calls * * Accepts - a whole bunch of regs and flags, returns - nothing */ char chType[9] ; char chBuff[MAX_BUFF+1]; LPSTR lpDest; char Dummy[50]; BOOL fTimeInt21 = FALSE; short hTimerInt21 = 0; typedef struct _myfcb _MYFCB; struct _myfcb { char char1; char Reserved [5]; char Attrib; char DriveID; char FileName[8]; char Extension[3]; int CurrentBlock; int RecordSize; long FileSize; int Date; int Time; char LongReserved[8]; char CurrentRecord; long RelativeRecord; } ; _MYFCB FAR * pmyFCB; typedef struct _fn17hfcb _FN17HFCB; struct _fn17hfcb { char DriveID; char OldFileName[8]; char OldExtension[3]; char Reserved[5]; char NewFileName[8]; char NewExtension[3]; char Zeroed[9]; }; _FN17HFCB FAR * pfn17FCB; int iCount = 0; char szFileName [9]; char szExtension [4]; char szNewFileName [9]; char szNewExtension [4]; char szPathName [MAX_PATH_NAME_LEN]; LPSTR pPathName; WORD Int21Function = 0; void _loadds LogInt21Calls ( WORD wFlags, WORD wBP, WORD wSS, WORD wES, WORD wDS, WORD wSI, WORD wDI, WORD wDX, WORD wCX, WORD wBX, WORD wAX, WORD Dummy1, WORD Dummy2, WORD Dummy3, WORD Dummy4, WORD wIP, WORD wCS ) { if (!cLogInInt21) { // makes sure that we are not logging spurious disk // I/O. // log only if at an odd level & log only if logger has logged // one Windows API. if (((nLogIndent) & 1) && fLogIn) { // set the int21 handler to be handled by the original handler. // We need to log the Int21 call, right? GetSetKernelDOSProc ((DWORD)OrigHandler); // print & count only if the call is not from // the KERNEL, GDI or USER. // if ((lstrcmp (ModuleEntry.szModule, "KERNEL") != 0) && // (lstrcmp (ModuleEntry.szModule, "USER") != 0) && // (lstrcmp (ModuleEntry.szModule, "GDI") != 0)) { // for the present just add up all Int21 calls made by app cInt21CallsByApp++; lpDest = (LPSTR)chBuff; // filter out all Int 21 Function 50 calls if (HIBYTE(wAX) != 0x50) { wsprintf( lpDest, (LPSTR)"%02X|APICALL: Int21h %x", nLogIndent, HIBYTE(wAX)); WriteBuff( lpDest ); nLineLen += 3; } memset (szPathName, '\0', MAX_PATH_NAME_LEN); switch (HIBYTE(wAX)) { case 0x0E: // Select Disk case 0x1C: // Get Drive Data case 0x36: // Get Disk free Space wsprintf( lpDest, (LPSTR)"%x ", LOBYTE(wDX)); WriteBuff( (LPSTR)lpDest ) ; break; // FCB based File operations /* case 0x0F: // OpenFile with FCB case 0x10: // CloseFile with FCB case 0x11: // Find First File case 0x12: // Find Next File case 0x13: // Delete File case 0x14: // Sequential Read case 0x15: // Sequential Write case 0x16: // Create File with FCB case 0x21: // Random Read with FCB case 0x22: // Random Write with FCB case 0x23: // Get File Size with FCB case 0x24: // Set Relative Record with FCB case 0x27: // Random Block Read with FCB case 0x28: // Random Block Write with FCB // make a long pointer out if DS:DX for the FCB. pmyFCB = MAKELP (wDS, wDX); // make strings out of the FileName & Extension while (iCount < 8) { szFileName[iCount] = pmyFCB->FileName[iCount++]; } szFileName[iCount] = '\0'; iCount = 0; while (iCount < 3) { szExtension[iCount] = pmyFCB->Extension[iCount++]; } szExtension[iCount] = '\0'; wsprintf (lpDest, "GARBAGE"); WriteBuff((LPSTR)lpDest); wsprintf (lpDest, "%x %d %s %s %d %d %l %d %d %d %l ", pmyFCB->Attrib, pmyFCB->DriveID, szFileName, szExtension, pmyFCB->CurrentBlock, pmyFCB->RecordSize, pmyFCB->FileSize, pmyFCB->Date, pmyFCB->Time, pmyFCB->CurrentRecord, pmyFCB->RelativeRecord); // write 'em all out. WriteBuff( (LPSTR)lpDest ) ; // if Block I/O, dump # records if ((wAX == 0x27) || (wAX == 0x28)) { wsprintf (lpDest, "%x ", wCX); WriteBuff ((LPSTR) lpDest); } break; case 0x17: // Rename File with FCB // uses a special FCB pfn17FCB = MAKELP (wDS, wDX); iCount = 0; // make strings out of the FileNames & Extensions while (iCount < 8) { szFileName[iCount] = pfn17FCB->OldFileName[iCount]; szNewFileName[iCount] = pfn17FCB->OldFileName[iCount++]; } szFileName[iCount] = '\0'; szNewFileName[iCount] = '\0'; iCount = 0; while (iCount < 3) { szExtension[iCount] = pfn17FCB->OldExtension[iCount]; szNewExtension[iCount] = pfn17FCB->NewExtension[iCount++]; } szExtension[iCount] = '\0'; szNewExtension[iCount] = '\0'; wsprintf (lpDest, "%d %s %s %s %s ", pfn17FCB->DriveID, szFileName, szExtension, szNewFileName, szNewExtension); // write 'em all out. WriteBuff( (LPSTR)lpDest ) ; break; */ case 0x1A: // Set DTA Address wsprintf( lpDest, (LPSTR)"%x:%x ", wDS, wDX); WriteBuff( (LPSTR)lpDest ) ; break; case 0x3C: // Create File with Handle case 0x3D: // Open File with Handle case 0x41: // Delete File case 0x4E: // Find First File case 0x5B: // Create New File // get the attribute for Create File/FindFirst/ // Create New File if ((HIBYTE (wAX) == 0x3C) || (HIBYTE (wAX) == 0x4E) ||(HIBYTE (wAX) == 0x5B) ) { wsprintf( lpDest, (LPSTR)"%x ", wCX); WriteBuff( (LPSTR)lpDest ) ; } // get the access code if Open File call else if (HIBYTE (wAX) == 0x3D) { wsprintf( lpDest, (LPSTR)"%x ", LOBYTE(wAX)); WriteBuff( (LPSTR)lpDest ) ; } // get the path name pPathName = MAKELP (wDS, wDX); iCount = 0; while (*pPathName != '\0') { szPathName[iCount++] = *pPathName; pPathName++; } wsprintf (lpDest, "%s ", szPathName); WriteBuff( (LPSTR) szPathName); break; case 0x3E: // Close File with Handle, BX contains handle wsprintf (lpDest, "%x ", wBX); WriteBuff( (LPSTR) lpDest); break; case 0x3F: // Read File thru' Handle case 0x40: // Write File thru' Handle // dump the handle and the # bytes read/written wsprintf (lpDest, "%x %x ", wBX, wCX); WriteBuff( (LPSTR) lpDest); break; case 0x42: // move file pointer wsprintf (lpDest, "%x %x %x %x ", LOBYTE(wAX), wBX, wCX, wDX); WriteBuff( (LPSTR) lpDest); break; case 0x43: // Get/Set File Attributes wsprintf (lpDest, "%x ", LOBYTE (wAX)); WriteBuff( (LPSTR) lpDest); // get attributes to set if (LOBYTE(wAX) == 0) { wsprintf (lpDest, "%x ", wCX); WriteBuff( (LPSTR) lpDest); } // get the path name pPathName = MAKELP (wDS, wDX); iCount = 0; while (*pPathName != '\0') { szPathName[iCount++] = *pPathName; pPathName++; } wsprintf (lpDest, "%s ", szPathName); WriteBuff( (LPSTR) szPathName); break; case 0x45: // duplicate file handle case 0x46: // force duplicate file handle wsprintf (lpDest, "%x ", wBX); WriteBuff( (LPSTR) lpDest); if (HIBYTE(wAX) == 0x46) { wsprintf (lpDest, "%x ", wCX); WriteBuff( (LPSTR) lpDest); } break; case 0x44: // IOCTL calls. Just record the // sub-function wsprintf (lpDest, "%x ", LOBYTE(wAX)); WriteBuff( (LPSTR) lpDest); break; default: break; } // end of switch (HIBYTE(wAX)) // at the time of returning, AX may not contain // the name of the Int21 Function. So, in the // routine where we log output params, in order to // know the Function, we need to save it in a global. Int21Function = HIBYTE(wAX); // you don't want to End line for Function 50 calls. if (Int21Function != 0x50) EndLineBuff(); fTimeInt21 = TRUE; *lpOrig = GetSetKernelDOSProc ((DWORD) _Int21_Handler); } } ++ nLogIndent; // let us bump up the log level. We need only odd // level Int21s. These will be those called by the // application. // add up all the Int21 calls made (app or otherwise) ++cAllInt21Calls; if( ACCESS(fTiming) && ACCESS(fElapsedTimes) ) { // Time all Int21s TimerOpen ((short far *)&TimerHandle[nLogIndent-1], MICROSECONDS); TimerInit (TimerHandle[nLogIndent-1]); } return; } void _loadds LogOut21Calls ( WORD wFlags, WORD wDS, WORD wES, WORD wSI, WORD wDI, WORD wDX, WORD wCX, WORD wBX, WORD wAX, WORD wIP, WORD wCS ) { --nLogIndent; // Time int21s if it is the right call. if (fTimeInt21) { if( fTiming ) { ulElapsedTime = TimerRead (TimerHandle[nLogIndent]); if( ACCESS(fElapsedTimes) ) { TimerClose (TimerHandle[nLogIndent]); } } // set the int21 handler to be handled by the original handler. // more disk writing to do. I don't want this to go into // an infinite loop. GetSetKernelDOSProc ((DWORD)OrigHandler); // discard Int21 Function 50 calls if (Int21Function != 0x50) { lpDest = (LPSTR)&chBuff[0]; wsprintf( lpDest, (LPSTR)"%02X|APIRET:Int21h ", nLogIndent ); WriteBuff( lpDest ); nLineLen += 3; wsprintf( lpDest, (LPSTR)"%x %x ", wFlags, wAX); WriteBuff( (LPSTR)lpDest ) ; } switch (Int21Function) { /* case 0x1B: // get default drive data case 0x1C: // get drive data // FCB based File operations case 0x0F: // OpenFile with FCB case 0x10: // CloseFile with FCB case 0x11: // Find First File case 0x12: // Find Next File case 0x13: // Delete File case 0x14: // Sequential Read case 0x15: // Sequential Write case 0x16: // Create File with FCB case 0x21: // Random Read with FCB case 0x22: // Random Write with FCB case 0x23: // Get File Size with FCB case 0x24: // Set Relative Record with FCB case 0x27: // Random Block Read with FCB case 0x28: // Random Block Write with FCB // print out the return value. wsprintf( lpDest, (LPSTR)"%x ", LOBYTE(wAX)); WriteBuff( (LPSTR)lpDest ) ; pmyFCB = MAKELP (wDS, wDX); wsprintf (lpDest, "%x %d %s %s %d %d %l %d %d %d %l ", pmyFCB->Attrib, pmyFCB->DriveID, szFileName, szExtension, pmyFCB->CurrentBlock, pmyFCB->RecordSize, pmyFCB->FileSize, pmyFCB->Date, pmyFCB->Time, pmyFCB->CurrentRecord, pmyFCB->RelativeRecord); WriteBuff( (LPSTR)lpDest ) ; break; case 0x17: // Rename File with FCB // print out the return value. wsprintf( lpDest, (LPSTR)"%x", LOBYTE(wAX)); WriteBuff( (LPSTR)lpDest ) ; // uses a special FCB pfn17FCB = MAKELP (wDS, wDX); iCount = 0; // make strings out of the FileNames & Extensions while (iCount < 8) { szFileName[iCount] = pfn17FCB->OldFileName[iCount]; szNewFileName[iCount] = pfn17FCB->OldFileName[iCount++]; } szFileName[iCount] = '\0'; szNewFileName[iCount] = '\0'; iCount = 0; while (iCount < 3) { szExtension[iCount] = pfn17FCB->OldExtension[iCount]; szNewExtension[iCount] = pfn17FCB->NewExtension[iCount++]; } szExtension[iCount] = '\0'; szNewExtension[iCount] = '\0'; wsprintf (lpDest, "%d %s %s %s %s", pfn17FCB->DriveID, szFileName, szExtension, szNewFileName, szNewExtension); // write 'em all out. WriteBuff( (LPSTR)lpDest ) ; break; */ case 0x36: // Get Disk Free Space wsprintf (lpDest, "%x %x %x %x ", wAX, wBX, wCX, wDX); WriteBuff( (LPSTR) lpDest); break; case 0x3C: // Create File with Handle case 0x3D: // Open File with Handle case 0x3E: // Close File with Handle case 0x3F: // Read File thru' Handle case 0x40: // Write File thru' Handle case 0x41: // Delete File case 0x4E: // Find First File case 0x5B: // Create New File break; case 0x42: // move file pointer wsprintf (lpDest, "%x ", wDX); WriteBuff( (LPSTR) lpDest); break; case 0x43: // Get / Set File Attributes wsprintf (lpDest, "%x ", wCX); WriteBuff( (LPSTR) lpDest); break; default: break; } // end of switch (HIBYTE(wAX)) if (Int21Function != 0x50) EndLineBuff(); if( fTiming ) { if (Int21Function != 0x50) { lpDest = (LPSTR)&chBuff[0]; wsprintf( lpDest, (LPSTR)"%02X|APITIME:Int21h ", nLogIndent ); WriteBuff( lpDest ); wsprintf( lpDest, (LPSTR)"%lu ", ulElapsedTime); WriteBuff( (LPSTR)lpDest ) ; EndLineBuff(); } } fTimeInt21 = FALSE; // set it back to our Int21 handler *lpOrig = GetSetKernelDOSProc ((DWORD) _Int21_Handler); } } #pragma pack() // default packing #else // Dummy for conditional compiles without -DINT21H #if !defined(WIN32) void _loadds LogInt21Calls ( WORD wFlags, WORD wBP, WORD wSS, WORD wES, WORD wDS, WORD wSI, WORD wDI, WORD wDX, WORD wCX, WORD wBX, WORD wAX, WORD Dummy1, WORD Dummy2, WORD Dummy3, WORD Dummy4, WORD wIP, WORD wCS ) { } void _loadds LogOut21Calls ( WORD wFlags, WORD wDS, WORD wES, WORD wSI, WORD wDI, WORD wDX, WORD wCX, WORD wBX, WORD wAX, WORD wIP, WORD wCS ) { } #endif #endif