What we are trying to do here is get the TIF filter to tell us when it has new information regarding the TS that we are locked on to. Then we try tuning to EVERY possible channel and capture the information the TIF filter collects.
We do this in two parts. We firstly "connect" the TIF filter to ourselves so it will notify us when changes to the TS occur, then we kick off a channel scan.
To connect the TIF filter to ourselves:
First implement the IGuideDataEvent interface on your class.
http://msdn.microsoft.com/library/en-us/di...ntinterface.asp
After we have connected to the TIF filter, it will call us on this interface to notify us of changes to program and service information. The TIF filter will want to run QueryInterface on us to see that we support the IGuideDataEvent interface so don't forget to implement the IUnknown interface as well.
Then find the TIF filter in your graph. The way you do this depends on how you've built the graph in the first place. If you have manually built the graph then you'll already have a reference to it.
Once you have the TIF filter, get a reference to its IConnectionPointContainer interface.
http://msdn.microsoft.com/library/en-us/co.../cmi_c_2ar8.asp
CODE
private:
DWORD m_dwAdviseCookie; //The cookie given to us by Advise
IConnectionPoint *m_pConnection; //The interface where we called Advise/Unadvise.
...
Then after the TIF has been created.
...
HRESULT hr = E_UNEXPECTED;
IConnectionPointContainer *pContaner = NULL;
IConnectionPoint *pConnection = NULL;
// First we need to get the IConnectionPointContainer
// interface from the TIF
hr = pTIF->QueryInterface(__uuidof(IConnectionPointContainer),(void **)&pContainer);
if (SUCCEEDED(hr)) {
// Now, see if the event source will fire off events of the IGuideDataEvent kind.
hr = pContainer->FindConnectionPoint(__uuidof(IGuideDataEvent), &m_pConnection);
if (SUCCEEDED(hr)) {
IUnknown *me = 0;
// We know this will work...
this->QueryInterface(__uuidof(IUnknown),(void **)&me);
// Now that we know that the source fires our kind of events, we can attach to it.
hr = m_pConnection->Advise(me, &m_dwAdviseCookie);
}
// We are done with this interface now so we free it up.
pContainer->Release();
}
...
// In our cleanup code when the application is destroying filters,
// before destroying the TIF filter disconnect the connection point.
m_pConnection->Unadvise(m_dwAdviseCookie);
// And release the connection
m_pConnection->Release();
DWORD m_dwAdviseCookie; //The cookie given to us by Advise
IConnectionPoint *m_pConnection; //The interface where we called Advise/Unadvise.
...
Then after the TIF has been created.
...
HRESULT hr = E_UNEXPECTED;
IConnectionPointContainer *pContaner = NULL;
IConnectionPoint *pConnection = NULL;
// First we need to get the IConnectionPointContainer
// interface from the TIF
hr = pTIF->QueryInterface(__uuidof(IConnectionPointContainer),(void **)&pContainer);
if (SUCCEEDED(hr)) {
// Now, see if the event source will fire off events of the IGuideDataEvent kind.
hr = pContainer->FindConnectionPoint(__uuidof(IGuideDataEvent), &m_pConnection);
if (SUCCEEDED(hr)) {
IUnknown *me = 0;
// We know this will work...
this->QueryInterface(__uuidof(IUnknown),(void **)&me);
// Now that we know that the source fires our kind of events, we can attach to it.
hr = m_pConnection->Advise(me, &m_dwAdviseCookie);
}
// We are done with this interface now so we free it up.
pContainer->Release();
}
...
// In our cleanup code when the application is destroying filters,
// before destroying the TIF filter disconnect the connection point.
m_pConnection->Unadvise(m_dwAdviseCookie);
// And release the connection
m_pConnection->Release();
That's enough to register with the TIF filter to send us events.
Now when tuning we expect our IGuideDataEvent::ServiceChanged() method to be called when the TIF gets new channel information.
The documentation specifies that we MUST NOT block in any method in the IGuideDataEvent interface. What this means is that we must somehow inform our application that there are changes waiting to be read and return immediately.
As to how this is accomplished depends on the application you are writing. If you are writing this for a GUI then you could use GUI events. If for a command line app, use threads and blocking.
For example, you could have an application thread block on an event and then have ServiceChanged() set some internal variables and then call SetEvent() to get the thread running again.
CODE
private:
HANDLE m_hGuideDataChangedEvent;
HRESULT CMyClass::ServiceChanged(VARIANT varServiceDescriptionID) {
HRESULT Result = S_OK;
m_bServiceChanged = TRUE;
SetEvent(m_hGuideDataChangedEvent);
return Result;
}
CMyClass::GuideCheckingThread(...) {
m_hGuideDataChangedEvent = CreateEvent(
NULL,
TRUE,
FALSE,
"GuideDataChangedEvent"
);
if (m_hGuideDataChangedEvent != NULL) {
while (1) {
ResetEvent(m_hGuideDataChangedEvent);
WaitForSingleObject(m_hGuideDataChangedEvent, INFINITE);
if (m_bServiceChanged == TRUE) {
// Get updated service parameters
...
// Reset m_bServiceChanged
m_bServiceChanged = FALSE;
}
if (m_bProgramChanged == TRUE) {
...
}
if ...
}
}
}
In the following block use the TIF filter's IGuideData interface to get services.
if (m_bServiceChanged == TRUE) {
// Get updated service parameters
HRESULT hr = E_UNEXPECTED;
IGuideData *pGuideData = NULL;
IEnumTuneRequests *pEnumTuneRequests = NULL;
// First we need to get the IGuideData
// interface from the TIF
hr = pTIF->QueryInterface(__uuidof(IGuideData),(void **)&pGuideData);
if (SUCCEEDED(hr)) {
pGuideData->GetServices(&pEnumTuneRequests);
HANDLE m_hGuideDataChangedEvent;
HRESULT CMyClass::ServiceChanged(VARIANT varServiceDescriptionID) {
HRESULT Result = S_OK;
m_bServiceChanged = TRUE;
SetEvent(m_hGuideDataChangedEvent);
return Result;
}
CMyClass::GuideCheckingThread(...) {
m_hGuideDataChangedEvent = CreateEvent(
NULL,
TRUE,
FALSE,
"GuideDataChangedEvent"
);
if (m_hGuideDataChangedEvent != NULL) {
while (1) {
ResetEvent(m_hGuideDataChangedEvent);
WaitForSingleObject(m_hGuideDataChangedEvent, INFINITE);
if (m_bServiceChanged == TRUE) {
// Get updated service parameters
...
// Reset m_bServiceChanged
m_bServiceChanged = FALSE;
}
if (m_bProgramChanged == TRUE) {
...
}
if ...
}
}
}
In the following block use the TIF filter's IGuideData interface to get services.
if (m_bServiceChanged == TRUE) {
// Get updated service parameters
HRESULT hr = E_UNEXPECTED;
IGuideData *pGuideData = NULL;
IEnumTuneRequests *pEnumTuneRequests = NULL;
// First we need to get the IGuideData
// interface from the TIF
hr = pTIF->QueryInterface(__uuidof(IGuideData),(void **)&pGuideData);
if (SUCCEEDED(hr)) {
pGuideData->GetServices(&pEnumTuneRequests);
And so on to get TuneRequests:
http://msdn.microsoft.com/library/en-us/di...getservices.asp
This SHOULD get you all the information you need to tune programs.
Incidently getting the TIF to call our IGuideData interface is how we get Now/Next information and probably other good stuff.