1485 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1485 lines
		
	
	
		
			48 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//------------------------------------------------------------------------------
 | 
						|
// File: WXDebug.cpp
 | 
						|
//
 | 
						|
// Desc: DirectShow base classes - implements ActiveX system debugging
 | 
						|
//       facilities.
 | 
						|
//
 | 
						|
// Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
 | 
						|
#ifndef _WINDLL
 | 
						|
#define _WINDLL
 | 
						|
#endif
 | 
						|
 | 
						|
#undef NOMINMAX
 | 
						|
#include <streams.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <dvdmedia.h>
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
#ifdef UNICODE
 | 
						|
#ifndef _UNICODE
 | 
						|
#define _UNICODE
 | 
						|
#endif // _UNICODE
 | 
						|
#endif // UNICODE
 | 
						|
#endif // DEBUG
 | 
						|
 | 
						|
#include <tchar.h>
 | 
						|
#include <strsafe.h>
 | 
						|
 | 
						|
#ifndef max
 | 
						|
#define max(a, b) (((a) > (b)) ? (a) : (b))
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef min
 | 
						|
#define min(a, b) (((a) < (b)) ? (a) : (b))
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi);
 | 
						|
static void DisplayRECT(LPCTSTR szLabel, const RECT& rc);
 | 
						|
 | 
						|
// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer.
 | 
						|
// See the documentation for wsprintf()'s lpOut parameter for more information.
 | 
						|
const INT iDEBUGINFO = 1024;                 // Used to format strings
 | 
						|
 | 
						|
/* For every module and executable we store a debugging level for each of
 | 
						|
   the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy
 | 
						|
   to isolate and debug individual modules without seeing everybody elses
 | 
						|
   spurious debug output. The keys are stored in the registry under the
 | 
						|
   HKEY_LOCAL_MACHINE\SOFTWARE\Debug\<Module Name>\<KeyName> key values
 | 
						|
   NOTE these must be in the same order as their enumeration definition */
 | 
						|
 | 
						|
const LPCTSTR pKeyNames[] = {
 | 
						|
    TEXT("TIMING"),      // Timing and performance measurements
 | 
						|
    TEXT("TRACE"),       // General step point call tracing
 | 
						|
    TEXT("MEMORY"),      // Memory and object allocation/destruction
 | 
						|
    TEXT("LOCKING"),     // Locking/unlocking of critical sections
 | 
						|
    TEXT("ERROR"),       // Debug error notification
 | 
						|
    TEXT("CUSTOM1"),
 | 
						|
    TEXT("CUSTOM2"),
 | 
						|
    TEXT("CUSTOM3"),
 | 
						|
    TEXT("CUSTOM4"),
 | 
						|
    TEXT("CUSTOM5")
 | 
						|
    };
 | 
						|
 | 
						|
const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s");
 | 
						|
const TCHAR CAutoTrace::_szLeaving[]  = TEXT("<-: %s");
 | 
						|
 | 
						|
const INT iMAXLEVELS = NUMELMS(pKeyNames);  // Maximum debug categories
 | 
						|
 | 
						|
HINSTANCE m_hInst;                          // Module instance handle
 | 
						|
TCHAR m_ModuleName[iDEBUGINFO];             // Cut down module name
 | 
						|
DWORD m_Levels[iMAXLEVELS];                 // Debug level per category
 | 
						|
CRITICAL_SECTION m_CSDebug;                 // Controls access to list
 | 
						|
DWORD m_dwNextCookie;                       // Next active object ID
 | 
						|
ObjectDesc *pListHead = NULL;               // First active object
 | 
						|
DWORD m_dwObjectCount;                      // Active object count
 | 
						|
BOOL m_bInit = FALSE;                       // Have we been initialised
 | 
						|
HANDLE m_hOutput = INVALID_HANDLE_VALUE;    // Optional output written here
 | 
						|
DWORD dwWaitTimeout = INFINITE;             // Default timeout value
 | 
						|
DWORD dwTimeOffset;			    // Time of first DbgLog call
 | 
						|
bool g_fUseKASSERT = false;                 // don't create messagebox
 | 
						|
bool g_fDbgInDllEntryPoint = false;
 | 
						|
bool g_fAutoRefreshLevels = false;
 | 
						|
 | 
						|
LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug");
 | 
						|
LPCTSTR pGlobalKey = TEXT("GLOBAL");
 | 
						|
static const CHAR *pUnknownName = "UNKNOWN";
 | 
						|
 | 
						|
LPCTSTR TimeoutName = TEXT("TIMEOUT");
 | 
						|
 | 
						|
/* This sets the instance handle that the debug library uses to find
 | 
						|
   the module's file name from the Win32 GetModuleFileName function */
 | 
						|
 | 
						|
void WINAPI DbgInitialise(HINSTANCE hInst)
 | 
						|
{
 | 
						|
    InitializeCriticalSection(&m_CSDebug);
 | 
						|
    m_bInit = TRUE;
 | 
						|
 | 
						|
    m_hInst = hInst;
 | 
						|
    DbgInitModuleName();
 | 
						|
    if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0))
 | 
						|
       DebugBreak();
 | 
						|
    DbgInitModuleSettings(false);
 | 
						|
    DbgInitGlobalSettings(true);
 | 
						|
    dwTimeOffset = timeGetTime();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This is called to clear up any resources the debug library uses - at the
 | 
						|
   moment we delete our critical section and the object list. The values we
 | 
						|
   retrieve from the registry are all done during initialisation but we don't
 | 
						|
   go looking for update notifications while we are running, if the values
 | 
						|
   are changed then the application has to be restarted to pick them up */
 | 
						|
 | 
						|
