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

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.

Related

WIA 2.0, C++: IWiaDevMgr2::EnumDeviceInfo doesn't detect connected camera

I'm trying to write a program that transfers images and videos from a camera (for my personal use, on Win 8.1). I'm using Microsoft's example code as a starting point (WIA Tutorial), and I've hit a wall trying to detect connected camera devices. The problem is that there are no errors and the code seems to work, but it just doesn't detect any connected camera (I've tried with two different cameras), while the camera is clearly detected by the OS (shows up in Windows Explorer).
Am I missing something? Is IWiaDevMgr2::EnumDeviceInfo not the way to detect connected devices? Here's the code I'm using:
HRESULT WiaCreateDeviceManager(IWiaDevMgr2 **ppWiaDevMgr)
{
if(NULL == ppWiaDevMgr) return E_INVALIDARG;
*ppWiaDevMgr = NULL;
// Create an instance of the device manager
HRESULT hr = CoCreateInstance(CLSID_WiaDevMgr2, NULL, CLSCTX_LOCAL_SERVER, IID_IWiaDevMgr2, (void**)ppWiaDevMgr);
return hr;
}
HRESULT WiaEnumerateDevices(IWiaDevMgr2 *pWiaDevMgr)
{
if(NULL == pWiaDevMgr)
{
return E_INVALIDARG;
}
// Get a device enumerator interface
IEnumWIA_DEV_INFO *pWiaEnumDevInfo = NULL;
HRESULT hr = pWiaDevMgr->EnumDeviceInfo(WIA_DEVINFO_ENUM_LOCAL, &pWiaEnumDevInfo);
assert(hr == S_OK);
if(SUCCEEDED(hr))
{
ULONG count(911);
HRESULT res = pWiaEnumDevInfo->GetCount(&count);
if(res == S_OK) printf("EnumDeviceInfo: count = %lu\n", count); // count is always zero
else printf("IEnumWIA_DEV_INFO::GetCount() failed!\n");
// Loop until you get an error or pWiaEnumDevInfo->Next returns
// S_FALSE to signal the end of the list.
while(S_OK == hr)
{
// Get the next device's property storage interface pointer
IWiaPropertyStorage *pWiaPropertyStorage = NULL;
hr = pWiaEnumDevInfo->Next(1, &pWiaPropertyStorage, NULL);
// pWiaEnumDevInfo->Next will return S_FALSE when the list is
// exhausted, so check for S_OK before using the returned
// value.
if(hr == S_OK)
{
// Do something with the device's IWiaPropertyStorage*
WiaReadProperties(pWiaPropertyStorage); // this line is never reached
// Release the device's IWiaPropertyStorage*
pWiaPropertyStorage->Release();
pWiaPropertyStorage = NULL;
}
}
// If the result of the enumeration is S_FALSE (which
// is normal), change it to S_OK.
if(S_FALSE == hr) hr = S_OK;
// Release the enumerator
pWiaEnumDevInfo->Release();
pWiaEnumDevInfo = NULL;
}
return hr;
}
int main()
{
...
IWiaDevMgr2 *wiamgr;
WiaCreateDeviceManager(&wiamgr);
HRESULT res = WiaEnumerateDevices(wiamgr); // res is always S_OK, but no device is detected
...
}
Apparently, WIA does not support camera devices on Windows Vista and later. I've only seen this implied or mentioned in passing twice in the WIA documentation, the last time being on this page. I can't believe this is happening, after I've spent so much time researching WIA. Apparently, I'm supposed to be using WPD for cameras, not WIA.
Edit: That being said, I'm still not sure what's going on. If I can't use WIA programmatically on Win 8.1, then why do these PowerShell commands work?
$WIAdialog = New-Object -ComObject "WIA.CommonDialog"
$Device = $WIAdialog.ShowSelectDevice()
$i=$WIAdialog.ShowAcquireImage()
$i.SaveFile("$pwd\test.$($i.fileExtension)")
Is it that only the API doesn't work for cameras, while the Scripting Model does?

How to make scheduled process run as the current user?

