enumerate forms in BeforeNavigate2 event - c++

I'm writing an IE BHO, I'd like to know how to enumerate forms in event callback.
here's the code that enumerates forms in BeforeNavigate2 event, but the length is always 0.
STDMETHODIMP CEventSink::Invoke(DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS *pDispParams,VARIANT *pVarResult,EXCEPINFO *pExcepInfo,UINT *puArgErr)
{
HRESULT hr;
char bf[1024];
if(!IsEqualIID(riid, IID_NULL))
return DISP_E_UNKNOWNINTERFACE;
if(dispIdMember == DISPID_BEFORENAVIGATE2) {
IWebBrowser2* pSite = (IWebBrowser2*)pDispParams->rgvarg[6].pdispVal;
IDispatch* pHtmlDocDispatch;
hr = pSite->get_Document(&pHtmlDocDispatch);
if (FAILED(hr) || !pHtmlDocDispatch)
return S_OK;
IHTMLDocument2* pHtmlDoc = 0;
hr = pHtmlDocDispatch->QueryInterface(IID_IHTMLDocument2, (void**)&pHtmlDoc);
if(SUCCEEDED(hr) && pHtmlDoc) {
CComPtr<IHTMLElementCollection> pColl=NULL;
hr = pHtmlDoc->get_forms(&pColl);
if (SUCCEEDED (hr) && (pColl != NULL))
{
long nLength = 0;
hr = pColl->get_length (&nLength);
if(SUCCEEDED(hr)) {
sprintf(bf, "len = %d", nLength);
OutputDebugString(bf); // always 0
}
}
}
}
return S_OK;
}
Why it always output 0?
Thanks.

