//============================================================================
// Copyright (c) 1995, Microsoft Corporation
//
// File: trace.h
//
// History:
//    Abolade Gbadegesin    July-24-1995    Created
//
// Private declarations for tracing API functions
//
// Support for both ANSI and Unicode is achieved by having separate
// versions of all code-page dependent functions for each.
// All source files containing code-page dependent functions contain only
// code-page dependent functions, and the build instructions copy the
// source files containing code-page dependent functions to two separate
// files, one of which is compiled with UNICODE defined, the other without.
//
// At this time the macros in this header file are resolved either to
// ANSI declarations or Unicode declarations for types and functions.
// Thus there is only one set of sources to maintain but compilation produces
// separate execution paths for clients using ANSI and Unicode.

// For example the file api.c which contains TraceRegisterEx will be copied
// to both api_a.c and api_w.c, and api_w.c will be compiled with -DUNICODE
// causing TraceRegisterEx in the file to resolve to TraceRegisterExW,
// and causing TCHAR and LPTSTR and LPCTSTR to resolve to WCHAR, LPWSTR, and
// LPCWSTR respectively; api_a.c will be compiled with UNICODE undefined,
// causing TraceRegisterEx to resolve to TraceRegisterExA, and causing TCHAR,
// LPTSTR and LPCTSTR to resolve to CHAR, LPSTR and LPCSTR respectively.
// The final DLL will then contain both TraceRegisterExA and TraceRegisterExW
// and clients which define UNICODE will end up invoking TraceRegisterExW
// and the other Unicode variants, while clients which do not will invoke
// TraceRegisterExA and the other ANSI variants.
//
// The server thread and the functions it invokes include explicit
// calls to the correct code-page dependent function based on whether the
// flag TRACEFLAGS_UNICODE is set in the client structure being operated on.
// Thus, the server is the only part of the system aware that more than one
// code page is in use, and the file server.c is compiled as is so the 
// single set of its functions deals with both ANSI and Unicode clients.
// The alternative would be to have two server threads when both
// ANSI and Unicode clients register in a single process, but this alternative
// is too costly in terms of resources and additional synchronization.
//============================================================================
    

#ifndef _TRACE_H_
#define _TRACE_H_


#define TRACEFLAGS_DISABLED     0x00000001
#define TRACEFLAGS_USEFILE      0x00000002
#define TRACEFLAGS_USECONSOLE   0x00000004
#define TRACEFLAGS_REGCONFIG    0x00000008
#define TRACEFLAGS_SERVERTHREAD 0x00000010


#define MAX_CLIENT_COUNT        60
#define MAX_CLIENTNAME_LENGTH   64


//
// strings associated with client registry configuration 
//

#define REGKEY_TRACING          TEXT("Software\\Microsoft\\Tracing")

#define REGVAL_ENABLEFILETRACING    TEXT("EnableFileTracing")
#define REGVAL_ENABLECONSOLETRACING TEXT("EnableConsoleTracing")
#define REGVAL_FILETRACINGMASK      TEXT("FileTracingMask")
#define REGVAL_CONSOLETRACINGMASK   TEXT("ConsoleTracingMask")
#define REGVAL_MAXFILESIZE          TEXT("MaxFileSize")
#define REGVAL_FILEDIRECTORY        TEXT("FileDirectory")

#define DEF_ENABLEFILETRACING       0
#define DEF_ENABLECONSOLETRACING    0
#define DEF_FILETRACINGMASK         0xffff0000
#define DEF_CONSOLETRACINGMASK      0xffff0000
#define DEF_MAXFILESIZE             0x100000
#define DEF_FILEDIRECTORY           TEXT("%windir%\\tracing")

#define DEF_SCREENBUF_WIDTH         128
#define DEF_SCREENBUF_HEIGHT        5000

//max line length:349
#define DEF_PRINT_BUFSIZE           10000
#define BYTES_PER_DUMPLINE          16

#define STR_DIRSEP                  TEXT("\\")
#define STR_LOGEXT                  TEXT(".LOG")
#define STR_OLDEXT                  TEXT(".OLD")



//
// structure describing each client.
// a client struct should be locked for writing when
//  enabling or disabling it, and when loading its configuration
// a client struct should be locked for reading on all other accesses
// 

typedef struct _TRACE_CLIENT {

    RTL_RESOURCE        ReadWriteLock;

    DWORD               TC_Flags;
    DWORD               TC_ClientID;

    CHAR                TC_ClientNameA[MAX_CLIENTNAME_LENGTH];
    WCHAR               TC_ClientNameW[MAX_CLIENTNAME_LENGTH];
#ifdef UNICODE
#define TC_ClientName   TC_ClientNameW
#else
#define TC_ClientName   TC_ClientNameA
#endif

    HANDLE              TC_File;
    HANDLE              TC_Console;
    DWORD               TC_FileMask;
    DWORD               TC_ConsoleMask;
    DWORD               TC_MaxFileSize;

    CHAR                TC_FileDirA[MAX_PATH];
    WCHAR               TC_FileDirW[MAX_PATH];

#ifdef UNICODE
#define TC_FileDir      TC_FileDirW
#else
#define TC_FileDir      TC_FileDirA
#endif

    HKEY                TC_ConfigKey;
    HANDLE              TC_ConfigEvent;

} TRACE_CLIENT, *LPTRACE_CLIENT;



