How to detect if a Microphone is present - vb6

I just had a very long tech support call because a customer didn't have a Mic on their laptop. (Stupid me: they said they'd used the mic earlier and I have never heard of a laptop not having a Mic).
I'm wondering if there is a way to detect whether there is a Microphone (recording capability) on Windows XP, Vista, 7.
(I've got error handling enabled and it logs the error and then exits the Function but the app just crashes on Windows 7 if there's no Microphone. )

I'd use IMMDeviceEnumerator::GetDefaultAudioEndpoint - this returns the default audio device for the specified role and data flow.
In particular, you would use:
CComPtr<IMMDeviceEnumerator> pEnumerator;
CComPtr<IMMDevice> pDevice;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
CLSCTX_ALL, IID_PPV_ARGS(&pEnumerator));
if (SUCCEEDED(hr))
{
hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
}
if (!pDevice || hr == ERROR_NOT_FOUND)
{
// no microphone
}

Check out System Tray Audio Device Switcher
In this VB source code you will an example on how to enumerate audio I/O devices.

in C++
#include "stdafx.h"
#include "Mmdeviceapi.h"
#include <atlbase.h>
int _tmain(int argc, _TCHAR* argv[])
{
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CComPtr<IMMDeviceEnumerator> pEnumerator = NULL;
CComPtr<IMMDevice> pDevice;
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
HRESULT hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
if (FAILED(hr))
{
printf("failed");
}
else
{
hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
if (!pDevice || hr == ERROR_NOT_FOUND)
{
printf("no microphone");
}
else
{
printf("microphone present");
}
}
return 0;
}

I think the only way you will be able to do this in VB 6 is through Direct X:
http://msdn.microsoft.com/en-us/library/bb318770(VS.85).aspx
You can check this out:
http://msdn.microsoft.com/en-us/library/bb280815(VS.85).aspx
CaptureDevices Collection Class (Microsoft.DirectX.DirectSound)
http://msdn.microsoft.com/en-us/library/ms810619.aspx
you can also call dxdiag..

Related

How can I programmatically set the default input and output audio device for an application?

