AJA NTV2 SDK  18.0.0.2717
NTV2 SDK 18.0.0.2717
wxdebug.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
2 // File: WXDebug.cpp
3 //
4 // Desc: DirectShow base classes - implements ActiveX system debugging
5 // facilities.
6 //
7 // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 //------------------------------------------------------------------------------
9 
10 
11 #define _WINDLL
12 
13 #include <streams.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16 #include <dvdmedia.h>
17 
18 #ifdef DEBUG
19 #ifdef UNICODE
20 #ifndef _UNICODE
21 #define _UNICODE
22 #endif // _UNICODE
23 #endif // UNICODE
24 #endif // DEBUG
25 
26 #include <tchar.h>
27 #include <strsafe.h>
28 
29 #ifdef DEBUG
30 static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi);
31 static void DisplayRECT(LPCTSTR szLabel, const RECT& rc);
32 
33 // The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer.
34 // See the documentation for wsprintf()'s lpOut parameter for more information.
35 const INT iDEBUGINFO = 1024; // Used to format strings
36 
37 /* For every module and executable we store a debugging level for each of
38  the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy
39  to isolate and debug individual modules without seeing everybody elses
40  spurious debug output. The keys are stored in the registry under the
41  HKEY_LOCAL_MACHINE\SOFTWARE\Debug<Module Name><KeyName> key values
42  NOTE these must be in the same order as their enumeration definition */
43 
44 const LPCTSTR pKeyNames[] = {
45  TEXT("TIMING"), // Timing and performance measurements
46  TEXT("TRACE"), // General step point call tracing
47  TEXT("MEMORY"), // Memory and object allocation/destruction
48  TEXT("LOCKING"), // Locking/unlocking of critical sections
49  TEXT("ERROR"), // Debug error notification
50  TEXT("CUSTOM1"),
51  TEXT("CUSTOM2"),
52  TEXT("CUSTOM3"),
53  TEXT("CUSTOM4"),
54  TEXT("CUSTOM5")
55  };
56 
57 const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s");
58 const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s");
59 
60 const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories
61 
62 HINSTANCE m_hInst; // Module instance handle
63 TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name
64 DWORD m_Levels[iMAXLEVELS]; // Debug level per category
65 CRITICAL_SECTION m_CSDebug; // Controls access to list
66 DWORD m_dwNextCookie; // Next active object ID
67 ObjectDesc *pListHead = NULL; // First active object
68 DWORD m_dwObjectCount; // Active object count
69 BOOL m_bInit = FALSE; // Have we been initialised
70 HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here
71 DWORD dwWaitTimeout = INFINITE; // Default timeout value
72 DWORD dwTimeOffset; // Time of first DbgLog call
73 bool g_fUseKASSERT = false; // don't create messagebox
74 bool g_fDbgInDllEntryPoint = false;
75 bool g_fAutoRefreshLevels = false;
76 
77 LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug");
78 LPCTSTR pGlobalKey = TEXT("GLOBAL");
79 static CHAR *pUnknownName = "UNKNOWN";
80 
81 LPCTSTR TimeoutName = TEXT("TIMEOUT");
82 
83 /* This sets the instance handle that the debug library uses to find
84  the module's file name from the Win32 GetModuleFileName function */
85 
86 void WINAPI DbgInitialise(HINSTANCE hInst)
87 {
88  InitializeCriticalSection(&m_CSDebug);
89  m_bInit = TRUE;
90 
91  m_hInst = hInst;
92  DbgInitModuleName();
93  if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0))
94  DebugBreak();
95  DbgInitModuleSettings(false);
96  DbgInitGlobalSettings(true);
97  dwTimeOffset = timeGetTime();
98 }
99 
100 
101 /* This is called to clear up any resources the debug library uses - at the
102  moment we delete our critical section and the object list. The values we
103  retrieve from the registry are all done during initialisation but we don't
104  go looking for update notifications while we are running, if the values
105  are changed then the application has to be restarted to pick them up */
106 
107 void WINAPI DbgTerminate()
108 {
109  if (m_hOutput != INVALID_HANDLE_VALUE) {
110  EXECUTE_ASSERT(CloseHandle(m_hOutput));
111  m_hOutput = INVALID_HANDLE_VALUE;
112  }
113  DeleteCriticalSection(&m_CSDebug);
114  m_bInit = FALSE;
115 }
116 
117 
118 /* This is called by DbgInitLogLevels to read the debug settings
119  for each logging category for this module from the registry */
120 
121 void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax)
122 {
123  LONG lReturn; // Create key return value
124  LONG lKeyPos; // Current key category
125  DWORD dwKeySize; // Size of the key value
126  DWORD dwKeyType; // Receives it's type
127  DWORD dwKeyValue; // This fields value
128 
129  /* Try and read a value for each key position in turn */
130  for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
131 
132  dwKeySize = sizeof(DWORD);
133  lReturn = RegQueryValueEx(
134  hKey, // Handle to an open key
135  pKeyNames[lKeyPos], // Subkey name derivation
136  NULL, // Reserved field
137  &dwKeyType, // Returns the field type
138  (LPBYTE) &dwKeyValue, // Returns the field's value
139  &dwKeySize ); // Number of bytes transferred
140 
141  /* If either the key was not available or it was not a DWORD value
142  then we ensure only the high priority debug logging is output
143  but we try and update the field to a zero filled DWORD value */
144 
145  if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) {
146 
147  dwKeyValue = 0;
148  lReturn = RegSetValueEx(
149  hKey, // Handle of an open key
150  pKeyNames[lKeyPos], // Address of subkey name
151  (DWORD) 0, // Reserved field
152  REG_DWORD, // Type of the key field
153  (PBYTE) &dwKeyValue, // Value for the field
154  sizeof(DWORD)); // Size of the field buffer
155 
156  if (lReturn != ERROR_SUCCESS) {
157  DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
158  dwKeyValue = 0;
159  }
160  }
161  if(fTakeMax)
162  {
163  m_Levels[lKeyPos] = max(dwKeyValue,m_Levels[lKeyPos]);
164  }
165  else
166  {
167  if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) {
168  m_Levels[lKeyPos] = dwKeyValue;
169  }
170  }
171  }
172 
173  /* Read the timeout value for catching hangs */
174  dwKeySize = sizeof(DWORD);
175  lReturn = RegQueryValueEx(
176  hKey, // Handle to an open key
177  TimeoutName, // Subkey name derivation
178  NULL, // Reserved field
179  &dwKeyType, // Returns the field type
180  (LPBYTE) &dwWaitTimeout, // Returns the field's value
181  &dwKeySize ); // Number of bytes transferred
182 
183  /* If either the key was not available or it was not a DWORD value
184  then we ensure only the high priority debug logging is output
185  but we try and update the field to a zero filled DWORD value */
186 
187  if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) {
188 
189  dwWaitTimeout = INFINITE;
190  lReturn = RegSetValueEx(
191  hKey, // Handle of an open key
192  TimeoutName, // Address of subkey name
193  (DWORD) 0, // Reserved field
194  REG_DWORD, // Type of the key field
195  (PBYTE) &dwWaitTimeout, // Value for the field
196  sizeof(DWORD)); // Size of the field buffer
197 
198  if (lReturn != ERROR_SUCCESS) {
199  DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
200  dwWaitTimeout = INFINITE;
201  }
202  }
203 }
204 
205 void WINAPI DbgOutString(LPCTSTR psz)
206 {
207  if (m_hOutput != INVALID_HANDLE_VALUE) {
208  UINT cb = lstrlen(psz);
209  DWORD dw;
210 #ifdef UNICODE
211  CHAR szDest[2048];
212  WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0);
213  WriteFile (m_hOutput, szDest, cb, &dw, NULL);
214 #else
215  WriteFile (m_hOutput, psz, cb, &dw, NULL);
216 #endif
217  } else {
218  OutputDebugString (psz);
219  }
220 }
221 
222 
223 
224 
225 HRESULT DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName)
226 {
227  HRESULT hr = S_OK;
228  const TCHAR *pIn = inName;
229  int dotPos = -1;
230 
231  //scan the input and record the last '.' position
232  while (*pIn && (pIn - inName) < MAX_PATH)
233  {
234  if ( TEXT('.') == *pIn )
235  dotPos = (int)(pIn-inName);
236  ++pIn;
237  }
238 
239  if (*pIn) //input should be zero-terminated within MAX_PATH
240  return E_INVALIDARG;
241 
242  DWORD dwProcessId = GetCurrentProcessId();
243 
244  if (dotPos < 0)
245  {
246  //no extension in the input, appending process id to the input
247  hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId);
248  }
249  else
250  {
251  TCHAR pathAndBasename[MAX_PATH] = {0};
252 
253  //there's an extension - zero-terminate the path and basename first by copying
254  hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos);
255 
256  //re-combine path, basename and extension with processId appended to a basename
257  if (SUCCEEDED(hr))
258  hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos);
259  }
260 
261  return hr;
262 }
263 
264 
265 /* Called by DbgInitGlobalSettings to setup alternate logging destinations
266  */
267 
268 void WINAPI DbgInitLogTo (
269  HKEY hKey)
270 {
271  LONG lReturn;
272  DWORD dwKeyType;
273  DWORD dwKeySize;
274  TCHAR szFile[MAX_PATH] = {0};
275  static const TCHAR cszKey[] = TEXT("LogToFile");
276 
277  dwKeySize = MAX_PATH;
278  lReturn = RegQueryValueEx(
279  hKey, // Handle to an open key
280  cszKey, // Subkey name derivation
281  NULL, // Reserved field
282  &dwKeyType, // Returns the field type
283  (LPBYTE) szFile, // Returns the field's value
284  &dwKeySize); // Number of bytes transferred
285 
286  // create an empty key if it does not already exist
287  //
288  if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ)
289  {
290  dwKeySize = sizeof(TCHAR);
291  lReturn = RegSetValueEx(
292  hKey, // Handle of an open key
293  cszKey, // Address of subkey name
294  (DWORD) 0, // Reserved field
295  REG_SZ, // Type of the key field
296  (PBYTE)szFile, // Value for the field
297  dwKeySize); // Size of the field buffer
298  }
299 
300  // if an output-to was specified. try to open it.
301  //
302  if (m_hOutput != INVALID_HANDLE_VALUE) {
303  EXECUTE_ASSERT(CloseHandle (m_hOutput));
304  m_hOutput = INVALID_HANDLE_VALUE;
305  }
306  if (szFile[0] != 0)
307  {
308  if (!lstrcmpi(szFile, TEXT("Console"))) {
309  m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
310  if (m_hOutput == INVALID_HANDLE_VALUE) {
311  AllocConsole ();
312  m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
313  }
314  SetConsoleTitle (TEXT("ActiveX Debug Output"));
315  } else if (szFile[0] &&
316  lstrcmpi(szFile, TEXT("Debug")) &&
317  lstrcmpi(szFile, TEXT("Debugger")) &&
318  lstrcmpi(szFile, TEXT("Deb")))
319  {
320  m_hOutput = CreateFile(szFile, GENERIC_WRITE,
321  FILE_SHARE_READ,
322  NULL, OPEN_ALWAYS,
323  FILE_ATTRIBUTE_NORMAL,
324  NULL);
325 
326  if (INVALID_HANDLE_VALUE == m_hOutput &&
327  GetLastError() == ERROR_SHARING_VIOLATION)
328  {
329  TCHAR uniqueName[MAX_PATH] = {0};
330  if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName)))
331  {
332  m_hOutput = CreateFile(uniqueName, GENERIC_WRITE,
333  FILE_SHARE_READ,
334  NULL, OPEN_ALWAYS,
335  FILE_ATTRIBUTE_NORMAL,
336  NULL);
337  }
338  }
339 
340  if (INVALID_HANDLE_VALUE != m_hOutput)
341  {
342  static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n");
343  SetFilePointer (m_hOutput, 0, NULL, FILE_END);
344  DbgOutString (cszBar);
345  }
346  }
347  }
348 }
349 
350 
351 
352 /* This is called by DbgInitLogLevels to read the global debug settings for
353  each logging category for this module from the registry. Normally each
354  module has it's own values set for it's different debug categories but
355  setting the global SOFTWARE\Debug\Global applies them to ALL modules */
356 
357 void WINAPI DbgInitGlobalSettings(bool fTakeMax)
358 {
359  LONG lReturn; // Create key return value
360  TCHAR szInfo[iDEBUGINFO]; // Constructs key names
361  HKEY hGlobalKey; // Global override key
362 
363  /* Construct the global base key name */
364  (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey);
365 
366  /* Create or open the key for this module */
367  lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
368  szInfo, // Address of subkey name
369  (DWORD) 0, // Reserved value
370  NULL, // Address of class name
371  (DWORD) 0, // Special options flags
372  GENERIC_READ | GENERIC_WRITE, // Desired security access
373  NULL, // Key security descriptor
374  &hGlobalKey, // Opened handle buffer
375  NULL); // What really happened
376 
377  if (lReturn != ERROR_SUCCESS) {
378  lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
379  szInfo, // Address of subkey name
380  (DWORD) 0, // Reserved value
381  NULL, // Address of class name
382  (DWORD) 0, // Special options flags
383  GENERIC_READ, // Desired security access
384  NULL, // Key security descriptor
385  &hGlobalKey, // Opened handle buffer
386  NULL); // What really happened
387  if (lReturn != ERROR_SUCCESS) {
388  DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key")));
389  }
390  return;
391  }
392 
393  DbgInitKeyLevels(hGlobalKey, fTakeMax);
394  RegCloseKey(hGlobalKey);
395 }
396 
397 
398 /* This sets the debugging log levels for the different categories. We start
399  by opening (or creating if not already available) the SOFTWARE\Debug key
400  that all these settings live under. We then look at the global values
401  set under SOFTWARE\Debug\Global which apply on top of the individual
402  module settings. We then load the individual module registry settings */
403 
404 void WINAPI DbgInitModuleSettings(bool fTakeMax)
405 {
406  LONG lReturn; // Create key return value
407  TCHAR szInfo[iDEBUGINFO]; // Constructs key names
408  HKEY hModuleKey; // Module key handle
409 
410  /* Construct the base key name */
411  (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName);
412 
413  /* Create or open the key for this module */
414  lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
415  szInfo, // Address of subkey name
416  (DWORD) 0, // Reserved value
417  NULL, // Address of class name
418  (DWORD) 0, // Special options flags
419  GENERIC_READ | GENERIC_WRITE, // Desired security access
420  NULL, // Key security descriptor
421  &hModuleKey, // Opened handle buffer
422  NULL); // What really happened
423 
424  if (lReturn != ERROR_SUCCESS) {
425  lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
426  szInfo, // Address of subkey name
427  (DWORD) 0, // Reserved value
428  NULL, // Address of class name
429  (DWORD) 0, // Special options flags
430  GENERIC_READ, // Desired security access
431  NULL, // Key security descriptor
432  &hModuleKey, // Opened handle buffer
433  NULL); // What really happened
434  if (lReturn != ERROR_SUCCESS) {
435  DbgLog((LOG_ERROR,1,TEXT("Could not access module key")));
436  }
437  return;
438  }
439 
440  DbgInitLogTo(hModuleKey);
441  DbgInitKeyLevels(hModuleKey, fTakeMax);
442  RegCloseKey(hModuleKey);
443 }
444 
445 
446 /* Initialise the module file name */
447 
448 void WINAPI DbgInitModuleName()
449 {
450  TCHAR FullName[iDEBUGINFO]; // Load the full path and module name
451  LPTSTR pName; // Searches from the end for a backslash
452 
453  GetModuleFileName(m_hInst,FullName,iDEBUGINFO);
454  pName = _tcsrchr(FullName,'\\');
455  if (pName == NULL) {
456  pName = FullName;
457  } else {
458  pName++;
459  }
460  (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName);
461 }
462 
463 struct MsgBoxMsg
464 {
465  HWND hwnd;
466  LPCTSTR szTitle;
467  LPCTSTR szMessage;
468  DWORD dwFlags;
469  INT iResult;
470 };
471 
472 //
473 // create a thread to call MessageBox(). calling MessageBox() on
474 // random threads at bad times can confuse the host (eg IE).
475 //
476 DWORD WINAPI MsgBoxThread(
477  __inout LPVOID lpParameter // thread data
478  )
479 {
480  MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter;
481  pmsg->iResult = MessageBox(
482  pmsg->hwnd,
483  pmsg->szTitle,
484  pmsg->szMessage,
485  pmsg->dwFlags);
486 
487  return 0;
488 }
489 
490 INT MessageBoxOtherThread(
491  HWND hwnd,
492  LPCTSTR szTitle,
493  LPCTSTR szMessage,
494  DWORD dwFlags)
495 {
496  if(g_fDbgInDllEntryPoint)
497  {
498  // can't wait on another thread because we have the loader
499  // lock held in the dll entry point.
500  // This can crash sometimes so just skip it
501  // return MessageBox(hwnd, szTitle, szMessage, dwFlags);
502  return IDCANCEL;
503  }
504  else
505  {
506  MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0};
507  DWORD dwid;
508  HANDLE hThread = CreateThread(
509  0, // security
510  0, // stack size
511  MsgBoxThread,
512  (void *)&msg, // arg
513  0, // flags
514  &dwid);
515  if(hThread)
516  {
517  WaitForSingleObject(hThread, INFINITE);
518  CloseHandle(hThread);
519  return msg.iResult;
520  }
521 
522  // break into debugger on failure.
523  return IDCANCEL;
524  }
525 }
526 
527 /* Displays a message box if the condition evaluated to FALSE */
528 
529 void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
530 {
531  if(g_fUseKASSERT)
532  {
533  DbgKernelAssert(pCondition, pFileName, iLine);
534  }
535  else
536  {
537 
538  TCHAR szInfo[iDEBUGINFO];
539 
540  (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
541  pCondition, iLine, pFileName);
542 
543  INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
544  MB_SYSTEMMODAL |
545  MB_ICONHAND |
546  MB_YESNOCANCEL |
547  MB_SETFOREGROUND);
548  switch (MsgId)
549  {
550  case IDNO: /* Kill the application */
551 
552  FatalAppExit(FALSE, TEXT("Application terminated"));
553  break;
554 
555  case IDCANCEL: /* Break into the debugger */
556 
557  DebugBreak();
558  break;
559 
560  case IDYES: /* Ignore assertion continue execution */
561  break;
562  }
563  }
564 }
565 
566 /* Displays a message box at a break point */
567 
568 void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
569 {
570  if(g_fUseKASSERT)
571  {
572  DbgKernelAssert(pCondition, pFileName, iLine);
573  }
574  else
575  {
576  TCHAR szInfo[iDEBUGINFO];
577 
578  (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
579  pCondition, iLine, pFileName);
580 
581  INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
582  MB_SYSTEMMODAL |
583  MB_ICONHAND |
584  MB_YESNOCANCEL |
585  MB_SETFOREGROUND);
586  switch (MsgId)
587  {
588  case IDNO: /* Kill the application */
589 
590  FatalAppExit(FALSE, TEXT("Application terminated"));
591  break;
592 
593  case IDCANCEL: /* Break into the debugger */
594 
595  DebugBreak();
596  break;
597 
598  case IDYES: /* Ignore break point continue execution */
599  break;
600  }
601  }
602 }
603 
604 void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...)
605 {
606  // A debug break point message can have at most 2000 characters if
607  // ANSI or UNICODE characters are being used. A debug break point message
608  // can have between 1000 and 2000 double byte characters in it. If a
609  // particular message needs more characters, then the value of this constant
610  // should be increased.
611  const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000;
612 
613  TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE];
614 
615  va_list va;
616  va_start( va, szFormatString );
617 
618  HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va );
619 
620  va_end(va);
621 
622  if( FAILED(hr) ) {
623  DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because StringCchVPrintf() failed." );
624  return;
625  }
626 
627  ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine );
628 }
629 
630 
631 /* When we initialised the library we stored in the m_Levels array the current
632  debug output level for this module for each of the five categories. When
633  some debug logging is sent to us it can be sent with a combination of the
634  categories (if it is applicable to many for example) in which case we map
635  the type's categories into their current debug levels and see if any of
636  them can be accepted. The function looks at each bit position in turn from
637  the input type field and then compares it's debug level with the modules.
638 
639  A level of 0 means that output is always sent to the debugger. This is
640  due to producing output if the input level is <= m_Levels.
641 */
642 
643 
644 BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level)
645 {
646  if(g_fAutoRefreshLevels)
647  {
648  // re-read the registry every second. We cannot use RegNotify() to
649  // notice registry changes because it's not available on win9x.
650  static DWORD g_dwLastRefresh = 0;
651  DWORD dwTime = timeGetTime();
652  if(dwTime - g_dwLastRefresh > 1000) {
653  g_dwLastRefresh = dwTime;
654 
655  // there's a race condition: multiple threads could update the
656  // values. plus read and write not synchronized. no harm
657  // though.
658  DbgInitModuleSettings(false);
659  }
660  }
661 
662 
663  DWORD Mask = 0x01;
664 
665  // If no valid bits are set return FALSE
666  if ((Type & ((1<<iMAXLEVELS)-1))) {
667 
668  // speed up unconditional output.
669  if (0==Level)
670  return(TRUE);
671 
672  for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
673  if (Type & Mask) {
674  if (Level <= (m_Levels[lKeyPos] & ~LOG_FORCIBLY_SET)) {
675  return TRUE;
676  }
677  }
678  Mask <<= 1;
679  }
680  }
681  return FALSE;
682 }
683 
684 
685 /* Set debug levels to a given value */
686 
687 void WINAPI DbgSetModuleLevel(DWORD Type, DWORD Level)
688 {
689  DWORD Mask = 0x01;
690 
691  for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
692  if (Type & Mask) {
693  m_Levels[lKeyPos] = Level | LOG_FORCIBLY_SET;
694  }
695  Mask <<= 1;
696  }
697 }
698 
699 /* whether to check registry values periodically. this isn't turned
700  automatically because of the potential performance hit. */
701 void WINAPI DbgSetAutoRefreshLevels(bool fAuto)
702 {
703  g_fAutoRefreshLevels = fAuto;
704 }
705 
706 #ifdef UNICODE
707 //
708 // warning -- this function is implemented twice for ansi applications
709 // linking to the unicode library
710 //
711 void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...)
712 {
713  /* Check the current level for this type combination */
714 
715  BOOL bAccept = DbgCheckModuleLevel(Type,Level);
716  if (bAccept == FALSE) {
717  return;
718  }
719 
720  TCHAR szInfo[2000];
721 
722  /* Format the variable length parameter list */
723 
724  va_list va;
725  va_start(va, pFormat);
726 
727  (void)StringCchPrintf(szInfo, NUMELMS(szInfo),
728  TEXT("%s(tid %x) %8d : "),
729  m_ModuleName,
730  GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
731 
732  CHAR szInfoA[2000];
733  WideCharToMultiByte(CP_ACP, 0, szInfo, -1, szInfoA, NUMELMS(szInfoA), 0, 0);
734 
735  (void)StringCchVPrintfA(szInfoA + lstrlenA(szInfoA), NUMELMS(szInfoA) - lstrlenA(szInfoA), pFormat, va);
736  (void)StringCchCatA(szInfoA, NUMELMS(szInfoA), "\r\n");
737 
738  WCHAR wszOutString[2000];
739  MultiByteToWideChar(CP_ACP, 0, szInfoA, -1, wszOutString, NUMELMS(wszOutString));
740  DbgOutString(wszOutString);
741 
742  va_end(va);
743 }
744 
745 void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
746 {
747  if(g_fUseKASSERT)
748  {
749  DbgKernelAssert(pCondition, pFileName, iLine);
750  }
751  else
752  {
753 
754  TCHAR szInfo[iDEBUGINFO];
755 
756  (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
757  pCondition, iLine, pFileName);
758 
759  INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
760  MB_SYSTEMMODAL |
761  MB_ICONHAND |
762  MB_YESNOCANCEL |
763  MB_SETFOREGROUND);
764  switch (MsgId)
765  {
766  case IDNO: /* Kill the application */
767 
768  FatalAppExit(FALSE, TEXT("Application terminated"));
769  break;
770 
771  case IDCANCEL: /* Break into the debugger */
772 
773  DebugBreak();
774  break;
775 
776  case IDYES: /* Ignore assertion continue execution */
777  break;
778  }
779  }
780 }
781 
782 /* Displays a message box at a break point */
783 
784 void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
785 {
786  if(g_fUseKASSERT)
787  {
788  DbgKernelAssert(pCondition, pFileName, iLine);
789  }
790  else
791  {
792  TCHAR szInfo[iDEBUGINFO];
793 
794  (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
795  pCondition, iLine, pFileName);
796 
797  INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
798  MB_SYSTEMMODAL |
799  MB_ICONHAND |
800  MB_YESNOCANCEL |
801  MB_SETFOREGROUND);
802  switch (MsgId)
803  {
804  case IDNO: /* Kill the application */
805 
806  FatalAppExit(FALSE, TEXT("Application terminated"));
807  break;
808 
809  case IDCANCEL: /* Break into the debugger */
810 
811  DebugBreak();
812  break;
813 
814  case IDYES: /* Ignore break point continue execution */
815  break;
816  }
817  }
818 }
819 
820 void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
821 {
822  DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%hs) at line %d in file %hs"),
823  pCondition, iLine, pFileName));
824  DebugBreak();
825 }
826 
827 #endif
828 
829 /* Print a formatted string to the debugger prefixed with this module's name
830  Because the COMBASE classes are linked statically every module loaded will
831  have their own copy of this code. It therefore helps if the module name is
832  included on the output so that the offending code can be easily found */
833 
834 //
835 // warning -- this function is implemented twice for ansi applications
836 // linking to the unicode library
837 //
838 void WINAPI DbgLogInfo(DWORD Type,DWORD Level,LPCTSTR pFormat,...)
839 {
840 
841  /* Check the current level for this type combination */
842 
843  BOOL bAccept = DbgCheckModuleLevel(Type,Level);
844  if (bAccept == FALSE) {
845  return;
846  }
847 
848  TCHAR szInfo[2000];
849 
850  /* Format the variable length parameter list */
851 
852  va_list va;
853  va_start(va, pFormat);
854 
855  (void)StringCchPrintf(szInfo, NUMELMS(szInfo),
856  TEXT("%s(tid %x) %8d : "),
857  m_ModuleName,
858  GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
859 
860  (void)StringCchVPrintf(szInfo + lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), pFormat, va);
861  (void)StringCchCat(szInfo, NUMELMS(szInfo), TEXT("\r\n"));
862  DbgOutString(szInfo);
863 
864  va_end(va);
865 }
866 
867 
868 /* If we are executing as a pure kernel filter we cannot display message
869  boxes to the user, this provides an alternative which puts the error
870  condition on the debugger output with a suitable eye catching message */
871 
872 void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
873 {
874  DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%s) at line %d in file %s"),
875  pCondition, iLine, pFileName));
876  DebugBreak();
877 }
878 
879 
880 
881 /* Each time we create an object derived from CBaseObject the constructor will
882  call us to register the creation of the new object. We are passed a string
883  description which we store away. We return a cookie that the constructor
884  uses to identify the object when it is destroyed later on. We update the
885  total number of active objects in the DLL mainly for debugging purposes */
886 
887 DWORD WINAPI DbgRegisterObjectCreation(LPCSTR szObjectName,
888  LPCWSTR wszObjectName)
889 {
890  /* If this fires you have a mixed DEBUG/RETAIL build */
891 
892  ASSERT(!!szObjectName ^ !!wszObjectName);
893 
894  /* Create a place holder for this object description */
895 
896  ObjectDesc *pObject = new ObjectDesc;
897  ASSERT(pObject);
898 
899  /* It is valid to pass a NULL object name */
900  if (pObject == NULL) {
901  return FALSE;
902  }
903 
904  /* Check we have been initialised - we may not be initialised when we are
905  being pulled in from an executable which has globally defined objects
906  as they are created by the C++ run time before WinMain is called */
907 
908  if (m_bInit == FALSE) {
909  DbgInitialise(GetModuleHandle(NULL));
910  }
911 
912  /* Grab the list critical section */
913  EnterCriticalSection(&m_CSDebug);
914 
915  /* If no name then default to UNKNOWN */
916  if (!szObjectName && !wszObjectName) {
917  szObjectName = pUnknownName;
918  }
919 
920  /* Put the new description at the head of the list */
921 
922  pObject->m_szName = szObjectName;
923  pObject->m_wszName = wszObjectName;
924  pObject->m_dwCookie = ++m_dwNextCookie;
925  pObject->m_pNext = pListHead;
926 
927  pListHead = pObject;
928  m_dwObjectCount++;
929 
930  DWORD ObjectCookie = pObject->m_dwCookie;
931  ASSERT(ObjectCookie);
932 
933  if(wszObjectName) {
934  DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"),
935  pObject->m_dwCookie, wszObjectName, m_dwObjectCount));
936  } else {
937  DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"),
938  pObject->m_dwCookie, szObjectName, m_dwObjectCount));
939  }
940 
941  LeaveCriticalSection(&m_CSDebug);
942  return ObjectCookie;
943 }
944 
945 
946 /* This is called by the CBaseObject destructor when an object is about to be
947  destroyed, we are passed the cookie we returned during construction that
948  identifies this object. We scan the object list for a matching cookie and
949  remove the object if successful. We also update the active object count */
950 
951 BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie)
952 {
953  /* Grab the list critical section */
954  EnterCriticalSection(&m_CSDebug);
955 
956  ObjectDesc *pObject = pListHead;
957  ObjectDesc *pPrevious = NULL;
958 
959  /* Scan the object list looking for a cookie match */
960 
961  while (pObject) {
962  if (pObject->m_dwCookie == dwCookie) {
963  break;
964  }
965  pPrevious = pObject;
966  pObject = pObject->m_pNext;
967  }
968 
969  if (pObject == NULL) {
970  DbgBreak("Apparently destroying a bogus object");
971  LeaveCriticalSection(&m_CSDebug);
972  return FALSE;
973  }
974 
975  /* Is the object at the head of the list */
976 
977  if (pPrevious == NULL) {
978  pListHead = pObject->m_pNext;
979  } else {
980  pPrevious->m_pNext = pObject->m_pNext;
981  }
982 
983  /* Delete the object and update the housekeeping information */
984 
985  m_dwObjectCount--;
986 
987  if(pObject->m_wszName) {
988  DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"),
989  pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount));
990  } else {
991  DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"),
992  pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount));
993  }
994 
995  delete pObject;
996  LeaveCriticalSection(&m_CSDebug);
997  return TRUE;
998 }
999 
1000 
1001 /* This runs through the active object list displaying their details */
1002 
1003 void WINAPI DbgDumpObjectRegister()
1004 {
1005  TCHAR szInfo[iDEBUGINFO];
1006 
1007  /* Grab the list critical section */
1008 
1009  EnterCriticalSection(&m_CSDebug);
1010  ObjectDesc *pObject = pListHead;
1011 
1012  /* Scan the object list displaying the name and cookie */
1013 
1014  DbgLog((LOG_MEMORY,2,TEXT("")));
1015  DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description")));
1016  DbgLog((LOG_MEMORY,2,TEXT("")));
1017 
1018  while (pObject) {
1019  if(pObject->m_wszName) {
1020  (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName);
1021  } else {
1022  (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName);
1023  }
1024  DbgLog((LOG_MEMORY,2,szInfo));
1025  pObject = pObject->m_pNext;
1026  }
1027 
1028  (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount);
1029  DbgLog((LOG_MEMORY,2,TEXT("")));
1030  DbgLog((LOG_MEMORY,1,szInfo));
1031  LeaveCriticalSection(&m_CSDebug);
1032 }
1033 
1034 /* Debug infinite wait stuff */
1035 DWORD WINAPI DbgWaitForSingleObject(HANDLE h)
1036 {
1037  DWORD dwWaitResult;
1038  do {
1039  dwWaitResult = WaitForSingleObject(h, dwWaitTimeout);
1040  ASSERT(dwWaitResult == WAIT_OBJECT_0);
1041  } while (dwWaitResult == WAIT_TIMEOUT);
1042  return dwWaitResult;
1043 }
1044 DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount,
1045  __in_ecount(nCount) CONST HANDLE *lpHandles,
1046  BOOL bWaitAll)
1047 {
1048  DWORD dwWaitResult;
1049  do {
1050  dwWaitResult = WaitForMultipleObjects(nCount,
1051  lpHandles,
1052  bWaitAll,
1053  dwWaitTimeout);
1054  ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS);
1055  } while (dwWaitResult == WAIT_TIMEOUT);
1056  return dwWaitResult;
1057 }
1058 
1059 void WINAPI DbgSetWaitTimeout(DWORD dwTimeout)
1060 {
1061  dwWaitTimeout = dwTimeout;
1062 }
1063 
1064 #endif /* DEBUG */
1065 
1066 #ifdef _OBJBASE_H_
1067 
1068  /* Stuff for printing out our GUID names */
1069 
1070  GUID_STRING_ENTRY g_GuidNames[] = {
1071  #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
1072  { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } },
1073  #include <uuids.h>
1074  };
1075 
1076  CGuidNameList GuidNames;
1077  int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]);
1078 
1079  char *CGuidNameList::operator [] (const GUID &guid)
1080  {
1081  for (int i = 0; i < g_cGuidNames; i++) {
1082  if (g_GuidNames[i].guid == guid) {
1083  return g_GuidNames[i].szName;
1084  }
1085  }
1086  if (guid == GUID_NULL) {
1087  return "GUID_NULL";
1088  }
1089 
1090  // !!! add something to print FOURCC guids?
1091 
1092  // shouldn't this print the hex CLSID?
1093  return "Unknown GUID Name";
1094  }
1095 
1096 #endif /* _OBJBASE_H_ */
1097 
1098 /* CDisp class - display our data types */
1099 
1100 // clashes with REFERENCE_TIME
1101 CDisp::CDisp(LONGLONG ll, int Format)
1102 {
1103  // note: this could be combined with CDisp(LONGLONG) by
1104  // introducing a default format of CDISP_REFTIME
1105  LARGE_INTEGER li;
1106  li.QuadPart = ll;
1107  switch (Format) {
1108  case CDISP_DEC:
1109  {
1110  TCHAR temp[20];
1111  int pos=20;
1112  temp[--pos] = 0;
1113  int digit;
1114  // always output at least one digit
1115  do {
1116  // Get the rightmost digit - we only need the low word
1117  digit = li.LowPart % 10;
1118  li.QuadPart /= 10;
1119  temp[--pos] = (TCHAR) digit+L'0';
1120  } while (li.QuadPart);
1121  (void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos);
1122  break;
1123  }
1124  case CDISP_HEX:
1125  default:
1126  (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart);
1127  }
1128 };
1129 
1130 CDisp::CDisp(REFCLSID clsid)
1131 {
1132 #ifdef UNICODE
1133  (void)StringFromGUID2(clsid, m_String, NUMELMS(m_String));
1134 #else
1135  WCHAR wszTemp[50];
1136  (void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp));
1137  (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp);
1138 #endif
1139 };
1140 
1141 #ifdef __STREAMS__
1142 /* Display stuff */
1143 CDisp::CDisp(CRefTime llTime)
1144 {
1145  LONGLONG llDiv;
1146  if (llTime < 0) {
1147  llTime = -llTime;
1148  (void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-"));
1149  }
1150  llDiv = (LONGLONG)24 * 3600 * 10000000;
1151  if (llTime >= llDiv) {
1152  (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv));
1153  llTime = llTime % llDiv;
1154  }
1155  llDiv = (LONGLONG)3600 * 10000000;
1156  if (llTime >= llDiv) {
1157  (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv));
1158  llTime = llTime % llDiv;
1159  }
1160  llDiv = (LONGLONG)60 * 10000000;
1161  if (llTime >= llDiv) {
1162  (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv));
1163  llTime = llTime % llDiv;
1164  }
1165  (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"),
1166  (LONG)llTime / 10000000,
1167  (LONG)((llTime % 10000000) / 10000));
1168 };
1169 
1170 #endif // __STREAMS__
1171 
1172 
1173 /* Display pin */
1174 CDisp::CDisp(IPin *pPin)
1175 {
1176  PIN_INFO pi;
1177  TCHAR str[MAX_PIN_NAME];
1178  CLSID clsid;
1179 
1180  if (pPin) {
1181  pPin->QueryPinInfo(&pi);
1182  pi.pFilter->GetClassID(&clsid);
1184  #ifndef UNICODE
1185  WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1,
1186  str, MAX_PIN_NAME, NULL, NULL);
1187  #else
1188  (void)StringCchCopy(str, NUMELMS(str), pi.achName);
1189  #endif
1190  } else {
1191  (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin"));
1192  }
1193 
1194  m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64];
1195  if (!m_pString) {
1196  return;
1197  }
1198 
1199  (void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str);
1200 }
1201 
1202 /* Display filter or pin */
1203 CDisp::CDisp(IUnknown *pUnk)
1204 {
1205  IBaseFilter *pf;
1206  HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf);
1207  if(SUCCEEDED(hr))
1208  {
1209  FILTER_INFO fi;
1210  hr = pf->QueryFilterInfo(&fi);
1211  if(SUCCEEDED(hr))
1212  {
1214 
1215  size_t len = lstrlenW(fi.achName) + 1;
1216 
1217  m_pString = new TCHAR[len];
1218  if(m_pString)
1219  {
1220 #ifdef UNICODE
1221  (void)StringCchCopy(m_pString, len, fi.achName);
1222 #else
1223  (void)StringCchPrintf(m_pString, len, "%S", fi.achName);
1224 #endif
1225  }
1226  }
1227 
1228  pf->Release();
1229 
1230  return;
1231  }
1232 
1233  IPin *pp;
1234  hr = pUnk->QueryInterface(IID_IPin, (void **)&pp);
1235  if(SUCCEEDED(hr))
1236  {
1237  CDisp::CDisp(pp);
1238  pp->Release();
1239  return;
1240  }
1241 }
1242 
1243 
1245 {
1246 }
1247 
1249 {
1250  if (m_pString != m_String) {
1251  delete [] m_pString;
1252  }
1253 }
1254 
1255 CDisp::CDisp(double d)
1256 {
1257  (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000));
1258 }
1259 
1260 
1261 /* If built for debug this will display the media type details. We convert the
1262  major and subtypes into strings and also ask the base classes for a string
1263  description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit
1264  We also display the fields in the BITMAPINFOHEADER structure, this should
1265  succeed as we do not accept input types unless the format is big enough */
1266 
1267 #ifdef DEBUG
1268 void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn)
1269 {
1270 
1271  /* Dump the GUID types and a short description */
1272 
1273  DbgLog((LOG_TRACE,5,TEXT("")));
1274  DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label,
1275  GuidNames[pmtIn->majortype],
1276  GuidNames[pmtIn->subtype]));
1277  DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype)));
1278 
1279  /* Dump the generic media types */
1280 
1281  if (pmtIn->bTemporalCompression) {
1282  DbgLog((LOG_TRACE,5,TEXT("Temporally compressed")));
1283  } else {
1284  DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed")));
1285  }
1286 
1287  if (pmtIn->bFixedSizeSamples) {
1288  DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize));
1289  } else {
1290  DbgLog((LOG_TRACE,5,TEXT("Variable size samples")));
1291  }
1292 
1293  if (pmtIn->formattype == FORMAT_VideoInfo) {
1294 
1295  VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat;
1296 
1297  DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource);
1298  DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget);
1299  DisplayBITMAPINFO(HEADER(pmtIn->pbFormat));
1300 
1301  } if (pmtIn->formattype == FORMAT_VideoInfo2) {
1302 
1303  VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat;
1304 
1305  DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource);
1306  DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget);
1307  DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"),
1308  pVideoInfo2->dwPictAspectRatioX,
1309  pVideoInfo2->dwPictAspectRatioY));
1310  DisplayBITMAPINFO(&pVideoInfo2->bmiHeader);
1311 
1312  } else if (pmtIn->majortype == MEDIATYPE_Audio) {
1313  DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"),
1314  GuidNames[pmtIn->formattype]));
1315  DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"),
1316  GuidNames[pmtIn->subtype]));
1317 
1318  if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet)
1319  && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT)))
1320  {
1321  /* Dump the contents of the WAVEFORMATEX type-specific format structure */
1322 
1323  WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat;
1324  DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag));
1325  DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels));
1326  DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec));
1327  DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec));
1328  DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign));
1329  DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample));
1330 
1331  /* PCM uses a WAVEFORMAT and does not have the extra size field */
1332 
1333  if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) {
1334  DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize));
1335  }
1336  } else {
1337  }
1338 
1339  } else {
1340  DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"),
1341  GuidNames[pmtIn->formattype]));
1342  }
1343 }
1344 
1345 
1346 void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi)
1347 {
1348  DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize));
1349  if (pbmi->biCompression < 256) {
1350  DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"),
1351  pbmi->biWidth, pbmi->biHeight,
1352  pbmi->biBitCount, pbmi->biCompression));
1353  } else {
1354  DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"),
1355  pbmi->biWidth, pbmi->biHeight,
1356  pbmi->biBitCount, &pbmi->biCompression));
1357  }
1358 
1359  DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage));
1360  DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes));
1361  DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter));
1362  DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter));
1363  DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed));
1364 }
1365 
1366 
1367 void DisplayRECT(LPCTSTR szLabel, const RECT& rc)
1368 {
1369  DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"),
1370  szLabel,
1371  rc.left,
1372  rc.top,
1373  rc.right,
1374  rc.bottom));
1375 }
1376 
1377 
1378 void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel)
1379 {
1380  if( !pGraph )
1381  {
1382  return;
1383  }
1384 
1385  IEnumFilters *pFilters;
1386 
1387  DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph));
1388 
1389  if (FAILED(pGraph->EnumFilters(&pFilters))) {
1390  DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!")));
1391  }
1392 
1393  IBaseFilter *pFilter;
1394  ULONG n;
1395  while (pFilters->Next(1, &pFilter, &n) == S_OK) {
1396  FILTER_INFO info;
1397 
1398  if (FAILED(pFilter->QueryFilterInfo(&info))) {
1399  DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] -- failed QueryFilterInfo"), pFilter));
1400  } else {
1402 
1403  // !!! should QueryVendorInfo here!
1404 
1405  DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] '%ls'"), pFilter, info.achName));
1406 
1407  IEnumPins *pins;
1408 
1409  if (FAILED(pFilter->EnumPins(&pins))) {
1410  DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!")));
1411  } else {
1412 
1413  IPin *pPin;
1414  while (pins->Next(1, &pPin, &n) == S_OK) {
1415  PIN_INFO pinInfo;
1416 
1417  if (FAILED(pPin->QueryPinInfo(&pinInfo))) {
1418  DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin));
1419  } else {
1420  QueryPinInfoReleaseFilter(pinInfo);
1421 
1422  IPin *pPinConnected = NULL;
1423 
1424  HRESULT hr = pPin->ConnectedTo(&pPinConnected);
1425 
1426  if (pPinConnected) {
1427  DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%p] '%ls' [%sput]")
1428  TEXT(" Connected to pin [%p]"),
1429  pPin, pinInfo.achName,
1430  pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"),
1431  pPinConnected));
1432 
1433  pPinConnected->Release();
1434 
1435  // perhaps we should really dump the type both ways as a sanity
1436  // check?
1437  if (pinInfo.dir == PINDIR_OUTPUT) {
1438  AM_MEDIA_TYPE mt;
1439 
1440  hr = pPin->ConnectionMediaType(&mt);
1441 
1442  if (SUCCEEDED(hr)) {
1443  DisplayType(TEXT("Connection type"), &mt);
1444 
1445  FreeMediaType(mt);
1446  }
1447  }
1448  } else {
1449  DbgLog((LOG_TRACE,dwLevel,
1450  TEXT(" Pin [%x] '%ls' [%sput]"),
1451  pPin, pinInfo.achName,
1452  pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out")));
1453 
1454  }
1455  }
1456 
1457  pPin->Release();
1458 
1459  }
1460 
1461  pins->Release();
1462  }
1463 
1464  }
1465 
1466  pFilter->Release();
1467  }
1468 
1469  pFilters->Release();
1470 
1471 }
1472 
1473 #endif
1474 
MAX_PATH
#define MAX_PATH
Definition: ajatypes.h:350
DbgRegisterObjectCreation
#define DbgRegisterObjectCreation(pObjectName)
Definition: wxdebug.h:187
DbgRegisterObjectDestruction
#define DbgRegisterObjectDestruction(dwCookie)
Definition: wxdebug.h:188
DbgSetWaitTimeout
#define DbgSetWaitTimeout(dwTimeout)
Definition: wxdebug.h:198
DbgWaitForSingleObject
#define DbgWaitForSingleObject(h)
Definition: wxdebug.h:195
HANDLE
short HANDLE
Definition: ajatypes.h:338
GetSubtypeName
#define GetSubtypeName
Definition: wxutil.h:423
streams.h
NULL
#define NULL
Definition: ntv2caption608types.h:19
NUMELMS
#define NUMELMS(aa)
Definition: types.h:430
LOG_TRACE
@ LOG_TRACE
Definition: wxdebug.h:45
tag_ObjectDesc::m_szName
LPCSTR m_szName
Definition: wxdebug.h:67
DbgBreak
#define DbgBreak(_x_)
Definition: wxdebug.h:201
DbgWaitForMultipleObjects
#define DbgWaitForMultipleObjects(nCount, lpHandles, bWaitAll)
Definition: wxdebug.h:196
QueryFilterInfoReleaseGraph
#define QueryFilterInfoReleaseGraph(fi)
Definition: amfilter.h:37
tag_ObjectDesc::m_wszName
LPCWSTR m_wszName
Definition: wxdebug.h:68
DumpGraph
#define DumpGraph(pGraph, label)
Definition: wxdebug.h:219
FreeMediaType
void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE &mt)
Definition: mtype.cpp:423
nlohmann::json_abiNLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON_v3_11_NLOHMANN_JSON_VERSION_PATCH::detail::void
j template void())
Definition: json.hpp:4893
tag_ObjectDesc
Definition: wxdebug.h:66
n
unsigned int n
Definition: pstream.cpp:148
CDISP_HEX
@ CDISP_HEX
Definition: wxdebug.h:58
iDEBUGINFO
const INT iDEBUGINFO
Definition: perflog.cpp:114
QueryPinInfoReleaseFilter
#define QueryPinInfoReleaseFilter(pi)
Definition: amfilter.h:39
CDisp::CDisp
CDisp(LONGLONG ll, int Format=CDISP_HEX)
Definition: wxdebug.cpp:1101
DbgCheckModuleLevel
#define DbgCheckModuleLevel(Type, Level)
Definition: wxdebug.h:191
LOG_ERROR
@ LOG_ERROR
Definition: wxdebug.h:48
pName
CHAR * pName
Definition: amvideo.cpp:26
DbgLog
#define DbgLog(_x_)
Definition: wxdebug.h:183
CDispBasic::~CDispBasic
~CDispBasic()
Definition: wxdebug.cpp:1248
LOG_FORCIBLY_SET
#define LOG_FORCIBLY_SET
Definition: wxdebug.h:56
CDispBasic::m_pString
PTCHAR m_pString
Definition: wxdebug.h:295
tag_ObjectDesc::m_dwCookie
DWORD m_dwCookie
Definition: wxdebug.h:69
LOG_MEMORY
@ LOG_MEMORY
Definition: wxdebug.h:46
DbgSetAutoRefreshLevels
#define DbgSetAutoRefreshLevels(fAuto)
Definition: wxdebug.h:193
DbgSetModuleLevel
#define DbgSetModuleLevel(Type, Level)
Definition: wxdebug.h:192
EXECUTE_ASSERT
#define EXECUTE_ASSERT(_x_)
Definition: wxdebug.h:207
CRefTime
Definition: reftime.h:49
ObjectDesc
struct tag_ObjectDesc ObjectDesc
ULONG
ULONG(__stdcall *_RegisterTraceGuids)(__in IN WMIDPREQUEST RequestAddress
tag_ObjectDesc::m_pNext
tag_ObjectDesc * m_pNext
Definition: wxdebug.h:70
DbgDumpObjectRegister
#define DbgDumpObjectRegister()
Definition: wxdebug.h:189
DbgInitialise
#define DbgInitialise(hInst)
Definition: wxdebug.h:181
DbgTerminate
#define DbgTerminate()
Definition: wxdebug.h:182
CDISP_DEC
@ CDISP_DEC
Definition: wxdebug.h:59
CDisp::~CDisp
~CDisp()
Definition: wxdebug.cpp:1244
CDispBasic::m_String
TCHAR m_String[50]
Definition: wxdebug.h:296
DisplayType
#define DisplayType(label, pmtIn)
Definition: wxdebug.h:218
INVALID_HANDLE_VALUE
#define INVALID_HANDLE_VALUE
Definition: ajatypes.h:352
DbgOutString
#define DbgOutString(psz)
Definition: wxdebug.h:184
ASSERT
#define ASSERT(_x_)
Definition: wxdebug.h:205
hr
__out HRESULT & hr
Definition: pstream.cpp:145