程序设计的过程经常会遇到很多预想不到的情况。当情况发生的时候我们经常不知所措,调试的时候如果方法不对,经常会陷入绝望的地步,因为此时发生了错误,但是就是找不到该错误究竟在什么地方。在使用DShow的过程中,经常会遇到这种情况,我们单步跟踪,不知不觉我们就来到了汇编里面,此时只能茫然。下面我来说说我在使用dshow的过程常使用的方法。
使用GraphEdit
GraphEdit是DXSDK里面自带的一个创建和调试Filter Graph工具(DXSDK ROOT/DXSDK/Bin/DXUtils/graphedt.exe)。对于其说明可以参见其帮助文档。
所见即所得
在使用Filter的时候,当我们不知道该Filter是否能和另外一个Filter的Pin建立连接得时候,我们可以在GraphEdit里面进行,动动鼠标,结果便会呈现在你的眼前。
程序运行时候Graph的显示
运用SDK里面的函数AddToRot和RemoveFromRot,可以在程序运行的时候把Graph的信息显示出来。
#001 //Parameters:
#002 //IUnknown – pointer to the graph to be outputted
#003 //DWORD - The pecess identifier.
#004 HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
#005 {
#006 IMoniker * pMoniker;
#007 IRunningObjectTable *pROT;
#008 if (FAILED(GetRunningObjectTable(0, &pROT)))
#009 {
#010 return E_FAIL;
#011 }
#012 WCHAR wsz[256];
#013 wsprintfW(wsz, L"FilterGraph %08x pid %08x", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());
#014
#015 HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);
#016
#017 if (SUCCEEDED(hr))
#018 {
#019 hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE,
#020 pUnkGraph,
#021 pMoniker, pdwRegister);
#022 pMoniker->Release();
#023 }
#024 pROT->Release();
#025 return hr;
#026 }
#001 void RemoveFromRot(DWORD pdwRegister)
#002 {
#003 IRunningObjectTable *pROT;
#004 if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {
#005 pROT->Revoke(pdwRegister);
#006 pROT->Release();
#007 }
#008 }
示例代码:
#001 //suppose that the IGraphBuilder interface has been initialized
#002 IGaphBuilder *pGraph = NULL;
#003 //……Initialize here
#004 DWORD dwGraphRegister;
#005 HRESULT hr = AddToRot(pGraph, &dwGraphRegister);
#006 If(FAILED(hr))
#007 {
#008 //exceptions here
#009 }
#010 //……programming running
#011 //Before program shutdown or the IGraphBuilder release
#012 RemoveFromRot(dwGraphRegister);
#013 //……program clean up
保存Graph供察看和调试
首先可以调用SDK里面的函数用来保存Graph
#001 //Parameters:
#002 //IGraphBuiler – pointer to the graph to be saved
#003 //WCHAR – the file where to be saved.
#004 HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath)
#005 {
#006 const WCHAR wszStreamName[] = L"ActiveMovieGraph";
#007 HRESULT hr;
#008
#009 IStorage *pStorage = NULL;
#010 hr = StgCreateDocfile(
#011 wszPath,
#012 STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
#013 0, &pStorage);
#014 if(FAILED(hr))
#015 {
#016 return hr;
#017 }
#018
#019 IStream *pStream;
#020 hr = pStorage->CreateStream(
#021 wszStreamName,
#022 STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
#023 0, 0, &pStream);
#024 if (FAILED(hr))
#025 {
#026 pStorage->Release();
#027 return hr;
#028 }
#029
#030 IPersistStream *pPersist = NULL;
#031 pGraph->QueryInterface(IID_IPersistStream, (void**)&pPersist);
#032 hr = pPersist->Save(pStream, TRUE);
#033 pStream->Release();
#034 pPersist->Release();
#035 if (SUCCEEDED(hr))
#036 {
#037 hr = pStorage->Commit(STGC_DEFAULT);
#038 }
#039 pStorage->Release();
#040 return hr;
#041 }
使用方法我就不用多说了J.保存的Graph File可以被方法“所见即所得”使用J.
宏JIF的妙用
首先宏JIF的定义如下:
#001 void Msg(TCHAR *szFormat, ...)
#002 {
#003 TCHAR szBuffer[1024]; // Large buffer for long filenames or URLs
#004 const size_t NUMCHARS=sizeof(szBuffer)/sizeof(szBuffer[0]);
#005 const int LASTCHAR = NUMCHARS - 1;
#006
#007 // Format the input string
#008 va_list pArgs;
#009 va_start(pArgs, szFormat);
#010
#011 // Use a bounded buffer size to prevent buffer overruns. Limit // count to
#012 // character size minus one to allow for a NULL terminating //character.
#013 _vsntprintf(szBuffer, NUMCHARS - 1, szFormat, pArgs);
#014 va_end(pArgs);
#015
#016 // Ensure that the formatted string is NULL-terminated
#017 szBuffer[LASTCHAR] = TEXT('/0');
#018
#019 // Display a message box with the formatted string
#020 ::MessageBox(NULL, szBuffer, TEXT("Warning"), MB_OK);
#021 }
#001 #define JIF(x) if (FAILED(hr=(x))) /
#002 {Msg(TEXT("FAILED(hr=0x%x) in ") TEXT(#x) TEXT("/n/0"), hr);/
#003 return hr;}
当我们在调用COM的一个接口初始化一个变量或者对一个接口进行操作的时候,如果发生错误,JIF宏会给出提示错误的返回值和所执行操作的名字。
现在有一个问题,如果我们在程序中多次执行同样的操作,而这个操作抛出了一个异常,那这个异常究竟是哪一次操作所抛出的呢L?我们可以修改该宏:
#001 #define JIF(x) if (FAILED(hr=(x))) /
#002 {Msg(TEXT("FAILED(hr=0x%x) in ") /
#003 TEXT(#x) TEXT("/tFILE: %s/tLINE: %d"), /
#004 hr, __FILE__, __LINE__);}