Is there a way to get the InfoQueue or set the break parameters before the Device is created?
Right now i am creating the Device and then getting the InfoQueue, but any messages that are emitted before that point are going to be ignored and buried in the output window.
ID3D11Device* pDevice;
//...Create Device...
ID3D11InfoQueue* pInfoQueue;
pDevice->QueryInterface(__uuidof(ID3D11InfoQueue), &pInfoQueue);
pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE);
And I want something like:
ID3D11InfoQueue* pInfoQueue;
//...Get InfoQueue...
pInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, TRUE);
ID3D11Device* pDevice;
//...Create Device...
Given the documentation for ID3D11InfoQueue saying that you get the interface pointer via a QueryInterface call on the device I would say the answer is 'no'.
What you want to do is enable DXGI debugging which will provide debug information for the device & swapchain creation.
#include <dxgidebug.h>
#if defined(_DEBUG)
Microsoft::WRL::ComPtr<IDXGIInfoQueue> dxgiInfoQueue;
typedef HRESULT (WINAPI * LPDXGIGETDEBUGINTERFACE)(REFIID, void ** );
HMODULE dxgidebug = LoadLibraryEx( L"dxgidebug.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32 );
if ( dxgidebug )
{
auto dxgiGetDebugInterface = reinterpret_cast<LPDXGIGETDEBUGINTERFACE>(
reinterpret_cast<void*>( GetProcAddress( dxgidebug, "DXGIGetDebugInterface" ) ) );
if ( SUCCEEDED( dxgiGetDebugInterface( IID_PPV_ARGS( dxgiInfoQueue.GetAddressOf() ) ) ) )
{
dxgiInfoQueue->SetBreakOnSeverity( DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, true );
dxgiInfoQueue->SetBreakOnSeverity( DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, true );
}
}
#endif
See this blog post and this one
Related
The answers I've found link to fHideIcon, but I get a 404 error on Microsoft's page for those links.
I've also tried:
SHELLSTATE ss;
SecureZeroMemory(&ss, sizeof(ss));
SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE);
But that didn't work.
Does anyone know how to do this?
The following approach which uses the official shell API is a little bit involved, but works even under Windows 10.
Steps:
Get the IFolderView2 interface of the desktop (supported since Windows Vista).
Call IFolderView2::SetCurrentFolderFlags() with FWF_NOICONS for both the dwMask and dwFlags parameters.
The effect of the flag is visible immediately. There is no need to restart the computer nor "explorer.exe". The flag also persists after logoff or reboot.
The tricky thing is step 1). Raymond Chen shows C++ code for that in his article "Manipulating the positions of desktop icons", specifically in his FindDesktopFolderView() function.
Here is a full example in form of a console application. It is based on Raymond Chen's code. The program toggles the visibility of the desktop icons each time it is run.
The code has been tested under Windows 10 Version 1803.
"Library" code:
#include <ShlObj.h> // Shell API
#include <atlcomcli.h> // CComPtr & Co.
#include <string>
#include <iostream>
#include <system_error>
// Throw a std::system_error if the HRESULT indicates failure.
template< typename T >
void ThrowIfFailed( HRESULT hr, T&& msg )
{
if( FAILED( hr ) )
throw std::system_error{ hr, std::system_category(), std::forward<T>( msg ) };
}
// RAII wrapper to initialize/uninitialize COM
struct CComInit
{
CComInit() { ThrowIfFailed( ::CoInitialize( nullptr ), "CoInitialize failed" ); }
~CComInit() { ::CoUninitialize(); }
CComInit( CComInit const& ) = delete;
CComInit& operator=( CComInit const& ) = delete;
};
// Query an interface from the desktop shell view.
void FindDesktopFolderView( REFIID riid, void **ppv, std::string const& interfaceName )
{
CComPtr<IShellWindows> spShellWindows;
ThrowIfFailed(
spShellWindows.CoCreateInstance( CLSID_ShellWindows ),
"Failed to create IShellWindows instance" );
CComVariant vtLoc( CSIDL_DESKTOP );
CComVariant vtEmpty;
long lhwnd;
CComPtr<IDispatch> spdisp;
ThrowIfFailed(
spShellWindows->FindWindowSW(
&vtLoc, &vtEmpty, SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp ),
"Failed to find desktop window" );
CComQIPtr<IServiceProvider> spProv( spdisp );
if( ! spProv )
ThrowIfFailed( E_NOINTERFACE, "Failed to get IServiceProvider interface for desktop" );
CComPtr<IShellBrowser> spBrowser;
ThrowIfFailed(
spProv->QueryService( SID_STopLevelBrowser, IID_PPV_ARGS( &spBrowser ) ),
"Failed to get IShellBrowser for desktop" );
CComPtr<IShellView> spView;
ThrowIfFailed(
spBrowser->QueryActiveShellView( &spView ),
"Failed to query IShellView for desktop" );
ThrowIfFailed(
spView->QueryInterface( riid, ppv ),
"Could not query desktop IShellView for interface " + interfaceName );
}
Example to toggle desktop icons using the above code:
void ToggleDesktopIcons()
{
CComPtr<IFolderView2> spView;
FindDesktopFolderView( IID_PPV_ARGS(&spView), "IFolderView2" );
DWORD flags = 0;
ThrowIfFailed(
spView->GetCurrentFolderFlags( &flags ),
"GetCurrentFolderFlags failed" );
ThrowIfFailed(
spView->SetCurrentFolderFlags( FWF_NOICONS, flags ^ FWF_NOICONS ),
"SetCurrentFolderFlags failed" );
}
int wmain(int argc, wchar_t **argv)
{
try
{
CComInit init;
ToggleDesktopIcons();
std::cout << "Desktop icons have been toggled.\n";
}
catch( std::system_error const& e )
{
std::cout << "ERROR: " << e.what() << ", error code: " << e.code() << "\n";
return 1;
}
return 0;
}
The third parameter isn't about changing the setting, it's to select the SHGetSetSettings() behavior.
FALSE will get the value of the current setting and store it in ss, TRUE will set the value of the setting to what is in ss.
So basically you have to do ss.fHideIcons = TRUE and then call SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE) to set it.
I know, it's weird, but on the other hand it allows you to change multiple settings simultaneously because SSF_* is a bitmask.
The following seems to work (adapted from https://stackoverflow.com/a/6403014/5743288):
#include <windows.h>
int main ()
{
HWND hProgman = FindWindowW (L"Progman", L"Program Manager");
HWND hChild = GetWindow (hProgman, GW_CHILD);
ShowWindow (hChild, SW_HIDE);
Sleep (2000);
ShowWindow (hChild, SW_SHOW);
}
Please note: this approach is not supported by Microsoft and disables right-clicking on ths desktop.
The answers I've found link to fHideIcon, but I get a 404 error on Microsoft's page for those links.
I've also tried:
SHELLSTATE ss;
SecureZeroMemory(&ss, sizeof(ss));
SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE);
But that didn't work.
Does anyone know how to do this?
The following approach which uses the official shell API is a little bit involved, but works even under Windows 10.
Steps:
Get the IFolderView2 interface of the desktop (supported since Windows Vista).
Call IFolderView2::SetCurrentFolderFlags() with FWF_NOICONS for both the dwMask and dwFlags parameters.
The effect of the flag is visible immediately. There is no need to restart the computer nor "explorer.exe". The flag also persists after logoff or reboot.
The tricky thing is step 1). Raymond Chen shows C++ code for that in his article "Manipulating the positions of desktop icons", specifically in his FindDesktopFolderView() function.
Here is a full example in form of a console application. It is based on Raymond Chen's code. The program toggles the visibility of the desktop icons each time it is run.
The code has been tested under Windows 10 Version 1803.
"Library" code:
#include <ShlObj.h> // Shell API
#include <atlcomcli.h> // CComPtr & Co.
#include <string>
#include <iostream>
#include <system_error>
// Throw a std::system_error if the HRESULT indicates failure.
template< typename T >
void ThrowIfFailed( HRESULT hr, T&& msg )
{
if( FAILED( hr ) )
throw std::system_error{ hr, std::system_category(), std::forward<T>( msg ) };
}
// RAII wrapper to initialize/uninitialize COM
struct CComInit
{
CComInit() { ThrowIfFailed( ::CoInitialize( nullptr ), "CoInitialize failed" ); }
~CComInit() { ::CoUninitialize(); }
CComInit( CComInit const& ) = delete;
CComInit& operator=( CComInit const& ) = delete;
};
// Query an interface from the desktop shell view.
void FindDesktopFolderView( REFIID riid, void **ppv, std::string const& interfaceName )
{
CComPtr<IShellWindows> spShellWindows;
ThrowIfFailed(
spShellWindows.CoCreateInstance( CLSID_ShellWindows ),
"Failed to create IShellWindows instance" );
CComVariant vtLoc( CSIDL_DESKTOP );
CComVariant vtEmpty;
long lhwnd;
CComPtr<IDispatch> spdisp;
ThrowIfFailed(
spShellWindows->FindWindowSW(
&vtLoc, &vtEmpty, SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp ),
"Failed to find desktop window" );
CComQIPtr<IServiceProvider> spProv( spdisp );
if( ! spProv )
ThrowIfFailed( E_NOINTERFACE, "Failed to get IServiceProvider interface for desktop" );
CComPtr<IShellBrowser> spBrowser;
ThrowIfFailed(
spProv->QueryService( SID_STopLevelBrowser, IID_PPV_ARGS( &spBrowser ) ),
"Failed to get IShellBrowser for desktop" );
CComPtr<IShellView> spView;
ThrowIfFailed(
spBrowser->QueryActiveShellView( &spView ),
"Failed to query IShellView for desktop" );
ThrowIfFailed(
spView->QueryInterface( riid, ppv ),
"Could not query desktop IShellView for interface " + interfaceName );
}
Example to toggle desktop icons using the above code:
void ToggleDesktopIcons()
{
CComPtr<IFolderView2> spView;
FindDesktopFolderView( IID_PPV_ARGS(&spView), "IFolderView2" );
DWORD flags = 0;
ThrowIfFailed(
spView->GetCurrentFolderFlags( &flags ),
"GetCurrentFolderFlags failed" );
ThrowIfFailed(
spView->SetCurrentFolderFlags( FWF_NOICONS, flags ^ FWF_NOICONS ),
"SetCurrentFolderFlags failed" );
}
int wmain(int argc, wchar_t **argv)
{
try
{
CComInit init;
ToggleDesktopIcons();
std::cout << "Desktop icons have been toggled.\n";
}
catch( std::system_error const& e )
{
std::cout << "ERROR: " << e.what() << ", error code: " << e.code() << "\n";
return 1;
}
return 0;
}
The third parameter isn't about changing the setting, it's to select the SHGetSetSettings() behavior.
FALSE will get the value of the current setting and store it in ss, TRUE will set the value of the setting to what is in ss.
So basically you have to do ss.fHideIcons = TRUE and then call SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE) to set it.
I know, it's weird, but on the other hand it allows you to change multiple settings simultaneously because SSF_* is a bitmask.
The following seems to work (adapted from https://stackoverflow.com/a/6403014/5743288):
#include <windows.h>
int main ()
{
HWND hProgman = FindWindowW (L"Progman", L"Program Manager");
HWND hChild = GetWindow (hProgman, GW_CHILD);
ShowWindow (hChild, SW_HIDE);
Sleep (2000);
ShowWindow (hChild, SW_SHOW);
}
Please note: this approach is not supported by Microsoft and disables right-clicking on ths desktop.
I am currently trying to make a game app in Windows with XAudio2 and I cannot figure out how to make the application not block when playing a sound. I tried calling a new thread in the samples in this repository.
But it will just cause an error. I tried passing a reference to the mastering voice in the function but then it just raises a "XAudio2: Must create a mastering voice first" error. Am I missing something? I am just trying to make it play two sounds at once and build from there. I went over the documentation but it's very vague.
XAudio2 is a non-blocking API. To play two sounds simultaneously, you need two 'source voices' and one 'mastering voice' at a minimum.
DX::ThrowIfFailed(
CoInitializeEx( nullptr, COINIT_MULTITHREADED )
);
Microsoft::WRL::ComPtr<IXAudio2> pXAudio2;
// Note that only IXAudio2 (and APOs) are COM reference counted
DX::ThrowIfFailed(
XAudio2Create( pXAudio2.GetAddressOf(), 0 )
);
IXAudio2MasteringVoice* pMasteringVoice = nullptr;
DX::ThrowIfFailed(
pXAudio2->CreateMasteringVoice( &pMasteringVoice )
);
IXAudio2SourceVoice* pSourceVoice1 = nullptr;
DX::ThrowIfFailed(
pXaudio2->CreateSourceVoice( &pSourceVoice1, &wfx ) )
// The default 'pSendList' will be just to the pMasteringVoice
);
IXAudio2SourceVoice* pSourceVoice2 = nullptr;
DX::ThrowIfFailed(
pXaudio2->CreateSourceVoice( &pSourceVoice2, &wfx) )
// Doesn't have to be same format as other source voice
// And doesn't have to match the mastering voice either
);
DX::ThrowIfFailed(
pSourceVoice1->SubmitSourceBuffer( &buffer )
);
DX::ThrowIfFailed(
pSourceVoice2->SubmitSourceBuffer( &buffer /* could be different WAV data or not */)
);
DX::ThrowIfFailed(
pSourceVoice1->Start( 0 );
);
DX::ThrowIfFailed(
pSourceVoice2->Start( 0 );
);
You should take a look at the samples on GitHub as well as DirectX Tool Kit for Audio
If you wanted to ensure both source voices started at precisely the same time, you'd use:
DX::ThrowIfFailed(
pSourceVoice1->Start( 0, 1 );
);
DX::ThrowIfFailed(
pSourceVoice2->Start( 0, 1 );
);
DX::ThrowIfFailed(
pSourceVoice2->CommitChanges( 1 );
);
If you want to play multiple sounds simultaneously have a playSound function and launch various threads to play your various sounds each one of a certain source voice.
XAudio2 will take care of mapping each sound to available channels (or if you have a more advanced system you can specify the mapping yourself using IXAudio2Voice::SetOutputMatrix).
void playSound( IXAudio2SourceVoice* sourceVoice )
{
BOOL isPlayingSound = TRUE;
XAUDIO2_VOICE_STATE soundState = {0};
HRESULT hres = sourceVoice->Start( 0u );
while ( SUCCEEDED( hres ) && isPlayingSound )
{// loop till sound completion
sourceVoice->GetState( &soundState );
isPlayingSound = ( soundState.BuffersQueued > 0 ) != 0;
Sleep( 100 );
}
}
For example to play two sounds simultaneously:
IXAudio2SourceVoice* pSourceVoice1 = nullptr;
IXAudio2SourceVoice* pSourceVoice2 = nullptr;
// setup the source voices, load the sounds etc..
std::thread thr1{ playSound, pSourceVoice1 };
std::thread thr2{ playSound, pSourceVoice2 };
thr1.join();
thr2.join();
I want to show the Windows file properties dialog for a file from my C++ code (on Windows 7, using VS 2012). I found the following code in this answer (which also contains a full MCVE). I also tried calling CoInitializeEx() first, as mentioned in the documentation of ShellExecuteEx():
// Whether I initialize COM or not doesn't seem to make a difference.
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
SHELLEXECUTEINFO info = {0};
info.cbSize = sizeof info;
info.lpFile = L"D:\\Test.txt";
info.nShow = SW_SHOW;
info.fMask = SEE_MASK_INVOKEIDLIST;
info.lpVerb = L"properties";
ShellExecuteEx(&info);
This code works, i.e. the properties dialog is shown and ShellExecuteEx() returns TRUE. However, in the Details tab, the size property is wrong and the date properties are missing:
The rest of the properties in the Details tab (e.g. the file attributes) are correct. Strangely, the size and date properties are shown correctly in the General tab (left-most tab).
If I open the properties window via the Windows Explorer (file → right-click → Properties), then all properties in the Details tab are shown correctly:
I tried it with several files and file types (e.g. txt, rtf, pdf) on different drives and on three different PCs (1x German 64-bit Windows 7, 1x English 64-bit Windows 7, 1x English 32-bit Windows 7). I always get the same result, even if I run my program as administrator. On (64-bit) Windows 8.1 the code is working for me, though.
My original program in which I discovered the problem is an MFC application, but I see the same problem if I put the above code into a console application.
What do I have to do to show the correct values in the Details tab on Windows 7? Is it even possible?
As Raymond Chen suggested, replacing the path with a PIDL (SHELLEXECUTEINFO::lpIDList) makes the properties dialog correctly show the size and date fields under Windows 7 when invoked through ShellExecuteEx().
It seems that the Windows 7 implementation of ShellExecuteEx() is buggy since newer versions of the OS do not have an issue with SHELLEXCUTEINFO::lpFile.
There is another solution possible that involves creating an instance of IContextMenu and calling the IContextMenu::InvokeCommand() method. I guess this is what ShellExecuteEx() does under the hood. Scroll down to Solution 2 for example code.
Solution 1 - using a PIDL with ShellExecuteEx
#include <atlcom.h> // CComHeapPtr
#include <shlobj.h> // SHParseDisplayName()
#include <shellapi.h> // ShellExecuteEx()
// CComHeapPtr is a smart pointer that automatically calls CoTaskMemFree() when
// the current scope ends.
CComHeapPtr<ITEMIDLIST> pidl;
SFGAOF sfgao = 0;
// Convert the path into a PIDL.
HRESULT hr = ::SHParseDisplayName( L"D:\\Test.txt", nullptr, &pidl, 0, &sfgao );
if( SUCCEEDED( hr ) )
{
// Show the properties dialog of the file.
SHELLEXECUTEINFO info{ sizeof(info) };
info.hwnd = GetSafeHwnd();
info.nShow = SW_SHOWNORMAL;
info.fMask = SEE_MASK_INVOKEIDLIST;
info.lpIDList = pidl;
info.lpVerb = L"properties";
if( ! ::ShellExecuteEx( &info ) )
{
// Make sure you don't put ANY code before the call to ::GetLastError()
// otherwise the last error value might be invalidated!
DWORD err = ::GetLastError();
// TODO: Do your error handling here.
}
}
else
{
// TODO: Do your error handling here
}
This code works for me under both Win 7 and Win 10 (other versions not tested) when called from a button click handler of a simple dialog-based MFC application.
It also works for console applications if you set info.hwnd to NULL (simply remove the line info.hwnd = GetSafeHwnd(); from the example code as it is already initialized with 0). In the SHELLEXECUTEINFO reference it is stated that the hwnd member is optional.
Don't forget the mandatory call to CoInitialize() or CoInitializeEx() at the startup of your application and CoUninitialize() at shutdown to properly initialize and deinitialize COM.
Notes:
CComHeapPtr is a smart pointer included in ATL that automatically calls CoTaskMemFree() when the scope ends. It's an ownership-transferring pointer with semantics similar to the deprecated std::auto_ptr. That is, when you assign a CComHeapPtr object to another one, or use the constructor that has a CComHeapPtr parameter, the original object will become a NULL pointer.
CComHeapPtr<ITEMIDLIST> pidl2( pidl1 ); // pidl1 allocated somewhere before
// Now pidl1 can't be used anymore to access the ITEMIDLIST object.
// It has transferred ownership to pidl2!
I'm still using it because it is ready to use out-of-the-box and plays well together with the COM APIs.
Solution 2 - using IContextMenu
The following code requires Windows Vista or newer as I'm using the "modern" IShellItem API.
I wrapped the code into a function ShowPropertiesDialog() that takes a window handle and a filesystem path. If any error occurs, the function throws a std::system_error exception.
#include <atlcom.h>
#include <string>
#include <system_error>
/// Show the shell properties dialog for the given filesystem object.
/// \exception Throws std::system_error in case of any error.
void ShowPropertiesDialog( HWND hwnd, const std::wstring& path )
{
using std::system_error;
using std::system_category;
if( path.empty() )
throw system_error( std::make_error_code( std::errc::invalid_argument ),
"Invalid empty path" );
// SHCreateItemFromParsingName() returns only a generic error (E_FAIL) if
// the path is incorrect. We can do better:
if( ::GetFileAttributesW( path.c_str() ) == INVALID_FILE_ATTRIBUTES )
{
// Make sure you don't put ANY code before the call to ::GetLastError()
// otherwise the last error value might be invalidated!
DWORD err = ::GetLastError();
throw system_error( static_cast<int>( err ), system_category(), "Invalid path" );
}
// Create an IShellItem from the path.
// IShellItem basically is a wrapper for an IShellFolder and a child PIDL, simplifying many tasks.
CComPtr<IShellItem> pItem;
HRESULT hr = ::SHCreateItemFromParsingName( path.c_str(), nullptr, IID_PPV_ARGS( &pItem ) );
if( FAILED( hr ) )
throw system_error( hr, system_category(), "Could not get IShellItem object" );
// Bind to the IContextMenu of the item.
CComPtr<IContextMenu> pContextMenu;
hr = pItem->BindToHandler( nullptr, BHID_SFUIObject, IID_PPV_ARGS( &pContextMenu ) );
if( FAILED( hr ) )
throw system_error( hr, system_category(), "Could not get IContextMenu object" );
// Finally invoke the "properties" verb of the context menu.
CMINVOKECOMMANDINFO cmd{ sizeof(cmd) };
cmd.lpVerb = "properties";
cmd.hwnd = hwnd;
cmd.nShow = SW_SHOWNORMAL;
hr = pContextMenu->InvokeCommand( &cmd );
if( FAILED( hr ) )
throw system_error( hr, system_category(),
"Could not invoke the \"properties\" verb from the context menu" );
}
In the following I show an example of how to use ShowPropertiesDialog() from a button handler of a CDialog-derived class. Actually ShowPropertiesDialog() is independent from MFC, as it just needs a window handle, but OP mentioned that he wants to use the code in an MFC app.
#include <sstream>
#include <codecvt>
// Convert a multi-byte (ANSI) string returned from std::system_error::what()
// to Unicode (UTF-16).
std::wstring MultiByteToWString( const std::string& s )
{
std::wstring_convert< std::codecvt< wchar_t, char, std::mbstate_t >> conv;
try { return conv.from_bytes( s ); }
catch( std::range_error& ) { return {}; }
}
// A button click handler.
void CMyDialog::OnPropertiesButtonClicked()
{
std::wstring path( L"c:\\temp\\test.txt" );
// The code also works for the following paths:
//std::wstring path( L"c:\\temp" );
//std::wstring path( L"C:\\" );
//std::wstring path( L"\\\\127.0.0.1\\share" );
//std::wstring path( L"\\\\127.0.0.1\\share\\test.txt" );
try
{
ShowPropertiesDialog( GetSafeHwnd(), path );
}
catch( std::system_error& e )
{
std::wostringstream msg;
msg << L"Could not open the properties dialog for:\n" << path << L"\n\n"
<< MultiByteToWString( e.what() ) << L"\n"
<< L"Error code: " << e.code();
AfxMessageBox( msg.str().c_str(), MB_ICONERROR );
}
}
For Video mixing renderer, I have
//IFilterGraph * m_FilterGraph
IVideoFrameStep * ivfs=0;
HRESULT hr = m_FilterGraph->QueryInterface(IID_IVideoFrameStep, (void**)&ivfs );
if ( SUCCEEDED(hr) )
{
ivfs->Step( 1, 0 );
}
SAFE_RELEASE( ivfs );
and it works, but I cannot make the same using a derived class of baseclasses CBaseRenderer. Reading the reference pages, I tried to implement IKsPropertySet interface on the renderer, but it is never queried so that's about it...
So how to enable frame stepping on a custom renderer?
I'm also curious to know how to implement the actual stepping.
For a dirty quick solution, due to the fact that I seem to own a direct pointer to the renderer, I just call
//CBaseRenderer * m_pRenderer
m_pRenderer->BeginFlush();
m_pRenderer->EndFlush();
from the application thread. It works until I switch from stepping state (=paused) to playing state. Essentially, it never breaks down, but there seems to be a lag equal to the duration of the stepping state. Obviously it is not correct.
Ok, I got it after I found EC_STEP_COMPLETE notification. So this'll do it.
STDMETHODIMP CSteppingBaseRenderer::NonDelegatingQueryInterface(const IID &riid, void **ppv){
if (!ppv)
return E_POINTER;
if ( riid == IID_IKsPropertySet ){
return GetInterface( (IKsPropertySet*)this, ppv );
}
return CBaseRenderer::NonDelegatingQueryInterface(riid,ppv);
}
STDMETHODIMP CSteppingBaseRenderer::Set(
REFGUID guidPropSet,
DWORD dwPropID,
LPVOID pInstanceData,
DWORD cbInstanceData,
LPVOID pPropData,
DWORD cbPropData)
{
if ( guidPropSet == AM_KSPROPSETID_FrameStep )
{
if (dwPropID == AM_PROPERTY_FRAMESTEP_STEP )
{
m_Stepping = 1;
return S_OK;
}else if ( dwPropID == AM_PROPERTY_FRAMESTEP_CANSTEP )
{
return S_OK;
}
}
return E_PROP_SET_UNSUPPORTED;
}
HRESULT CSteppingBaseRenderer::DoRenderSample(IMediaSample *pMediaSample){
//...
if ( m_Stepping && !(--m_Stepping) )
{
this->NotifyEvent( EC_STEP_COMPLETE, 0, 0 );
}
return NOERROR;
}