//============================================================================ // Copyright (c) 1995, Microsoft Corporation // // File: api.c // // History: // Abolade Gbadegesin July-25-1995 Created // // API entry-points for tracing dll //============================================================================ #include #include #include #include #include #include #include "trace.h" //#define STRSAFE_LIB #include #define ENTER_TRACE_API(lpserver) \ (((lpserver)!=NULL) && ((lpserver)->TS_StopEvent != NULL)) // // called before any other functions; responsible for creating // and initializing a client structure for the caller // and notifying the server of the new client // DWORD APIENTRY TraceRegisterEx( IN LPCTSTR lpszCallerName, IN DWORD dwFlags ) { DWORD dwErr, dwClientID; LPTRACE_SERVER lpserver; LPTRACE_CLIENT lpclient, *lplpc, *lplpcstart, *lplpcend; HRESULT hrResult; if (!lpszCallerName) return INVALID_TRACEID; lpserver = GET_TRACE_SERVER(); ASSERTMSG ("Could not create trace server ", lpserver!=NULL); if (!lpserver) return INVALID_TRACEID; TRACE_ACQUIRE_WRITELOCK(lpserver); // // complete the console thread event creations if not done before // if (lpserver->TS_TableEvent == NULL) { dwErr = TraceCreateServerComplete(lpserver); if (dwErr != 0) { TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } } lpclient = TraceFindClient(lpserver, lpszCallerName); if (lpclient != NULL) { // // client already exists // TRACE_RELEASE_WRITELOCK(lpserver); return (lpclient->TC_ClientID ^ CLIENT_SIGNATURE); } // // find an empty space // lplpcstart = lpserver->TS_ClientTable; lplpcend = lplpcstart + MAX_CLIENT_COUNT; for (lplpc = lplpcstart; lplpc < lplpcend; lplpc++) { if (*lplpc == NULL) { break; } } if (lplpc >= lplpcend) { // // no space in table // TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } // // create the new client and enable it // dwErr = TraceCreateClient(lplpc); if (dwErr != 0) { // // something wrong, so abort // TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } lpclient = *lplpc; lpclient->TC_ClientID = dwClientID = (DWORD)(lplpc - lplpcstart); hrResult = StringCchCopy( lpclient->TC_ClientName, MAX_CLIENTNAME_LENGTH, lpszCallerName ); if (FAILED(hrResult)) { TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } // // copy the client name in the other format as well // sssafe // #ifdef UNICODE if (wcstombs( lpclient->TC_ClientNameA, lpclient->TC_ClientNameW, MAX_CLIENTNAME_LENGTH //dont subtract 1 ) == (size_t)-1) { TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } if (lpclient->TC_ClientNameA[MAX_CLIENTNAME_LENGTH-1] != '\0') { TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } #else if (mbstowcs( lpclient->TC_ClientNameW, lpclient->TC_ClientNameA, MAX_CLIENTNAME_LENGTH //dont subtract 1 ) == (size_t)-1) { TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } if (lpclient->TC_ClientNameW[MAX_CLIENTNAME_LENGTH-1] != L'\0') { TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } #endif if ((dwFlags & TRACE_USE_FILE) || (dwFlags & TRACE_USE_CONSOLE)) { if (dwFlags & TRACE_USE_FILE) { lpclient->TC_Flags |= TRACEFLAGS_USEFILE; } if (dwFlags & TRACE_USE_CONSOLE) { lpclient->TC_Flags |= TRACEFLAGS_USECONSOLE; } } else { lpclient->TC_Flags |= TRACEFLAGS_REGCONFIG; } // // load client's configuration and open its file // and its console buffer if necessary // dwErr = TraceEnableClient(lpserver, lpclient, TRUE); if (dwErr != 0) { // // something wrong, so abort // TraceDeleteClient(lpserver, lplpc); TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } // // Create trace server thread if required // if (g_serverThread==NULL) { dwErr = TraceCreateServerThread(dwFlags, TRUE,TRUE); //have lock,check if (NO_ERROR != dwErr){ TRACE_RELEASE_WRITELOCK(lpserver); return INVALID_TRACEID; } } TRACE_RELEASE_WRITELOCK(lpserver); // // tell server there is a new client in the table // SetEvent(lpserver->TS_TableEvent); return (dwClientID ^ CLIENT_SIGNATURE); } DWORD APIENTRY TraceDeregisterEx( IN DWORD dwTraceID, IN DWORD dwFlags ); // // called to stop tracing. // frees client state and notifies server of change // DWORD APIENTRY TraceDeregister( IN DWORD dwTraceID ) { return TraceDeregisterEx(dwTraceID, 0); } DWORD APIENTRY TraceDeregisterEx( IN DWORD dwTraceID, IN DWORD dwFlags ) { DWORD dwErr; LPTRACE_CLIENT *lplpc; LPTRACE_SERVER lpserver; // check for uninitialized traceregister. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID) { ASSERT(TRUE); return ERROR_INVALID_PARAMETER; } dwTraceID ^= CLIENT_SIGNATURE; if (dwTraceID >= MAX_CLIENT_COUNT) { return ERROR_INVALID_PARAMETER; } lpserver = GET_TRACE_SERVER_NO_INIT (); if (lpserver==NULL) // rtutils being unloaded bug. return 0; if (!ENTER_TRACE_API(lpserver)) { return ERROR_CAN_NOT_COMPLETE; } // // lock the server, unless the flag says not to. // if (!(dwFlags & TRACE_NO_SYNCH)) { TRACE_ACQUIRE_WRITELOCK(lpserver); } // // get the client pointer // lplpc = lpserver->TS_ClientTable + dwTraceID; dwErr = TraceDeleteClient(lpserver, lplpc); // // reset array for client change notifications. // only used if server thread is not created // if (!g_serverThread) { SetWaitArray(lpserver); } if (!(dwFlags & TRACE_NO_SYNCH)) { TRACE_RELEASE_WRITELOCK(lpserver); } // // tell the server that a client has left // SetEvent(lpserver->TS_TableEvent); return 0; } DWORD APIENTRY TraceGetConsole( IN DWORD dwTraceID, OUT LPHANDLE lphConsole ) { LPTRACE_CLIENT lpclient; LPTRACE_SERVER lpserver; // check for uninitialized traceregister. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID) { ASSERT(TRUE); return ERROR_INVALID_PARAMETER; } dwTraceID ^= CLIENT_SIGNATURE; if (dwTraceID >= MAX_CLIENT_COUNT || lphConsole == NULL) { return ERROR_INVALID_PARAMETER; } lpserver = GET_TRACE_SERVER_NO_INIT (); ASSERTMSG ("Server not initialized ", lpserver); if (!ENTER_TRACE_API(lpserver)) { return ERROR_CAN_NOT_COMPLETE; } *lphConsole = NULL; TRACE_ACQUIRE_READLOCK(lpserver); lpclient = lpserver->TS_ClientTable[dwTraceID]; if (lpclient == NULL) { TRACE_RELEASE_READLOCK(lpserver); return ERROR_INVALID_PARAMETER; } TRACE_ACQUIRE_READLOCK(lpclient); *lphConsole = lpclient->TC_Console; TRACE_RELEASE_READLOCK(lpclient); TRACE_RELEASE_READLOCK(lpserver); return 0; } DWORD APIENTRY TracePrintf( IN DWORD dwTraceID, IN LPCTSTR lpszFormat, IN ... OPTIONAL ) { DWORD dwSize; va_list arglist; // check for uninitialized traceregister. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID) { ASSERT(TRUE); return ERROR_INVALID_PARAMETER; } dwTraceID ^= CLIENT_SIGNATURE; if (dwTraceID >= MAX_CLIENT_COUNT) { return 0; } if (lpszFormat==NULL) return 0; CREATE_SERVER_THREAD_IF_REQUIRED(); va_start(arglist, lpszFormat); dwSize = TraceVprintfInternal(dwTraceID, 0, lpszFormat, arglist); va_end(arglist); return dwSize; } DWORD APIENTRY TracePrintfEx( IN DWORD dwTraceID, IN DWORD dwFlags, IN LPCTSTR lpszFormat, IN ... OPTIONAL ) { DWORD dwSize; va_list arglist; // check for uninitialized traceregister. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID) { ASSERT(TRUE); return ERROR_INVALID_PARAMETER; } dwTraceID ^= CLIENT_SIGNATURE; if (dwTraceID >= MAX_CLIENT_COUNT) { return 0; } if (lpszFormat==NULL) return 0; CREATE_SERVER_THREAD_IF_REQUIRED(); va_start(arglist, lpszFormat); dwSize = TraceVprintfInternal(dwTraceID, dwFlags, lpszFormat, arglist); va_end(arglist); return dwSize; } DWORD APIENTRY TraceVprintfEx( IN DWORD dwTraceID, IN DWORD dwFlags, IN LPCTSTR lpszFormat, IN va_list arglist ) { // check for uninitialized traceregister. if (dwTraceID == 0 || dwTraceID == INVALID_TRACEID) { ASSERT(TRUE); return ERROR_INVALID_PARAMETER; } dwTraceID ^= CLIENT_SIGNATURE; if (dwTraceID >= MAX_CLIENT_COUNT) { return 0; } if (lpszFormat==NULL) return 0; CREATE_SERVER_THREAD_IF_REQUIRED(); return TraceVprintfInternal(dwTraceID, dwFlags, lpszFormat, arglist); } /* Note: return 0 if error. do not return error code */ DWORD TraceVprintfInternal( IN DWORD dwTraceID, IN DWORD dwFlags, IN LPCTSTR lpszFormat, IN va_list arglist ) { SYSTEMTIME st; DWORD dwThread; DWORD dwErr=NO_ERROR, dwSize=0; HRESULT hrResult=S_OK; LPTRACE_CLIENT lpclient; LPTRACE_SERVER lpserver; PTCHAR szFormat, szBuffer; BOOL bFormatBufferGlobal=FALSE, bPrintBufferGlobal = FALSE; if (lpszFormat==NULL) return 0; lpserver = GET_TRACE_SERVER_NO_INIT (); if (lpserver==NULL) // rtutils being unloaded bug. return 0; ASSERTMSG ("Server not initialized ", lpserver); if (!ENTER_TRACE_API(lpserver)) { return 0; } // // return quickly if no output will be generated; // if (dwFlags & TRACE_USE_MASK) { if (!(*(lpserver->TS_FlagsCache + dwTraceID) & (dwFlags & 0xffff0000))) { return 0; } } else { if (!*(lpserver->TS_FlagsCache + dwTraceID)) { return 0; } } TRACE_ACQUIRE_READLOCK(lpserver); lpclient = lpserver->TS_ClientTable[dwTraceID]; if (lpclient == NULL) { TRACE_RELEASE_READLOCK(lpserver); return 0; } TRACE_ACQUIRE_READLOCK(lpclient); if (TRACE_CLIENT_IS_DISABLED(lpclient)) { TRACE_RELEASE_READLOCK(lpclient); TRACE_RELEASE_READLOCK(lpserver); return 0; } if (szFormat = InterlockedExchangePointer(&g_FormatBuffer, NULL)) { bFormatBufferGlobal = TRUE; } else { szFormat = (PTCHAR) HeapAlloc(GetProcessHeap(), 0, DEF_PRINT_BUFSIZE); if (!szFormat) { TRACE_RELEASE_READLOCK(lpclient); TRACE_RELEASE_READLOCK(lpserver); return 0; } } if (szBuffer = InterlockedExchangePointer(&g_PrintBuffer, NULL)) { bPrintBufferGlobal = TRUE; } else { szBuffer = (PTCHAR) HeapAlloc(GetProcessHeap(), 0, DEF_PRINT_BUFSIZE); if (!szBuffer) { TRACE_RELEASE_READLOCK(lpclient); TRACE_RELEASE_READLOCK(lpserver); if (!bFormatBufferGlobal) HeapFree(GetProcessHeap(), 0, szFormat); else InterlockedExchangePointer(&g_FormatBuffer, szFormat); return 0; } } // // default format for output is // \n