I just copy/pasted your code in my BHO and got a non-zero length collection.
Try that URL: http://linuxfr.org/ Use random user/password values and try to connect. That will trigger a DISPID_BEFORENAVIGATE2 and you will get 3 forms.
So, it seems there is no form in the page your are navigating away.
Also, your code leaks memory and is not quite correct in using COM interfaces (ag: you should QueryInterface for obtaining an IWebBrowser2 from a IDispatch.
Rewritten:
CComPtr<IDispatch> spIDispatch( pDispParams->rgvarg[6].pdispVal );
CComPtr<IWebBrowser2> spIWebBrowser2;
HRESULT hr = spIDispatch.QueryInterface<IWebBrowser2>( &spIWebBrowser2 );
if ( SUCCEEDED( hr ) && spIWebBrowser2 ) {
CComPtr<IDispatch> spIDispatchDoc;
hr = spIWebBrowser2->get_Document( &spIDispatchDoc );
if ( SUCCEEDED( hr ) && spIDispatchDoc ) {
CComPtr<IHTMLDocument2> spIHTMLDocument2;
hr = spIDispatchDoc.QueryInterface<IHTMLDocument2>( &spIHTMLDocument2 );
if ( SUCCEEDED( hr ) && spIHTMLDocument2 ) {
CComPtr<IHTMLElementCollection> spIHTMLElementCollection;
hr = spIHTMLDocument2->get_forms( &spIHTMLElementCollection );
if ( SUCCEEDED( hr ) && spIHTMLElementCollection ) {
[...]
}
}
}
}

Related

Getting output of Async SAPI call?

I have a working example using the Windows text-to-speech API, but the problem is it freezes when given a large amount of text.
To solve this I want to make the process asynchronous. I've found the SpeechVoiceSpeakFlags::SVSFlagsAsync flag, but how do I get the results of a previously-submitted request?
Here is my code:
char* TextToWavInner( const wchar_t* voiceRequiredAttributes, const wchar_t* voiceOptionalAttributes, long rate, const wchar_t* textToRender, ULONG* pBytesRead )
{
HRESULT hr;
CComPtr<ISpVoice> cpVoice; //Will send data to ISpStream
CComPtr<ISpStream> cpStream; //Will contain IStream
CComPtr<IStream> cpBaseStream; //raw data
ISpObjectToken* cpToken( NULL ); //Will set voice characteristics
GUID guidFormat;
WAVEFORMATEX* pWavFormatEx = nullptr;
hr = cpVoice.CoCreateInstance( CLSID_SpVoice );
if ( FAILED( hr ) )
return NULL;
hr = SpFindBestToken( SPCAT_VOICES, voiceRequiredAttributes, voiceOptionalAttributes, &cpToken );
if ( FAILED( hr ) )
return NULL;
hr = cpVoice->SetVoice( cpToken );
cpToken->Release();
if ( FAILED( hr ) )
return NULL;
cpVoice->SetRate( rate );
hr = cpStream.CoCreateInstance( CLSID_SpStream );
if ( FAILED( hr ) )
return NULL;
hr = CreateStreamOnHGlobal( NULL, true, &cpBaseStream );
if ( FAILED( hr ) )
return NULL;
hr = SpConvertStreamFormatEnum( SPSF_44kHz16BitMono, &guidFormat, &pWavFormatEx );
if ( FAILED( hr ) )
return NULL;
hr = cpStream->SetBaseStream( cpBaseStream, guidFormat, pWavFormatEx );
if ( FAILED( hr ) )
return NULL;
hr = cpVoice->SetOutput( cpStream, false );
if ( FAILED( hr ) )
return NULL;
SpeechVoiceSpeakFlags voiceFlags = ( SpeechVoiceSpeakFlags ) ( SpeechVoiceSpeakFlags::SVSFlagsAsync | SpeechVoiceSpeakFlags::SVSFPurgeBeforeSpeak );
hr = cpVoice->Speak( textToRender, voiceFlags, NULL );
if ( FAILED( hr ) )
return NULL;
LARGE_INTEGER a = { 0 };
hr = cpStream->Seek( a, STREAM_SEEK_SET, NULL );
if ( FAILED( hr ) )
return NULL;
STATSTG stats;
cpStream->Stat( &stats, STATFLAG_NONAME );
ULONG sSize = stats.cbSize.LowPart;
char* pBuffer = new char[ sSize ];
cpStream->Read( pBuffer, sSize, pBytesRead );
return pBuffer;
}

Firewall exception code just works for outgoing connections

I took this code from the web to add a firewall exception for my application:
STDAPI AddApplicationToExceptionListW( const WCHAR* strGameExeFullPath, const WCHAR* strFriendlyAppName )
{
HRESULT hr = E_FAIL;
bool bCleanupCOM = false;
BSTR bstrFriendlyAppName = NULL;
BSTR bstrGameExeFullPath = NULL;
INetFwAuthorizedApplication* pFwApp = NULL;
INetFwAuthorizedApplications* pFwApps = NULL;
INetFwProfile* pFwProfile = NULL;
#ifdef SHOW_DEBUG_MSGBOXES
WCHAR sz[1024];
StringCchPrintf( sz, 1024, L"strFriendlyAppName='%s' strGameExeFullPath='%s'", strFriendlyAppName, strGameExeFullPath );
MessageBox( NULL, sz, L"AddApplicationToExceptionListW", MB_OK );
#endif
if( strGameExeFullPath == NULL || strFriendlyAppName == NULL )
{
assert( false );
return E_INVALIDARG;
}
bstrGameExeFullPath = SysAllocString( strGameExeFullPath );
bstrFriendlyAppName = SysAllocString( strFriendlyAppName );
if( bstrGameExeFullPath == NULL || bstrFriendlyAppName == NULL )
{
hr = E_OUTOFMEMORY;
goto LCleanup;
}
hr = CoInitialize( 0 );
bCleanupCOM = SUCCEEDED( hr );
pFwProfile = GetFirewallProfile();
if( pFwProfile == NULL )
{
hr = E_FAIL;
goto LCleanup;
}
hr = pFwProfile->get_AuthorizedApplications( &pFwApps );
if( FAILED( hr ) )
goto LCleanup;
// Create an instance of an authorized application.
hr = CoCreateInstance( __uuidof( NetFwAuthorizedApplication ), NULL,
CLSCTX_INPROC_SERVER, __uuidof( INetFwAuthorizedApplication ), ( void** )&pFwApp );
if( FAILED( hr ) )
goto LCleanup;
// Set the process image file name.
hr = pFwApp->put_ProcessImageFileName( bstrGameExeFullPath );
if( FAILED( hr ) )
goto LCleanup;
// Set the application friendly name.
hr = pFwApp->put_Name( bstrFriendlyAppName );
if( FAILED( hr ) )
goto LCleanup;
// Add the application to the collection.
hr = pFwApps->Add( pFwApp );
LCleanup:
if( bstrFriendlyAppName ) SysFreeString( bstrFriendlyAppName );
if( bstrGameExeFullPath ) SysFreeString( bstrGameExeFullPath );
if( pFwApp ) pFwApp->Release();
if( pFwApps ) pFwApps->Release();
if( pFwProfile ) pFwProfile->Release();
if( bCleanupCOM ) CoUninitialize();
return hr;
}
Everything works great when I try to send data through the Windows firewall, but incoming connections are still blocked. So I have to disable my firewall to recieve data. I thought, that exception would allow all connections (outgoing and incoming)...
Does somebody know what I should add to this code so I can recieve incoming data?
It is not enough to just add the application by itself. The firewall has no way of discovering which port(s) the application is listening on for inbound connections. You have to tell the firewall which port(s) the application is using. You do that via the INetFwProfile::GloballyOpenPorts collection, eg:
INetFwOpenPorts *pFwPorts = NULL;
INetFwOpenPort *pFWPort = NULL;
...
hr = pFwProfile->get_GloballyOpenPorts( &pFwPorts );
if( FAILED( hr ) )
goto LCleanup;
// Create an instance of an open port.
hr = CoCreateInstance( __uuidof( NetFwOpenPort ), NULL, CLSCTX_INPROC_SERVER, __uuidof( INetFwOpenPort ), ( void** )&pFwPort );
if( FAILED( hr ) )
goto LCleanup;
// Set the port number.
hr = pFWPort->put_Port( ... );
if( FAILED( hr ) )
goto LCleanup;
// Add the port to the collection.
hr = pFwPorts->Add( pFwPort );
...
if( pFwPort ) pFwPort->Release();
if( pFwPorts ) pFwPorts->Release();
In my case the solution was deleting the firewall rules that blocked my application. I don't know where these rules came from, but now it finally works.

Obtaining the Excel.Application IDispatch* within a dll that's been loaded into Excel

Does anyone know how to get hold of the Excel.Application IDispatch* pointer associated with an excel process into which an dll has been loaded?
A key thing here is that the process is excel.exe, and the pointer I need must belong to that process. Using the Running Object Table will not fly since Excel only registers its first instance with that.
I'm hoping there is some low-level COM trickery, but I'm not an expert in that field.
EDITED II Code is under the WTFPL license version 2.
EDITED: Add PID parameter to allow filtering when several Excel processes are currently running, as per comment suggestion from #EricBrown.
I managed to get a working IDispatch* to an Excel "Application" object without using the ROT. The trick is to use MSAA. My code works as a stand alone console application, but I think that if the code is executed in an Excel process, via DLL Injection, it MAY works fine. You may have to be in a dedicated thread. Let me know if you want me to push the expriment to the DLL injection level.
Tested OK on Window7 64b, with a UNICODE builds (32 bits and 64 bits).
Excel version 2010 64 bits (version "14")
I get the IDispatch via the "application" property from an "Worksheet" object. Consequence: there must be an opened worksheet. In order to find the good MSSA Window, I need the class name of the Top Level Excel Frame Window. In Excel 2010, it's "XLMAIN". The class name for worksheets is "EXCEL7" and that seems to be a "standard".
I was not able to directly get a working IDispatch* from the main Excel Window, but have not tried very hard. That may involve #import with a automation DLL from Excel, in order to QueryInterface the IDispatch that MSAA gives for the main Window (that IDispatch is NOT for an Application object)
#include <atlbase.h>
#pragma comment( lib, "Oleacc.lib" )
HRESULT GetExcelAppDispatch( CComPtr<IDispatch> & spIDispatchExcelApp, DWORD dwExcelPID ) {
struct ew {
struct ep {
_TCHAR* pszClassName;
DWORD dwPID;
HWND hWnd;
};
static BOOL CALLBACK ewp( HWND hWnd, LPARAM lParam ) {
TCHAR szClassName[ 64 ];
if ( GetClassName( hWnd, szClassName, 64 ) ) {
ep* pep = reinterpret_cast<ep*>( lParam );
if ( _tcscmp( szClassName, pep->pszClassName ) == 0 ) {
if ( pep->dwPID == 0 ) {
pep->hWnd = hWnd;
return FALSE;
} else {
DWORD dwPID;
if ( GetWindowThreadProcessId( hWnd, &dwPID ) ) {
if ( dwPID == pep->dwPID ) {
pep->hWnd = hWnd;
return FALSE;
}
}
}
}
}
return TRUE;
}
};
ew::ep ep;
ep.pszClassName = _TEXT( "XLMAIN" );
ep.dwPID = dwExcelPID;
ep.hWnd = NULL;
EnumWindows( ew::ewp, reinterpret_cast<LPARAM>( &ep ) );
HWND hWndExcel = ep.hWnd;
if ( ep.hWnd == NULL ) {
printf( "Can't Find Main Excel Window with EnumWindows\n" );
return -1;
}
ep.pszClassName = _TEXT( "EXCEL7" );
ep.dwPID = 0;
ep.hWnd = NULL;
EnumChildWindows( hWndExcel, ew::ewp, reinterpret_cast<LPARAM>( &ep ) );
HWND hWndWorkSheet = ep.hWnd;
if ( hWndWorkSheet == NULL ) {
printf( "Can't Find a WorkSheet with EnumChildWindows\n" );
return -1;
}
CComPtr<IDispatch> spIDispatchWorkSheet;
HRESULT hr = AccessibleObjectFromWindow( hWndWorkSheet, OBJID_NATIVEOM, IID_IDispatch,
reinterpret_cast<void**>( &spIDispatchWorkSheet ) );
if ( FAILED( hr ) || ( spIDispatchWorkSheet == 0 ) ) {
printf( "AccessibleObjectFromWindow Failed\n" );
return hr;
}
CComVariant vExcelApp;
hr = spIDispatchWorkSheet.GetPropertyByName( CComBSTR( "Application" ), &vExcelApp );
if ( SUCCEEDED( hr ) && ( vExcelApp.vt == VT_DISPATCH ) ) {
spIDispatchExcelApp = vExcelApp.pdispVal;
return S_OK;
}
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwExcelPID = 0;
if ( argc > 1 ) dwExcelPID = _ttol( argv[ 1 ] );
HRESULT hr = CoInitialize( NULL );
bool bCoUnInitializeTodo = false;
if ( SUCCEEDED( hr ) ) {
bCoUnInitializeTodo = true;
CComPtr<IDispatch> spDispatchExcelApp;
hr = GetExcelAppDispatch( spDispatchExcelApp, dwExcelPID );
if ( SUCCEEDED( hr ) && spDispatchExcelApp ) {
CComVariant vExcelVer;
hr = spDispatchExcelApp.GetPropertyByName( CComBSTR( "Version" ), &vExcelVer );
if ( SUCCEEDED( hr ) && ( vExcelVer.vt == VT_BSTR ) ) {
wprintf( L"Excel Version is %s\n", vExcelVer.bstrVal );
}
}
}
if ( bCoUnInitializeTodo ) CoUninitialize();
return 0;
}
You should be able to find out how to do this by reviewing the code in ExcelDNA. This project contains code that hooks back into Excel from the extension library. The code is likely to be more elaborate that you need, but will implement the reference you require.
This is how I do it: (acknowledge #manuell). dispatch_wrapper is a class, here is the constructor to set m_disp_application:
dispatch_wrapper(void)
{
DWORD target_process_id = ::GetProcessId(::GetCurrentProcess());
if (getProcessName() == "excel.exe"){
HWND hwnd = ::FindWindowEx(0, 0, "XLMAIN", NULL);
while (hwnd){
DWORD process_id;
::GetWindowThreadProcessId(hwnd, &process_id);
if (process_id == target_process_id){
HWND hwnd_desk = ::FindWindowEx(hwnd, 0, "XLDESK", NULL);
HWND hwnd_7 = ::FindWindowEx(hwnd_desk, 0, "EXCEL7", NULL);
IDispatch* p = nullptr;
if (SUCCEEDED(::AccessibleObjectFromWindow(hwnd_7, OBJID_NATIVEOM, IID_IDispatch, (void**)&p))){
LPOLESTR name[1] = {L"Application"};
DISPID dispid;
if (SUCCEEDED(p->GetIDsOfNames(IID_NULL, name, 1U, LOCALE_SYSTEM_DEFAULT, &dispid))){
CComVariant v;
DISPPARAMS dp;
::memset(&dp, NULL, sizeof(DISPPARAMS));
EXCEPINFO ei;
::memset(&ei, NULL, sizeof(EXCEPINFO));
if (SUCCEEDED(p->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &dp, &v, &ei, NULL))){
if (v.vt == VT_DISPATCH){
m_disp_application = v.pdispVal;
m_disp_application->AddRef();
return;
}
}
}
}
}
hwnd = ::FindWindowEx(0, hwnd, "XLMAIN", NULL);
}
}
m_disp_application = nullptr;
}
getProcessName() returns lower case.
Because Office applications register their documents in the ROT, you can attach to instances beside the first one (which is already in the ROT) by getting IDispatch for documents in the ROT, then you can use document.Application.hwnd (this is VBA, you need to translate to IDispatch::GetIDsOfNames and IDispatch::Invoke with DISPATCH_PROPERTYGET) to get the window handles of all Excel instances.
Now you have a mapping between IDispatch and Windows handles of all Excel instances, it is time to find your own Excel instance. You can call GetWindowThreadProcessId on the window handles to get the process ids, then compare to your own process id returned by GetCurrentProcessId to see which excel window belongs to your current process, and look up in the HWND to IDispatch mapping to find your current Excel application's IDispatch interface.

Accessing HTML source on event DownloadComplete?

I am working on a ads/popup blocker BHO and I am trying to access the html of a website from the event "downloadcomplete", so I can filter all the ads and malicious uris.
My code looks something like this:
case DISPID_DOWNLOADCOMPLETE:
{
if(iBrowser) //IWebBrowser2*
{
HRESULT hr;
IUnknown *pUnkBrowser = NULL;
hr = iBrowser->QueryInterface(IID_IUnknown, (void**)&pUnkBrowser);
if( SUCCEEDED(hr) && pUnkBrowser!=NULL)
{
if( SUCCEEDED(hr) )
{
IDispatch* pHtmlDocDispatch = NULL;
IHTMLDocument2 * pHtmlDoc = NULL;
hr = iBrowser->get_Document (&pHtmlDocDispatch);
if (SUCCEEDED (hr) && (pHtmlDocDispatch != NULL))
{
hr = pHtmlDocDispatch->QueryInterface (IID_IHTMLDocument2, (void**)&pHtmlDoc);
if (SUCCEEDED (hr) && (pHtmlDoc != NULL))
{
IHTMLElement *pBody = 0;
pHtmlDoc->get_body( &pBody );
// I want to get the html here and filter out the ads but pBody is always null
if(pHtmlDoc) pHtmlDoc->Release();
}
if(pHtmlDocDispatch) pHtmlDocDispatch->Release();
}
}
if(pUnkBrowser) pUnkBrowser->Release();
}
}
return S_OK;
}
break;
How could I access and modify the html from this event?
Wrong event, you can "play" with the dom on the DocumentComplete, not the DownloadComplete.
Also I would advise you to use CComPtr, that way you don't need to call the release() on every interface.

multiple web cams in AMCap

I built the AMCap sample under direct show in SDK. It is able to handle 2 or more web cam, how do I modify the program for me to use them simultaneously… like press one button that says ‘start capture’ and make sure that all the cameras start capturing and one button that says ‘stop capture’ to stop all the cameras. i want the frames from different cameras to be save in different files. I am new to C++ and any kind of help is appreciated ! Thanks for your time!
Use GraphEdit tool. There you can build you own graph with all video input devices connected. Please see http://en.wikipedia.org/wiki/GraphEdit
If you're just starting out with DirectShow programming, this might be a bit of a hill climb, but I hope it's of some help, or points you in the right direction.
M$DN has a page describing how to select a capture device. It's a little thin on examples, so I've provided a simple implementation below.
The theory is that you need to enumerate all devices in the CLSID_VideoInputDeviceCategory, and attempt to create a render graph for each valid item in the category.
First I'll show you the code to iterate the names of the devices in the category. Below are 3 static functions you can use to iterate the devices in a category. Once you've added these functions to your project, you can list the devices in the Video Input Device category by calling the following function:
ListDevicesInCategory(CLSID_VideoInputDeviceCategory);
Okay, here are the three functions. ListDevicesInCategory() is where the work happens. It depends on other two functions, FindDeviceInCategory() and CountDevicesInCategory()
#define RFAIL(x) { HRESULT hr = x; if(FAILED(hr)) {return hr;} }
static HRESULT FindDeviceInCategory(IBaseFilter** pSrc, const IID& cls, wstring& wFilterName,int devNum)
{
CComPtr<ICreateDevEnum> spDevEnum;
CComPtr<IEnumMoniker> spEnum;
int i;
RFAIL( spDevEnum.CoCreateInstance(CLSID_SystemDeviceEnum) );
RFAIL( spDevEnum->CreateClassEnumerator(cls, &spEnum, 0) );
if(spEnum == 0)
return E_FAIL;
for(i = 0; i >= 0; i++)
{
CComPtr<IMoniker> spiMoniker;
if( spEnum->Next(1, &spiMoniker, 0) != S_OK )
return E_FAIL;
if( devNum == i)
{
CComVariant varName;
CComPtr<IPropertyBag> spiPropBag;
RFAIL(spiMoniker->BindToStorage(0, 0, IID_IPropertyBag,reinterpret_cast<void**>(&spiPropBag)));
RFAIL(spiPropBag->Read(L"FriendlyName", &varName, 0));
RFAIL(spiMoniker->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(pSrc)));
wFilterName = V_BSTR(&varName);
varName.Clear();
return S_OK;
}
}
return E_FAIL;
}
static HRESULT CountDevicesInCategory( int *pCount, const IID& categoryClass )
{
// pass in a category class like CLSID_VideoInputDeviceCategory, writes the count of the number of filters in that category
// available on the local machine
HRESULT hr = S_OK;
CComPtr<ICreateDevEnum> spIDevEnum;
CComPtr<IEnumMoniker> spIEnum;
CComPtr<IMoniker> spIMoniker;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, reinterpret_cast<void**>(&spIDevEnum));
if( ! SUCCEEDED(hr) || hr == S_FALSE )
{
*pCount = 0;
return hr;
}
hr = spIDevEnum->CreateClassEnumerator( categoryClass, &spIEnum, 0 );
if( ! SUCCEEDED(hr) || hr == S_FALSE )
{
*pCount = 0;
return hr;
}
if( spIEnum )
{
while( spIEnum->Next(1, &spIMoniker, 0) == S_OK )
{
(*pCount) ++;
spIMoniker.Detach();
}
}
return S_OK;
}
static HRESULT ListDevicesInCategory( const GUID & cls )
{
CComPtr<IBaseFilter> spSource;
wstring * psNextFilter = NULL;
int nDeviceNum = 0;
int nTotalNumDevices = 0;
HRESULT hr = S_OK;
bool bComplete = false;
DeviceNames CaptureDeviceNames;
if( FAILED(CountDevicesInCategory( &nTotalNumDevices, (IID)cls )) )
bComplete = TRUE;
if( nTotalNumDevices == 0 )
bComplete = TRUE;
while( ! bComplete )
{
psNextFilter = new std::wstring;
hr = FindDeviceInCategory( &spSource, (IID)cls, *psNextFilter, nDeviceNum++ );
if( SUCCEEDED(hr) && spSource )
{
if ( *psNextFilter )
{
wcout << *psNextFilter << endl;
delete *psNextFilter;
psNextFilter = NULL;
}
spSource.Release();
spSource = NULL;
}
else
bComplete = TRUE;
}
return S_OK;
}
Once you've identified an item in a category that you're interested in, you can add it to a graph with the IGraphBuilder::AddFilter call.
To add a filter to your graph, you'll first need to get an IBaseFilter* to that filter. I've got one more function for you to do this with.
Define an IBaseFilter smart pointer:
CComPtr<IBaseFilter> spSource;
Attach to the filter:
m_spSource.Attach(
GetFilter(CLSID_VideoInputDeviceCategory, CComBSTR(L"Osprey-450e Video Device 1A"))
);
Here's that last function - GetFilter:
static IBaseFilter * GetFilter( REFCLSID clsidDeviceClass, CComBSTR & sName )
{
HRESULT hr;
IBaseFilter * pRetFilter = NULL;
ICreateDevEnum * pSysDevEnum = NULL;
IEnumMoniker * pEnum = NULL;
IMoniker * pMoniker = NULL;
int nSameSrcCounter = 0;
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pSysDevEnum);
if( pSysDevEnum )
hr = pSysDevEnum->CreateClassEnumerator(clsidDeviceClass, &pEnum, 0);
if (hr != S_OK)
return NULL;
USES_CONVERSION;
while ( pEnum->Next(1, &pMoniker, NULL) == S_OK )
{
IPropertyBag *pPropBag = NULL;
VARIANT var;
VariantInit(&var);
pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
hr = pPropBag->Read(L"FriendlyName", &var, 0);
if (SUCCEEDED(hr))
{
if(sName == OLE2T(var.bstrVal))
{
hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&pRetFilter);
if (FAILED(hr))
pRetFilter = NULL;
VariantClear(&var);
pPropBag->Release();
pMoniker->Release();
break;
}
}
VariantClear(&var);
pPropBag->Release();
pMoniker->Release();
}
pSysDevEnum->Release();
pEnum->Release();
return pRetFilter;
}