Decide on allocator with transinplacefilter - c++

CTransInPlaceFilter do not seem to implement GetAllocatorRequirements in their input pin. Because I get a E_NOTIMPL error when trying to call this method on a upstream filter.
I know that CTransInPlace Filter only have one buffer instead of a input and a output buffer.
But how do I handle this in my upstream filter?
How do I implmement DecideAllocator to support CTransInPlaceFilters?
This is my DecideAllocator function in the upstream filter:
HRESULT MCMyOutputPin::DecideAllocator(IMemInputPin *pPin, IMemAllocator **ppAlloc)
{
ALLOCATOR_PROPERTIES *pprops = new ALLOCATOR_PROPERTIES;
HRESULT hr = pPin->GetAllocatorRequirements(pprops); //returns E_NOTIMPL
if (FAILED(hr))
return hr;
hr = pPin->GetAllocator(ppAlloc);
if (hr == VFW_E_NO_ALLOCATOR)
{
hr = InitAllocator(ppAlloc);
if (FAILED(hr))
return hr;
}
hr = DecideBufferSize(*ppAlloc, pprops);
if (FAILED(hr))
return hr;
hr = pPin->NotifyAllocator(*ppAlloc, TRUE);
if (FAILED(hr))
{
return hr;
}
*ppAlloc = m_pAllocator;
//m_pAllocator = *ppAlloc;
m_pAllocator->Commit();
m_pAllocator->AddRef();
return hr;
}
Or did I miss something and the reason for the error is something different?

The part about inplace transofrmations is irrelevant to the question and redundant. You are asking how to deal with peer filters/pin that don't implement IMemInputPin::GetAllocatorRequirements. From MSDN:
The input pin is not required to implement this method. If the filter has specific alignment or prefix requirements, it should implement this method.
Implementation of this method is not mandatory. This means that on your output pin you are free to configure the memory allocator at your own discretion, no need to consider peer pin opinion on the allocator properties.

Related

IGlobalInterfaceTable::RegisterInterfaceInGlobal returns E_NOTIMPL

Does anyone know why IGlobalInterfaceTable::RegisterInterfaceInGlobal might return E_NOTIMPL?
I'm using ATL's CComGITPtr and simply assigning it to a COM pointer. The assignment, in turn, calls the following ATL code:
HRESULT Attach(_In_ T* p) throw()
{
if (p)
{
CComPtr<IGlobalInterfaceTable> spGIT;
HRESULT hr = E_FAIL;
hr = AtlGetGITPtr(&spGIT);
ATLASSERT(spGIT != NULL);
ATLASSERT(SUCCEEDED(hr));
if (FAILED(hr))
return hr;
if (m_dwCookie != 0)
hr = spGIT->RevokeInterfaceFromGlobal(m_dwCookie);
if (FAILED(hr))
return hr;
return spGIT->RegisterInterfaceInGlobal(p, __uuidof(T), &m_dwCookie);
}
else
{
return Revoke();
}
}
Apparently that last call to spGIT->RegisterInterfaceInGlobal results in E_NOTIMPL.
I'm performing the assignment in the context of an in-proc Explorer extension, and I'm doing it on the main UI thread.
Also, I'm not sure if this is related, but I get the same error when trying to use RoGetAgileReference (on Windows 8.1), doing something like this (with an IShellItemArray):
HRESULT hr;
CComPtr<IAgileReference> par;
hr = RoGetAgileReference(AGILEREFERENCE_DEFAULT, IID_IShellItemArray, psia, &par);
Any ideas what might be going wrong?

Determining whether all items in an IShellItemArray come from the same directory