If I go to Settings on a Windows 10 (1803) computer, I have access to a page ("App Volume and Device Preferences") that lets me set the default input and output device for a running application.
How can I set these options programmatically?
Related:
Set audio endpoint devices application specific (programmatically)Seems to refer to a more specific problem, and is unanswered.
Controlling “App volume and device preferences” menu, from settings, with python 3.6, or any language(Windows). Automatic App audio device switchingToo broad, wrong site.
IAudioSessionControl2 and related familyAllows reading the device and setting volume and mute, but doesn't seem to allow changing the device
GitHub issue page for SoundSwitch also looking for APIImplies API is undocumented by design (default device being controlled by user)
Here you can enumerate all the playback devices
#include <windows.h>
#include <mmsystem.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "Winmm.lib")
int main()
{
int nSoundCardCount = waveOutGetNumDevs();
for (int i = 0; i < nSoundCardCount; i++)
{
WAVEOUTCAPS woc;
waveOutGetDevCaps(i, &woc, sizeof(woc));
cout << woc.szPname << endl;
}
system("pause");
return 0;
}
Here you need to use PolicyConfig.h and SetDefaultAudioPlaybackDevice to add .h files and interfaces. Refer to this project
1.Add the header file PolicyConfig.h
2.Add the head file and interface.
#include "Mmdeviceapi.h"
#include "PolicyConfig.h"
#include "Propidl.h"
#include "Functiondiscoverykeys_devpkey.h"
HRESULT SetDefaultAudioPlaybackDevice( LPCWSTR devID )
{
IPolicyConfigVista *pPolicyConfig;
ERole reserved = eConsole;
HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient),
NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID *)&pPolicyConfig);
if (SUCCEEDED(hr))
{
hr = pPolicyConfig->SetDefaultEndpoint(devID, reserved);
pPolicyConfig->Release();
}
return hr;
}
3.Use the above interface to write a function to set the default output device.
It's MFC Project. Maybe you need to change.
Which output device needs to be set, you can modify the content of the macro yourself.
I get the name of output device using waveOutGetDevCaps()
//Set the default audio playback device
#define DEF_AUDIO_NAME _T("Speakers (2- Logitech USB Heads") //modify it, my device is Speakers (2- Logitech USB Heads
void InitDefaultAudioDevice()
{
HRESULT hr = CoInitialize(NULL);
if (SUCCEEDED(hr))
{
IMMDeviceEnumerator *pEnum = NULL;
// Create a multimedia device enumerator.
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnum);
if (SUCCEEDED(hr))
{
//Determine if it is the default audio device
bool bExit = false;
IMMDevice *pDefDevice = NULL;
hr = pEnum->GetDefaultAudioEndpoint(eRender, eMultimedia,&pDefDevice);
if (SUCCEEDED(hr))
{
IPropertyStore *pStore;
hr = pDefDevice->OpenPropertyStore(STGM_READ, &pStore);
if (SUCCEEDED(hr))
{
PROPVARIANT friendlyName;
PropVariantInit(&friendlyName);
hr = pStore->GetValue(PKEY_Device_FriendlyName, &friendlyName);
if (SUCCEEDED(hr))
{
CString strTmp = friendlyName.pwszVal;
if (strTmp.Find(DEF_AUDIO_NAME) != -1)
{
bExit = true;
}
PropVariantClear(&friendlyName);
}
pStore->Release();
}
pDefDevice->Release();
}
if (bExit)
{
pEnum->Release();
return;
}
IMMDeviceCollection *pDevices;
// Enumerate the output devices.
hr = pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
if (SUCCEEDED(hr))
{
UINT count;
pDevices->GetCount(&count);
if (SUCCEEDED(hr))
{
for (int i = 0; i < count; i++)
{
bool bFind = false;
IMMDevice *pDevice;
hr = pDevices->Item(i, &pDevice);
if (SUCCEEDED(hr))
{
LPWSTR wstrID = NULL;
hr = pDevice->GetId(&wstrID);
if (SUCCEEDED(hr))
{
IPropertyStore *pStore;
hr = pDevice->OpenPropertyStore(STGM_READ, &pStore);
if (SUCCEEDED(hr))
{
PROPVARIANT friendlyName;
PropVariantInit(&friendlyName);
hr = pStore->GetValue(PKEY_Device_FriendlyName, &friendlyName);
if (SUCCEEDED(hr))
{
// if no options, print the device
// otherwise, find the selected device and set it to be default
CString strTmp = friendlyName.pwszVal;
if (strTmp.Find(DEF_AUDIO_NAME) != -1)
{
SetDefaultAudioPlaybackDevice(wstrID);
bFind = true;
}
PropVariantClear(&friendlyName);
}
pStore->Release();
}
}
pDevice->Release();
}
if (bFind)
{
break;
}
}
}
pDevices->Release();
}
pEnum->Release();
}
}
CoUninitialize();
}
This sample can only change the output of Master volume. I don't know whether it can meet your requirements? If you need to change other apps, you have to explore for a while.
So I have been using SoundVolumeView for a while that let me mute and unmute my mic for meeting with a command line and I have discovered recently (because of OBS and monitoring audio) that it can also change device for an app or global default device
http://www.nirsoft.net/utils/sound_volume_view.html
And using /SetDefault and /SetAppDefault as shown in the doc example to the bottom of the page
I have put that in a batch script and bind a macro to my keyboard and it's doing a good job so far :)

Windows Biometric Framework fail

My friend asked me to write a simple program that captures a fingerprint from the built-in reader on a computer and prints out some kind of identifier. I can choose operating system myself, like a laptop with Windows or Linux, or an Android phone.
I thought that would be simple, surely there are many API:s for this, and I noticed that Microsoft themselves actually provides an API for it. Since I can log into my win10 laptop with the fingerprint reader, I know that the reader works.
For some reason the example that Microsoft themselves provide in their documention does not work for me. https://learn.microsoft.com/en-us/windows/desktop/api/Winbio/nf-winbio-winbiocapturesample
I suppose that the people writing those pages forgot to mention some important aspect or step, perhaps there is a way to add permission somewhere in Visual Studio.
After rewriting and trying many things, at least I get ONE step further in the process, but it still fails.
Here is the current version
#include "pch.h"
#include <iostream>
#include "Windows.h"
#include "Stdio.h"
#include "Conio.h"
#include "Winbio.h"
HRESULT CaptureSample();
void capture(WINBIO_SESSION_HANDLE sessionHandle, int flag);
int main()
{
std::cout << "Hello World!\n";
HRESULT x = CaptureSample();
}
HRESULT CaptureSample()
{
HRESULT hr = S_OK;
WINBIO_SESSION_HANDLE sessionHandle = NULL;
WINBIO_REJECT_DETAIL rejectDetail = 0;
// Connect to the system pool.
hr = WinBioOpenSession(
WINBIO_TYPE_FINGERPRINT, // Service provider
WINBIO_POOL_SYSTEM, // Pool type
WINBIO_FLAG_DEFAULT, // Access: Capture raw data
NULL, // Array of biometric unit IDs
0, // Count of biometric unit IDs
WINBIO_DB_DEFAULT, // Default database
&sessionHandle // [out] Session handle
);
if (FAILED(hr))
{
wprintf_s(L"WinBioOpenSession failed. hr = 0x%x\n", hr);
goto e_Exit;
}
wprintf_s(L"Start my fingerprint capturing...\n");
capture(sessionHandle, WINBIO_DATA_FLAG_INTEGRITY);
capture(sessionHandle, WINBIO_DATA_FLAG_PRIVACY);
capture(sessionHandle, WINBIO_DATA_FLAG_SIGNED);
capture(sessionHandle, WINBIO_DATA_FLAG_OPTION_MASK_PRESENT);
capture(sessionHandle, WINBIO_DATA_FLAG_RAW);
capture(sessionHandle, WINBIO_DATA_FLAG_INTERMEDIATE);
capture(sessionHandle, WINBIO_DATA_FLAG_PROCESSED);
hr = WinBioEnrollCapture(sessionHandle, &rejectDetail);
wprintf_s(L"WinBioEnrollCapture hr=%x rejection = %d\n", hr, rejectDetail);
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
e_Exit:
wprintf_s(L"\n Press any key to exit...");
_getch();
return hr;
}
void capture(WINBIO_SESSION_HANDLE sessionHandle, int flag) {
WINBIO_UNIT_ID unitId = 0;
WINBIO_REJECT_DETAIL rejectDetail = 0;
PWINBIO_BIR sample = NULL;
SIZE_T sampleSize = 0;
wprintf_s(L"\n Calling WinBioCaptureSample. Flag = %d.\n", flag);
HRESULT hr = WinBioCaptureSample(
sessionHandle,
WINBIO_PURPOSE_IDENTIFY,
flag,
&unitId,
&sample,
&sampleSize,
&rejectDetail
);
if (FAILED(hr))
{
if (hr == WINBIO_E_BAD_CAPTURE)
{
wprintf_s(L"\n Bad capture; reason: %d\n", rejectDetail);
}
else if (hr == E_ACCESSDENIED)
{
wprintf_s(L"\n WinBioCaptureSample failed, access denied.");
}
else
{
wprintf_s(L"\n WinBioCaptureSample failed. hr = 0x%x\n", hr);
}
goto e_Exit;
}
wprintf_s(L"\n Swipe processed - Unit ID: %d\n", unitId);
wprintf_s(L"\n Captured %d bytes.\n", sampleSize);
e_Exit:
if (sample != NULL)
{
WinBioFree(sample);
sample = NULL;
}
}
and here is the result of running it:
Hello World!
Start my fingerprint capturing...
Calling WinBioCaptureSample. Flag = 1.
WinBioCaptureSample failed, access denied.
Calling WinBioCaptureSample. Flag = 2.
WinBioCaptureSample failed, access denied.
Calling WinBioCaptureSample. Flag = 4.
WinBioCaptureSample failed, access denied.
Calling WinBioCaptureSample. Flag = 8.
WinBioCaptureSample failed, access denied.
Calling WinBioCaptureSample. Flag = 32.
WinBioCaptureSample failed, access denied.
Calling WinBioCaptureSample. Flag = 64.
WinBioCaptureSample failed, access denied.
Calling WinBioCaptureSample. Flag = 128.
WinBioCaptureSample failed, access denied.WinBioEnrollCapture hr=8009802c rejection = 0
Press any key to exit...
What am I missing?
I think you should try using another API, though your objective is not clear here. You can check the CloudABIS™ which is superscalar, biometrics-as-a-service (BaaS) matching system for fast deployment at lower costs. The API is provided by M2SYS TEchnology and they have an vast array of hardware also.

How to access Windows.Services.Store namespace from a Win32 app converted to UWP with the "Project Centennial converter" to enable in-app purchases?

I have a native C++/MFC app that is developed in VS 2008, no .NET stuff, that I converted into a UWP app using the Project Centennial converter. So now I have an .appx package that runs in Windows 10 v 1607 as a UWP app.
My next goal is to add in-app purchase support before submission to Windows Store.
The question though is how do I access Windows.Services.Store namespace from a pure Win32 app from a native C or C++ code?
Use WRL. Here's an example on how to purchase an in app purchase:
#include <windows.h>
#include <Windows.Services.Store.h>
#include <wrl.h>
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Services::Store;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
#define CheckHr(hr) do { if (FAILED(hr)) __debugbreak(); } while (false)
const wchar_t kItemFriendlyName[] = L"10 coins";
const wchar_t kItemStoreId[] = L"ten_coins";
void OnPurchaseOperationDone(IAsyncOperation<StorePurchaseResult*>* operation, AsyncStatus status);
void Purchase10Coins()
{
ComPtr<IStoreContextStatics> storeContextStatics;
auto hr = RoGetActivationFactory(HStringReference(L"Windows.Services.Store.StoreContext").Get(), __uuidof(storeContextStatics), &storeContextStatics);
CheckHr(hr);
ComPtr<IStoreContext> storeContext;
hr = storeContextStatics->GetDefault(&storeContext);
CheckHr(hr);
ComPtr<IStorePurchasePropertiesFactory> purchasePropertiesFactory;
hr = RoGetActivationFactory(HStringReference(L"Windows.Services.Store.StorePurchaseProperties").Get(), __uuidof(purchasePropertiesFactory), &purchasePropertiesFactory);
CheckHr(hr);
ComPtr<IStorePurchaseProperties> purchaseProperties;
hr = purchasePropertiesFactory->Create(HStringReference(kItemFriendlyName).Get(), &purchaseProperties);
CheckHr(hr);
ComPtr<IAsyncOperation<StorePurchaseResult*>> purchaseOperation;
hr = storeContext->RequestPurchaseWithPurchasePropertiesAsync(HStringReference(kItemStoreId).Get(), purchaseProperties.Get(), &purchaseOperation);
CheckHr(hr);
// Change the following line to call Callback<IAsyncOperationCompletedHandler<StorePurchaseResult*>> if you want the callback to happen back on the UI thread
// Implementing FtmBase allows it to fire on the thread the operation finished
auto onCompletedCallback = Callback<Implements<RuntimeClassFlags<ClassicCom>, IAsyncOperationCompletedHandler<StorePurchaseResult*>, FtmBase>>(
[](IAsyncOperation<StorePurchaseResult*>* operation, AsyncStatus status)
{
OnPurchaseOperationDone(operation, status);
return S_OK;
});
hr = purchaseOperation->put_Completed(onCompletedCallback.Get());
CheckHr(hr);
}
void OnPurchaseOperationDone(IAsyncOperation<StorePurchaseResult*>* operation, AsyncStatus status)
{
if (status != AsyncStatus::Completed)
{
// It failed for some reason. Find out why.
ComPtr<IAsyncInfo> asyncInfo;
auto hr = operation->QueryInterface(__uuidof(asyncInfo), &asyncInfo);
CheckHr(hr);
HRESULT errorCode;
hr = asyncInfo->get_ErrorCode(&errorCode);
CheckHr(hr);
// Do something with the errorCode
// Return once error is handled
return;
}
ComPtr<IStorePurchaseResult> purchaseResult;
auto hr = operation->GetResults(&purchaseResult);
CheckHr(hr);
StorePurchaseStatus purchaseStatus;
hr = purchaseResult->get_Status(&purchaseStatus);
CheckHr(hr);
switch (purchaseStatus)
{
case StorePurchaseStatus_Succeeded:
case StorePurchaseStatus_AlreadyPurchased:
// Success. Product was purchased
break;
case StorePurchaseStatus_NotPurchased:
// User canceled the purchase
break;
case StorePurchaseStatus_NetworkError:
// The device could not reach windows store
break;
case StorePurchaseStatus_ServerError:
// Something broke on the server
break;
}
}
Here's how to check if application is on trial:
void CheckIsTrial(std::function<void(bool)> onCompleted)
{
ComPtr<IStoreContextStatics> storeContextStatics;
auto hr = RoGetActivationFactory(HStringReference(L"Windows.Services.Store.StoreContext").Get(), __uuidof(storeContextStatics), &storeContextStatics);
CheckHr(hr);
ComPtr<IStoreContext> storeContext;
hr = storeContextStatics->GetDefault(&storeContext);
CheckHr(hr);
ComPtr<IAsyncOperation<StoreAppLicense*>> getLicenseOperation;
hr = storeContext->GetAppLicenseAsync(&getLicenseOperation);
CheckHr(hr);
hr = getLicenseOperation->put_Completed(Callback<Implements<RuntimeClassFlags<ClassicCom>, IAsyncOperationCompletedHandler<StoreAppLicense*>, FtmBase>>(
[onCompleted{ std::move(onCompleted) }](IAsyncOperation<StoreAppLicense*>* operation, AsyncStatus status)
{
if (status != AsyncStatus::Completed)
{
// It failed for some reason. Find out why.
ComPtr<IAsyncInfo> asyncInfo;
auto hr = operation->QueryInterface(__uuidof(asyncInfo), &asyncInfo);
CheckHr(hr);
HRESULT errorCode;
hr = asyncInfo->get_ErrorCode(&errorCode);
CheckHr(hr);
// Do something with the errorCode
// Return once error is handled
return S_OK;
}
ComPtr<IStoreAppLicense> appLicense;
auto hr = operation->GetResults(&appLicense);
CheckHr(hr);
boolean isActive, isTrial = false;
hr = appLicense->get_IsActive(&isActive);
CheckHr(hr);
if (isActive)
{
hr = appLicense->get_IsTrial(&isTrial);
CheckHr(hr);
}
onCompleted(static_cast<bool>(isActive));
return S_OK;
}).Get());
CheckHr(hr);
}
See here: https://msdn.microsoft.com/en-us/library/windows/apps/Windows.Services.Store.StoreContext.aspx
It states:
Note  In a Windows desktop application that uses the Desktop Bridge,
you must add some additional code to configure the StoreContext object
before your app can use this object. For more information, see Using
the StoreContext class in a desktop application that uses the Desktop
Bridge.
https://msdn.microsoft.com/windows/uwp/monetize/in-app-purchases-and-trials#desktop
With the following changes, this compiled and worked for me:
1) #include <utility.h>
2) write an onCompleted handler:
void onCompleted(bool bActiveLicense)
{
// App has active license or not
}
3) Change capture as follows:
[=, onCompleted{ std::move(onCompleted) }]

Using IShellDispatch2->ShellExecute for launching a non-elevated process from an elevated process

I have the following code (main part taken from MS SDK v7.1 Sample code, which demonstrates how to start an non-elevated process from an elevated one)-
The elevated and non-elevated process will be started on an (unsupervised) server, so user interaction is a no-go (except for the configuring part, if needed, of course).
The problem is, that the non-elevated process started through IShellDispatch2->ShellExecute is still elevated (expected was to be non-elevated).
This was confirmed by using IsUserAnAdmin() API.
Any ideas why the process created through ShellExecute() does have still elevated rights?
Some more relevant details: on my machine UAC is disabled.
The VS 2013 based application is manifested:
)
(manifesting can be disabled with /MANIFEST:no linker flag, if it will help in solving this).
I'm compiling it on Windows 7 x64 using VS 2013.
#include <shlwapi.h>
#include <shlobj.h>
#include <comutil.h>
#pragma comment(lib, "shlwapi.lib")
// link with (at least) OleAut32.lib shlwapi.lib comsupp.lib shell32.lib uuid.lib
// sorry for the bad formatting
int main(void)
{
std::wstring processName(L"myapp.exe"), processParams(L"-myAppParam");
LPWSTR processNamePtr = const_cast<LPWSTR>(processName.c_str());
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IShellView *psv;
HRESULT hr = GetShellViewForDesktop(IID_PPV_ARGS(&psv));
if (SUCCEEDED(hr))
{
IShellDispatch2 *psd;
hr = GetShellDispatchFromView(psv, IID_PPV_ARGS(&psd));
if (SUCCEEDED(hr))
{
BSTR bstrProcessName = SysAllocString(processNamePtr);
hr = bstrProcessName ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
VARIANT vtEmpty = {}; // VT_EMPTY
LPWSTR processParamsPtr = const_cast<LPWSTR>(processParams.c_str());
_bstr_t bstrProcessParams(processParamsPtr);
VARIANT varParams;
varParams.vt = VT_BSTR;
varParams.bstrVal = bstrProcessParams;
char processDir[MAX_PATH + 1];
::GetCurrentDirectory(MAX_PATH, processDir);
_bstr_t bstrProcessDir(processDir);
VARIANT varProcessDir;
varProcessDir.vt = VT_BSTR;
varProcessDir.bstrVal = bstrProcessDir;
_bstr_t bstrOperation("open");
VARIANT varOperation;
varOperation.vt = VT_BSTR;
varOperation.bstrVal = bstrOperation;
hr = psd->ShellExecute(bstrProcessName,
varParams, // reinterpret_cast<_variant_t&>(bstrProcessParams),
varProcessDir,
varOperation,
vtEmpty);
SysFreeString(bstrProcessName);
SysFreeString(bstrProcessParams);
}
psd->Release();
}
psv->Release();
}
CoUninitialize();
}
} // main()
// use the shell view for the desktop using the shell windows automation to find the
// desktop web browser and then grabs its view
//
// returns:
// IShellView, IFolderView and related interfaces
HRESULT GetShellViewForDesktop(REFIID riid, void **ppv)
{
*ppv = NULL;
IShellWindows *psw;
HRESULT hr = CoCreateInstance(CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER, IID_PPV_ARGS(&psw));
if (SUCCEEDED(hr))
{
HWND hwnd;
IDispatch* pdisp;
VARIANT vEmpty = {}; // VT_EMPTY
if (S_OK == psw->FindWindowSW(&vEmpty, &vEmpty, SWC_DESKTOP, (long*)&hwnd, SWFO_NEEDDISPATCH, &pdisp))
{
IShellBrowser *psb;
hr = IUnknown_QueryService(pdisp, SID_STopLevelBrowser, IID_PPV_ARGS(&psb));
if (SUCCEEDED(hr))
{
IShellView *psv;
hr = psb->QueryActiveShellView(&psv);
if (SUCCEEDED(hr))
{
hr = psv->QueryInterface(riid, ppv);
psv->Release();
}
psb->Release();
}
pdisp->Release();
}
else
{
hr = E_FAIL;
}
psw->Release();
}
return hr;
} // GetShellViewForDesktop()
// From a shell view object gets its automation interface and from that gets the shell
// application object that implements IShellDispatch2 and related interfaces.
HRESULT GetShellDispatchFromView(IShellView *psv, REFIID riid, void **ppv)
{
*ppv = NULL;
IDispatch *pdispBackground;
HRESULT hr = psv->GetItemObject(SVGIO_BACKGROUND, IID_PPV_ARGS(&pdispBackground));
if (SUCCEEDED(hr))
{
IShellFolderViewDual *psfvd;
hr = pdispBackground->QueryInterface(IID_PPV_ARGS(&psfvd));
if (SUCCEEDED(hr))
{
IDispatch *pdisp;
hr = psfvd->get_Application(&pdisp);
if (SUCCEEDED(hr))
{
hr = pdisp->QueryInterface(riid, ppv);
pdisp->Release();
}
psfvd->Release();
}
pdispBackground->Release();
}
return hr;
} // GetShellDispatchFromView()
On my machine UAC is disabled.
Right there is your problem. By disabling UAC you stop the system from creating processes as standard user. If the logged on user is an administrator, then processes run with a fully privileged token.
With UAC disabled, the explorer process that runs the shell is started using the full token of the interactive user, which it seems is the token of an admin user. And so when the shell starts a new process with IShellDispatch2->ShellExecute that new process runs under the same user token.
You'll need to enable UAC to allow the system to create processes with standard user tokens. When you enable UAC, the shell's explorer process will run as standard user and so IShellDispatch2->ShellExecute will create new processes running as standard user.