void WINAPI DbgTerminate()
 | 
						|
{
 | 
						|
    if (m_hOutput != INVALID_HANDLE_VALUE) {
 | 
						|
       EXECUTE_ASSERT(CloseHandle(m_hOutput));
 | 
						|
       m_hOutput = INVALID_HANDLE_VALUE;
 | 
						|
    }
 | 
						|
    DeleteCriticalSection(&m_CSDebug);
 | 
						|
    m_bInit = FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This is called by DbgInitLogLevels to read the debug settings
 | 
						|
   for each logging category for this module from the registry */
 | 
						|
 | 
						|
void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax)
 | 
						|
{
 | 
						|
    LONG lReturn;               // Create key return value
 | 
						|
    LONG lKeyPos;               // Current key category
 | 
						|
    DWORD dwKeySize;            // Size of the key value
 | 
						|
    DWORD dwKeyType;            // Receives it's type
 | 
						|
    DWORD dwKeyValue;           // This fields value
 | 
						|
 | 
						|
    /* Try and read a value for each key position in turn */
 | 
						|
    for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
 | 
						|
 | 
						|
        dwKeySize = sizeof(DWORD);
 | 
						|
        lReturn = RegQueryValueEx(
 | 
						|
            hKey,                       // Handle to an open key
 | 
						|
            pKeyNames[lKeyPos],         // Subkey name derivation
 | 
						|
            NULL,                       // Reserved field
 | 
						|
            &dwKeyType,                 // Returns the field type
 | 
						|
            (LPBYTE) &dwKeyValue,       // Returns the field's value
 | 
						|
            &dwKeySize );               // Number of bytes transferred
 | 
						|
 | 
						|
        /* If either the key was not available or it was not a DWORD value
 | 
						|
           then we ensure only the high priority debug logging is output
 | 
						|
           but we try and update the field to a zero filled DWORD value */
 | 
						|
 | 
						|
        if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD)  {
 | 
						|
 | 
						|
            dwKeyValue = 0;
 | 
						|
            lReturn = RegSetValueEx(
 | 
						|
                hKey,                   // Handle of an open key
 | 
						|
                pKeyNames[lKeyPos],     // Address of subkey name
 | 
						|
                (DWORD) 0,              // Reserved field
 | 
						|
                REG_DWORD,              // Type of the key field
 | 
						|
                (PBYTE) &dwKeyValue,    // Value for the field
 | 
						|
                sizeof(DWORD));         // Size of the field buffer
 | 
						|
 | 
						|
            if (lReturn != ERROR_SUCCESS) {
 | 
						|
                DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
 | 
						|
                dwKeyValue = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if(fTakeMax)
 | 
						|
        {
 | 
						|
            m_Levels[lKeyPos] = max(dwKeyValue,m_Levels[lKeyPos]);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) {
 | 
						|
                m_Levels[lKeyPos] = dwKeyValue;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /*  Read the timeout value for catching hangs */
 | 
						|
    dwKeySize = sizeof(DWORD);
 | 
						|
    lReturn = RegQueryValueEx(
 | 
						|
        hKey,                       // Handle to an open key
 | 
						|
        TimeoutName,                // Subkey name derivation
 | 
						|
        NULL,                       // Reserved field
 | 
						|
        &dwKeyType,                 // Returns the field type
 | 
						|
        (LPBYTE) &dwWaitTimeout,    // Returns the field's value
 | 
						|
        &dwKeySize );               // Number of bytes transferred
 | 
						|
 | 
						|
    /* If either the key was not available or it was not a DWORD value
 | 
						|
       then we ensure only the high priority debug logging is output
 | 
						|
       but we try and update the field to a zero filled DWORD value */
 | 
						|
 | 
						|
    if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD)  {
 | 
						|
 | 
						|
        dwWaitTimeout = INFINITE;
 | 
						|
        lReturn = RegSetValueEx(
 | 
						|
            hKey,                   // Handle of an open key
 | 
						|
            TimeoutName,            // Address of subkey name
 | 
						|
            (DWORD) 0,              // Reserved field
 | 
						|
            REG_DWORD,              // Type of the key field
 | 
						|
            (PBYTE) &dwWaitTimeout, // Value for the field
 | 
						|
            sizeof(DWORD));         // Size of the field buffer
 | 
						|
 | 
						|
        if (lReturn != ERROR_SUCCESS) {
 | 
						|
            DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
 | 
						|
            dwWaitTimeout = INFINITE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void WINAPI DbgOutString(LPCTSTR psz)
 | 
						|
{
 | 
						|
    if (m_hOutput != INVALID_HANDLE_VALUE) {
 | 
						|
        UINT  cb = lstrlen(psz);
 | 
						|
        DWORD dw;
 | 
						|
#ifdef UNICODE
 | 
						|
        CHAR szDest[2048];
 | 
						|
        WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0);
 | 
						|
        WriteFile (m_hOutput, szDest, cb, &dw, NULL);
 | 
						|
#else
 | 
						|
        WriteFile (m_hOutput, psz, cb, &dw, NULL);
 | 
						|
#endif
 | 
						|
    } else {
 | 
						|
        OutputDebugString (psz);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
HRESULT  DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName)
 | 
						|
{
 | 
						|
    HRESULT hr = S_OK;
 | 
						|
    const TCHAR *pIn = inName;
 | 
						|
    int dotPos = -1;
 | 
						|
 | 
						|
    //scan the input and record the last '.' position
 | 
						|
    while (*pIn && (pIn - inName) < MAX_PATH)
 | 
						|
    {
 | 
						|
        if ( TEXT('.') == *pIn )
 | 
						|
            dotPos = (int)(pIn-inName);
 | 
						|
        ++pIn;
 | 
						|
    }
 | 
						|
 | 
						|
    if (*pIn) //input should be zero-terminated within MAX_PATH
 | 
						|
        return E_INVALIDARG;
 | 
						|
 | 
						|
    DWORD dwProcessId = GetCurrentProcessId();
 | 
						|
 | 
						|
    if (dotPos < 0) 
 | 
						|
    {
 | 
						|
        //no extension in the input, appending process id to the input
 | 
						|
        hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        TCHAR pathAndBasename[MAX_PATH] = {0};
 | 
						|
        
 | 
						|
        //there's an extension  - zero-terminate the path and basename first by copying
 | 
						|
        hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos);
 | 
						|
 | 
						|
        //re-combine path, basename and extension with processId appended to a basename
 | 
						|
        if (SUCCEEDED(hr))
 | 
						|
            hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos);
 | 
						|
    }
 | 
						|
 | 
						|
    return hr;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Called by DbgInitGlobalSettings to setup alternate logging destinations
 | 
						|
 */
 | 
						|
 | 
						|
void WINAPI DbgInitLogTo (
 | 
						|
    HKEY hKey)
 | 
						|
{
 | 
						|
    LONG  lReturn;
 | 
						|
    DWORD dwKeyType;
 | 
						|
    DWORD dwKeySize;
 | 
						|
    TCHAR szFile[MAX_PATH] = {0};
 | 
						|
    static const TCHAR cszKey[] = TEXT("LogToFile");
 | 
						|
 | 
						|
    dwKeySize = MAX_PATH;
 | 
						|
    lReturn = RegQueryValueEx(
 | 
						|
        hKey,                       // Handle to an open key
 | 
						|
        cszKey,                     // Subkey name derivation
 | 
						|
        NULL,                       // Reserved field
 | 
						|
        &dwKeyType,                 // Returns the field type
 | 
						|
        (LPBYTE) szFile,            // Returns the field's value
 | 
						|
        &dwKeySize);                // Number of bytes transferred
 | 
						|
 | 
						|
    // create an empty key if it does not already exist
 | 
						|
    //
 | 
						|
    if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ)
 | 
						|
       {
 | 
						|
       dwKeySize = sizeof(TCHAR);
 | 
						|
       lReturn = RegSetValueEx(
 | 
						|
            hKey,                   // Handle of an open key
 | 
						|
            cszKey,                 // Address of subkey name
 | 
						|
            (DWORD) 0,              // Reserved field
 | 
						|
            REG_SZ,                 // Type of the key field
 | 
						|
            (PBYTE)szFile,          // Value for the field
 | 
						|
            dwKeySize);            // Size of the field buffer
 | 
						|
       }
 | 
						|
 | 
						|
    // if an output-to was specified.  try to open it.
 | 
						|
    //
 | 
						|
    if (m_hOutput != INVALID_HANDLE_VALUE) {
 | 
						|
       EXECUTE_ASSERT(CloseHandle (m_hOutput));
 | 
						|
       m_hOutput = INVALID_HANDLE_VALUE;
 | 
						|
    }
 | 
						|
    if (szFile[0] != 0)
 | 
						|
       {
 | 
						|
       if (!lstrcmpi(szFile, TEXT("Console"))) {
 | 
						|
          m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
 | 
						|
          if (m_hOutput == INVALID_HANDLE_VALUE) {
 | 
						|
             AllocConsole ();
 | 
						|
             m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
 | 
						|
          }
 | 
						|
          SetConsoleTitle (TEXT("ActiveX Debug Output"));
 | 
						|
       } else if (szFile[0] &&
 | 
						|
                lstrcmpi(szFile, TEXT("Debug")) &&
 | 
						|
                lstrcmpi(szFile, TEXT("Debugger")) &&
 | 
						|
                lstrcmpi(szFile, TEXT("Deb")))
 | 
						|
          {
 | 
						|
            m_hOutput = CreateFile(szFile, GENERIC_WRITE,
 | 
						|
                                 FILE_SHARE_READ,
 | 
						|
                                 NULL, OPEN_ALWAYS,
 | 
						|
                                 FILE_ATTRIBUTE_NORMAL,
 | 
						|
                                 NULL);
 | 
						|
 | 
						|
            if (INVALID_HANDLE_VALUE == m_hOutput &&
 | 
						|
                GetLastError() == ERROR_SHARING_VIOLATION)
 | 
						|
            {
 | 
						|
               TCHAR uniqueName[MAX_PATH] = {0};
 | 
						|
               if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName)))
 | 
						|
               {
 | 
						|
                    m_hOutput = CreateFile(uniqueName, GENERIC_WRITE,
 | 
						|
                                         FILE_SHARE_READ,
 | 
						|
                                         NULL, OPEN_ALWAYS,
 | 
						|
                                         FILE_ATTRIBUTE_NORMAL,
 | 
						|
                                         NULL);
 | 
						|
               }
 | 
						|
            }
 | 
						|
               
 | 
						|
            if (INVALID_HANDLE_VALUE != m_hOutput)
 | 
						|
            {
 | 
						|
              static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n");
 | 
						|
              SetFilePointer (m_hOutput, 0, NULL, FILE_END);
 | 
						|
              DbgOutString (cszBar);
 | 
						|
            }
 | 
						|
          }
 | 
						|
       }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* This is called by DbgInitLogLevels to read the global debug settings for
 | 
						|
   each logging category for this module from the registry. Normally each
 | 
						|
   module has it's own values set for it's different debug categories but
 | 
						|
   setting the global SOFTWARE\Debug\Global applies them to ALL modules */
 | 
						|
 | 
						|