//
// structure describing each server.
// a server struct must be locked for writing when adding
//  or removing a client to the client table, and when changing
//  the owner of the console
// a server should be locked for reading on all other accesses
//

typedef struct _TRACE_SERVER {

    RTL_RESOURCE        ReadWriteLock;

    DWORD               TS_Flags;
    DWORD               TS_ClientCount;
    DWORD               TS_ConsoleOwner;

    HANDLE              TS_Console;
    HANDLE              TS_StopEvent;
    HANDLE              TS_TableEvent;

    DWORD               TS_FlagsCache[MAX_CLIENT_COUNT];
    LPTRACE_CLIENT      TS_ClientTable[MAX_CLIENT_COUNT];


} TRACE_SERVER, *LPTRACE_SERVER;


#define GET_TRACE_SERVER() (                                    \
    (g_server!=NULL) ? g_server : TraceCreateServer(&g_server)	\
    )

#define GET_TRACE_SERVER_NO_INIT()	(g_server)

//
// macros used to lock client and server structures
//
#define TRACE_STARTUP_LOCKING(ob)                                       \
            RtlInitializeResource(&(ob)->ReadWriteLock)
#define TRACE_CLEANUP_LOCKING(ob)                                       \
            RtlDeleteResource(&(ob)->ReadWriteLock)
#define TRACE_ACQUIRE_READLOCK(ob)                                      \
            RtlAcquireResourceShared(&(ob)->ReadWriteLock, TRUE)
#define TRACE_RELEASE_READLOCK(ob)                                      \
            RtlReleaseResource(&(ob)->ReadWriteLock)
#define TRACE_ACQUIRE_WRITELOCK(ob)                                     \
            RtlAcquireResourceExclusive(&(ob)->ReadWriteLock, TRUE)
#define TRACE_RELEASE_WRITELOCK(ob)                                     \
            RtlReleaseResource(&(ob)->ReadWriteLock)
#define TRACE_READ_TO_WRITELOCK(ob)                                     \
            RtlConvertSharedToExclusive(&(ob)->ReadWriteLock)
#define TRACE_WRITE_TO_READLOCK(ob)                                     \
            RtlConvertExclusiveToShared(&(ob)->ReadWriteLock)


//
// macros used to interpret client flags
//
#define TRACE_CLIENT_IS_DISABLED(c)                                     \
            ((c)->TC_Flags & TRACEFLAGS_DISABLED)
#define TRACE_CLIENT_USES_FILE(c)                                       \
            ((c)->TC_Flags & TRACEFLAGS_USEFILE)
#define TRACE_CLIENT_USES_CONSOLE(c)                                    \
            ((c)->TC_Flags & TRACEFLAGS_USECONSOLE)
#define TRACE_CLIENT_USES_REGISTRY(c)                                   \
            ((c)->TC_Flags & TRACEFLAGS_REGCONFIG)
#define TRACE_CLIENT_USES_UNICODE(c)                                    \
            ((c)->TC_Flags & TRACEFLAGS_UNICODE)


// macro used to create server thread if required

DWORD
TraceCreateServerThread (
    DWORD Flags,
    BOOL bHaveLock,
    BOOL bTraceRegister
    );
    
#define CREATE_SERVER_THREAD_IF_REQUIRED()   {\
    if (!g_serverThread) TraceCreateServerThread(0, FALSE,FALSE);}



//
// code-page independent function declarations
//
LPTRACE_SERVER
TraceCreateServer(
    LPTRACE_SERVER *lpserver
    );

BOOL
TraceShutdownServer(
    LPTRACE_SERVER lpserver
    );

DWORD
TraceCleanUpServer(
    LPTRACE_SERVER lpserver
    );

DWORD
TraceServerThread(
    LPVOID lpvParam
    );

DWORD
TraceCreateServerComplete(
    LPTRACE_SERVER lpserver
    );


DWORD
TraceProcessConsoleInput(
    LPTRACE_SERVER lpserver
    );

DWORD
TraceShiftConsoleWindow(
    LPTRACE_CLIENT lpclient,
    INT iXShift,
    INT iYShift,
    PCONSOLE_SCREEN_BUFFER_INFO pcsbi
    );

DWORD
TraceUpdateConsoleOwner(
    LPTRACE_SERVER lpserver,
    INT dir
    );

VOID
SetWaitArray(
    LPTRACE_SERVER lpserver
    );


//
// code-page dependent function declarations
//
// ANSI declarations
//

LPTRACE_CLIENT
TraceFindClientA(
    LPTRACE_SERVER lpserver,
    LPCSTR lpszClient
    );

DWORD
TraceCreateClientA(
    LPTRACE_CLIENT *lplpentry
    );

DWORD
TraceDeleteClientA(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT *lplpentry
    );

