1
//------------------------------------------------------------------------------
4
// Desc: DirectShow base classes - implements ActiveX system debugging
7
// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8
//------------------------------------------------------------------------------
10
#include <pjmedia-videodev/config.h>
12
#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
33
static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi);
34
static void DisplayRECT(LPCTSTR szLabel, const RECT& rc);
36
// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer.
37
// See the documentation for wsprintf()'s lpOut parameter for more information.
38
const INT iDEBUGINFO = 1024; // Used to format strings
40
/* For every module and executable we store a debugging level for each of
41
the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy
42
to isolate and debug individual modules without seeing everybody elses
43
spurious debug output. The keys are stored in the registry under the
44
HKEY_LOCAL_MACHINE\SOFTWARE\Debug\<Module Name>\<KeyName> key values
45
NOTE these must be in the same order as their enumeration definition */
47
const LPCTSTR pKeyNames[] = {
48
TEXT("TIMING"), // Timing and performance measurements
49
TEXT("TRACE"), // General step point call tracing
50
TEXT("MEMORY"), // Memory and object allocation/destruction
51
TEXT("LOCKING"), // Locking/unlocking of critical sections
52
TEXT("ERROR"), // Debug error notification
60
const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s");
61
const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s");
63
const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories
65
HINSTANCE m_hInst; // Module instance handle
66
TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name
67
DWORD m_Levels[iMAXLEVELS]; // Debug level per category
68
CRITICAL_SECTION m_CSDebug; // Controls access to list
69
DWORD m_dwNextCookie; // Next active object ID
70
ObjectDesc *pListHead = NULL; // First active object
71
DWORD m_dwObjectCount; // Active object count
72
BOOL m_bInit = FALSE; // Have we been initialised
73
HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here
74
DWORD dwWaitTimeout = INFINITE; // Default timeout value
75
DWORD dwTimeOffset; // Time of first DbgLog call
76
bool g_fUseKASSERT = false; // don't create messagebox
77
bool g_fDbgInDllEntryPoint = false;
78
bool g_fAutoRefreshLevels = false;
80
LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug");
81
LPCTSTR pGlobalKey = TEXT("GLOBAL");
82
static CHAR *pUnknownName = "UNKNOWN";
84
LPCTSTR TimeoutName = TEXT("TIMEOUT");
86
/* This sets the instance handle that the debug library uses to find
87
the module's file name from the Win32 GetModuleFileName function */
89
void WINAPI DbgInitialise(HINSTANCE hInst)
91
InitializeCriticalSection(&m_CSDebug);
96
if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0))
98
DbgInitModuleSettings(false);
99
DbgInitGlobalSettings(true);
100
dwTimeOffset = timeGetTime();
104
/* This is called to clear up any resources the debug library uses - at the
105
moment we delete our critical section and the object list. The values we
106
retrieve from the registry are all done during initialisation but we don't
107
go looking for update notifications while we are running, if the values
108
are changed then the application has to be restarted to pick them up */
110
void WINAPI DbgTerminate()
112
if (m_hOutput != INVALID_HANDLE_VALUE) {
113
EXECUTE_ASSERT(CloseHandle(m_hOutput));
114
m_hOutput = INVALID_HANDLE_VALUE;
116
DeleteCriticalSection(&m_CSDebug);
121
/* This is called by DbgInitLogLevels to read the debug settings
122
for each logging category for this module from the registry */
124
void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax)
126
LONG lReturn; // Create key return value
127
LONG lKeyPos; // Current key category
128
DWORD dwKeySize; // Size of the key value
129
DWORD dwKeyType; // Receives it's type
130
DWORD dwKeyValue; // This fields value
132
/* Try and read a value for each key position in turn */
133
for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
135
dwKeySize = sizeof(DWORD);
136
lReturn = RegQueryValueEx(
137
hKey, // Handle to an open key
138
pKeyNames[lKeyPos], // Subkey name derivation
139
NULL, // Reserved field
140
&dwKeyType, // Returns the field type
141
(LPBYTE) &dwKeyValue, // Returns the field's value
142
&dwKeySize ); // Number of bytes transferred
144
/* If either the key was not available or it was not a DWORD value
145
then we ensure only the high priority debug logging is output
146
but we try and update the field to a zero filled DWORD value */
148
if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) {
151
lReturn = RegSetValueEx(
152
hKey, // Handle of an open key
153
pKeyNames[lKeyPos], // Address of subkey name
154
(DWORD) 0, // Reserved field
155
REG_DWORD, // Type of the key field
156
(PBYTE) &dwKeyValue, // Value for the field
157
sizeof(DWORD)); // Size of the field buffer
159
if (lReturn != ERROR_SUCCESS) {
160
DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
166
m_Levels[lKeyPos] = max(dwKeyValue,m_Levels[lKeyPos]);
170
if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) {
171
m_Levels[lKeyPos] = dwKeyValue;
176
/* Read the timeout value for catching hangs */
177
dwKeySize = sizeof(DWORD);
178
lReturn = RegQueryValueEx(
179
hKey, // Handle to an open key
180
TimeoutName, // Subkey name derivation
181
NULL, // Reserved field
182
&dwKeyType, // Returns the field type
183
(LPBYTE) &dwWaitTimeout, // Returns the field's value
184
&dwKeySize ); // Number of bytes transferred
186
/* If either the key was not available or it was not a DWORD value
187
then we ensure only the high priority debug logging is output
188
but we try and update the field to a zero filled DWORD value */
190
if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) {
192
dwWaitTimeout = INFINITE;
193
lReturn = RegSetValueEx(
194
hKey, // Handle of an open key
195
TimeoutName, // Address of subkey name
196
(DWORD) 0, // Reserved field
197
REG_DWORD, // Type of the key field
198
(PBYTE) &dwWaitTimeout, // Value for the field
199
sizeof(DWORD)); // Size of the field buffer
201
if (lReturn != ERROR_SUCCESS) {
202
DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
203
dwWaitTimeout = INFINITE;
208
void WINAPI DbgOutString(LPCTSTR psz)
210
if (m_hOutput != INVALID_HANDLE_VALUE) {
211
UINT cb = lstrlen(psz);
215
WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0);
216
WriteFile (m_hOutput, szDest, cb, &dw, NULL);
218
WriteFile (m_hOutput, psz, cb, &dw, NULL);
221
OutputDebugString (psz);
228
HRESULT DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName)
231
const TCHAR *pIn = inName;
234
//scan the input and record the last '.' position
235
while (*pIn && (pIn - inName) < MAX_PATH)
237
if ( TEXT('.') == *pIn )
238
dotPos = (int)(pIn-inName);
242
if (*pIn) //input should be zero-terminated within MAX_PATH
245
DWORD dwProcessId = GetCurrentProcessId();
249
//no extension in the input, appending process id to the input
250
hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId);
254
TCHAR pathAndBasename[MAX_PATH] = {0};
256
//there's an extension - zero-terminate the path and basename first by copying
257
hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos);
259
//re-combine path, basename and extension with processId appended to a basename
261
hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos);
268
/* Called by DbgInitGlobalSettings to setup alternate logging destinations
271
void WINAPI DbgInitLogTo (
277
TCHAR szFile[MAX_PATH] = {0};
278
static const TCHAR cszKey[] = TEXT("LogToFile");
280
dwKeySize = MAX_PATH;
281
lReturn = RegQueryValueEx(
282
hKey, // Handle to an open key
283
cszKey, // Subkey name derivation
284
NULL, // Reserved field
285
&dwKeyType, // Returns the field type
286
(LPBYTE) szFile, // Returns the field's value
287
&dwKeySize); // Number of bytes transferred
289
// create an empty key if it does not already exist
291
if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ)
293
dwKeySize = sizeof(TCHAR);
294
lReturn = RegSetValueEx(
295
hKey, // Handle of an open key
296
cszKey, // Address of subkey name
297
(DWORD) 0, // Reserved field
298
REG_SZ, // Type of the key field
299
(PBYTE)szFile, // Value for the field
300
dwKeySize); // Size of the field buffer
303
// if an output-to was specified. try to open it.
305
if (m_hOutput != INVALID_HANDLE_VALUE) {
306
EXECUTE_ASSERT(CloseHandle (m_hOutput));
307
m_hOutput = INVALID_HANDLE_VALUE;
311
if (!lstrcmpi(szFile, TEXT("Console"))) {
312
m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
313
if (m_hOutput == INVALID_HANDLE_VALUE) {
315
m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
317
SetConsoleTitle (TEXT("ActiveX Debug Output"));
318
} else if (szFile[0] &&
319
lstrcmpi(szFile, TEXT("Debug")) &&
320
lstrcmpi(szFile, TEXT("Debugger")) &&
321
lstrcmpi(szFile, TEXT("Deb")))
323
m_hOutput = CreateFile(szFile, GENERIC_WRITE,
326
FILE_ATTRIBUTE_NORMAL,
329
if (INVALID_HANDLE_VALUE == m_hOutput &&
330
GetLastError() == ERROR_SHARING_VIOLATION)
332
TCHAR uniqueName[MAX_PATH] = {0};
333
if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName)))
335
m_hOutput = CreateFile(uniqueName, GENERIC_WRITE,
338
FILE_ATTRIBUTE_NORMAL,
343
if (INVALID_HANDLE_VALUE != m_hOutput)
345
static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n");
346
SetFilePointer (m_hOutput, 0, NULL, FILE_END);
347
DbgOutString (cszBar);
355
/* This is called by DbgInitLogLevels to read the global debug settings for
356
each logging category for this module from the registry. Normally each
357
module has it's own values set for it's different debug categories but
358
setting the global SOFTWARE\Debug\Global applies them to ALL modules */
360
void WINAPI DbgInitGlobalSettings(bool fTakeMax)
362
LONG lReturn; // Create key return value
363
TCHAR szInfo[iDEBUGINFO]; // Constructs key names
364
HKEY hGlobalKey; // Global override key
366
/* Construct the global base key name */
367
(void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey);
369
/* Create or open the key for this module */
370
lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
371
szInfo, // Address of subkey name
372
(DWORD) 0, // Reserved value
373
NULL, // Address of class name
374
(DWORD) 0, // Special options flags
375
GENERIC_READ | GENERIC_WRITE, // Desired security access
376
NULL, // Key security descriptor
377
&hGlobalKey, // Opened handle buffer
378
NULL); // What really happened
380
if (lReturn != ERROR_SUCCESS) {
381
lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
382
szInfo, // Address of subkey name
383
(DWORD) 0, // Reserved value
384
NULL, // Address of class name
385
(DWORD) 0, // Special options flags
386
GENERIC_READ, // Desired security access
387
NULL, // Key security descriptor
388
&hGlobalKey, // Opened handle buffer
389
NULL); // What really happened
390
if (lReturn != ERROR_SUCCESS) {
391
DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key")));
396
DbgInitKeyLevels(hGlobalKey, fTakeMax);
397
RegCloseKey(hGlobalKey);
401
/* This sets the debugging log levels for the different categories. We start
402
by opening (or creating if not already available) the SOFTWARE\Debug key
403
that all these settings live under. We then look at the global values
404
set under SOFTWARE\Debug\Global which apply on top of the individual
405
module settings. We then load the individual module registry settings */
407
void WINAPI DbgInitModuleSettings(bool fTakeMax)
409
LONG lReturn; // Create key return value
410
TCHAR szInfo[iDEBUGINFO]; // Constructs key names
411
HKEY hModuleKey; // Module key handle
413
/* Construct the base key name */
414
(void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName);
416
/* Create or open the key for this module */
417
lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
418
szInfo, // Address of subkey name
419
(DWORD) 0, // Reserved value
420
NULL, // Address of class name
421
(DWORD) 0, // Special options flags
422
GENERIC_READ | GENERIC_WRITE, // Desired security access
423
NULL, // Key security descriptor
424
&hModuleKey, // Opened handle buffer
425
NULL); // What really happened
427
if (lReturn != ERROR_SUCCESS) {
428
lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
429
szInfo, // Address of subkey name
430
(DWORD) 0, // Reserved value
431
NULL, // Address of class name
432
(DWORD) 0, // Special options flags
433
GENERIC_READ, // Desired security access
434
NULL, // Key security descriptor
435
&hModuleKey, // Opened handle buffer
436
NULL); // What really happened
437
if (lReturn != ERROR_SUCCESS) {
438
DbgLog((LOG_ERROR,1,TEXT("Could not access module key")));
443
DbgInitLogTo(hModuleKey);
444
DbgInitKeyLevels(hModuleKey, fTakeMax);
445
RegCloseKey(hModuleKey);
449
/* Initialise the module file name */
451
void WINAPI DbgInitModuleName()
453
TCHAR FullName[iDEBUGINFO]; // Load the full path and module name
454
LPTSTR pName; // Searches from the end for a backslash
456
GetModuleFileName(m_hInst,FullName,iDEBUGINFO);
457
pName = _tcsrchr(FullName,'\\');
463
(void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName);
476
// create a thread to call MessageBox(). calling MessageBox() on
477
// random threads at bad times can confuse the host (eg IE).
479
DWORD WINAPI MsgBoxThread(
480
__inout LPVOID lpParameter // thread data
483
MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter;
484
pmsg->iResult = MessageBox(
493
INT MessageBoxOtherThread(
499
if(g_fDbgInDllEntryPoint)
501
// can't wait on another thread because we have the loader
502
// lock held in the dll entry point.
503
// This can crash sometimes so just skip it
504
// return MessageBox(hwnd, szTitle, szMessage, dwFlags);
509
MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0};
511
HANDLE hThread = CreateThread(
520
WaitForSingleObject(hThread, INFINITE);
521
CloseHandle(hThread);
525
// break into debugger on failure.
530
/* Displays a message box if the condition evaluated to FALSE */
532
void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
536
DbgKernelAssert(pCondition, pFileName, iLine);
541
TCHAR szInfo[iDEBUGINFO];
543
(void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
544
pCondition, iLine, pFileName);
546
INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
553
case IDNO: /* Kill the application */
555
FatalAppExit(FALSE, TEXT("Application terminated"));
558
case IDCANCEL: /* Break into the debugger */
563
case IDYES: /* Ignore assertion continue execution */
569
/* Displays a message box at a break point */
571
void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
575
DbgKernelAssert(pCondition, pFileName, iLine);
579
TCHAR szInfo[iDEBUGINFO];
581
(void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
582
pCondition, iLine, pFileName);
584
INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
591
case IDNO: /* Kill the application */
593
FatalAppExit(FALSE, TEXT("Application terminated"));
596
case IDCANCEL: /* Break into the debugger */
601
case IDYES: /* Ignore break point continue execution */
607
void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...)
609
// A debug break point message can have at most 2000 characters if
610
// ANSI or UNICODE characters are being used. A debug break point message
611
// can have between 1000 and 2000 double byte characters in it. If a
612
// particular message needs more characters, then the value of this constant
613
// should be increased.
614
const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000;
616
TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE];
619
va_start( va, szFormatString );
621
HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va );
626
DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because StringCchVPrintf() failed." );
630
::DbgBreakPoint( szBreakPointMessage, pFileName, iLine );
634
/* When we initialised the library we stored in the m_Levels array the current
635
debug output level for this module for each of the five categories. When
636
some debug logging is sent to us it can be sent with a combination of the
637
categories (if it is applicable to many for example) in which case we map
638
the type's categories into their current debug levels and see if any of
639
them can be accepted. The function looks at each bit position in turn from
640
the input type field and then compares it's debug level with the modules.
642
A level of 0 means that output is always sent to the debugger. This is
643
due to producing output if the input level is <= m_Levels.
647
BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level)
649
if(g_fAutoRefreshLevels)
651
// re-read the registry every second. We cannot use RegNotify() to
652
// notice registry changes because it's not available on win9x.
653
static DWORD g_dwLastRefresh = 0;
654
DWORD dwTime = timeGetTime();
655
if(dwTime - g_dwLastRefresh > 1000) {
656
g_dwLastRefresh = dwTime;
658
// there's a race condition: multiple threads could update the
659
// values. plus read and write not synchronized. no harm
661
DbgInitModuleSettings(false);
668
// If no valid bits are set return FALSE
669
if ((Type & ((1<<iMAXLEVELS)-1))) {
671
// speed up unconditional output.
675
for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
677
if (Level <= (m_Levels[lKeyPos] & ~LOG_FORCIBLY_SET)) {
688
/* Set debug levels to a given value */
690
void WINAPI DbgSetModuleLevel(DWORD Type, DWORD Level)
694
for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
696
m_Levels[lKeyPos] = Level | LOG_FORCIBLY_SET;
702
/* whether to check registry values periodically. this isn't turned
703
automatically because of the potential performance hit. */
704
void WINAPI DbgSetAutoRefreshLevels(bool fAuto)
706
g_fAutoRefreshLevels = fAuto;
711
// warning -- this function is implemented twice for ansi applications
712
// linking to the unicode library
714
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...)
716
/* Check the current level for this type combination */
718
BOOL bAccept = DbgCheckModuleLevel(Type,Level);
719
if (bAccept == FALSE) {
725
/* Format the variable length parameter list */
728
va_start(va, pFormat);
730
(void)StringCchPrintf(szInfo, NUMELMS(szInfo),
731
TEXT("%s(tid %x) %8d : "),
733
GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
736
WideCharToMultiByte(CP_ACP, 0, szInfo, -1, szInfoA, NUMELMS(szInfoA), 0, 0);
738
(void)StringCchVPrintfA(szInfoA + lstrlenA(szInfoA), NUMELMS(szInfoA) - lstrlenA(szInfoA), pFormat, va);
739
(void)StringCchCatA(szInfoA, NUMELMS(szInfoA), "\r\n");
741
WCHAR wszOutString[2000];
742
MultiByteToWideChar(CP_ACP, 0, szInfoA, -1, wszOutString, NUMELMS(wszOutString));
743
DbgOutString(wszOutString);
748
void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
752
DbgKernelAssert(pCondition, pFileName, iLine);
757
TCHAR szInfo[iDEBUGINFO];
759
(void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
760
pCondition, iLine, pFileName);
762
INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
769
case IDNO: /* Kill the application */
771
FatalAppExit(FALSE, TEXT("Application terminated"));
774
case IDCANCEL: /* Break into the debugger */
779
case IDYES: /* Ignore assertion continue execution */
785
/* Displays a message box at a break point */
787
void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
791
DbgKernelAssert(pCondition, pFileName, iLine);
795
TCHAR szInfo[iDEBUGINFO];
797
(void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
798
pCondition, iLine, pFileName);
800
INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
807
case IDNO: /* Kill the application */
809
FatalAppExit(FALSE, TEXT("Application terminated"));
812
case IDCANCEL: /* Break into the debugger */
817
case IDYES: /* Ignore break point continue execution */
823
void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
825
DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%hs) at line %d in file %hs"),
826
pCondition, iLine, pFileName));
832
/* Print a formatted string to the debugger prefixed with this module's name
833
Because the COMBASE classes are linked statically every module loaded will
834
have their own copy of this code. It therefore helps if the module name is
835
included on the output so that the offending code can be easily found */
838
// warning -- this function is implemented twice for ansi applications
839
// linking to the unicode library
841
void WINAPI DbgLogInfo(DWORD Type,DWORD Level,LPCTSTR pFormat,...)
844
/* Check the current level for this type combination */
846
BOOL bAccept = DbgCheckModuleLevel(Type,Level);
847
if (bAccept == FALSE) {
853
/* Format the variable length parameter list */
856
va_start(va, pFormat);
858
(void)StringCchPrintf(szInfo, NUMELMS(szInfo),
859
TEXT("%s(tid %x) %8d : "),
861
GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
863
(void)StringCchVPrintf(szInfo + lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), pFormat, va);
864
(void)StringCchCat(szInfo, NUMELMS(szInfo), TEXT("\r\n"));
865
DbgOutString(szInfo);
871
/* If we are executing as a pure kernel filter we cannot display message
872
boxes to the user, this provides an alternative which puts the error
873
condition on the debugger output with a suitable eye catching message */
875
void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
877
DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%s) at line %d in file %s"),
878
pCondition, iLine, pFileName));
884
/* Each time we create an object derived from CBaseObject the constructor will
885
call us to register the creation of the new object. We are passed a string
886
description which we store away. We return a cookie that the constructor
887
uses to identify the object when it is destroyed later on. We update the
888
total number of active objects in the DLL mainly for debugging purposes */
890
DWORD WINAPI DbgRegisterObjectCreation(LPCSTR szObjectName,
891
LPCWSTR wszObjectName)
893
/* If this fires you have a mixed DEBUG/RETAIL build */
895
ASSERT(!!szObjectName ^ !!wszObjectName);
897
/* Create a place holder for this object description */
899
ObjectDesc *pObject = new ObjectDesc;
902
/* It is valid to pass a NULL object name */
903
if (pObject == NULL) {
907
/* Check we have been initialised - we may not be initialised when we are
908
being pulled in from an executable which has globally defined objects
909
as they are created by the C++ run time before WinMain is called */
911
if (m_bInit == FALSE) {
912
DbgInitialise(GetModuleHandle(NULL));
915
/* Grab the list critical section */
916
EnterCriticalSection(&m_CSDebug);
918
/* If no name then default to UNKNOWN */
919
if (!szObjectName && !wszObjectName) {
920
szObjectName = pUnknownName;
923
/* Put the new description at the head of the list */
925
pObject->m_szName = szObjectName;
926
pObject->m_wszName = wszObjectName;
927
pObject->m_dwCookie = ++m_dwNextCookie;
928
pObject->m_pNext = pListHead;
933
DWORD ObjectCookie = pObject->m_dwCookie;
934
ASSERT(ObjectCookie);
937
DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"),
938
pObject->m_dwCookie, wszObjectName, m_dwObjectCount));
940
DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"),
941
pObject->m_dwCookie, szObjectName, m_dwObjectCount));
944
LeaveCriticalSection(&m_CSDebug);
949
/* This is called by the CBaseObject destructor when an object is about to be
950
destroyed, we are passed the cookie we returned during construction that
951
identifies this object. We scan the object list for a matching cookie and
952
remove the object if successful. We also update the active object count */
954
BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie)
956
/* Grab the list critical section */
957
EnterCriticalSection(&m_CSDebug);
959
ObjectDesc *pObject = pListHead;
960
ObjectDesc *pPrevious = NULL;
962
/* Scan the object list looking for a cookie match */
965
if (pObject->m_dwCookie == dwCookie) {
969
pObject = pObject->m_pNext;
972
if (pObject == NULL) {
973
DbgBreak("Apparently destroying a bogus object");
974
LeaveCriticalSection(&m_CSDebug);
978
/* Is the object at the head of the list */
980
if (pPrevious == NULL) {
981
pListHead = pObject->m_pNext;
983
pPrevious->m_pNext = pObject->m_pNext;
986
/* Delete the object and update the housekeeping information */
990
if(pObject->m_wszName) {
991
DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"),
992
pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount));
994
DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"),
995
pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount));
999
LeaveCriticalSection(&m_CSDebug);
1004
/* This runs through the active object list displaying their details */
1006
void WINAPI DbgDumpObjectRegister()
1008
TCHAR szInfo[iDEBUGINFO];
1010
/* Grab the list critical section */
1012
EnterCriticalSection(&m_CSDebug);
1013
ObjectDesc *pObject = pListHead;
1015
/* Scan the object list displaying the name and cookie */
1017
DbgLog((LOG_MEMORY,2,TEXT("")));
1018
DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description")));
1019
DbgLog((LOG_MEMORY,2,TEXT("")));
1022
if(pObject->m_wszName) {
1023
(void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName);
1025
(void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName);
1027
DbgLog((LOG_MEMORY,2,szInfo));
1028
pObject = pObject->m_pNext;
1031
(void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount);
1032
DbgLog((LOG_MEMORY,2,TEXT("")));
1033
DbgLog((LOG_MEMORY,1,szInfo));
1034
LeaveCriticalSection(&m_CSDebug);
1037
/* Debug infinite wait stuff */
1038
DWORD WINAPI DbgWaitForSingleObject(HANDLE h)
1042
dwWaitResult = WaitForSingleObject(h, dwWaitTimeout);
1043
ASSERT(dwWaitResult == WAIT_OBJECT_0);
1044
} while (dwWaitResult == WAIT_TIMEOUT);
1045
return dwWaitResult;
1047
DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount,
1048
__in_ecount(nCount) CONST HANDLE *lpHandles,
1053
dwWaitResult = WaitForMultipleObjects(nCount,
1057
ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS);
1058
} while (dwWaitResult == WAIT_TIMEOUT);
1059
return dwWaitResult;
1062
void WINAPI DbgSetWaitTimeout(DWORD dwTimeout)
1064
dwWaitTimeout = dwTimeout;
1071
/* Stuff for printing out our GUID names */
1073
GUID_STRING_ENTRY g_GuidNames[] = {
1074
#define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
1075
{ #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } },
1079
CGuidNameList GuidNames;
1080
int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]);
1082
char *CGuidNameList::operator [] (const GUID &guid)
1084
for (int i = 0; i < g_cGuidNames; i++) {
1085
if (g_GuidNames[i].guid == guid) {
1086
return g_GuidNames[i].szName;
1089
if (guid == GUID_NULL) {
1093
// !!! add something to print FOURCC guids?
1095
// shouldn't this print the hex CLSID?
1096
return "Unknown GUID Name";
1099
#endif /* _OBJBASE_H_ */
1101
/* CDisp class - display our data types */
1103
// clashes with REFERENCE_TIME
1104
CDisp::CDisp(LONGLONG ll, int Format)
1106
// note: this could be combined with CDisp(LONGLONG) by
1107
// introducing a default format of CDISP_REFTIME
1117
// always output at least one digit
1119
// Get the rightmost digit - we only need the low word
1120
digit = li.LowPart % 10;
1122
temp[--pos] = (TCHAR) digit+L'0';
1123
} while (li.QuadPart);
1124
(void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos);
1129
(void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart);
1133
CDisp::CDisp(REFCLSID clsid)
1136
(void)StringFromGUID2(clsid, m_String, NUMELMS(m_String));
1139
(void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp));
1140
(void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp);
1146
CDisp::CDisp(CRefTime llTime)
1151
(void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-"));
1153
llDiv = (LONGLONG)24 * 3600 * 10000000;
1154
if (llTime >= llDiv) {
1155
(void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv));
1156
llTime = llTime % llDiv;
1158
llDiv = (LONGLONG)3600 * 10000000;
1159
if (llTime >= llDiv) {
1160
(void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv));
1161
llTime = llTime % llDiv;
1163
llDiv = (LONGLONG)60 * 10000000;
1164
if (llTime >= llDiv) {
1165
(void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv));
1166
llTime = llTime % llDiv;
1168
(void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"),
1169
(LONG)llTime / 10000000,
1170
(LONG)((llTime % 10000000) / 10000));
1173
#endif // __STREAMS__
1177
CDisp::CDisp(IPin *pPin)
1180
TCHAR str[MAX_PIN_NAME];
1184
pPin->QueryPinInfo(&pi);
1185
pi.pFilter->GetClassID(&clsid);
1186
QueryPinInfoReleaseFilter(pi);
1188
WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1,
1189
str, MAX_PIN_NAME, NULL, NULL);
1191
(void)StringCchCopy(str, NUMELMS(str), pi.achName);
1194
(void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin"));
1197
m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64];
1202
(void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str);
1205
/* Display filter or pin */
1206
CDisp::CDisp(IUnknown *pUnk)
1209
HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf);
1213
hr = pf->QueryFilterInfo(&fi);
1216
QueryFilterInfoReleaseGraph(fi);
1218
size_t len = lstrlenW(fi.achName) + 1;
1220
m_pString = new TCHAR[len];
1224
(void)StringCchCopy(m_pString, len, fi.achName);
1226
(void)StringCchPrintf(m_pString, len, "%S", fi.achName);
1237
hr = pUnk->QueryInterface(IID_IPin, (void **)&pp);
1251
CDispBasic::~CDispBasic()
1253
if (m_pString != m_String) {
1254
delete [] m_pString;
1258
CDisp::CDisp(double d)
1260
(void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000));
1264
/* If built for debug this will display the media type details. We convert the
1265
major and subtypes into strings and also ask the base classes for a string
1266
description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit
1267
We also display the fields in the BITMAPINFOHEADER structure, this should
1268
succeed as we do not accept input types unless the format is big enough */
1271
void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn)
1274
/* Dump the GUID types and a short description */
1276
DbgLog((LOG_TRACE,5,TEXT("")));
1277
DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label,
1278
GuidNames[pmtIn->majortype],
1279
GuidNames[pmtIn->subtype]));
1280
DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype)));
1282
/* Dump the generic media types */
1284
if (pmtIn->bTemporalCompression) {
1285
DbgLog((LOG_TRACE,5,TEXT("Temporally compressed")));
1287
DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed")));
1290
if (pmtIn->bFixedSizeSamples) {
1291
DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize));
1293
DbgLog((LOG_TRACE,5,TEXT("Variable size samples")));
1296
if (pmtIn->formattype == FORMAT_VideoInfo) {
1298
VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat;
1300
DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource);
1301
DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget);
1302
DisplayBITMAPINFO(HEADER(pmtIn->pbFormat));
1304
} if (pmtIn->formattype == FORMAT_VideoInfo2) {
1306
VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat;
1308
DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource);
1309
DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget);
1310
DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"),
1311
pVideoInfo2->dwPictAspectRatioX,
1312
pVideoInfo2->dwPictAspectRatioY));
1313
DisplayBITMAPINFO(&pVideoInfo2->bmiHeader);
1315
} else if (pmtIn->majortype == MEDIATYPE_Audio) {
1316
DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"),
1317
GuidNames[pmtIn->formattype]));
1318
DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"),
1319
GuidNames[pmtIn->subtype]));
1321
if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet)
1322
&& (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT)))
1324
/* Dump the contents of the WAVEFORMATEX type-specific format structure */
1326
WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat;
1327
DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag));
1328
DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels));
1329
DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec));
1330
DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec));
1331
DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign));
1332
DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample));
1334
/* PCM uses a WAVEFORMAT and does not have the extra size field */
1336
if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) {
1337
DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize));
1343
DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"),
1344
GuidNames[pmtIn->formattype]));
1349
void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi)
1351
DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize));
1352
if (pbmi->biCompression < 256) {
1353
DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"),
1354
pbmi->biWidth, pbmi->biHeight,
1355
pbmi->biBitCount, pbmi->biCompression));
1357
DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"),
1358
pbmi->biWidth, pbmi->biHeight,
1359
pbmi->biBitCount, &pbmi->biCompression));
1362
DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage));
1363
DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes));
1364
DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter));
1365
DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter));
1366
DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed));
1370
void DisplayRECT(LPCTSTR szLabel, const RECT& rc)
1372
DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"),
1381
void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel)
1388
IEnumFilters *pFilters;
1390
DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph));
1392
if (FAILED(pGraph->EnumFilters(&pFilters))) {
1393
DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!")));
1396
IBaseFilter *pFilter;
1398
while (pFilters->Next(1, &pFilter, &n) == S_OK) {
1401
if (FAILED(pFilter->QueryFilterInfo(&info))) {
1402
DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] -- failed QueryFilterInfo"), pFilter));
1404
QueryFilterInfoReleaseGraph(info);
1406
// !!! should QueryVendorInfo here!
1408
DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] '%ls'"), pFilter, info.achName));
1412
if (FAILED(pFilter->EnumPins(&pins))) {
1413
DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!")));
1417
while (pins->Next(1, &pPin, &n) == S_OK) {
1420
if (FAILED(pPin->QueryPinInfo(&pinInfo))) {
1421
DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin));
1423
QueryPinInfoReleaseFilter(pinInfo);
1425
IPin *pPinConnected = NULL;
1427
HRESULT hr = pPin->ConnectedTo(&pPinConnected);
1429
if (pPinConnected) {
1430
DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%p] '%ls' [%sput]")
1431
TEXT(" Connected to pin [%p]"),
1432
pPin, pinInfo.achName,
1433
pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"),
1436
pPinConnected->Release();
1438
// perhaps we should really dump the type both ways as a sanity
1440
if (pinInfo.dir == PINDIR_OUTPUT) {
1443
hr = pPin->ConnectionMediaType(&mt);
1445
if (SUCCEEDED(hr)) {
1446
DisplayType(TEXT("Connection type"), &mt);
1452
DbgLog((LOG_TRACE,dwLevel,
1453
TEXT(" Pin [%x] '%ls' [%sput]"),
1454
pPin, pinInfo.achName,
1455
pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out")));
1472
pFilters->Release();
1478
#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */