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
Related
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;
}
Context:
I need to scan for, gather information and copy some media files from specific directories.
I have been having quite some trouble with some files not being detected, etc
Problem:
Warning to reader: As seen on the screenshot and noted in a comment,
the title and premise of this question are possible moot, as the error
was more likely to be dec 32 (== 0x20) == ERROR_SHARING_VIOLATION,
which has an "easy" explantion in the answer to this question.
In the code below, I use a c-style cast to convert my QString into a LPCWSTR for the CopyFileExW which I found in this SO post. I have tried many different conversions, but non of them seems to work correctly - which for now is besides the point.
The problem this 'conversion' technique gives is the error ERROR_NOT_SUPPORTED
ERROR_NOT_SUPPORTED
50 (0x32)
The request is not supported.
Frankly, this makes absolutely no sense to me in this context. I am copying from NTFS -> NTFS (same hard drive for testing), with destination file length < 200 characters (see image, 192 to be exact).
The core code: (see bottom for full details)
// QString src (src file location), dst (destination file location)
LPCWSTR localC_src = (LPCWSTR) src.utf16();
LPCWSTR localC_dst = (LPCWSTR) dst.utf16();
LPCWSTR dirC = (LPCWSTR) dir.utf16();
auto rc = CopyFileExW(localC_src, localC_dst, &BackupManager::copyProgress, this, &bStopBackup, 0);
if (rc == 0) {
DWORD lastError = GetLastError(); // Error = 0x32
bool dirExist = DirExists(dirC); // true
bool fileExists = FileExists(localC_src); // true
printWarning(TAG, QString("File Copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
if (FileExists(localC_src)) {
qDebug() << "#FailedCopy: Windows file exists but copy failed" << src; // this gets hit using the implemented c-style cast
}
else {
if (QFile::exists(src)) {
qDebug() << "#FailedCopy: Windows is really being full of shit! " << src; // this always gets triggered when using QString::toStdWString.c_str()
}
else {
qDebug() << "#FailedCopy: Windows file copy failed outright" << src;
}
}
// ...
} else {
// success
}
What does this error mean in the FileCopyExW context?
(also, if anyone has the source for windows.h implementation to allow me to trace the error further, please post it as a comment)
Image of debugger, etc
Full Code Implemenation:
static QString toString(HRESULT hr)
{
_com_error err{hr};
const TCHAR* lastError = err.ErrorMessage();
return QStringLiteral("Error 0x%1: %2").arg((quint32)hr, 8, 16, QLatin1Char('0'))
.arg(lastError);
}
static QString getLastErrorMsg()
{
DWORD lastError = GetLastError();
QString s = toString(HRESULT_FROM_WIN32(lastError));
return s;
}
BOOL FileExists(LPCWSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
// not used
static const wchar_t* toLPCWSTR(QString s)
{
std::wstring dstWString = s.toStdWString();
const wchar_t* localC_src = dstWString.c_str();
return localC_src;
}
static bool DirExists(LPCWSTR szPath)
{
DWORD ftyp = GetFileAttributes(szPath);
if (ftyp == INVALID_FILE_ATTRIBUTES)
return false; //something is wrong with your path!
if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
return true; // this is a directory!
return false; // this is not a directory!
}
BackupResult BackupManager::copyFile(QString m_src, QString m_dst)
{
QFileInfo fi(m_src);
QString dir = fi.dir().path();
// const wchar_t* dirC = toLPCWSTR(dir);
QString src = QString(m_src).replace("/", "\\");
QString dst = QString(m_src).replace("/", "\\");
// const wchar_t* localC_src = toLPCWSTR(src);
// const wchar_t* localC_dst = toLPCWSTR(dst);
LPCWSTR localC_src = (LPCWSTR) src.utf16();
LPCWSTR localC_dst = (LPCWSTR) dst.utf16();
LPCWSTR dirC = (LPCWSTR) dir.utf16();
auto rc = CopyFileExW(localC_src, localC_dst, &BackupManager::copyProgress, this, &bStopBackup, 0);
if (rc == 0) {
DWORD lastError = GetLastError(); // Error = 0x32
bool dirExist = DirExists(dirC); // true
bool fileExists = FileExists(localC_src); // true
printWarning(TAG, QString("File Copy Error: %1").arg(getLastErrorMsg()));
#ifdef QT_DEBUG
if (FileExists(localC_src)) {
qDebug() << "#FailedCopy: Windows file exists but copy failed" << src; // this gets hit using the implemented c-style cast
}
else {
if (QFile::exists(src)) {
qDebug() << "#FailedCopy: Windows is really being full of shit! " << src; // this always gets triggered when using QString::toStdWString.c_str()
}
else {
qDebug() << "#FailedCopy: Windows file copy failed outright" << src;
}
}
#endif
// copy failed
return BackupResult::IOError;
}
// copy success
return BackupResult::Success;
}
I suggest you check whether the copied file handle is opened in another process.
I created a simple sample, the code is as follows:
#include <iostream>
#include <Windows.h>
using namespace std;
int main(int argc, const char* argv[])
{
CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
int e = GetLastError();
cout << "error code is :" << e << endl;
return 0;
}
This sample of course successfully copied the file.But if I add the code to open the handle of this file, it will return error code 32.
#include <iostream>
#include <Windows.h>
using namespace std;
int main(int argc, const char* argv[])
{
CreateFileW(L"D:\\test\\test.txt", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
int e = GetLastError();
cout << "error code is :" << e << endl;
return 0;
}
Outout:
So I think you did not close it properly after opening the handle in other locations. If you need to copy files while the handle is open, you can modify the dwShareMode parameter to FILE_SHARE_READ. In this way, the file copy operation can be performed when the handle is opened.
Here is the sample:
#include <iostream>
#include <Windows.h>
using namespace std;
int main(int argc, const char* argv[])
{
CreateFileW(L"D:\\test\\test.txt", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL);
CopyFileEx(L"D:\\test\\test.txt", L"D:\\test\\test2.txt", NULL, NULL, 0, 0);
int e = GetLastError();
cout << "error code is :" << e << endl;
return 0;
}
Output:
More reference:CreateFileW and CopyFileExA
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.
If any kind soul out there please go through following source and tell me why MSXML "load" function fails to load this XML.
Here i'm trying to load a UTF-8 encoded XML using MSXML parser's "load" function. And i have a BSTR [UTF-16 encoded] as an argument, so i'm trying to convert it, into a SAFEARRAY of bytes so that i can passed it into the "load" function of MSXML. But the issue is load function failed to load this XML. If anyone could provide a solution to i would be really grateful.
#include <windows.h>
#include <objsafe.h>
#include <objbase.h>
#include <atlbase.h>
#include <string>
#include <comutil.h>
#include <msxml2.h>
#include <iostream>
using namespace std;
#define STATUS_SUCCESS 0
#define STATUS_FAIL -1
long LoadXmlData(BSTR xmlDoc)
{
HRESULT hr = S_OK;
CComPtr <IXMLDOMDocument> xmlDomDoc = NULL;
CComPtr <IXMLDOMElement> docRoot = NULL;
VARIANT_BOOL isParseSucess = FALSE;
CoInitialize(NULL);
hr = xmlDomDoc.CoCreateInstance(__uuidof(DOMDocument30));
if (FAILED(hr))
{
return STATUS_FAIL;
}
BYTE HUGEP *pByte;
int len = WideCharToMultiByte(CP_UTF8, 0, xmlDoc, -1, NULL, 0, NULL, NULL);
SAFEARRAYBOUND rgsabound[1];
rgsabound[0].cElements = len;
rgsabound[0].lLbound = 0;
SAFEARRAY* psa = SafeArrayCreate(VT_UI1, 1, rgsabound);
if (psa != NULL)
{
hr = SafeArrayAccessData(psa, (void HUGEP**)&pByte);
if (!FAILED(hr))
{
if (len > 0)
{
WideCharToMultiByte(CP_UTF8, 0, xmlDoc, -1, (LPSTR)&pByte[0], len, NULL, NULL);
//cout << "Converted Byte Array: " << pByte << endl << endl;
}
else
{
return STATUS_FAIL;
}
SafeArrayUnaccessData(psa);
}
}
VARIANT v;
VariantInit(&v);
V_VT(&v) = VT_ARRAY | VT_UI1;
V_ARRAY(&v) = psa;
hr = xmlDomDoc->load(v, &isParseSucess);
//hr = xmlDomDoc->loadXML(xmlDoc, &isParseSucess); //can't use this function because XML is encoded in UTF-8
if (FAILED(hr) || (!isParseSucess))
{
return STATUS_FAIL;
}
else
{
return STATUS_SUCCESS;
}
}
int main()
{
BSTR xmlDoc = SysAllocString(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?> <response> </response> ");
long ret = LoadXmlData(xmlDoc);
if (ret == STATUS_SUCCESS)
{
cout << "MSXML: loading the XML succeeded";
}
else
{
cout << "MSXML: loading the XML failed";
}
//string str;
//getline(cin, str);
return 0;
}
ps: If anyone try to compile this source you may get a link error first time, add comsuppw.lib as a linker dependency in VS settings. And XML is UTF-8 encoded, so i can't use "LoadXML" function in MSXML.
XML files are UTF-8 but there is no conversion needed here because Windows functions will automatically convert between UTF-16 and UTF-8 when needed (unless input/output is BYTE*...)
BSTR needs cleanup. You can use CComBSTR(str) which has automatic cleanup.
You can use const wchar_t* to pass strings to your own functions. BSTR is required for COM etc.
As noted in comments, IXMLDOMDocument::load expects a file name as input. Use IXMLDOMDocument::loadXML in this case.
#include <iostream>
#include <windows.h>
#include <atlbase.h>
#include <msxml2.h>
long LoadXmlData(const wchar_t* content)
{
HRESULT hr = S_FALSE;
CComPtr<IXMLDOMDocument> doc = NULL;
CComPtr<IXMLDOMElement> docRoot = NULL;
hr = doc.CoCreateInstance(__uuidof(DOMDocument30));
if(FAILED(hr))
return S_FALSE;
VARIANT_BOOL is_success = FALSE;
CComBSTR arg(content);
hr = doc->loadXML(arg, &is_success);
//if you are loading from a file:
//hr = doc->load(CComVariant(L"c:\\test\\test.xml"), &is_success);
if(FAILED(hr) || !is_success)
return S_FALSE;
//if save is needed:
//doc->save(CComVariant(L"c:\\test\\test.xml"));
return S_OK;
}
int main()
{
CoInitialize(NULL);
//ελληνική γλώσσα Greek text for testing
CComBSTR data(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?><response>ελληνική γλώσσα</response>");
long ret = LoadXmlData(data);
if(ret == S_OK)
std::cout << "MSXML: loading the XML succeeded\n";
else
std::cout << "MSXML: loading the XML failed\n";
CoUninitialize();
return 0;
}
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);
}