void WINAPI DbgInitGlobalSettings(bool fTakeMax)
 | 
						|
{
 | 
						|
    LONG lReturn;               // Create key return value
 | 
						|
    TCHAR szInfo[iDEBUGINFO];   // Constructs key names
 | 
						|
    HKEY hGlobalKey;            // Global override key
 | 
						|
 | 
						|
    /* Construct the global base key name */
 | 
						|
    (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey);
 | 
						|
 | 
						|
    /* Create or open the key for this module */
 | 
						|
    lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE,   // Handle of an open key
 | 
						|
                             szInfo,               // Address of subkey name
 | 
						|
                             (DWORD) 0,            // Reserved value
 | 
						|
                             NULL,                 // Address of class name
 | 
						|
                             (DWORD) 0,            // Special options flags
 | 
						|
                             GENERIC_READ | GENERIC_WRITE,   // Desired security access
 | 
						|
                             NULL,                 // Key security descriptor
 | 
						|
                             &hGlobalKey,          // Opened handle buffer
 | 
						|
                             NULL);                // What really happened
 | 
						|
 | 
						|
    if (lReturn != ERROR_SUCCESS) {
 | 
						|
        lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE,   // Handle of an open key
 | 
						|
                                 szInfo,               // Address of subkey name
 | 
						|
                                 (DWORD) 0,            // Reserved value
 | 
						|
                                 NULL,                 // Address of class name
 | 
						|
                                 (DWORD) 0,            // Special options flags
 | 
						|
                                 GENERIC_READ,         // Desired security access
 | 
						|
                                 NULL,                 // Key security descriptor
 | 
						|
                                 &hGlobalKey,          // Opened handle buffer
 | 
						|
                                 NULL);                // What really happened
 | 
						|
        if (lReturn != ERROR_SUCCESS) {
 | 
						|
            DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key")));
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    DbgInitKeyLevels(hGlobalKey, fTakeMax);
 | 
						|
    RegCloseKey(hGlobalKey);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This sets the debugging log levels for the different categories. We start
 | 
						|
   by opening (or creating if not already available) the SOFTWARE\Debug key
 | 
						|
   that all these settings live under. We then look at the global values
 | 
						|
   set under SOFTWARE\Debug\Global which apply on top of the individual
 | 
						|
   module settings. We then load the individual module registry settings */
 | 
						|
 | 
						|
void WINAPI DbgInitModuleSettings(bool fTakeMax)
 | 
						|
{
 | 
						|
    LONG lReturn;               // Create key return value
 | 
						|
    TCHAR szInfo[iDEBUGINFO];   // Constructs key names
 | 
						|
    HKEY hModuleKey;            // Module key handle
 | 
						|
 | 
						|
    /* Construct the base key name */
 | 
						|
    (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName);
 | 
						|
 | 
						|
    /* Create or open the key for this module */
 | 
						|
    lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE,   // Handle of an open key
 | 
						|
                             szInfo,               // Address of subkey name
 | 
						|
                             (DWORD) 0,            // Reserved value
 | 
						|
                             NULL,                 // Address of class name
 | 
						|
                             (DWORD) 0,            // Special options flags
 | 
						|
                             GENERIC_READ | GENERIC_WRITE, // Desired security access
 | 
						|
                             NULL,                 // Key security descriptor
 | 
						|
                             &hModuleKey,          // Opened handle buffer
 | 
						|
                             NULL);                // What really happened
 | 
						|
 | 
						|
    if (lReturn != ERROR_SUCCESS) {
 | 
						|
        lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE,   // Handle of an open key
 | 
						|
                                 szInfo,               // Address of subkey name
 | 
						|
                                 (DWORD) 0,            // Reserved value
 | 
						|
                                 NULL,                 // Address of class name
 | 
						|
                                 (DWORD) 0,            // Special options flags
 | 
						|
                                 GENERIC_READ,         // Desired security access
 | 
						|
                                 NULL,                 // Key security descriptor
 | 
						|
                                 &hModuleKey,          // Opened handle buffer
 | 
						|
                                 NULL);                // What really happened
 | 
						|
        if (lReturn != ERROR_SUCCESS) {
 | 
						|
            DbgLog((LOG_ERROR,1,TEXT("Could not access module key")));
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    DbgInitLogTo(hModuleKey);
 | 
						|
    DbgInitKeyLevels(hModuleKey, fTakeMax);
 | 
						|
    RegCloseKey(hModuleKey);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Initialise the module file name */
 | 
						|
 | 
						|
void WINAPI DbgInitModuleName()
 | 
						|
{
 | 
						|
    TCHAR FullName[iDEBUGINFO];     // Load the full path and module name
 | 
						|
    LPTSTR pName;                   // Searches from the end for a backslash
 | 
						|
 | 
						|
    GetModuleFileName(m_hInst,FullName,iDEBUGINFO);
 | 
						|
    pName = _tcsrchr(FullName,'\\');
 | 
						|
    if (pName == NULL) {
 | 
						|
        pName = FullName;
 | 
						|
    } else {
 | 
						|
        pName++;
 | 
						|
    }
 | 
						|
    (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName);
 | 
						|
}
 | 
						|
 | 
						|
struct MsgBoxMsg
 | 
						|
{
 | 
						|
    HWND hwnd;
 | 
						|
    LPCTSTR szTitle;
 | 
						|
    LPCTSTR szMessage;
 | 
						|
    DWORD dwFlags;
 | 
						|
    INT iResult;
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// create a thread to call MessageBox(). calling MessageBox() on
 | 
						|
// random threads at bad times can confuse the host (eg IE).
 | 
						|
//
 | 
						|
DWORD WINAPI MsgBoxThread(
 | 
						|
  __inout LPVOID lpParameter   // thread data
 | 
						|
  )
 | 
						|
{
 | 
						|
    MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter;
 | 
						|
    pmsg->iResult = MessageBox(
 | 
						|
        pmsg->hwnd,
 | 
						|
        pmsg->szTitle,
 | 
						|
        pmsg->szMessage,
 | 
						|
        pmsg->dwFlags);
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
INT MessageBoxOtherThread(
 | 
						|
    HWND hwnd,
 | 
						|
    LPCTSTR szTitle,
 | 
						|
    LPCTSTR szMessage,
 | 
						|
    DWORD dwFlags)
 | 
						|
{
 | 
						|
    if(g_fDbgInDllEntryPoint)
 | 
						|
    {
 | 
						|
        // can't wait on another thread because we have the loader
 | 
						|
        // lock held in the dll entry point.
 | 
						|
        // This can crash sometimes so just skip it
 | 
						|
        // return MessageBox(hwnd, szTitle, szMessage, dwFlags);
 | 
						|
        return IDCANCEL;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0};
 | 
						|
        DWORD dwid;
 | 
						|
        HANDLE hThread = CreateThread(
 | 
						|
            0,                      // security
 | 
						|
            0,                      // stack size
 | 
						|
            MsgBoxThread,
 | 
						|
            (void *)&msg,           // arg
 | 
						|
            0,                      // flags
 | 
						|
            &dwid);
 | 
						|
        if(hThread)
 | 
						|
        {
 | 
						|
            WaitForSingleObject(hThread, INFINITE);
 | 
						|
            CloseHandle(hThread);
 | 
						|
            return msg.iResult;
 | 
						|
        }
 | 
						|
 | 
						|
        // break into debugger on failure.
 | 
						|
        return IDCANCEL;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Displays a message box if the condition evaluated to FALSE */
 | 
						|
 | 
						|
void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
 | 
						|
{
 | 
						|
    if(g_fUseKASSERT)
 | 
						|
    {
 | 
						|
        DbgKernelAssert(pCondition, pFileName, iLine);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
 | 
						|
        TCHAR szInfo[iDEBUGINFO];
 | 
						|
 | 
						|
        (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
 | 
						|
                 pCondition, iLine, pFileName);
 | 
						|
 | 
						|
        INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
 | 
						|
                                          MB_SYSTEMMODAL |
 | 
						|
                                          MB_ICONHAND |
 | 
						|
                                          MB_YESNOCANCEL |
 | 
						|
                                          MB_SETFOREGROUND);
 | 
						|
        switch (MsgId)
 | 
						|
        {
 | 
						|
          case IDNO:              /* Kill the application */
 | 
						|
 | 
						|
              FatalAppExit(FALSE, TEXT("Application terminated"));
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDCANCEL:          /* Break into the debugger */
 | 
						|
 | 
						|
              DebugBreak();
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDYES:             /* Ignore assertion continue execution */
 | 
						|
              break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Displays a message box at a break point */
 | 
						|
 | 
						|
void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
 | 
						|
{
 | 
						|
    if(g_fUseKASSERT)
 | 
						|
    {
 | 
						|
        DbgKernelAssert(pCondition, pFileName, iLine);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        TCHAR szInfo[iDEBUGINFO];
 | 
						|
 | 
						|
        (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
 | 
						|
                 pCondition, iLine, pFileName);
 | 
						|
 | 
						|
        INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
 | 
						|
                                          MB_SYSTEMMODAL |
 | 
						|
                                          MB_ICONHAND |
 | 
						|
                                          MB_YESNOCANCEL |
 | 
						|
                                          MB_SETFOREGROUND);
 | 
						|
        switch (MsgId)
 | 
						|
        {
 | 
						|
          case IDNO:              /* Kill the application */
 | 
						|
 | 
						|
              FatalAppExit(FALSE, TEXT("Application terminated"));
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDCANCEL:          /* Break into the debugger */
 | 
						|
 | 
						|
              DebugBreak();
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDYES:             /* Ignore break point continue execution */
 | 
						|
              break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...)
 | 
						|
{
 | 
						|
    // A debug break point message can have at most 2000 characters if
 | 
						|
    // ANSI or UNICODE characters are being used.  A debug break point message
 | 
						|
    // can have between 1000 and 2000 double byte characters in it.  If a
 | 
						|
    // particular message needs more characters, then the value of this constant
 | 
						|
    // should be increased.
 | 
						|
    const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000;
 | 
						|
 | 
						|
    TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE];
 | 
						|
 | 
						|
    va_list va;
 | 
						|
    va_start( va, szFormatString );
 | 
						|
 | 
						|
    HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va );
 | 
						|
 | 
						|
    va_end(va);
 | 
						|
 | 
						|
    if( FAILED(hr) ) {
 | 
						|
        DbgBreak( "ERROR in DbgBreakPoint().  The variable length debug message could not be displayed because StringCchVPrintf() failed." );
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* When we initialised the library we stored in the m_Levels array the current
 | 
						|
   debug output level for this module for each of the five categories. When
 | 
						|
   some debug logging is sent to us it can be sent with a combination of the
 | 
						|
   categories (if it is applicable to many for example) in which case we map
 | 
						|
   the type's categories into their current debug levels and see if any of
 | 
						|
   them can be accepted. The function looks at each bit position in turn from
 | 
						|
   the input type field and then compares it's debug level with the modules.
 | 
						|
 | 
						|
   A level of 0 means that output is always sent to the debugger.  This is
 | 
						|
   due to producing output if the input level is <= m_Levels.
 | 
						|
*/
 | 
						|
 | 
						|
 | 
						|
BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level)
 | 
						|
{
 | 
						|
    if(g_fAutoRefreshLevels)
 | 
						|
    {
 | 
						|
        // re-read the registry every second. We cannot use RegNotify() to
 | 
						|
        // notice registry changes because it's not available on win9x.
 | 
						|
        static DWORD g_dwLastRefresh = 0;
 | 
						|
        DWORD dwTime = timeGetTime();
 | 
						|
        if(dwTime - g_dwLastRefresh > 1000) {
 | 
						|
            g_dwLastRefresh = dwTime;
 | 
						|
 | 
						|
            // there's a race condition: multiple threads could update the
 | 
						|
            // values. plus read and write not synchronized. no harm
 | 
						|
            // though.
 | 
						|
            DbgInitModuleSettings(false);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    DWORD Mask = 0x01;
 | 
						|
 | 
						|
    // If no valid bits are set return FALSE
 | 
						|
    if ((Type & ((1<<iMAXLEVELS)-1))) {
 | 
						|
 | 
						|
	// speed up unconditional output.
 | 
						|
	if (0==Level)
 | 
						|
	    return(TRUE);
 | 
						|
	
 | 
						|
        for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
 | 
						|
            if (Type & Mask) {
 | 
						|
                if (Level <= (m_Levels[lKeyPos] & ~LOG_FORCIBLY_SET)) {
 | 
						|
                    return TRUE;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            Mask <<= 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Set debug levels to a given value */
 | 
						|
 | 
						|
void WINAPI DbgSetModuleLevel(DWORD Type, DWORD Level)
 | 
						|
{
 | 
						|
    DWORD Mask = 0x01;
 | 
						|
 | 
						|
    for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
 | 
						|
        if (Type & Mask) {
 | 
						|
            m_Levels[lKeyPos] = Level | LOG_FORCIBLY_SET;
 | 
						|
        }
 | 
						|
        Mask <<= 1;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* whether to check registry values periodically. this isn't turned
 | 
						|
   automatically because of the potential performance hit. */
 | 
						|
void WINAPI DbgSetAutoRefreshLevels(bool fAuto)
 | 
						|
{
 | 
						|
    g_fAutoRefreshLevels = fAuto;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef UNICODE
 | 
						|
//
 | 
						|
// warning -- this function is implemented twice for ansi applications
 | 
						|
// linking to the unicode library
 | 
						|
//
 | 
						|
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...)
 | 
						|
{
 | 
						|
    /* Check the current level for this type combination */
 | 
						|
 | 
						|
    BOOL bAccept = DbgCheckModuleLevel(Type,Level);
 | 
						|
    if (bAccept == FALSE) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    TCHAR szInfo[2000];
 | 
						|
 | 
						|
    /* Format the variable length parameter list */
 | 
						|
 | 
						|
    va_list va;
 | 
						|
    va_start(va, pFormat);
 | 
						|
 | 
						|
    (void)StringCchPrintf(szInfo, NUMELMS(szInfo),
 | 
						|
             TEXT("%s(tid %x) %8d : "),
 | 
						|
             m_ModuleName,
 | 
						|
             GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
 | 
						|
 | 
						|
    CHAR szInfoA[2000];
 | 
						|
    WideCharToMultiByte(CP_ACP, 0, szInfo, -1, szInfoA, NUMELMS(szInfoA), 0, 0);
 | 
						|
 | 
						|
    (void)StringCchVPrintfA(szInfoA + lstrlenA(szInfoA), NUMELMS(szInfoA) - lstrlenA(szInfoA), pFormat, va);
 | 
						|
    (void)StringCchCatA(szInfoA, NUMELMS(szInfoA), "\r\n");
 | 
						|
 | 
						|
    WCHAR wszOutString[2000];
 | 
						|
    MultiByteToWideChar(CP_ACP, 0, szInfoA, -1, wszOutString, NUMELMS(wszOutString));
 | 
						|
    DbgOutString(wszOutString);
 | 
						|
 | 
						|
    va_end(va);
 | 
						|
}
 | 
						|
 | 
						|
void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
 | 
						|
{
 | 
						|
    if(g_fUseKASSERT)
 | 
						|
    {
 | 
						|
        DbgKernelAssert(pCondition, pFileName, iLine);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
 | 
						|
        TCHAR szInfo[iDEBUGINFO];
 | 
						|
 | 
						|
        (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
 | 
						|
                 pCondition, iLine, pFileName);
 | 
						|
 | 
						|
        INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
 | 
						|
                                          MB_SYSTEMMODAL |
 | 
						|
                                          MB_ICONHAND |
 | 
						|
                                          MB_YESNOCANCEL |
 | 
						|
                                          MB_SETFOREGROUND);
 | 
						|
        switch (MsgId)
 | 
						|
        {
 | 
						|
          case IDNO:              /* Kill the application */
 | 
						|
 | 
						|
              FatalAppExit(FALSE, TEXT("Application terminated"));
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDCANCEL:          /* Break into the debugger */
 | 
						|
 | 
						|
              DebugBreak();
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDYES:             /* Ignore assertion continue execution */
 | 
						|
              break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Displays a message box at a break point */
 | 
						|
 | 
						|
void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
 | 
						|
{
 | 
						|
    if(g_fUseKASSERT)
 | 
						|
    {
 | 
						|
        DbgKernelAssert(pCondition, pFileName, iLine);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        TCHAR szInfo[iDEBUGINFO];
 | 
						|
 | 
						|
        (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
 | 
						|
                 pCondition, iLine, pFileName);
 | 
						|
 | 
						|
        INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
 | 
						|
                                          MB_SYSTEMMODAL |
 | 
						|
                                          MB_ICONHAND |
 | 
						|
                                          MB_YESNOCANCEL |
 | 
						|
                                          MB_SETFOREGROUND);
 | 
						|
        switch (MsgId)
 | 
						|
        {
 | 
						|
          case IDNO:              /* Kill the application */
 | 
						|
 | 
						|
              FatalAppExit(FALSE, TEXT("Application terminated"));
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDCANCEL:          /* Break into the debugger */
 | 
						|
 | 
						|
              DebugBreak();
 | 
						|
              break;
 | 
						|
 | 
						|
          case IDYES:             /* Ignore break point continue execution */
 | 
						|
              break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
 | 
						|
{
 | 
						|
    DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%hs) at line %d in file %hs"),
 | 
						|
           pCondition, iLine, pFileName));
 | 
						|
    DebugBreak();
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
/* Print a formatted string to the debugger prefixed with this module's name
 | 
						|
   Because the COMBASE classes are linked statically every module loaded will
 | 
						|
   have their own copy of this code. It therefore helps if the module name is
 | 
						|
   included on the output so that the offending code can be easily found */
 | 
						|
 | 
						|
//
 | 
						|
// warning -- this function is implemented twice for ansi applications
 | 
						|
// linking to the unicode library
 | 
						|
//
 | 
						|
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,LPCTSTR pFormat,...)
 | 
						|
{
 | 
						|
 | 
						|
    /* Check the current level for this type combination */
 | 
						|
 | 
						|
    BOOL bAccept = DbgCheckModuleLevel(Type,Level);
 | 
						|
    if (bAccept == FALSE) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    TCHAR szInfo[2000];
 | 
						|
 | 
						|
    /* Format the variable length parameter list */
 | 
						|
 | 
						|
    va_list va;
 | 
						|
    va_start(va, pFormat);
 | 
						|
 | 
						|
    (void)StringCchPrintf(szInfo, NUMELMS(szInfo),
 | 
						|
             TEXT("%s(tid %x) %8d : "),
 | 
						|
             m_ModuleName,
 | 
						|
             GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
 | 
						|
 | 
						|
    (void)StringCchVPrintf(szInfo + lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), pFormat, va);
 | 
						|
    (void)StringCchCat(szInfo, NUMELMS(szInfo), TEXT("\r\n"));
 | 
						|
    DbgOutString(szInfo);
 | 
						|
 | 
						|
    va_end(va);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* If we are executing as a pure kernel filter we cannot display message
 | 
						|
   boxes to the user, this provides an alternative which puts the error
 | 
						|
   condition on the debugger output with a suitable eye catching message */
 | 
						|
 | 
						|
void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
 | 
						|
{
 | 
						|
    DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%s) at line %d in file %s"),
 | 
						|
           pCondition, iLine, pFileName));
 | 
						|
    DebugBreak();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* Each time we create an object derived from CBaseObject the constructor will
 | 
						|
   call us to register the creation of the new object. We are passed a string
 | 
						|
   description which we store away. We return a cookie that the constructor
 | 
						|
   uses to identify the object when it is destroyed later on. We update the
 | 
						|
   total number of active objects in the DLL mainly for debugging purposes */
 | 
						|
 | 
						|
DWORD WINAPI DbgRegisterObjectCreation(LPCSTR szObjectName,
 | 
						|
                                       LPCWSTR wszObjectName)
 | 
						|
{
 | 
						|
    /* If this fires you have a mixed DEBUG/RETAIL build */
 | 
						|
 | 
						|
    ASSERT(!!szObjectName ^ !!wszObjectName);
 | 
						|
 | 
						|
    /* Create a place holder for this object description */
 | 
						|
 | 
						|
    ObjectDesc *pObject = new ObjectDesc;
 | 
						|
    ASSERT(pObject);
 | 
						|
 | 
						|
    /* It is valid to pass a NULL object name */
 | 
						|
    if (pObject == NULL) {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Check we have been initialised - we may not be initialised when we are
 | 
						|
       being pulled in from an executable which has globally defined objects
 | 
						|
       as they are created by the C++ run time before WinMain is called */
 | 
						|
 | 
						|
    if (m_bInit == FALSE) {
 | 
						|
        DbgInitialise(GetModuleHandle(NULL));
 | 
						|
    }
 | 
						|
 | 
						|
    /* Grab the list critical section */
 | 
						|
    EnterCriticalSection(&m_CSDebug);
 | 
						|
 | 
						|
    /* If no name then default to UNKNOWN */
 | 
						|
    if (!szObjectName && !wszObjectName) {
 | 
						|
        szObjectName = pUnknownName;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Put the new description at the head of the list */
 | 
						|
 | 
						|
    pObject->m_szName = szObjectName;
 | 
						|
    pObject->m_wszName = wszObjectName;
 | 
						|
    pObject->m_dwCookie = ++m_dwNextCookie;
 | 
						|
    pObject->m_pNext = pListHead;
 | 
						|
 | 
						|
    pListHead = pObject;
 | 
						|
    m_dwObjectCount++;
 | 
						|
 | 
						|
    DWORD ObjectCookie = pObject->m_dwCookie;
 | 
						|
    ASSERT(ObjectCookie);
 | 
						|
 | 
						|
    if(wszObjectName) {
 | 
						|
        DbgLog((LOG_MEMORY,2,TEXT("Object created   %d (%ls) %d Active"),
 | 
						|
                pObject->m_dwCookie, wszObjectName, m_dwObjectCount));
 | 
						|
    } else {
 | 
						|
        DbgLog((LOG_MEMORY,2,TEXT("Object created   %d (%hs) %d Active"),
 | 
						|
                pObject->m_dwCookie, szObjectName, m_dwObjectCount));
 | 
						|
    }
 | 
						|
 | 
						|
    LeaveCriticalSection(&m_CSDebug);
 | 
						|
    return ObjectCookie;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This is called by the CBaseObject destructor when an object is about to be
 | 
						|
   destroyed, we are passed the cookie we returned during construction that
 | 
						|
   identifies this object. We scan the object list for a matching cookie and
 | 
						|
   remove the object if successful. We also update the active object count */
 | 
						|
 | 
						|
BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie)
 | 
						|
{
 | 
						|
    /* Grab the list critical section */
 | 
						|
    EnterCriticalSection(&m_CSDebug);
 | 
						|
 | 
						|
    ObjectDesc *pObject = pListHead;
 | 
						|
    ObjectDesc *pPrevious = NULL;
 | 
						|
 | 
						|
    /* Scan the object list looking for a cookie match */
 | 
						|
 | 
						|
    while (pObject) {
 | 
						|
        if (pObject->m_dwCookie == dwCookie) {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        pPrevious = pObject;
 | 
						|
        pObject = pObject->m_pNext;
 | 
						|
    }
 | 
						|
 | 
						|
    if (pObject == NULL) {
 | 
						|
        DbgBreak("Apparently destroying a bogus object");
 | 
						|
        LeaveCriticalSection(&m_CSDebug);
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Is the object at the head of the list */
 | 
						|
 | 
						|
    if (pPrevious == NULL) {
 | 
						|
        pListHead = pObject->m_pNext;
 | 
						|
    } else {
 | 
						|
        pPrevious->m_pNext = pObject->m_pNext;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Delete the object and update the housekeeping information */
 | 
						|
 | 
						|
    m_dwObjectCount--;
 | 
						|
 | 
						|
    if(pObject->m_wszName) {
 | 
						|
        DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"),
 | 
						|
                pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount));
 | 
						|
    } else {
 | 
						|
        DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"),
 | 
						|
                pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount));
 | 
						|
    }
 | 
						|
 | 
						|
    delete pObject;
 | 
						|
    LeaveCriticalSection(&m_CSDebug);
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* This runs through the active object list displaying their details */
 | 
						|
 | 
						|
void WINAPI DbgDumpObjectRegister()
 | 
						|
{
 | 
						|
    TCHAR szInfo[iDEBUGINFO];
 | 
						|
 | 
						|
    /* Grab the list critical section */
 | 
						|
 | 
						|
    EnterCriticalSection(&m_CSDebug);
 | 
						|
    ObjectDesc *pObject = pListHead;
 | 
						|
 | 
						|
    /* Scan the object list displaying the name and cookie */
 | 
						|
 | 
						|
    DbgLog((LOG_MEMORY,2,TEXT("")));
 | 
						|
    DbgLog((LOG_MEMORY,2,TEXT("   ID             Object Description")));
 | 
						|
    DbgLog((LOG_MEMORY,2,TEXT("")));
 | 
						|
 | 
						|
    while (pObject) {
 | 
						|
        if(pObject->m_wszName) {
 | 
						|
            (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName);
 | 
						|
        } else {
 | 
						|
            (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName);
 | 
						|
        }
 | 
						|
        DbgLog((LOG_MEMORY,2,szInfo));
 | 
						|
        pObject = pObject->m_pNext;
 | 
						|
    }
 | 
						|
 | 
						|
    (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount);
 | 
						|
    DbgLog((LOG_MEMORY,2,TEXT("")));
 | 
						|
    DbgLog((LOG_MEMORY,1,szInfo));
 | 
						|
    LeaveCriticalSection(&m_CSDebug);
 | 
						|
}
 | 
						|
 | 
						|
/*  Debug infinite wait stuff */
 | 
						|
DWORD WINAPI DbgWaitForSingleObject(HANDLE h)
 | 
						|
{
 | 
						|
    DWORD dwWaitResult;
 | 
						|
    do {
 | 
						|
        dwWaitResult = WaitForSingleObject(h, dwWaitTimeout);
 | 
						|
        ASSERT(dwWaitResult == WAIT_OBJECT_0);
 | 
						|
    } while (dwWaitResult == WAIT_TIMEOUT);
 | 
						|
    return dwWaitResult;
 | 
						|
}
 | 
						|
DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount,
 | 
						|
                                __in_ecount(nCount) CONST HANDLE *lpHandles,
 | 
						|
                                BOOL bWaitAll)
 | 
						|
{
 | 
						|
    DWORD dwWaitResult;
 | 
						|
    do {
 | 
						|
        dwWaitResult = WaitForMultipleObjects(nCount,
 | 
						|
                                              lpHandles,
 | 
						|
                                              bWaitAll,
 | 
						|
                                              dwWaitTimeout);
 | 
						|
        ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS);
 | 
						|
    } while (dwWaitResult == WAIT_TIMEOUT);
 | 
						|
    return dwWaitResult;
 | 
						|
}
 | 
						|
 | 
						|
void WINAPI DbgSetWaitTimeout(DWORD dwTimeout)
 | 
						|
{
 | 
						|
    dwWaitTimeout = dwTimeout;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* DEBUG */
 | 
						|
 | 
						|
#ifdef _OBJBASE_H_
 | 
						|
 | 
						|
    /*  Stuff for printing out our GUID names */
 | 
						|
 | 
						|
    GUID_STRING_ENTRY g_GuidNames[] = {
 | 
						|
    #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
 | 
						|
    { #name, { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } } },
 | 
						|
        #include <uuids.h>
 | 
						|
    };
 | 
						|
 | 
						|
    CGuidNameList GuidNames;
 | 
						|
    int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]);
 | 
						|
 | 
						|
    const char *CGuidNameList::operator [] (const GUID &guid)
 | 
						|
    {
 | 
						|
        for (int i = 0; i < g_cGuidNames; i++) {
 | 
						|
            if (g_GuidNames[i].guid == guid) {
 | 
						|
                return g_GuidNames[i].szName;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (guid == GUID_NULL) {
 | 
						|
            return "GUID_NULL";
 | 
						|
        }
 | 
						|
 | 
						|
	// !!! add something to print FOURCC guids?
 | 
						|
	
 | 
						|
	// shouldn't this print the hex CLSID?
 | 
						|
        return "Unknown GUID Name";
 | 
						|
    }
 | 
						|
 | 
						|
#endif /* _OBJBASE_H_ */
 | 
						|
 | 
						|
/*  CDisp class - display our data types */
 | 
						|
 | 
						|
// clashes with REFERENCE_TIME
 | 
						|
CDisp::CDisp(LONGLONG ll, int Format)
 | 
						|
{
 | 
						|
    // note: this could be combined with CDisp(LONGLONG) by
 | 
						|
    // introducing a default format of CDISP_REFTIME
 | 
						|
    LARGE_INTEGER li;
 | 
						|
    li.QuadPart = ll;
 | 
						|
    switch (Format) {
 | 
						|
	case CDISP_DEC:
 | 
						|
	{
 | 
						|
	    TCHAR  temp[20];
 | 
						|
	    int pos=20;
 | 
						|
	    temp[--pos] = 0;
 | 
						|
	    int digit;
 | 
						|
	    // always output at least one digit
 | 
						|
	    do {
 | 
						|
		// Get the rightmost digit - we only need the low word
 | 
						|
	        digit = li.LowPart % 10;
 | 
						|
		li.QuadPart /= 10;
 | 
						|
		temp[--pos] = (TCHAR) digit+L'0';
 | 
						|
	    } while (li.QuadPart);
 | 
						|
	    (void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos);
 | 
						|
	    break;
 | 
						|
	}
 | 
						|
	case CDISP_HEX:
 | 
						|
	default:
 | 
						|
	    (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart);
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
CDisp::CDisp(REFCLSID clsid)
 | 
						|
{
 | 
						|
#ifdef UNICODE 
 | 
						|
    (void)StringFromGUID2(clsid, m_String, NUMELMS(m_String));
 | 
						|
#else
 | 
						|
    WCHAR wszTemp[50];
 | 
						|
    (void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp));
 | 
						|
    (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp);
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
#ifdef __STREAMS__
 | 
						|
/*  Display stuff */
 | 
						|
CDisp::CDisp(CRefTime llTime)
 | 
						|
{
 | 
						|
    LONGLONG llDiv;
 | 
						|
    if (llTime < 0) {
 | 
						|
        llTime = -llTime;
 | 
						|
        (void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-"));
 | 
						|
    }
 | 
						|
    llDiv = (LONGLONG)24 * 3600 * 10000000;
 | 
						|
    if (llTime >= llDiv) {
 | 
						|
        (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv));
 | 
						|
        llTime = llTime % llDiv;
 | 
						|
    }
 | 
						|
    llDiv = (LONGLONG)3600 * 10000000;
 | 
						|
    if (llTime >= llDiv) {
 | 
						|
        (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv));
 | 
						|
        llTime = llTime % llDiv;
 | 
						|
    }
 | 
						|
    llDiv = (LONGLONG)60 * 10000000;
 | 
						|
    if (llTime >= llDiv) {
 | 
						|
        (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv));
 | 
						|
        llTime = llTime % llDiv;
 | 
						|
    }
 | 
						|
    (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"),
 | 
						|
             (LONG)llTime / 10000000,
 | 
						|
             (LONG)((llTime % 10000000) / 10000));
 | 
						|
};
 | 
						|
 | 
						|
#endif // __STREAMS__
 | 
						|
 | 
						|
 | 
						|
/*  Display pin */
 | 
						|
CDisp::CDisp(IPin *pPin)
 | 
						|
{
 | 
						|
    PIN_INFO pi;
 | 
						|
    TCHAR str[MAX_PIN_NAME];
 | 
						|
    CLSID clsid;
 | 
						|
 | 
						|
    if (pPin) {
 | 
						|
       pPin->QueryPinInfo(&pi);
 | 
						|
       pi.pFilter->GetClassID(&clsid);
 | 
						|
       QueryPinInfoReleaseFilter(pi);
 | 
						|
      #ifndef UNICODE
 | 
						|
       WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1,
 | 
						|
                           str, MAX_PIN_NAME, NULL, NULL);
 | 
						|
      #else
 | 
						|
       (void)StringCchCopy(str, NUMELMS(str), pi.achName);
 | 
						|
      #endif
 | 
						|
    } else {
 | 
						|
       (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin"));
 | 
						|
    }
 | 
						|
 | 
						|
    m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64];
 | 
						|
    if (!m_pString) {
 | 
						|
	return;
 | 
						|
    }
 | 
						|
 | 
						|
    (void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str);
 | 
						|
}
 | 
						|
 | 
						|
/*  Display filter or pin */
 | 
						|
CDisp::CDisp(IUnknown *pUnk)
 | 
						|
{
 | 
						|
    IBaseFilter *pf;
 | 
						|
    HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf);
 | 
						|
    if(SUCCEEDED(hr))
 | 
						|
    {
 | 
						|
        FILTER_INFO fi;
 | 
						|
        hr = pf->QueryFilterInfo(&fi);
 | 
						|
        if(SUCCEEDED(hr))
 | 
						|
        {
 | 
						|
            QueryFilterInfoReleaseGraph(fi);
 | 
						|
 | 
						|
            size_t len = lstrlenW(fi.achName)  + 1;
 | 
						|
 | 
						|
            m_pString = new TCHAR[len];
 | 
						|
            if(m_pString)
 | 
						|
            {
 | 
						|
#ifdef UNICODE
 | 
						|
                (void)StringCchCopy(m_pString, len, fi.achName);
 | 
						|
#else
 | 
						|
                (void)StringCchPrintf(m_pString, len, "%S", fi.achName);
 | 
						|
#endif
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        pf->Release();
 | 
						|
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    IPin *pp;
 | 
						|
    hr = pUnk->QueryInterface(IID_IPin, (void **)&pp);
 | 
						|
    if(SUCCEEDED(hr))
 | 
						|
    {
 | 
						|
        CDisp::CDisp(pp);
 | 
						|
        pp->Release();
 | 
						|
        return;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
CDisp::~CDisp()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
CDispBasic::~CDispBasic()
 | 
						|
{
 | 
						|
    if (m_pString != m_String) {
 | 
						|
	delete [] m_pString;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
CDisp::CDisp(double d)
 | 
						|
{
 | 
						|
    (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* If built for debug this will display the media type details. We convert the
 | 
						|
   major and subtypes into strings and also ask the base classes for a string
 | 
						|
   description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit
 | 
						|
   We also display the fields in the BITMAPINFOHEADER structure, this should
 | 
						|
   succeed as we do not accept input types unless the format is big enough */
 | 
						|
 | 
						|
#ifdef DEBUG
 | 
						|
void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn)
 | 
						|
{
 | 
						|
 | 
						|
    /* Dump the GUID types and a short description */
 | 
						|
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("")));
 | 
						|
    DbgLog((LOG_TRACE,2,TEXT("%s  M type %hs  S type %hs"), label,
 | 
						|
	    GuidNames[pmtIn->majortype],
 | 
						|
	    GuidNames[pmtIn->subtype]));
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype)));
 | 
						|
 | 
						|
    /* Dump the generic media types */
 | 
						|
 | 
						|
    if (pmtIn->bTemporalCompression) {
 | 
						|
        DbgLog((LOG_TRACE,5,TEXT("Temporally compressed")));
 | 
						|
    } else {
 | 
						|
        DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed")));
 | 
						|
    }
 | 
						|
 | 
						|
    if (pmtIn->bFixedSizeSamples) {
 | 
						|
        DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize));
 | 
						|
    } else {
 | 
						|
        DbgLog((LOG_TRACE,5,TEXT("Variable size samples")));
 | 
						|
    }
 | 
						|
 | 
						|
    if (pmtIn->formattype == FORMAT_VideoInfo) {
 | 
						|
 | 
						|
        VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat;
 | 
						|
 | 
						|
        DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource);
 | 
						|
        DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget);
 | 
						|
        DisplayBITMAPINFO(HEADER(pmtIn->pbFormat));
 | 
						|
 | 
						|
    } if (pmtIn->formattype == FORMAT_VideoInfo2) {
 | 
						|
 | 
						|
        VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat;
 | 
						|
 | 
						|
        DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource);
 | 
						|
        DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget);
 | 
						|
        DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"),
 | 
						|
            pVideoInfo2->dwPictAspectRatioX,
 | 
						|
            pVideoInfo2->dwPictAspectRatioY));
 | 
						|
        DisplayBITMAPINFO(&pVideoInfo2->bmiHeader);
 | 
						|
 | 
						|
    } else if (pmtIn->majortype == MEDIATYPE_Audio) {
 | 
						|
        DbgLog((LOG_TRACE,2,TEXT("     Format type %hs"),
 | 
						|
            GuidNames[pmtIn->formattype]));
 | 
						|
        DbgLog((LOG_TRACE,2,TEXT("     Subtype %hs"),
 | 
						|
            GuidNames[pmtIn->subtype]));
 | 
						|
 | 
						|
        if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet)
 | 
						|
          && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT)))
 | 
						|
        {
 | 
						|
            /* Dump the contents of the WAVEFORMATEX type-specific format structure */
 | 
						|
 | 
						|
            WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat;
 | 
						|
            DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag));
 | 
						|
            DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels));
 | 
						|
            DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec));
 | 
						|
            DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec));
 | 
						|
            DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign));
 | 
						|
            DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample));
 | 
						|
 | 
						|
            /* PCM uses a WAVEFORMAT and does not have the extra size field */
 | 
						|
 | 
						|
            if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) {
 | 
						|
                DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize));
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
        }
 | 
						|
 | 
						|
    } else {
 | 
						|
        DbgLog((LOG_TRACE,2,TEXT("     Format type %hs"),
 | 
						|
            GuidNames[pmtIn->formattype]));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi)
 | 
						|
{
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize));
 | 
						|
    if (pbmi->biCompression < 256) {
 | 
						|
        DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit  (%d)"),
 | 
						|
                pbmi->biWidth, pbmi->biHeight,
 | 
						|
                pbmi->biBitCount, pbmi->biCompression));
 | 
						|
    } else {
 | 
						|
        DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"),
 | 
						|
                pbmi->biWidth, pbmi->biHeight,
 | 
						|
                pbmi->biBitCount, &pbmi->biCompression));
 | 
						|
    }
 | 
						|
 | 
						|
    DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage));
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes));
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter));
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter));
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void DisplayRECT(LPCTSTR szLabel, const RECT& rc)
 | 
						|
{
 | 
						|
    DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"),
 | 
						|
            szLabel,
 | 
						|
            rc.left,
 | 
						|
            rc.top,
 | 
						|
            rc.right,
 | 
						|
            rc.bottom));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel)
 | 
						|
{
 | 
						|
    if( !pGraph )
 | 
						|
    {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    IEnumFilters *pFilters;
 | 
						|
 | 
						|
    DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph));
 | 
						|
 | 
						|
    if (FAILED(pGraph->EnumFilters(&pFilters))) {
 | 
						|
	DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!")));
 | 
						|
    }
 | 
						|
 | 
						|
    IBaseFilter *pFilter;
 | 
						|
    ULONG	n;
 | 
						|
    while (pFilters->Next(1, &pFilter, &n) == S_OK) {
 | 
						|
	FILTER_INFO	info;
 | 
						|
 | 
						|
	if (FAILED(pFilter->QueryFilterInfo(&info))) {
 | 
						|
	    DbgLog((LOG_TRACE,dwLevel,TEXT("    Filter [%p]  -- failed QueryFilterInfo"), pFilter));
 | 
						|
	} else {
 | 
						|
	    QueryFilterInfoReleaseGraph(info);
 | 
						|
 | 
						|
	    // !!! should QueryVendorInfo here!
 | 
						|
	
 | 
						|
	    DbgLog((LOG_TRACE,dwLevel,TEXT("    Filter [%p]  '%ls'"), pFilter, info.achName));
 | 
						|
 | 
						|
	    IEnumPins *pins;
 | 
						|
 | 
						|
	    if (FAILED(pFilter->EnumPins(&pins))) {
 | 
						|
		DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!")));
 | 
						|
	    } else {
 | 
						|
 | 
						|
		IPin *pPin;
 | 
						|
		while (pins->Next(1, &pPin, &n) == S_OK) {
 | 
						|
		    PIN_INFO	pinInfo;
 | 
						|
 | 
						|
		    if (FAILED(pPin->QueryPinInfo(&pinInfo))) {
 | 
						|
			DbgLog((LOG_TRACE,dwLevel,TEXT("          Pin [%x]  -- failed QueryPinInfo"), pPin));
 | 
						|
		    } else {
 | 
						|
			QueryPinInfoReleaseFilter(pinInfo);
 | 
						|
 | 
						|
			IPin *pPinConnected = NULL;
 | 
						|
 | 
						|
			HRESULT hr = pPin->ConnectedTo(&pPinConnected);
 | 
						|
 | 
						|
			if (pPinConnected) {
 | 
						|
			    DbgLog((LOG_TRACE,dwLevel,TEXT("          Pin [%p]  '%ls' [%sput]")
 | 
						|
							   TEXT("  Connected to pin [%p]"),
 | 
						|
				    pPin, pinInfo.achName,
 | 
						|
				    pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"),
 | 
						|
				    pPinConnected));
 | 
						|
 | 
						|
			    pPinConnected->Release();
 | 
						|
 | 
						|
			    // perhaps we should really dump the type both ways as a sanity
 | 
						|
			    // check?
 | 
						|
			    if (pinInfo.dir == PINDIR_OUTPUT) {
 | 
						|
				AM_MEDIA_TYPE mt;
 | 
						|
 | 
						|
				hr = pPin->ConnectionMediaType(&mt);
 | 
						|
 | 
						|
				if (SUCCEEDED(hr)) {
 | 
						|
				    DisplayType(TEXT("Connection type"), &mt);
 | 
						|
 | 
						|
				    FreeMediaType(mt);
 | 
						|
				}
 | 
						|
			    }
 | 
						|
			} else {
 | 
						|
			    DbgLog((LOG_TRACE,dwLevel,
 | 
						|
				    TEXT("          Pin [%x]  '%ls' [%sput]"),
 | 
						|
				    pPin, pinInfo.achName,
 | 
						|
				    pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out")));
 | 
						|
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		    pPin->Release();
 | 
						|
 | 
						|
		}
 | 
						|
 | 
						|
		pins->Release();
 | 
						|
	    }
 | 
						|
 | 
						|
	}
 | 
						|
	
 | 
						|
	pFilter->Release();
 | 
						|
    }
 | 
						|
 | 
						|
    pFilters->Release();
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 |