I schedule my application in the task scheduler using the ITask class incorporated with the winapi.
I have this piece of code: dwTask->SetAccountInformation(L"", NULL);
The first parameter requires the username of the user to run the task.
By setting it to blank it runs the task as a NTAUTHORITY/SYSTEM service and therefore I run into spikes in the system where when I run commands in that task it doesnt appear on the screen (I want to fix this, as I'd like to keep NTAUTHORITY/SYSTEM privileges with my application -> see my last question: Task Scheduler WorkItem Not Running)
The question for this post is; How can I set the first parameter to the current user that is logged in? I tried to use GetUserName but the first parameter is a WIDE CHAR array data type. I tried to use GetUserNameW but the program still failed to compile due to unknown errors. Has anyone been able to set their scheduled task as the current user? Thanks!
EDIT
Okay! I added the GetUserNameW as suggested into my code. Then I linked it to the first parameter of SetAccountInformation. There are no errors compile time. After I run the program by double clicking it, it doesnt add the process as a task. Clearly it didn't work. Here is the code that I am using...
static bool AddProcessAsTask()
{
LPWSTR uname=L"";
DWORD size = 1024;
ITask *pITask;
HRESULT hr = S_OK;
LPCWSTR pwszTaskName;
ITaskScheduler *pITS;
LPCWSTR pwszApplicationName;
hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance
(
CLSID_CTaskScheduler,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITaskScheduler,
(void **) &pITS
);
if (FAILED(hr))
{
CoUninitialize();
return FALSE;
}
}
else
{
return FALSE;
}
pwszTaskName = L"AV_Updater Watchdog";
hr = pITS->NewWorkItem
(
pwszTaskName,
CLSID_CTask,
IID_ITask,
(IUnknown**)&pITask
);
if (FAILED(hr))
{
CoUninitialize();
return FALSE;
}
pwszApplicationName = L"C:\\Windows\\watchdog.exe";
hr = pITask->SetApplicationName(pwszApplicationName);
if (FAILED(hr))
{
pITS->Release();
pITask->Release();
CoUninitialize();
return FALSE;
}
GetUserNameW(uname, &size);
pITask->SetAccountInformation(uname, NULL);
pITask->SetFlags(TASK_FLAG_RUN_ONLY_IF_LOGGED_ON);
pITS->AddWorkItem(pwszTaskName, pITask);
pITS->Release();
hr = pITask->Run();
if (FAILED(hr))
{
pITask->Release();
CoUninitialize();
return FALSE;
}
pITask->Release();
CoUninitialize();
return TRUE;
}

Decide on allocator with transinplacefilter

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.

Capture preview to Enhanced video renderer