Let's say you want to determine whether all items in an IShellItemArray belong to the same parent directory. How might you do that?
This is what I've come up with, but I was wondering if there's a more efficient or otherwise more acceptable way (it's based on the behaviors described here):
HRESULT ItemsInSameDirectory(IShellItemArray* psia, BOOL* fSameDir)
{
HRESULT hr;
CComPtr<IPropertyStore> pPropStore;
hr = psia->GetPropertyStore(GPS_FASTPROPERTIESONLY, IID_PPV_ARGS(&pPropStore));
if (FAILED(hr))
{
return hr;
}
wil::unique_prop_variant pv;
hr = pPropStore->GetValue(PKEY_ItemFolderPathDisplay, &pv);
if (FAILED(hr))
{
return hr;
}
*fSameDir = (pv.vt == VT_LPWSTR) ? TRUE : FALSE;
return S_OK;
}

How to use property pages on unregistrated filter?

I use filter DS LAME for compressing audio. I loaded it from file "lame.ax" as follows:
// pPath - path to LAME "lame.ax"
HRESULT CMyFilter::CreateObjectFromPath(wchar_t *pPath, REFCLSID clsid, IUnknown **ppUnk)
{
// load the target DLL directly
if (!m_hLibFilter) m_hLibFilter = LoadLibrary(pPath);
if (!m_hLibFilter)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// the entry point is an exported function
FN_DLLGETCLASSOBJECT fn = (FN_DLLGETCLASSOBJECT)GetProcAddress(m_hLibFilter, "DllGetClassObject");
if (fn == NULL)
{
return HRESULT_FROM_WIN32(GetLastError());
}
// create a class factory
IUnknownPtr pUnk;
HRESULT hr = fn(clsid, IID_IUnknown, (void**)(IUnknown**)&pUnk);
if (SUCCEEDED(hr))
{
IClassFactoryPtr pCF = pUnk;
if (pCF == NULL)
{
hr = E_NOINTERFACE;
}
else
{
// ask the class factory to create the object
hr = pCF->CreateInstance(NULL, IID_IUnknown, (void**)ppUnk);
}
}
return hr;
}
further
HRESULT hr = 0;
IUnknown *ppUnk = 0;
ULONG lRef = 0;
hr = CreateObjectFromPath(L"lame.ax", CLSID_LAMEDShowFilter, (IUnknown **)&ppUnk);
hr = ppUnk->QueryInterface(&m_pFilter);
lRef = ppUnk->Release();
It works perfectly. LAME encoding audio.
I want to show the filter settings - property page, but this code failed
bool ShowConfigWindow(HWND hParent)
{
ISpecifyPropertyPages *pProp;
HRESULT hr = m_pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
if (SUCCEEDED(hr))
{
// Get the filter's name and IUnknown pointer.
FILTER_INFO FilterInfo;
hr = m_pFilter->QueryFilterInfo(&FilterInfo);
IUnknown *pFilterUnk;
m_pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);
// Show the page.
CAUUID caGUID;
pProp->GetPages(&caGUID);
pProp->Release();
HRESULT hr = OleCreatePropertyFrame(
hParent, // Parent window
0, 0, // Reserved
FilterInfo.achName, // Caption for the dialog box
1, // Number of objects (just the filter)
&pFilterUnk, // Array of object pointers.
caGUID.cElems, // Number of property pages
caGUID.pElems, // Array of property page CLSIDs
0, // Locale identifier
0, NULL // Reserved
);
// Clean up.
pFilterUnk->Release();
FilterInfo.pGraph->Release();
CoTaskMemFree(caGUID.pElems);
}
return true;
}
I find https://groups.google.com/forum/#!topic/microsoft.public.win32.programmer.directx.video/jknSbMenWeM
I should call CoRegisterClassObject for each property page, but how to do it?
Or what the right way?
OleCreatePropertyFrame takes property page class identifiers (CLSIDs) so you need to find a way to make them "visible" for the API.
Use of CoRegisterClassObject is one of the ways to achieve the mentioned task (perhaps the easiest, another method would be reg-free COM). You need to retrieve IClassFactory pointers for property page CLSIDs the same way as you do it in the first snippet. Then instead of calling IClassFactory::CreateInstance you use the interface pointers as arguments for CoRegisterClassObject API. Make sure you do it on the same thread as the following OleCreatePropertyFrame call. CoRevokeClassObject will clean things up afterwards.

How to use Proximity Sensor (P-Sensor) class in MFC?

