I am using winsoft WCamera component with C++ Builder and would like to try and get the current time position from the AVIMUX part of the Directshow graph. Capture is working fine but when I look at the generated file it always seems longer in time than my elapsed time using GetTickCount.
As WCamera component doesn't provide the current media position I am using GetTickCount to give me an approximate position in the video recording to mark events which have occurred. However I am finding that the video is always longer than the time I measure. I would like to try and get the current position from the AVI MUX and see if this is more accurate but I am not sure how to do this.
I tried
HRESULT FindFilterInterface(
IGraphBuilder *pGraph, // Pointer to the Filter Graph Manager.
REFGUID iid, // IID of the interface to retrieve.
void **ppUnk) // Receives the interface pointer.
{
if (!pGraph || !ppUnk) return E_POINTER;
HRESULT hr = E_FAIL;
IEnumFilters *pEnum = NULL;
IBaseFilter *pF = NULL;
if (FAILED(pGraph->EnumFilters(&pEnum)))
{
return E_FAIL;
}
// Query every filter for the interface.
while (S_OK == pEnum->Next(1, &pF, 0))
{
hr = pF->QueryInterface(iid, ppUnk);
pF->Release();
if (SUCCEEDED(hr))
{
break;
}
}
pEnum->Release();
return hr;
}
But this gives the error
[bcc64 Error] main.cpp(29): non-const lvalue reference to type '_di_IEnumFilters' (aka 'DelphiInterface') cannot bind to a temporary of type 'Wdirectshow9::IEnumFilters **'
WDirectShow9.hpp(1392): passing argument to parameter 'ppEnum' here
[bcc64 Error] main.cpp(34): non-const lvalue reference to type '_di_IBaseFilter' (aka 'DelphiInterface') cannot bind to a temporary of type 'Wdirectshow9::IBaseFilter **'
WDirectShow9.hpp(1402): passing argument to parameter 'ppFilter' here
hpp file defines this as
__interface IEnumFilters;
typedef System::DelphiInterface<IEnumFilters> _di_IEnumFilters;
Any suggestions as to how I can access the IEnumFilters?
Related
I have a CLR hosting application that I'm trying to make it support WPF.
I attempted to set a value of a field to _Assembly but the problem is that I have to pass a variable of type VARIANT.
This is the C# code that I'm trying to convert to C++:
Assembly assembly = Assembly.Load(data);
...
field.SetValue(null, assembly); // I'm attempting to do that in C++
Here is what I did:
_AssemblyPtr pAssembly = NULL;
...
hr = AppDomain->Load_3(sa, &pAssembly);
...
CComVariant obj;
BindingFlags bFlags = (BindingFlags)(BindingFlags_SetField | BindingFlags_NonPublic | BindingFlags_Static);
hr = fieldInfo->SetValue(obj, CComVariant(pAssembly), bFlags, NULL, NULL);
It fails at fieldInfo->SetValue and more accurate at the 2nd argument which is supposed to be of type VARIANT. Error: hr = E_INVALIDARG One or more arguments are invalid.
If I set the second argument to CComVariant(NULL), it doesn't fail but I need to put the _Assembly there.
Any idea how I can deal with the problem?
I have a transform filter which exposes a custom interface says IMyInit. This interface used to be configured some basic setup setting before streaming.
DECLARE_INTERFACE_(IMyInit, IUnknown) {
STDMETHOD HRESULT SetPath(const wchar_t* wcsPath) PURE;
STDMETHOD HRESULT SetMode(UINT uMode) PURE;
};
Client code like:
CComPtr<IBaseFilter> pMyFilter;
HRESULT hr = CoCreateInstance(CLSID_MYFILTER, IID_MYFILTER, ..., (void**)&pMyFilter);
// hr is S_OK
CComPtr<IMyInit> pMyInit;
hr = pMyFilter->QueryInterface(IID_IMyInit, (void**)&pMyInit);
// hr is S_OK
hr = pMyInit->SetMode(1);
// hr is 0x80040213/VFW_E_NO_CLOCK
In my CMyFilter::SetMode(UINT uMode), there are only E_POINTER, E_INVALIDARG for parameters checking, and S_OK if uMode is set. It is not possible to return such error code, VFW_E_NO_CLOCK, related to transform filter.
Why?
I have implemented the IMyInit interface dispatch in NonDelegatingQueryInterface, and it seems like
if(riid == IID_IMyInit) {
return GetInterface((IMyInit*)this, ppv);
}
But! I forgot to let my CMyFilter concrete class inherit from the IMyInit interface. So there is no connection between IMyInit and CMyFilter.
The C style casting, (IMyInit*)this, then casts the ppv to CMyFilter's some base class, may be the direct show's CTransformFilter. The unknown method pointered by IMyInit::SetMode(UINT) may require clock to exist. This is why the VFW_E_NO_CLOCK will return.
I have been poking around with WRL at the ABI layer for the last couple of weeks and have run into this problem.
I have an interface defined in IDL as follows:
namespace Async{
[uuid(f469e110-7ef5-41df-a237-9ddef9aed55c), version(1.0)]
interface IDownloader : IInspectable
{
HRESULT GetFeed([in] HSTRING url,[out, retval] Windows.Web.Syndication.SyndicationFeed ** feed);
[propget]HRESULT Feed([out, retval]Windows.Web.Syndication.SyndicationFeed ** feed);
}
[version(1.0), activatable(1.0)]
runtimeclass Downloader
{
[default] interface IDownloader;
}
}
Which I have defined in my header file like so:
#pragma once
#include "Async_h.h"
namespace ABI {
namespace Async {
class Downloader : public Microsoft::WRL::RuntimeClass<ABI::Async::IDownloader>
{
InspectableClass(L"Async.Downloader", BaseTrust);
public:
Downloader();
STDMETHOD(GetFeed)(HSTRING url, ABI::Windows::Web::Syndication::ISyndicationFeed ** feed);
STDMETHOD(get_Feed)(ABI::Windows::Web::Syndication::ISyndicationFeed ** feed);
private:
//Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Uri> feedUrl;
Microsoft::WRL::ComPtr<ABI::Windows::Web::Syndication::ISyndicationFeed> m_feed;
};
ActivatableClass(Downloader);
}
}
In my cpp file I implement the functions:
STDMETHODIMP Downloader::GetFeed(HSTRING url, ISyndicationFeed** feed)
{
HRESULT hr;
RoInitializeWrapper ro(RO_INIT_MULTITHREADED);
ComPtr<IUriRuntimeClass> uri;
ComPtr<IUriRuntimeClassFactory> uriFactory;
hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(), &uriFactory);
hr = uriFactory->CreateUri(url, uri.GetAddressOf());
ComPtr<ISyndicationClient> client;
ComPtr<IInspectable> inspectable;
RoActivateInstance(HStringReference(RuntimeClass_Windows_Web_Syndication_SyndicationClient).Get(), &inspectable);
hr = inspectable.As(&client);
Event timerCompleted(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));
auto callback = Callback<IAsyncOperationWithProgressCompletedHandler<SyndicationFeed*,RetrievalProgress>>([&](IAsyncOperationWithProgress<SyndicationFeed*,RetrievalProgress> *op, AsyncStatus status) ->HRESULT
{
auto error = GetLastError();
if (status == AsyncStatus::Completed)
{
hr = op->GetResults(m_feed.GetAddressOf());
*feed = m_feed.Get();
}
return S_OK;
});
ComPtr<IAsyncOperationWithProgress<SyndicationFeed*,RetrievalProgress>> operation;
hr = client->RetrieveFeedAsync(uri.Get(), operation.GetAddressOf());
operation->put_Completed(callback.Get());
return S_OK;
}
STDMETHODIMP Downloader::get_Feed(ISyndicationFeed** feed)
{
*feed = m_feed.Get();
return S_OK;
}
The property works as expected it is projected to c++/cx as it should be. However,in the GetFeed method, when I attempt to set the feed parameter to the retrieved feed I get an access violation. Obviously I know that the memory is bad but the way I understand COM properties, they are essentially function calls and the property method and the GetFeed method are doing exactly the same thing minus the retrieval part.
Here are my questions:
What is the difference between COM property methods and regular interface methods in terms of the projected return value if any?
Why is the parameter to the property method initialized to nullptr and the parameter to the GetFeed Method not when they are described exactly the same in IDL?
If the out parameters in property methods are initialized, what part of the COM runtime is doing that for me and is that controllable? IE is there a way to get memory that I can write to passed to me?
I know that I could probably design that away but that is not the point. I am just trying to learn how it all works.
Thanks.
In your lambda you are capturing by reference with [&]. You need to capture the feed parameter by value, since the stack frame is long gone by the time your lambda executes.
The bigger issue is that the client has no idea when they can retrieve the results since you don't provide that information. (I see you create an unused Win32 Event object, so maybe there's some other code to make that work that you've deleted).
I am attempting to schedule a task (to open an .exe at a specific time) using C++ win32. But at one specific point I am getting an error, I have searched & searched to try & find the definition of this error but I cannot find it?
Do you know what this error means: Hexadecimal: 80004003 Decimal: 2147500035
I wont post the whole function because its rather long (unless you may need it to determine the error context?).
The code I am using (that causes the error) is the following:
// QI for the executable task pointer.
hr = action -> QueryInterface( IID_IExecAction, (void**) execAction );
action -> Release();
if( FAILED(hr) )
{
printf("QueryInterface call failed for IExecAction: %x %X %u \n", hr, hr, hr );
rootFolder -> Release();
task -> Release();
CoUninitialize();
return false;
}
The output is: QueryInterface call failed for IExecAction: 80004003 80004003 2147500035
0x80004003 is an "invalid pointer" error, a.k.a. E_POINTER.
I assume the declaration of execAction is something like:
IExecAction* execAction = NULL;
But, QueryInterface expects a pointer to an interface pointer. In other words, you pass a storage location in which to place an IUnknown*... or, in this specific case, a IExecAction*.
So, you need to pass the address of execAction so QueryInterface can return the interface pointer to you. As in:
hr = action -> QueryInterface( IID_IExecAction, (void**) &execAction );
I assume this is what's happening since initializing pointer values to NULL is a common coding practice, and QueryInterface is documented to return E_POINTER when the second argument is NULL. If not, please update your question with the declaration of execAction.
Using ATL (VS2008) how can I enumerate the available methods available on a given IDispatch interface (IDispatch*)? I need to search for a method with a specific name and, once I have the DISPID, invoke the method (I know the parameters the method takes.) Ideally I would like to do this using smart COM pointers (CComPtr<>).
Is this possible?
You can enumerate the methods an IDispatch exposes through the type info. There are two ways to get the type info:
through the type library (if any) for the dispinterface.
through calling IDispatch::GetTypeInfo.
Unfortunately, an IDispatch implementation is not obligated to provide type info about the methods and properties it implements.
If it does, however, the basic enumerating involves calling ITypeInfo::GetTypeAttr to get the TYPEATTR for the interface and looking at the number of implemented methods (cFuncs) and variables (cVars) and looping over these and calling ITypeInfo::GetFuncDesc() or ITypeInfo::GetVarDesc(). Of course, there are lot more details you will have to deal with as I can list here, but this should be a good starting point for your exploration.
Here's a nice article explaining the process in more details with code in VB.Net.
Here's some code that does the enumeration (it inserts the [Dispatch ID]-[Method Name] pairs in a map, but that's easy to change).
///
/// \brief Returns a map of [DispId, Method Name] for the passed-in IDispatch object
///
HRESULT COMTools::GetIDispatchMethods(_In_ IDispatch * pDisp,
_Out_ std::map<long, std::wstring> & methodsMap)
{
HRESULT hr = S_OK;
CComPtr<IDispatch> spDisp(pDisp);
if(!spDisp)
return E_INVALIDARG;
CComPtr<ITypeInfo> spTypeInfo;
hr = spDisp->GetTypeInfo(0, 0, &spTypeInfo);
if(SUCCEEDED(hr) && spTypeInfo)
{
TYPEATTR *pTatt = nullptr;
hr = spTypeInfo->GetTypeAttr(&pTatt);
if(SUCCEEDED(hr) && pTatt)
{
FUNCDESC * fd = nullptr;
for(int i = 0; i < pTatt->cFuncs; ++i)
{
hr = spTypeInfo->GetFuncDesc(i, &fd);
if(SUCCEEDED(hr) && fd)
{
CComBSTR funcName;
spTypeInfo->GetDocumentation(fd->memid, &funcName, nullptr, nullptr, nullptr);
if(funcName.Length()>0)
{
methodsMap[fd->memid] = funcName;
}
spTypeInfo->ReleaseFuncDesc(fd);
}
}
spTypeInfo->ReleaseTypeAttr(pTatt);
}
}
return hr;
}
You can't enumerate all the available methods unless the object implements IDispatchEx.
However, if you know the name of the method you want to call, you can use GetIDsOfNames to map the name to the proper DISPID.
HRESULT hr;
CComPtr<IDispatch> dispatch;
DISPID dispid;
WCHAR *member = "YOUR-FUNCTION-NAME-HERE";
DISPPARAMS* dispparams;
// Get your pointer to the IDispatch interface on the object here. Also setup your params in dispparams.
hr = dispatch->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (SUCCEEDED(hr)) {
hr = dispatch->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, dispparams, &varResult, NULL, NULL);
}
Edit: For completeness, I suspect there is a way to interrogate the ITypeInfo2 interface (assuming there is a type library for the object) that you get from IDispatch::GetTypeInfo for a list of methods, but I've not done it. See the other answer.