I am trying to basically render a preview from a capture card (720p) from a PS3 to the enhanced video render.
Ideally, I would like something like this:
I used to do this:
hr = m_pCapture->RenderStream (&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, m_pSrcFilter, NULL, NULL);
But I find that it only renders to an old default renderer, which is not adequate enough to stretch the image to 1080p (image becomes pixelated). [http://msdn.microsoft.com/en-us/library/aa930715.aspx ]
I want to use the enhanced video render as the sink but I have no idea how to. I viewed the tutorials here: http://msdn.microsoft.com/en-us/library/windows/desktop/ff625867%28v=vs.85%29.aspx
And tried to put my code in but it would not render.
Here is a snippet of the code that sets the source. Assume that setResolution will set the AM_MEDIA_TYPE format and that getVideoSourceByKeyword will get the AVermedia capture card device.
HRESULT DShowPlayer::SetPreviewDevice(PCWSTR keyname)
{
IBaseFilter *pSource = NULL;
// Create a new filter graph. (This also closes the old one, if any.)
HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pCapture));
if (FAILED(hr))
{
goto done;
}
hr = InitializeGraph();
if (FAILED(hr))
{
goto done;
}
// Add the source filter to the graph.
hr = getVideoSourceByKeyword(keyname, &pSource);
if (FAILED(hr))
{
goto done;
}
hr = m_pGraph->AddFilter(pSource, L"Source filter");
if (FAILED(hr))
{
goto done;
}
setResolution(pSource, 1280, 720);
// Try to render the streams.
hr = RenderStreams(pSource);
if (FAILED(hr))
{
goto done;
}
hr = m_pControl->Run();
done:
if (FAILED(hr))
{
TearDownGraph();
}
SafeRelease(&pSource);
return hr;
}
When the code runs RenderStreams, this is the code (from http://msdn.microsoft.com/en-us/library/windows/desktop/ff625878%28v=vs.85%29.aspx):
// Enumerate the pins on the source filter.
hr = pSource->EnumPins(&pEnum);
if (FAILED(hr))
{
goto done;
}
// Loop through all the pins
IPin *pPin;
while (S_OK == pEnum->Next(1, &pPin, NULL))
{
PIN_INFO pInfo;
pPin->QueryPinInfo(&pInfo);
// Try to render this pin.
// It's OK if we fail some pins, if at least one pin renders.
HRESULT hr2 = pGraph2->RenderEx(pPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
pPin->Release();
if (SUCCEEDED(hr2))
{
bRenderedAnyPin = TRUE;
}
}
In visual studio I debugged at the pin to get the source name ("Capture" pin name of the AVermedia capture card). It said it was successful to attach to the render at RenderEx however at
hr = m_pControl->Run();
It fails and there error is device is not connected.
I also tried to get the EVR renderer directly and tried to render the stream:
IBaseFilter* render;
m_pVideo->getRender(&render);
m_pGraph->AddFilter(render, L"EVR Filter");
hr = m_pCapture->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pSource, NULL, render);
if (FAILED(hr))
{
goto done;
}
But it fails and says that VFW_E_NOT_IN_GRAPH.
What I am asking: I am still pretty new at learning Directshow and I would like to be able to preview the capture card with EVR. I found no comprehensive tutorials or source code to do this. If you need anymore information, I can add more.
Thanks in advance.
EVR can be used programmatically very much the same way as VMR-7/9. The only difference is that EVR needs "windowless" mode, while earlier renderers supported also "windowed" mode where you need minimal initialization of the renderer.
I suppose you can see video on EVR in GraphEdit? You should be able to do so, just use Preview pin, not Capture. Or, connect Capture through Smart Tee filter and its preview output.
The error codes suggest that you don't build graph correctly. In particular, VFW_E_NOT_IN_GRAPH says your filter is not in graph and hence invalid argument. You don't need to use getRender, just CoCreateInstance the EVR the usual and straightforward way. At the first moment you get an error you are interested in putting everything on hold and reviewing the filter graph topology you have at the moment.
Windows SDK samples contain \Samples\multimedia\directshow\vmr9\windowless which shows VMR-9 in windowless mode, this is supposedly the closest starting point to just switch from VMR-9 to EVR.

DirectShow CLR having issue with global variables

I am trying to code up GMFBridge and DirectShow in CLR C++. I am trying to compare its performance against the GMFBridgeLib and the DirectShowLib in the same solution to see which is more efficient.
Right now I am following the GMFBridge source code for setting up C++ capture. One issue I am having is in objects that need to be global so that they can be accessed across the GUI buttons. The GMFBridge code does that as follows:
private:
IGMFBridgeControllerPtr m_pBridge;
that is then used in the setup code as follows:
HRESULT hr = m_pBridge.CreateInstance(__uuidof(GMFBridgeController));
if (FAILED(hr))
{
return hr;
}
// init to video-only, in discard mode (ie when source graph
// is running but not connected, buffers are discarded at the bridge)
hr = m_pBridge->AddStream(true, eMuxInputs, true);
My current problem is that CLR states that any global has to be a pointer of some form, * or ^ depending on managed or unmanaged. It will not just let me add in a global variable such as the GMFBridge source code does. If I create a pointer:
IGMFBridgeControllerPtr* pBridge2;
and try to use that in my GUI code:
(*pBridge2).CreateInstance(__uuidof(GMFBridgeController));
(*pBridge2).AddStream(true, eMuxInputs, true);
It does compile, but when i run it, the code crashes with
An unhandled exception of type 'System.NullReferenceException' occurred in Program.exe.
Addidional information: Object reference not set to an instance of an object.
on the block of code
void _Release() throw()
{
if (m_pInterface != NULL) { <--------------
m_pInterface->Release();
}
}
in comip.h line 823 called from:
HRESULT CreateInstance(const CLSID& rclsid, IUnknown* pOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) throw()
{
HRESULT hr;
_Release();
if (dwClsContext & (CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER)) { <----------
IUnknown* pIUnknown;
hr = CoCreateInstance(rclsid, pOuter, dwClsContext, __uuidof(IUnknown), reinterpret_cast<void**>(&pIUnknown));
if (SUCCEEDED(hr)) {
hr = OleRun(pIUnknown);
if (SUCCEEDED(hr)) {
hr = pIUnknown->QueryInterface(GetIID(), reinterpret_cast<void**>(&m_pInterface));
}
pIUnknown->Release();
}
}
else {
hr = CoCreateInstance(rclsid, pOuter, dwClsContext, GetIID(), reinterpret_cast<void**>(&m_pInterface));
}
if (FAILED(hr)) {
// just in case refcount = 0 and dtor gets called
m_pInterface = NULL;
}
return hr;
}
comip.h line 626 called from this line of code
(*pBridge2).CreateInstance(__uuidof(GMFBridgeController));
the only thing that seems to work is creating a local variable that is not a point object, but then i cant set it to a global, or use it across GUI objects.
if I make it local:
IGMFBridgeControllerPtr pBridge;
pBridge.CreateInstance(__uuidof(GMFBridgeController));
that works.
The problem seems to be that you do not assign anything to the pointer you declare:
IGMFBridgeControllerPtr* pBridge2;
You have to do something like:
pBridge2 = &m_pBridge;
Or just skip the use of pBridge2 completely and use &m_pBridge instead.