I am stuck with the problem when using Proximity Sensor class.
Recently, I have engaged in Proximity Sensor (P-Sensor) software development.
I found some relative reference from Google, e.g. Proximity Sensor class (website: msdn.microsoft.com/en-us/library/windows/apps/windows.devices.sensors.proximitysensor.aspx) and Sample Code (website: github.com/Microsoft/Windows-universal-samples/tree/master/Samples/ProximitySensor/cpp).
I tried to imitate the sample code, but it did not work.
As I know, it is necessary to create runtime api interface at first. The following code is how I create
the interface IProximitySensorStatics and it succeeded. The output prints "0".
The interface IProximitySensorStatics have to be activated by the api GetActivationFactory() before using.
ComPtr<IProximitySensorStatics> stProximitySensorStatics;
HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Sensors_ProximitySensor).Get(), &stProximitySensorStatics);
printf("CProximitySensorCtrl::GetActivationFactory stProximitySensorStatics hr = %x", hr);
if (FAILED(hr))
{
printf("GetActivationFactory stProximitySensorStatics failed");
return FALSE;
}
The next step is to create the interface IProximitySensor because the runtime api I want to apply is GetCurrentReading() which is the member of IProximitySensor.
Then I use the same method above. The output prints "GetActivationFactory stProximitySensor failed". HRESULT value is 80004002.
If I change HStringReference(RuntimeClass_Windows_Devices_Sensors_ProximitySensor) to HStringReference(RuntimeClass_Windows_Devices_Sensors_ProximitySensorReading), the HRESULT value is 80040154. I do not know how to solve it. HRESULT value list: https://msdn.microsoft.com/en-us/library/cc704587.aspx
ComPtr<IProximitySensor> stProximitySensor;
hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_Devices_Sensors_ProximitySensor).Get(), &stProximitySensor);
printf("CProximitySensorCtrl::GetActivationFactory stProximitySensor hr = %x", hr);
if (FAILED(hr))
{
printf("GetActivationFactory stProximitySensor failed");
return FALSE;
}
Now the problem is that I am wondering how to activate the interface IProximitySensor and even IProximitySensorReading. IProximitySensorReading is another interface which is used to catch the output of GetCurrentReading().
If GetCurrentReading() succeeds to get a value, everything is done.
In other sensor classes such as Accelerometer, Compass, LightSensor, ect, there is always a method GetDefault(). The GetDefault() might solve my problem, but ProximitySensor class does not have this method.
The following code is that I tried to use methods in ProximitySensor class in order to make it work. The hr prints "0", but the output "stProximitySensor" is NULL.
HSTRING m_hsString;
hr = stProximitySensorStatics->GetDeviceSelector(&m_hsString);
hr = stProximitySensorStatics->FromId(m_hsString, &stProximitySensor);
printf("FromId hr = %x", hr);
if (FAILED(hr))
{
printf("FromId failed");
return FALSE;
}
if (stProximitySensor == NULL)
{
printf("FromId stProximitySensor = null failed");
return FALSE;
}
Fully thanks in advance.

WASAPI: Choosing a wave format for exclusive output

I'm trying to open an exclusive stream with an output device using WASAPI. I'm having trouble choosing an acceptable format, since there appear to be no hints as to what formats are accepted by a given device.
In my case, IAudioClient::GetMixFormat(), which would otherwise return a sort of default format for the device, returns a format that can't be used in exclusive mode (IAudioClient::IsFormatSupported() returns AUDCLNT_E_UNSUPPORTED_FORMAT). I don't know where to go from there. There's a ridiculous number of combinations of wave format parameters - do I literally have to iterate through every one of them until something works?
Well, I asked the MSDN forums and they came up with a good answer.
You need to check the device's default device format via IMMDevice::OpenPropertyStore(), and subsequently IPropertyStore::GetValue(), not IAudioClient::GetMixFormat(). Here is the code that retrieved an acceptable WAVEFORMATEX structure:
//CoInitialize/Enumerate devices
IPropertyStore* store = nullptr;
hr = device->OpenPropertyStore(STGM_READ, &store);
if (FAILED(hr)) {
ExitProcess(1);
}
PROPVARIANT prop;
hr = store->GetValue(PKEY_AudioEngine_DeviceFormat, &prop);
if (FAILED(hr)) {
ExitProcess(2);
}
hr = device->Activate (
__uuidof(IAudioClient),
CLSCTX_ALL,
NULL,
(void**)&audioClient
);
device->Release();
device = nullptr;
if (FAILED(hr)) {
ExitProcess(3);
}
hr = audioClient->IsFormatSupported (
AUDCLNT_SHAREMODE_EXCLUSIVE,
(PWAVEFORMATEX)prop.blob.pBlobData,
NULL
);
if (FAILED(hr)) {
ExitProcess(4);
}
The final value of hr is S_OK.