DWORD
TraceEnableClientA(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient,
    BOOL bFirstTime
    );

DWORD
TraceDisableClientA(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceRegConfigClientA(
    LPTRACE_CLIENT lpclient,
    BOOL bFirstTime
    );

DWORD
TraceRegCreateDefaultsA(
    LPCSTR lpszTracing,
    PHKEY phkeyTracing
    );

DWORD
TraceOpenClientConsoleA(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceCloseClientConsoleA(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceCreateClientFileA(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceMoveClientFileA(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceCloseClientFileA(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceWriteOutputA(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient,
    DWORD dwFlags,
    LPCSTR lpszOutput
    );

DWORD
TraceUpdateConsoleTitleA(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceDumpLineA(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient,
    DWORD dwFlags,
    LPBYTE lpbBytes,
    DWORD dwLine,
    DWORD dwGroup,
    BOOL bPrefixAddr,
    LPBYTE lpbPrefix,
    LPCSTR lpszPrefix
    );

DWORD
TraceVprintfInternalA(
    DWORD dwTraceID,
    DWORD dwFlags,
    LPCSTR lpszFormat,
    va_list arglist
    );


//
// Unicode declarations
//
LPTRACE_CLIENT
TraceFindClientW(
    LPTRACE_SERVER lpserver,
    LPCWSTR lpszClient
    );

DWORD
TraceCreateClientW(
    LPTRACE_CLIENT *lplpentry
    );

DWORD
TraceDeleteClientW(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT *lplpentry
    );

DWORD
TraceEnableClientW(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient,
    BOOL bFirstTime
    );

DWORD
TraceDisableClientW(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceRegConfigClientW(
    LPTRACE_CLIENT lpclient,
    BOOL bFirstTime
    );

DWORD
TraceRegCreateDefaultsW(
    LPCWSTR lpszTracing,
    PHKEY phkeyTracing
    );

DWORD
TraceOpenClientConsoleW(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceCloseClientConsoleW(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceCreateClientFileW(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceMoveClientFileW(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceCloseClientFileW(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceWriteOutputW(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient,
    DWORD dwFlags,
    LPCWSTR lpszOutput
    );

DWORD
TraceUpdateConsoleTitleW(
    LPTRACE_CLIENT lpclient
    );

DWORD
TraceDumpLineW(
    LPTRACE_SERVER lpserver,
    LPTRACE_CLIENT lpclient,
    DWORD dwFlags,
    LPBYTE lpbBytes,
    DWORD dwLine,
    DWORD dwGroup,
    BOOL bPrefixAddr,
    LPBYTE lpbPrefix,
    LPCWSTR lpszPrefix
    );

DWORD
TraceVprintfInternalW(
    DWORD dwTraceID,
    DWORD dwFlags,
    LPCWSTR lpszFormat,
    va_list arglist
    );




//
// code-page independent macro definitions
//

#ifdef UNICODE
#define TraceFindClient                 TraceFindClientW
#define TraceCreateClient               TraceCreateClientW
#define TraceDeleteClient               TraceDeleteClientW
#define TraceEnableClient               TraceEnableClientW
#define TraceDisableClient              TraceDisableClientW
#define TraceRegConfigClient            TraceRegConfigClientW
#define TraceRegCreateDefaults          TraceRegCreateDefaultsW
#define TraceOpenClientConsole          TraceOpenClientConsoleW
#define TraceCloseClientConsole         TraceCloseClientConsoleW
#define TraceCreateClientFile           TraceCreateClientFileW
#define TraceMoveClientFile             TraceMoveClientFileW
#define TraceCloseClientFile            TraceCloseClientFileW
#define TraceWriteOutput                TraceWriteOutputW
#define TraceUpdateConsoleTitle         TraceUpdateConsoleTitleW
#define TraceDumpLine                   TraceDumpLineW
#define TraceVprintfInternal            TraceVprintfInternalW
#else
#define TraceFindClient                 TraceFindClientA
#define TraceCreateClient               TraceCreateClientA
#define TraceDeleteClient               TraceDeleteClientA
#define TraceEnableClient               TraceEnableClientA
#define TraceDisableClient              TraceDisableClientA
#define TraceRegConfigClient            TraceRegConfigClientA
#define TraceRegCreateDefaults          TraceRegCreateDefaultsA
#define TraceOpenClientConsole          TraceOpenClientConsoleA
#define TraceCloseClientConsole         TraceCloseClientConsoleA
#define TraceCreateClientFile           TraceCreateClientFileA
#define TraceMoveClientFile             TraceMoveClientFileA
#define TraceCloseClientFile            TraceCloseClientFileA
#define TraceWriteOutput                TraceWriteOutputA
#define TraceUpdateConsoleTitle         TraceUpdateConsoleTitleA
#define TraceDumpLine                   TraceDumpLineA
#define TraceVprintfInternal            TraceVprintfInternalA
#endif


// global data declarations
//
extern LPTRACE_SERVER g_server;
extern HANDLE g_serverThread;

#endif  // _TRACE_H_