I'm trying to get the LegacyIAccessible values marked on the picture below:
So far I have been able to read these:
#include <UIAutomation.h> // UIAutomation includes.
#include <UIAutomationCore.h>
#include <UIAutomationClient.h>
#include "Oleacc.h"
#include "atlbase.h"
#pragma comment(lib,"Oleacc.lib")
LPCWSTR Acc(HWND hwnd) {
CComPtr<IUIAutomation> pUIAutomation;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation), (void**)&pUIAutomation);
if (SUCCEEDED(hr))
{
IUIAutomationElement* pRoot = NULL;
hr = pUIAutomation->ElementFromHandle(hwnd, &pRoot);
if (SUCCEEDED(hr))
{
IUIAutomationElementArray* pElementArray = nullptr;
IUIAutomationCondition* pCondition;
hr = pUIAutomation->CreateTrueCondition(&pCondition);
IUIAutomationElementArray* pEA;
IUIAutomationCacheRequest* pCacheRequest;
hr = pUIAutomation->CreateCacheRequest(&pCacheRequest);
pCacheRequest->AddProperty(UIA_NamePropertyId);
pCacheRequest->AddProperty(UIA_AutomationIdPropertyId);
pCacheRequest->AddProperty(UIA_LocalizedControlTypePropertyId);
//pCacheRequest->put_TreeScope((TreeScope)(TreeScope_Element | TreeScope_Descendants));
hr = pRoot->FindAllBuildCache(TreeScope_Descendants, pCondition, pCacheRequest, &pEA);
if (SUCCEEDED(hr))
{
int nNbItems = 0;
hr = pEA->get_Length(&nNbItems);
for (int nItem = 0; nItem <= nNbItems - 1; nItem++)
{
IUIAutomationElement* pElement = nullptr;
hr = pEA->GetElement(nItem, &pElement);
BSTR name;
pElement->get_CurrentName(&name);
UIA_HWND uia_hwnd = nullptr;
pElement->get_CurrentNativeWindowHandle(&uia_hwnd);
BSTR classname = nullptr;
pElement->get_CurrentClassName(&classname);
RECT rect;
pElement->get_CurrentBoundingRectangle(&rect);
pElement->Release();
}
}
pCacheRequest->Release();
pCondition->Release();
pRoot->Release();
}
//pUIAutomation->Release(); // <- needed?
}
CoUninitialize();
return (L"SUCCEEDED");
}
When I try to call for:
DWORD CurrentState;
pElement->get_CurrentState(&CurrentState);
I get this error: class "IUIAutomationElement" has no member "get_CurrentState".
I think I should be using IUIAutomationLegacyIAccessiblePattern but I couldn't figure out how to properly rewrite the function using it.
Also, what's the difference between the functions with and without 'cache'?
A example of GetCurrentPatternAs. Caching is not involved.
#include <Windows.h>
#include <UIAutomation.h>
#include <wchar.h>
int Element(IUIAutomation* automation)
{
// Get the element under the cursor
// Use GetPhysicalCursorPos to interact properly with
// High DPI
POINT pt;
GetPhysicalCursorPos(&pt);
IUIAutomationElement* pAtMouse;
HRESULT hr = automation->ElementFromPoint(pt, &pAtMouse);
if (FAILED(hr))
return hr;
// Get the element's name and print it
BSTR name;
hr = pAtMouse->get_CurrentName(&name);
if (SUCCEEDED(hr))
{
wprintf(L"Element's Name: %s \n", name);
SysFreeString(name);
//IUIAutomationValuePattern* pattern;
//pAtMouse->GetCurrentPatternAs(UIA_ValuePatternId, IID_IUIAutomationValuePattern,(void**)&pattern);
IUIAutomationLegacyIAccessiblePattern* pattern;
//pAtMouse->GetCurrentPatternAs(UIA_LegacyIAccessiblePatternId, IID_IUIAutomationLegacyIAccessiblePattern,(void**)&pattern);
pAtMouse->GetCurrentPatternAs(UIA_LegacyIAccessiblePatternId, IID_PPV_ARGS(&pattern));
//TODO
BSTR url = nullptr;
pattern->get_CurrentValue(&url);
DWORD state = 0;
pattern->get_CurrentState(&state);
BSTR elename = nullptr;
pattern->get_CurrentName(&elename);
DWORD role = 0;
pattern->get_CurrentRole(&role);
//wprintf(L"Element's ValuePattern: %s \n", url);
SysFreeString(url);
SysFreeString(elename);
}
// Get the element's Control Type (in the current languange)
// and print it
BSTR controlType;
hr = pAtMouse->get_CurrentLocalizedControlType(&controlType);
if (SUCCEEDED(hr))
{
wprintf(L"Element's Control Type: %s \n", controlType);
SysFreeString(controlType);
}
// Clean up our COM pointers
pAtMouse->Release();
return hr;
}
int main(int argc, TCHAR* argv[])
{
// Initialize COM and create the main Automation object
IUIAutomation* g_pAutomation;
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation),
(void**)&g_pAutomation);
if (FAILED(hr))
return (hr);
bool quit = false;
while (!quit)
{
SHORT leftControlMod = GetAsyncKeyState(VK_LCONTROL);
if (leftControlMod != 0)
{
Element(g_pAutomation);
}
quit = GetAsyncKeyState(VK_ESCAPE);
}
g_pAutomation->Release();
CoUninitialize();
return 0;
}
Related
I'm trying to code a C++ program to print the distinguishedName of an user in active directory. The program compiles without errors, however instantly crashes on start up. I admit that I don't know c++ very well, and I believe that the problem is somewhere there.
#include <iostream>
#include <jni.h>
#include<string.h>
#include "com_library_ldap_JNIHelper.h"
#include <iads.h>
#include <adshlp.h>
#include "activeds.h"
#include <windows.h>
#include <stdlib.h>
#include <atlbase.h>
using namespace std;
int main()
{
string username = "Admin10";
string password = "password#10";
wchar_t wName[20];
mbstowcs(wName, username.c_str(), username.length());
wchar_t wpwd[20];
mbstowcs(wpwd, password.c_str(), password.length());
//HRESULT hr = S_OK; // COM result variable
HRESULT hr;
ADS_SEARCH_COLUMN col; // COL for iterations
LPWSTR szUsername = wName; // user name
LPWSTR szPassword = wpwd; // password
// Interface Pointers.
IDirectorySearch* pDSSearch=NULL;
// Initialize COM.
//CoInitialize(0);
::CoInitialize(NULL);
// Add code to securely retrieve the user name and password or
// leave both as NULL to use the default security context.
// Open a connection with server.
hr = ADsOpenObject(L"LDAP://10.0.14.74/OU=Vimal,DC=test,DC=local",
szUsername,
szPassword,
ADS_SECURE_AUTHENTICATION,
IID_IDirectorySearch,
(void**)&pDSSearch);
string des = "description";
string name = "Name";
string dn = "distinguishedname";
string propertycheck = "(&(objectClass=user)(cn=Admin10))";
wchar_t wdes[20];
mbstowcs(wdes, des.c_str(), des.length());
LPWSTR szDes = wdes;
wchar_t wname[20];
mbstowcs(wname, name.c_str(), name.length());
LPWSTR szName = wname;
wchar_t wdn[20];
mbstowcs(wdn, dn.c_str(), dn.length());
LPWSTR szDN = wdn;
wchar_t wpc[20];
mbstowcs(wpc, propertycheck.c_str(), propertycheck.length());
LPWSTR szPC = wpc;
LPWSTR pszAttr[] = { szDes, szName, szDN };
ADS_SEARCH_HANDLE hSearch;
DWORD dwCount = 0;
DWORD dwAttrNameSize = sizeof(pszAttr) / sizeof(LPWSTR);
// Search for all objects with the 'cn' property that start with c.
hr = pDSSearch->ExecuteSearch(szPC, pszAttr, dwAttrNameSize, &hSearch);
LPWSTR pszColumn;
while (pDSSearch->GetNextRow(hSearch) != S_ADS_NOMORE_ROWS)
{
// Get the property.
hr = pDSSearch->GetColumn(hSearch, szDN, &col); // want user distinguishedname
// If this object supports this attribute, display it.
if (SUCCEEDED(hr))
{
if (col.dwADsType == ADSTYPE_CASE_IGNORE_STRING)
wprintf(L"The description property:%s\r\n", col.pADsValues->CaseIgnoreString);
pDSSearch->FreeColumn(&col);
}
else
puts("description property NOT available");
puts("------------------------------------------------");
dwCount++;
}
pDSSearch->CloseSearchHandle(hSearch);
pDSSearch->Release();
CoUninitialize();
return 0;
}
Below I add the screenshot of an error displaying in visual studio:
enter image description here
Exception thrown: read access violation.
pDSSearch was nullptr.
The above is the error message I got, but I have no idea how to trace it. Thanks in advance.
Now I find the solution to my problem. I would changed the datatype of username and password variable which is passed to ADsOpenObject function and some more changes... Below I add the complete code for the solution.
#include <iostream>
#include <jni.h>
#include<string.h>
#include <iads.h>
#include <adshlp.h>
#include "activeds.h"
#include <windows.h>
#include <stdlib.h>
#include <atlbase.h>
using namespace std;
int main()
{
string username = "username";
string password = "password";
string resDN="";
std::wstring stemp = std::wstring(username.begin(), username.end());
LPCWSTR lpszUserName = stemp.c_str();
std::wstring stemp1 = std::wstring(password.begin(), password.end());
LPCWSTR lpszPassword = stemp1.c_str();
ADS_SEARCH_COLUMN col; // COL for iterations
HRESULT hr;
string uType;
string check;
bool res = false;
// Interface Pointers.
IDirectorySearch* pDSSearch = NULL;
::CoInitialize(NULL);
hr = ADsOpenObject(L"LDAP://10.0.124.714/OU=Vimal,DC=test,DC=local",
lpszUserName,
lpszPassword,
ADS_SECURE_AUTHENTICATION,
IID_IDirectorySearch,
(void**)&pDSSearch);
std::cout << hr;
if (!SUCCEEDED(hr))
{
std::cout << "Not working!!!";
return 0;
}
if (SUCCEEDED(hr))
{
wstring des = L"description";
wstring name = L"Name";
wstring dn = L"distinguishedname";
wstring propertycheck = L"(&(objectClass=user)(cn=Vimaluser1))";
std::wstring sdes = std::wstring(des.begin(), des.end());
LPCWSTR lpszDes = sdes.c_str();
std::wstring sname = std::wstring(name.begin(), name.end());
LPCWSTR lpszName = sname.c_str();
std::wstring sdn = std::wstring(dn.begin(), dn.end());
LPCWSTR lpszDN = sdn.c_str();
std::wstring sprop = std::wstring(propertycheck.begin(), propertycheck.end());
LPCWSTR lpszProp = sprop.c_str();
LPCWSTR pszAttr[] = { lpszDes, lpszName, lpszDN };
ADS_SEARCH_HANDLE hSearch;
DWORD dwCount = 0;
DWORD dwAttrNameSize = sizeof(pszAttr) / sizeof(LPCWSTR);
hr = pDSSearch->ExecuteSearch((LPWSTR)lpszProp, (LPWSTR*)pszAttr, dwAttrNameSize, &hSearch);
LPCWSTR pszColumn;
while (pDSSearch->GetNextRow(hSearch) != S_ADS_NOMORE_ROWS)
{
// Get the property.
hr = pDSSearch->GetColumn(hSearch, (LPWSTR)lpszDN, &col); // want user distinguishedname
// If this object supports this attribute, display it.
if (SUCCEEDED(hr))
{
if (col.dwADsType == ADSTYPE_DN_STRING) {
wprintf(L"The distinguishedName property:%s\r\n", col.pADsValues->DNString);
//resDN += col.pADsValues->DNString;
}
else
std::cout << "dn not found";
pDSSearch->FreeColumn(&col);
}
else
puts("distinguishedName property NOT available");
dwCount++;
}
uType = "Success";
res = true;
pDSSearch->CloseSearchHandle(hSearch);
pDSSearch->Release();
CoUninitialize();
}
if (res == false)
uType = "Login details not found...";
std::cout << uType;
return 0;
}
So all I want in life is to have a program where I can say "Hey Computer" and it responds with "Hello". So I set myself upon the task and after some research produced the code below yet whenever I try to compile it through Visual Studio 2017 on Windows 10 I get this error: 'GetVersionExA': was declared deprecated but I don't understand because I don't call that function anywhere in my code.
#include <sphelper.h>
#include <sapi.h>
#include <iostream>
#include <string>
#include <vector>
#include <locale>
const ULONGLONG grammarId = 0;
const wchar_t* ruleName1 = L"ruleName1";
int start_listening(const std::string& word);
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command);
void get_text(ISpRecoContext* reco_context);
void check_result(const HRESULT& result);
ISpVoice * pVoice = NULL;
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
inline std::wstring s2w(const std::string &s, const std::locale &loc = std::locale())
{
typedef std::ctype<wchar_t> wchar_facet;
std::wstring return_value;
if (s.empty())
{
return return_value;
}
if (std::has_facet<wchar_facet>(loc))
{
std::vector<wchar_t> to(s.size() + 2, 0);
std::vector<wchar_t>::pointer toPtr = &to[0];
const wchar_facet &facet = std::use_facet<wchar_facet>(loc);
if (0 != facet.widen(s.c_str(), s.c_str() + s.size(), toPtr))
{
return_value = to.data();
}
}
return return_value;
}
int main(int argc, char** argv)
{
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
std::string hello = "hello";
start_listening("Hey computer");
hr = pVoice->Speak(s2w(hello).c_str(), 0, NULL);
return EXIT_SUCCESS;
}
// This function exits when the word passed as parameter is said by the user
int start_listening(const std::string& word)
{
// Initialize COM library
if (FAILED(::CoInitialize(nullptr))) {
return EXIT_FAILURE;
}
std::cout << "You should start Windows Recognition" << std::endl;
std::cout << "Just say \"" << word << "\"" << std::endl;
HRESULT hr;
ISpRecognizer* recognizer;
hr = CoCreateInstance(CLSID_SpSharedRecognizer,
nullptr, CLSCTX_ALL, IID_ISpRecognizer,
reinterpret_cast<void**>(&recognizer));
check_result(hr);
ISpRecoContext* recoContext;
hr = recognizer->CreateRecoContext(&recoContext);
check_result(hr);
// Disable context
hr = recoContext->Pause(0);
check_result(hr);
ISpRecoGrammar* recoGrammar = init_grammar(recoContext, word);
hr = recoContext->SetNotifyWin32Event();
check_result(hr);
HANDLE handleEvent;
handleEvent = recoContext->GetNotifyEventHandle();
if (handleEvent == INVALID_HANDLE_VALUE) {
check_result(E_FAIL);
}
ULONGLONG interest;
interest = SPFEI(SPEI_RECOGNITION);
hr = recoContext->SetInterest(interest, interest);
check_result(hr);
// Activate Grammar
hr = recoGrammar->SetRuleState(ruleName1, 0, SPRS_ACTIVE);
check_result(hr);
// Enable context
hr = recoContext->Resume(0);
check_result(hr);
// Wait for reco
HANDLE handles[1];
handles[0] = handleEvent;
WaitForMultipleObjects(1, handles, FALSE, INFINITE);
get_text(recoContext);
std::cout << "Hello user" << std::endl;
recoGrammar->Release();
::CoUninitialize();
system("PAUSE");
return EXIT_SUCCESS;
}
/**
* Create and initialize the Grammar.
* Create a rule for the grammar.
* Add word to the grammar.
*/
ISpRecoGrammar* init_grammar(ISpRecoContext* recoContext, const std::string& command)
{
HRESULT hr;
SPSTATEHANDLE sate;
ISpRecoGrammar* recoGrammar;
hr = recoContext->CreateGrammar(grammarId, &recoGrammar);
check_result(hr);
WORD langId = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH);
hr = recoGrammar->ResetGrammar(langId);
check_result(hr);
// TODO: Catch error and use default langId => GetUserDefaultUILanguage()
// Create rules
hr = recoGrammar->GetRule(ruleName1, 0, SPRAF_TopLevel | SPRAF_Active, true, &sate);
check_result(hr);
// Add a word
const std::wstring commandWstr = std::wstring(command.begin(), command.end());
hr = recoGrammar->AddWordTransition(sate, NULL, commandWstr.c_str(), L" ", SPWT_LEXICAL, 1, nullptr);
check_result(hr);
// Commit changes
hr = recoGrammar->Commit(0);
check_result(hr);
return recoGrammar;
}
void get_text(ISpRecoContext* reco_context)
{
const ULONG maxEvents = 10;
SPEVENT events[maxEvents];
ULONG eventCount;
HRESULT hr;
hr = reco_context->GetEvents(maxEvents, events, &eventCount);
// Warning hr equal S_FALSE if everything is OK
// but eventCount < requestedEventCount
if (!(hr == S_OK || hr == S_FALSE)) {
check_result(hr);
}
ISpRecoResult* recoResult;
recoResult = reinterpret_cast<ISpRecoResult*>(events[0].lParam);
wchar_t* text;
hr = recoResult->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, FALSE, &text, NULL);
check_result(hr);
CoTaskMemFree(text);
}
void check_result(const HRESULT& result)
{
if (result == S_OK) {
return;
}
std::string message;
switch (result) {
case E_INVALIDARG:
message = "One or more arguments are invalids.";
case E_ACCESSDENIED:
message = "Acces Denied.";
case E_NOINTERFACE:
message = "Interface does not exist.";
case E_NOTIMPL:
message = "Not implemented method.";
case E_OUTOFMEMORY:
message = "Out of memory.";
case E_POINTER:
message = "Invalid pointer.";
case E_UNEXPECTED:
message = "Unexpecter error.";
case E_FAIL:
message = "Failure";
default:
message = "Unknown : " + std::to_string(result);
}
throw std::exception(message.c_str());
}
It is suppressable with a pragma:
#pragma warning(disable:4996)
#include <sphelper.h>
#pragma warning(default: 4996)
GetVersionEx is being used by the header sphelper.h which you're including. It's using it to check that the function SpGetDescription() is running on Vista or later. You could probably work around this issue by targeting the 8.1 SDK version instead of 10. However, it's bad that the shipped MS SAPI API in the Windows 10 SDK is using functions which are deprecated in Windows 10.. I'd say this is a MS issue.
Alternately this would work:
#define FKG_FORCED_USAGE 1
#include <sphelper.h>
#undef FKG_FORCED_USAGE
I am trying to build my own screen reader using UIAutomation. I want my program to return the NameProperty of the element that is pointed by my cursor
This is what I have done so far; this is just sample code anyway:
#include <iostream>
#include <windows.h>
#include <UIAutomation.h>
const int MAX_WND_TEXT = 60;
IUIAutomation *automation = NULL;
BOOL InitializeUIAutomation(IUIAutomation **pAutomation)
{
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IUIAutomation), (void**)pAutomation);
return (SUCCEEDED(hr));
}
int main()
{
POINT p;
IUIAutomationElement *elem;
wchar_t wndName[MAX_WND_TEXT];
BOOL stat = InitializeUIAutomation(&automation);
while (true)
{
if (stat)
{
GetCursorPos(&p);
HRESULT hr = automation->ElementFromPoint(p, &elem);
if (SUCCEEDED(hr))
{
HRESULT hr = elem->GetCurrentPropertyValue(UIA_NamePropertyId,
(VARIANT*)wndName);
if (SUCCEEDED(hr))
std::cout << wndName << std::endl;
else
wndName[0] = '\0';
}
else
std::cout << "No element selected." << std::endl;
Sleep(100);
elem->Release();
}
}
automation->Release();
CoUninitialize();
return 0;
}
Now the problem is I can't make it to print the values I wanted. The program just output a specific hex number. And also I'm still a beginner in UIAutomation so I am still lost.
Can you help me or give me tips how to solve my problem?
Solved my problem using this code.
#include <iostream>
#include <string>
#include <Windows.h>
#include <UIAutomation.h>
BOOL InitializeUIAutomation(IUIAutomation **automation)
{
CoInitialize(NULL);
HRESULT hr = CoCreateInstance(__uuidof(CUIAutomation), NULL,
CLSCTX_INPROC_SERVER, __uuidof(IUIAutomation),
(void**)automation);
return (SUCCEEDED(hr));
}
int main()
{
IUIAutomation *automation = NULL;
IUIAutomationElement *elem = NULL;
BOOL stat = InitializeUIAutomation(&automation);
POINT mousePt;
BSTR elemName = NULL;
if (stat)
{
while(true)
{
GetCursorPos(&mousePt);
HRESULT hr = automation->ElementFromPoint(mousePt, &elem);
if (SUCCEEDED(hr) && elem != NULL)
{
elem->get_CurrentName(&elemName);
std::wstring ws(elemName, SysStringLen(elemName));
std::wcout << ws << std::endl;
}
SysFreeString(elemName);
elem->Release();
Sleep(200);
}
}
automation->Release();
CoUninitialize();
return 0;
}
The hex numbers printed was the BSTR header after all. Solve my problem by converting BSTR to wstring.
I'm writing a simple multimedia application in Visual Studio 2013 and I need to enumerate camera devices connected to my computer and create a media source object to link to one of them. I use Media Foundation SDK and tried to run the guide here: https://msdn.microsoft.com/en-us/library/windows/desktop/dd940326(v=vs.85).aspx :
#include <Mfapi.h>
#include <mfidl.h>
#include <mfobjects.h>
#include <iostream>
#pragma comment(lib, "Mfplat")
#pragma comment(lib, "Mf")
template <class T> void SafeRelease(T **ppT) {
if (*ppT) {
(*ppT)->Release();
*ppT = NULL;
}
}
HRESULT CreateVideoDeviceSource(IMFMediaSource **ppSource) {
*ppSource = NULL;
IMFMediaSource *pSource = NULL;
IMFAttributes *pAttributes = NULL;
IMFActivate **ppDevices = NULL;
// Create an attribute store to specify the enumeration parameters.
HRESULT hr = MFCreateAttributes(&pAttributes, 1);
if (FAILED(hr))
{
goto done;
}
// Source type: video capture devices
hr = pAttributes->SetGUID(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
);
if (FAILED(hr))
{
goto done;
}
// Enumerate devices.
UINT32 count;
hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
if (FAILED(hr))
{
goto done;
}
if (count == 0)
{
hr = E_FAIL;
goto done;
}
// Create the media source object.
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(&pSource));
if (FAILED(hr))
{
std::cout << "Failed to create device object" << hr <<std::endl;
goto done;
}
*ppSource = pSource;
(*ppSource)->AddRef();
DWORD chs;
(*ppSource)->GetCharacteristics(&chs);
std::cout << chs << std::endl;
done:
SafeRelease(&pAttributes);
for (DWORD i = 0; i < count; i++)
{
SafeRelease(&ppDevices[i]);
}
CoTaskMemFree(ppDevices);
SafeRelease(&pSource);
return hr;
}
int main(int argc, char* argv[]) {
IMFMediaSource* ppSource;
CreateVideoDeviceSource(&ppSource);
std::cout << "END" << std::endl;
return 0;
}
The problem is that this part of the code :
// Create the media source object.
hr = ppDevices[0]->ActivateObject(IID_PPV_ARGS(&pSource));
if (FAILED(hr))
{
goto done;
}
fails to create a media source object(the HRESULT returned is 0x800401F0 (CO_E_NOTINITIALIZED)--"CoInitialize has not been called.
"). What does the error code mean and What could be the problem causing the failure ? I'm using WIN8.1.
Com Libraries need to be initialized for each thread, through either of
CoInitialize
CoInitializeEx
OleInitialize
depending on which services are to be used in this thread.
Do this at the start of your program, for all threads that use COM, and don't forget to call the respective Uninitialize function
Here's how I obtain the PROPVARIANT structure with WASAPI API related functions:
//Pointer for stored audio stream
IAudioClient *iac = NULL;
//Endpoint device selection
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice;
IMMDeviceCollection *pCollection = NULL;
CoInitialize(NULL);
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);
//Create vector of IMMDevices
UINT endpointCount = NULL;
(*pCollection).GetCount(&endpointCount);
std::vector<IMMDevice**> IMMDevicePP; //IMMDevice seems to contain all endpoint devices, so why have a collection here?
for (UINT i = 0; i < (endpointCount); i++)
{
IMMDevice* pp = NULL;
(*pCollection).Item(i, &pp);
IMMDevicePP.assign(1, &pp);
}
UINT IMMDeviceCount = IMMDevicePP.size();
//Enumerate Properties of IMMDevices
std::vector<IPropertyStore*> IMMDeviceProperties;
for (int k = 0; k < IMMDeviceCount; k++) {
IPropertyStore* prop = NULL;
(**IMMDevicePP[k]).OpenPropertyStore(STGM_READ, &prop);
IMMDeviceProperties.assign(1, prop);
}
UINT PropertyStoreCount = IMMDeviceProperties.size();
//Find name property of device
std::vector<PROPVARIANT*> properties;
for (int i = 0; i < PropertyStoreCount; i++) {
DWORD propCount = 1;
HRESULT countResult = (*IMMDeviceProperties[i]).GetCount(&propCount);
if (countResult == S_OK) { }
else {
int x = 5;
}
for (int p = 0; p < propCount; p++) {
PROPERTYKEY key;
HRESULT keyResult = (*IMMDeviceProperties[i]).GetAt(p, &key);
HRESULT getAT;
PROPVARIANT propVari;
HRESULT propVariResult = (*IMMDeviceProperties[i]).GetValue(key, &propVari);
propVari.vt = VT_LPWSTR;
LPWSTR test = propVari.pwszVal;
//char pwszValTest;
//strcpy(&pwszValTest, propVari.pwszVal);
//WCHAR friendlyName = *propVari.pwszVal;
properties.assign(1, &propVari);
}
}
All HRESULT's return S_OK.
The resulting PROPVARIANT struct renders correctly at first glance. However, when inspecting further with VS's property watch all of the string type properties return the error reflected in the title of this question. So when I attempt to retrieve the name of my Audio Endpoint Device which is contained the the pwszVal property of my PROPVARIANT struct like so:
LPWSTR test = propVari.pwszVal;
I am unable to retrieve the desired data. I have tried copying the string with various converter methods to no avail. I know this error is on a ton of questions but I can't seem to crack this error.
Here's the doc for PROPVARIANT and its corresponding properties:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa380072(v=vs.85).aspx
In this documentation it states that "PROPVARIANT member vt is set to VT_LPWSTR" VT_LPWSTR is an enum type and corresponds to the value 31. Whereas VT_BLOB corresponds to the value 65. My vt member is being set to VT_BLOB or 65 instead of 31 or VT_LPWSTR. Why is this so? This is contradictory to the value stated in this documentation:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd370812(v=vs.85).aspx
Manually setting the vt member also does not change/fix the string reading error:
propVari.vt = VT_LPWSTR;
The PKEY_Device_FriendlyName is what I'm essentially after. Any help/tips is much appreciated.
You are not filling your vectors correctly. You are storing memory addresses of local variables, not the actual items that variables refer to.
And worse, you are using std::vector::assign() to add items. assign() replaces the entire contents of a vector with the specified value. If you have multiple devices in a collection, you will not end up with a vector of multiple devices. You should be using push_back() instead of assign().
You are making those mistakes with all of your vectors.
On a side note, you should use the -> operator instead of using (*). when calling methods of the objects. It will make the code cleaner and easier to read.
Try this instead:
//Endpoint device selection
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDeviceCollection *pCollection = NULL;
CoInitialize(NULL);
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);
pEnumerator->Release();
//Create vector of IMMDevices
std::vector<IMMDevice*> IMMDevice;
UINT endpointCount = 0;
hr = pCollection->GetCount(&endpointCount);
if (hr == S_OK) {
IMMDevice.reserve(endpointCount);
for (UINT i = 0; i < endpointCount; ++i) {
IMMDevice *pDevice = NULL;
hr = pCollection->Item(i, &pDevice);
if (hr == S_OK) {
IMMDevice.push_back(pDevice);
}
}
}
UINT IMMDeviceCount = IMMDevice.size();
pCollection->Release();
//Enumerate Properties of IMMDevices
std::vector<IPropertyStore*> IMMDeviceProperties;
IMMDeviceProperties.reserve(IMMDeviceCount);
for (int k = 0; k < IMMDeviceCount; k++) {
IPropertyStore* prop = NULL;
hr = IMMDevice[k]->OpenPropertyStore(STGM_READ, &prop);
if (hr == S_OK) {
IMMDeviceProperties.push_back(prop);
}
}
UINT PropertyStoreCount = IMMDeviceProperties.size();
//Find name property of devices
std::vector<std::wstring> MMDeviceFriendlyNames;
MMDeviceFriendlyNames.reserve(IMMDeviceCount);
for (int i = 0; i < PropertyStoreCount; i++) {
PROPVARIANT propVari;
PropVariantInit(&propVari);
hr = IMMDeviceProperties[i]->GetValue(PKEY_Device_FriendlyName, &propVari);
if (hr == S_OK) {
MMDeviceFriendlyNames.push_back(propVari.pwszVal);
PropVariantClear(&propVari);
}
}
// use vectors as needed...
for (UINT i = 0; i < PropertyStoreCount; ++i) {
IMMDeviceProperties[i]->Release();
}
for (UINT i = 0; i < IMMDeviceCount; ++i) {
IMMDevice[i]->Release();
}
The following code, based upon yours but without the obfuscating vectors appears to work fine. In runnin g it I get "FriendlyName: Speakers / HP (IDT High Definition Audio CODEC)" which seems correct here for this laptop.
When working with COM and without some kind of smart pointer, be really careful to release all the pointers. And always check all the results. COM calls can fail for all kinds of reasons.
#define WINVER _WIN32_WINNT_VISTA
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define STRICT
#include <windows.h>
#include <ole2.h>
#include <mmdeviceapi.h>
#include <propsys.h>
#include <propvarutil.h>
#include <stdio.h>
#include <Functiondiscoverykeys_devpkey.h>
#pragma comment(lib, "ole32")
#pragma comment(lib, "propsys")
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
static HRESULT
DumpDeviceProperties(IMMDevice *pDevice)
{
IPropertyStore *pStore = NULL;
HRESULT hr = pDevice->OpenPropertyStore(STGM_READ, &pStore);
if (SUCCEEDED(hr))
{
PROPVARIANT prop;
PropVariantInit(&prop);
hr = pStore->GetValue(PKEY_Device_FriendlyName, &prop);
if (SUCCEEDED(hr))
{
if (IsPropVariantString(prop))
wprintf(L"FriendlyName: %s\n", PropVariantToStringWithDefault(prop, L"(missing)"));
else
hr = E_UNEXPECTED;
}
PropVariantClear(&prop);
pStore->Release();
}
return hr;
}
int
wmain(int argc, WCHAR *argv[])
{
HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
IMMDeviceEnumerator *pEnumerator = NULL;
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, reinterpret_cast<void **>(&pEnumerator));
if (SUCCEEDED(hr))
{
IMMDeviceCollection *pCollection = NULL;
hr = pEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pCollection);
if (SUCCEEDED(hr))
{
UINT cEndpoints = 0;
hr = pCollection->GetCount(&cEndpoints);
if (SUCCEEDED(hr))
{
for (UINT n = 0; SUCCEEDED(hr) && n < cEndpoints; ++n)
{
IMMDevice *pDevice = NULL;
hr = pCollection->Item(n, &pDevice);
if (SUCCEEDED(hr))
{
hr = DumpDeviceProperties(pDevice);
pDevice->Release();
}
}
}
pCollection->Release();
}
pEnumerator->Release();
}
CoUninitialize();
}
return SUCCEEDED(hr) ? 0 : 1;
}
Compiled using: cl -nologo -MDd -Zi -W3 -Od lsdevices.cpp with MSVC 2013.
Code that I made, for people that wonder on this page like I did:
You also need this policyconfig.h file
#include <windows.h>
#include <ole2.h>
#include <ShellAPI.h>
#include <olectl.h>
#include <mmdeviceapi.h>
#include <propsys.h>
#include <propvarutil.h>
#include <stdio.h>
#include <Functiondiscoverykeys_devpkey.h>
#include <sstream>
#include <iostream>
#include <string>
#include <vector>
#include <atlstr.h>
#include <atlcore.h>
#include "Policyconfig.h"
#include "Propidl.h"
#include "Functiondiscoverykeys_devpkey.h"
#pragma comment(lib, "ole32")
#pragma comment(lib, "propsys")
using namespace std;
const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
class DeviceProps {
public:
string id;
string name;
string dll;
int iconID = 0;
bool isActive = false;
};
static HRESULT getDeviceProperty(IMMDevice* pDevice, DeviceProps* output)
{
IPropertyStore* pStore = NULL;
HRESULT hr = pDevice->OpenPropertyStore(STGM_READ, &pStore);
if (SUCCEEDED(hr))
{
PROPVARIANT prop;
PropVariantInit(&prop);
hr = pStore->GetValue(PKEY_Device_FriendlyName, &prop);
if (SUCCEEDED(hr))
{
if (IsPropVariantString(prop))
{
std::wstring wstr(PropVariantToStringWithDefault(prop, L"missing"));
std::string str(wstr.begin(), wstr.end());
output->name = str.c_str();
}
else
hr = E_UNEXPECTED;
}
hr = pStore->GetValue(PKEY_DeviceClass_IconPath, &prop);
if (SUCCEEDED(hr))
{
if (IsPropVariantString(prop))
{
PCWSTR propValue = PropVariantToStringWithDefault(prop, L"missing,0");
std::wstring propW(propValue);
std::string cPropValue(propW.begin(), propW.end());
vector<string> strings;
istringstream f(cPropValue);
string s;
while (getline(f, s, ',')) {
strings.push_back(s);
}
string location = strings[0];
string id = strings[1];
output->dll = location;
output->iconID = stoi(id);
}
else
hr = E_UNEXPECTED;
}
PropVariantClear(&prop);
pStore->Release();
}
return hr;
}
std::vector<DeviceProps> EnumAudioDevices(EDataFlow deviceType = eRender)
{
std::vector<DeviceProps> output;
HRESULT hr = CoInitializeEx(0, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
{
IMMDeviceEnumerator* pEnumerator = NULL;
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, reinterpret_cast<void**>(&pEnumerator));
if (SUCCEEDED(hr))
{
IMMDevice* pActive = NULL;
pEnumerator->GetDefaultAudioEndpoint(deviceType , eMultimedia, &pActive);
DeviceProps activeDevice;
getDeviceProperty(pActive, &activeDevice);
LPWSTR aid;
pActive->GetId(&aid);
std::wstring aid2(aid);
std::string aidS(aid2.begin(), aid2.end());
activeDevice.id = aidS;
//output.push_back(activeDevice);
pActive->Release();
IMMDeviceCollection* pCollection = NULL;
hr = pEnumerator->EnumAudioEndpoints(deviceType , DEVICE_STATE_ACTIVE, &pCollection);
if (SUCCEEDED(hr))
{
UINT cEndpoints = 0;
hr = pCollection->GetCount(&cEndpoints);
if (SUCCEEDED(hr))
{
for (UINT n = 0; SUCCEEDED(hr) && n < cEndpoints; ++n)
{
IMMDevice* pDevice = NULL;
hr = pCollection->Item(n, &pDevice);
if (SUCCEEDED(hr))
{
DeviceProps device;
hr = getDeviceProperty(pDevice, &device);
LPWSTR id;
pDevice->GetId(&id);
std::wstring id2(id);
std::string idS(id2.begin(), id2.end());
device.id = idS;
if (device.id == activeDevice.id)
device.isActive = true;
output.push_back(device);
pDevice->Release();
}
}
}
pCollection->Release();
}
pEnumerator->Release();
}
//CoUninitialize();
}
return output;
}
static HRESULT setDefaultDevice(string id)
{
string:wstring devID(id.begin(), id.end());
IPolicyConfigVista* pPolicyConfig;
HRESULT hr = CoCreateInstance(__uuidof(CPolicyConfigVistaClient),
NULL, CLSCTX_ALL, __uuidof(IPolicyConfigVista), (LPVOID*)&pPolicyConfig);
if (SUCCEEDED(hr))
{
hr = pPolicyConfig->SetDefaultEndpoint(devID.c_str(), eConsole);
hr = pPolicyConfig->SetDefaultEndpoint(devID.c_str(), eMultimedia);
hr = pPolicyConfig->SetDefaultEndpoint(devID.c_str(), eCommunications);
pPolicyConfig->Release();
}
return hr;
}
static int switchDefaultDevice(EDataFlow deviceType = eRender)
{
std::vector<DeviceProps> result = EnumAudioDevices(deviceType);
if (!result.empty())
{
std::string activateID("");
for (const auto& device : result)
{
if (activateID== "x") {
activateID = device.id;
break;
}
if (device.isActive) activateID= "x";
}
if (activateID == "x" || activateID == "") activateID = result[0].id;
setDefaultDevice(activateID);
return 1;
}
return 0;
}
int wmain(int argc, WCHAR* argv[])
{
std::vector<DeviceProps> result = EnumAudioDevices(eRender);
for (const auto& device : result)
{
std::cout << (device.isActive ? "ACTIVE:" : "") << "Name: " << device.name << " DLL: " << device.dll << " (#" << device.iconID << ")" << "\n" << device.id << "\n";
}
switchDefaultDevice(eRender);
}