I'm using the windows API to get a handle to a IAudioEndpointVolume and register a IAudioEndpointVolumeCallback. I've also got a IMMDeviceEnumerator with a registered callback for IMMNotificationClient so that when the default device changes I release the IAudioEndpointVolumeCallback and IAudioEndpointVolume and store new ones.
However, my program seems to silently crash on the callback thread when releasing IAudioEndpointVolume with no exception or output that I can see. Even when breaking on the line and trying to step over it will silently continue without getting to the next statement but also without the debugger coming down.
if(_volumeEndPoint)
{
if(_callback)
{
HRESULT hrUnReg = _volumeEndPoint->UnregisterControlChangeNotify(this);
if(hrUnReg != S_OK)
{
std::cout << hrUnReg; // this reports successful
}
}
_volumeEndPoint->Release(); // <--- cannot step over this line
_volumeEndPoint = nullptr;
}
if(deviceEndPoint == nullptr)
{
return;
}
Things I've tried:
Enabling all the exceptions in Debug->Windows->Exception Settings
Adding a try/catch all exceptions
Feels like it's probably related to it being a callback on a different thread? I'm not that well versed in C++ nor the WinAPI and the COM stuff so almost certain I'm doing something stupid but it would be good if it could tell me an error of some kind.
I am trying to convert the Microsoft "CaptureEngine video capture sample" code from Visual C++ to Embarcadero C++ Builder.
https://code.msdn.microsoft.com/windowsdesktop/Media-Foundation-Capture-78504c83
The code runs fine with Visual C++, but I need to include in a C++ Builder application. I basically have the code working, but there are a couple of issues I need help with.
I can select the video source, preview the video source and even start capture to file. However the video capture file just contains the one frame repeated for the length of the video, even though Audio is correctly recorded.
I am wondering if this is due to events not being handled properly.
The events from the media foundation capture engine are passed to the main thread using windows messaging which then calls the media engine event handler. However I have noticed the event handler to stop the recording and to stop the preview uses wait for result
void WaitForResult()
{
WaitForSingleObject(m_hEvent, INFINITE);
}
HRESULT CaptureManager::StopPreview()
{
HRESULT hr = S_OK;
if (m_pEngine == NULL)
{
return MF_E_NOT_INITIALIZED;
}
if (!m_bPreviewing)
{
return S_OK;
}
hr = m_pEngine->StopPreview();
if (FAILED(hr))
{
goto done;
}
WaitForResult();
if (m_fPowerRequestSet && m_hpwrRequest != INVALID_HANDLE_VALUE)
{
PowerClearRequest(m_hpwrRequest, PowerRequestExecutionRequired);
m_fPowerRequestSet = false;
}
done:
return hr;
}
The trouble is, this m_hEvent is triggered from the C++ Builder event handler which is part of the same main thread which is waiting for the event to be handled, so I get a thread lock when trying to stop the video recording. If I comment out the line, I don't lock but I also don't get valid recorded video file.
I am not sure how the Visual C++ separates the events from the Capture engine code, any suggestion as to how I can do this for C++ Builder?
Capture engine event callback is called on a worker thread and it is not "a part of same main thread".
// Callback method to receive events from the capture engine.
STDMETHODIMP CaptureManager::CaptureEngineCB::OnEvent( _In_ IMFMediaEvent* pEvent)
{
...
if (guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED)
{
m_pManager->OnPreviewStopped(hrStatus);
SetEvent(m_pManager->m_hEvent);
This essentially changes the behavior of the application. The controlling thread stops preview and blocks until worker thread delivers a notification which sets the event as I quoted above. From there controlling thread wakes up from wait operation and continues with preview stopped.
If this is not what you are seeing in your application I would suggest setting a breakpoint at the first line of callback function to make sure you receive the notification. If you receive, you can step the code and make sure you reach the event setting line. If you don't receive, something else is blocking and you will have to figure that out, such as for example, by breaking in and examining thread states of the application.
I have found the cause of my issue. The OnEvent routine in the Capture engine example is definitely in its own thread. The problem is that it then posts a message to the main application thread, rather than handling it itself. This means that the main thread is frozen as it waiting on the mutex.
// Callback method to receive events from the capture engine.
STDMETHODIMP CaptureManager::CaptureEngineCB::OnEvent( _In_ IMFMediaEvent* pEvent)
{
// Post a message to the application window, so the event is handled
// on the application's main thread.
if (m_fSleeping && m_pManager != NULL)
{
// We're about to fall asleep, that means we've just asked the CE to stop the preview
// and record. We need to handle it here since our message pump may be gone.
GUID guidType;
HRESULT hrStatus;
HRESULT hr = pEvent->GetStatus(&hrStatus);
if (FAILED(hr))
{
hrStatus = hr;
}
hr = pEvent->GetExtendedType(&guidType);
if (SUCCEEDED(hr))
{
if (guidType == MF_CAPTURE_ENGINE_PREVIEW_STOPPED)
{
m_pManager->OnPreviewStopped(hrStatus);
SetEvent(m_pManager->m_hEvent);
}
else if (guidType == MF_CAPTURE_ENGINE_RECORD_STOPPED)
{
m_pManager->OnRecordStopped(hrStatus);
SetEvent(m_pManager->m_hEvent);
}
else
{
// This is an event we don't know about, we don't really care and there's
// no clean way to report the error so just set the event and fall through.
SetEvent(m_pManager->m_hEvent);
}
}
return S_OK;
}
else
{
pEvent->AddRef(); // The application will release the pointer when it handles the message.
PostMessage(m_hwnd, WM_APP_CAPTURE_EVENT, (WPARAM)pEvent, 0L);
}
return S_OK;
}
I have created a ATL service and while testing I simply kept it running by leaving a while loop that ran forever (see code below)
HRESULT Run(_In_ int nShowCmd = SW_HIDE)
{
m_running = true;
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, &MyFunctionToRunInTheService, 0, 0, 0);
while(m_running);
return CAtlServiceModuleT::Run(nShowCmd);
}
Im now ready to actually run it as a real service but am not sure how I go about doing this? I have looked all over the next and dont seem to be able to find one example of a ATL service.
If I remove the thread code and call the method direct the service is constantly in a start status. If i remove the loop the service simply starts and stops straight away. Any sugestions?
Ive fixed the problem by changing the code to
HRESULT Run(_In_ int nShowCmd = SW_HIDE)
{
_beginthreadex(NULL, 0, &CheckForExpiredFiles, 0, 0, 0);
return CAtlServiceModuleT::Run(nShowCmd);
}
I didnt really need the while loop at all. On further investigation the code to keep the service alive comes as standard. The problem was that the PreMessageLoop method in atlbase.h was returning S_FALSE which casued the service to stop. The reason it returned S_FALSE in my case was becuase I had not added any COM objects. I have therefore overridden the PreMessageLoop method to return S_OK in this case.
Well, in my case, add _ATL_NO_COM_SUPPORT macro to C\C++ preprocessor solve the problem.
See more here...
i have a simple winform that writes to an EDITTEXT , as the program goes on the printing process executing perfectly . but once i click the STOP BUTTON which firstly calls the PAUSE()
function my program gets stuck inside the
SetWindowText(m_hWatermarksEditBox, &m_watermarkLog[0]);
all values are initialized and proper data gets in.
my guess is that i have to declare a METHOD WORKER , like in C#.NET but i dont know how.
STDMETHODIMP CNaveFilter::Pause()
{
ATLTRACE(L"(%0.5d)CNaveFilter::Pause() (this:0x%.8x)\r\n", GetCurrentThreadId(), (DWORD)this);
HRESULT hr = S_OK;
CAutoLock __lock(&m_cs);
hr = CBaseFilter::Pause();
return hr;
}
STDMETHODIMP CNaveFilter::Stop()
{
ATLTRACE(L"(%0.5d)CNaveFilter::Stop() (this:0x%.8x)\r\n", GetCurrentThreadId(), (DWORD)this);
HRESULT hr = S_OK;
CAutoLock __lock(&m_cs);
hr = CBaseFilter::Stop();
ATLASSERT(SUCCEEDED(hr));
return hr;
}
You don't show where you are doing SetWindowText but as you have the custom filter the most likely problem is that with this call you block your streaming/worker thread execution and the involved threads lock dead.
SetWindowText is only safe to be called from your UI thread (well, technically not only it, but definitely not a streaming thread). So if you want to update the control text or send any message to it, you have to do it in a different way, so that your caller thread could keep running.
Typically, you would store some relevant information in member variable (don't forget critical section lock) then PostMessage, receive the message on your window/control and handle it there in the right thread, calling SetWindowText there.
See controlling frame/rate and exposure time through sampleCB. It covers a bit different topic, but useful in terms of sending/posting messages in a DirectShow filter.
My application (the bootstrap application for an installer that I'm working on needs to launch some other applications (my installer and third party installers for my installer's prerequisites) and wait for them to complete. In order to allow the GUI to do screen updates while waiting for an app to complete, I put a message pump in the wait loop using the 'MFC-compatible' example in the Visual Studio documentation on idle loop processing as a guideline. My code (which is in a member function of a CWinApp-derived class) is as follows:
if (::CreateProcess(lpAppName, szCmdLineBuffer, NULL, NULL, TRUE, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
{
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
if (bWait)
while (dwExitCode == STILL_ACTIVE)
{
// In order to allow updates of the GUI to happen while we're waiting for
// the application to finish, we must run a mini message pump here to
// allow messages to go through and get processed. This message pump
// performs much like MFC's main message pump found in CWinThread::Run().
MSG msg;
while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!PumpMessage())
{
// a termination message (e.g. WM_DESTROY)
// was processed, so we need to stop waiting
dwExitCode = ERROR_CANT_WAIT;
::PostQuitMessage(0);
break;
}
}
// let MFC do its idle processing
LONG nIdle = 0;
while (OnIdle(nIdle++))
;
if (dwExitCode == STILL_ACTIVE) // was a termination message processed?
{
// no; wait for .1 second to see if the application is finished
::WaitForSingleObject(ProcessInfo.hProcess, 100);
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
}
}
::CloseHandle(ProcessInfo.hProcess);
::CloseHandle(ProcessInfo.hThread);
}
else
dwExitCode = ::GetLastError();
The problem that I'm having is that, at some point, this message pump seems to free up window and menu handles on the window that I have open at the time this code is run. I did a walk through in the debugger, and at no time did it ever get into the body of the if (!PumpMessage()) statement, so I don't know what's going on here to cause the window and menu handles to go south. If I don't have the message pump, everything works fine, except that the GUI can't update itself while the wait loop is running.
Does anyone have any ideas as to how to make this work? Alternatively, I'd like to launch a worker thread to launch the second app if bWait is TRUE, but I've never done anything with threads before, so I'll need some advice on how to do it without introducing synchronization issues, etc. (Code examples would be greatly appreciated in either case.)
I've also posted this question on the Microsoft forums, and thanks to the help of one Doug Harris at Microsoft, I found out my problem with my HWND and HMENU values was, indeed due to stale CWwnd* and CMenu* pointers (obtained using GetMenu() and GetDialogItem() calls. Getting the pointers again after launching the second app solved that problem. Also, he pointed me to a web site* that showed a better way of doing my loop using MsgWaitForMultipleObjects() to control it that doesn't involve the busy work of waiting a set amount of time and polling the process for an exit code.
My loop now looks like this:
if (bWait)
{
// In order to allow updates of the GUI to happen while we're
// waiting for the application to finish, we must run a message
// pump here to allow messages to go through and get processed.
LONG nIdleCount = 0;
for (;;)
{
MSG msg;
if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
PumpMessage();
else //if (!OnIdle(nIdleCount++))
{
nIdleCount = 0;
if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
DWORD nRes = ::MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess,
FALSE, INFINITE, QS_ALLEVENTS);
if (nRes == WAIT_OBJECT_0)
break;
}
}
}
}
::GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode);
*That Web site, if you're curious, is: http://members.cox.net/doug_web/threads.htm
I think your problem is in WaitForSingleObject
Looking in MSDN you see this
Use caution when calling the wait functions and code that directly or indirectly creates windows. If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. Two examples of code that indirectly creates windows are DDE and the CoInitialize function. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject.
In my code in the message pump use use MsgWaitForMultipleObjects (doc).
With a call this call.
MsgWaitForMultipleObjects(1, &ProcessInfo.hProcess, FALSE, 100, QS_ALLEVENTS);
This should stop your problem with the resources dissapearing.
When you say that window and menu handles seem to be being freed, do you mean that you've got actual HWND and HMENU values that no longer seem to work, or have you got MFC CWnd* and CMenu* variables that fail?
If the latter, the problem is most likely that you're getting the CWnd* pointers by calling CWnd::FromHandle() (or CMenu::FromHandle()) somewhere (or calling something that calls them), and OnIdle() is discarding them.
The underlying reason is that MFC maintains a map from window (or menu, etc.) handles to CWnd* objects in the system. When CWnd::FromHandle() is called, it looks for a match in the map: if one is found, it's returned. If not, a new, temporary CWnd is created, added to the map, and returned. The idea behind OnIdle() is that when it's called all message processing is done, so OnIdle() discards any of these temporary CWnd objects that still exist. That's why the CWnd::FromHandle() documentation warns that the returned pointer may be temporary.
The "correct" solution to this is to not hang onto the CWnd* pointers returned from CWnd::FromHandle(). Given the simplicity of your application, it might be easier to just remove the call OnIdle(): this shouldn't have any negative effects on an installer.
Of course, this is all something of a guess, but it sounds plausible...
There is a Windows function called DisableProcessWindowsGhosting (see http://msdn.microsoft.com/en-us/library/ms648415(v=vs.85).aspx) that prevents Windows from 'ghosting' your window, and continue updating the window (your animation).