MFCreateDeviceSource returns error 0x80070002 for webcam

I'm currently trying to implement webcam video capture into a project.
First I was trying Direct Show, which worked on one computer but not on another.
So now I'm trying Media Foundation.
I mostly followed the examples provided by Microsoft.
Upon calling MFCreateDeviceSource() I receive the error code 0x80070002 (-2147024894).
This error code is not really documented in this context.
I get this result for three separate webcams of two different types of webcam, all of which work with other programs using Direct Show (eg VLC).
Thank you for any hint.
Operating system: Windows7
SDK: Windows SDK v7.1
IDE: Visual Studio 2008
Code:
// MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET) -- is called successfully in a previous function)
IMFMediaSource* media_source = 0;
IMFSourceReader* source_reader = 0;
IMFAttributes* pAttributes = 0;
hr = MFCreateAttributes(&pAttributes, 2);
if (FAILED(hr)) {
return false;
}
// Set the device type to video.
hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
if (FAILED(hr)) {
return false;
}
// Set the symbolic link.
hr = pAttributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,(LPCWSTR)&device_name);
if (FAILED(hr)) {
return false;
}
// Create device source interface
hr = MFCreateDeviceSource(pAttributes, &media_source);
if (FAILED(hr)) {
// HERE I RECEIVE 0x80070002
return false;
}
// Create source reader
IMFAttributes* attr;
MFCreateAttributes(&attr,1);
attr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING,1);
hr = MFCreateSourceReaderFromMediaSource(media_source,attr,&source_reader);
if(FAILED(hr)) {
return false;
}
I edited your code to actually get the device name through enumerating capture devices present in the system and it worked fine, it lacks proper error checking, but I suggest you try the same, enumerate the devices and get the symbolic link from the actual device to see if that is the issue:
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#pragma comment(lib, "mfplat.lib")
#pragma comment(lib, "mf.lib")
#pragma comment(lib, "mfreadwrite.lib")
int main(int argc, char** argv)
{
HRESULT hr;
hr = ::CoInitialize(NULL);
if (FAILED(hr))
abort();
hr = ::MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
if (FAILED(hr))
abort();
IMFMediaSource* media_source = 0;
IMFSourceReader* source_reader = 0;
IMFAttributes* pAttributes = 0;
hr = MFCreateAttributes(&pAttributes, 2);
if (FAILED(hr))
abort();
// Set the device type to video.
hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
if (FAILED(hr))
abort();
UINT32 count;
IMFActivate **ppDevices = NULL;
hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
if (FAILED(hr))
abort();
if (count == 0)
abort();
// Create the media source object.
IMFMediaSource *pSource = NULL;
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(&pSource));
if (FAILED(hr))
abort();
pSource->AddRef();
IMFAttributes* pSourceAttributes;
hr = pSource->QueryInterface(__uuidof(IMFAttributes), (void**)&pSourceAttributes);
if (FAILED(hr))
abort();
const size_t nDeviceNameSize = 1024;
LPWSTR pDeviceName = new WCHAR[nDeviceNameSize];
UINT32 nActualBufferSize;
hr = pSourceAttributes->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, pDeviceName, nDeviceNameSize, &nActualBufferSize);
if (FAILED(hr))
abort();
// Set the symbolic link.
hr = pAttributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,pDeviceName);
if (FAILED(hr))
abort();
// Create device source interface
hr = MFCreateDeviceSource(pAttributes, &media_source);
if (FAILED(hr)) // HERE I RECEIVE 0x80070002
abort();
// Create source reader
IMFAttributes* attr;
MFCreateAttributes(&attr,1);
attr->SetUINT32(MF_SOURCE_READER_ENABLE_VIDEO_PROCESSING,1);
hr = MFCreateSourceReaderFromMediaSource(media_source,attr,&source_reader);
if(FAILED(hr))
abort();
::CoUninitialize();
return EXIT_SUCCESS;
}
Hope this helps.

Resources