Enumerate all file type associations - c++

I want to list all the file type associations app names. My code:
#include <windows.h>
#include <shlwapi.h>
#include <ShlObj.h>
#include <iostream>
#pragma comment(lib, "shlwapi.lib")
int main()
{
IQueryAssociations *iQueryAssoc = nullptr;
HRESULT assocHRes = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, reinterpret_cast<void**>(&iQueryAssoc));
if (assocHRes == S_OK) {
HWND hWnd = GetConsoleWindow();
LPCWSTR pszAssoc = L".xls";
HRESULT initAssocHRes = iQueryAssoc->Init(NULL, pszAssoc, NULL, hWnd);
if (initAssocHRes == S_OK) {
TCHAR buffer[1024];
DWORD bufferSize = 1024;
HRESULT getStrAssocHRes = iQueryAssoc->GetString(ASSOCF_NONE, ASSOCSTR_FRIENDLYAPPNAME, NULL, buffer, &bufferSize);
if (getStrAssocHRes == S_OK) {
std::wcout << "App name: " << std::wstring(buffer).c_str() << std::endl;
} else {
std::wcout << "iQueryAssoc GetString failed!" << std::endl;
}
} else {
std::wcout << "iQueryAssoc Init failed!" << std::endl;
}
} else {
std::wcout << "AssocCreate failed!" << std::endl;
}
iQueryAssoc->Release();
system("PAUSE");
return 0;
}
My code works but it displays app name only for the ".xls" extension. I think, I need to use the while (iQueryAssoc->QueryInterface()) to get all of them. Is there any example how to use it? Should I call init method first and then QueryInterface method or just call QueryInterface method without init method?
Additionally, I have found the SHAssocEnumHandlers method:
IEnumAssocHandlers *pEnumHandlers = nullptr;
IAssocHandler *assocHandler = nullptr;
HRESULT initAssocHRes = SHAssocEnumHandlers(NULL, ASSOC_FILTER_NONE, &pEnumHandlers);
if (initAssocHRes == S_OK) {
while (pEnumHandlers->Next(1, &assocHandler, nullptr) == S_OK) {
std::cout << "Test..." << std::endl;
}
} else {
std::cout << "Failed: " << initAssocHRes << std::endl;
}
But for me, it fails with the following error: Failed: -2147024882 E_OUTOFMEMORY - Failed to allocate necessary memory. I think, the issue with: IEnumAssocHandlers are null and not initialized. What method should I use to initialize the IEnumAssocHandlers? Thank you.
I have found, these lines of code leads to E_OUTOFMEMORY issue:
IEnumAssocHandlers *pEnumHandlers = NULL;
HRESULT initAssocHRes = SHAssocEnumHandlers(NULL, ASSOC_FILTER_RECOMMENDED, &pEnumHandlers);
Also, I got this warning:
Any ideas? Thank you.
Updated code:
#include <windows.h>
#include <shlwapi.h>
#include <ShlObj.h>
#include <iostream>
#include "hresinfo.h"
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "shell32.lib")
int main()
{
IEnumAssocHandlers *pEnumHandlers = nullptr;
HRESULT initAssocHRes = SHAssocEnumHandlers(NULL, ASSOC_FILTER_NONE, reinterpret_cast<IEnumAssocHandlers**>(&pEnumHandlers));
if (initAssocHRes == S_OK) {
IAssocHandler *pAssocHandler = nullptr;
LPWSTR pszName = nullptr;
while (pEnumHandlers->Next(1, &pAssocHandler, NULL) == S_OK) {
if (pAssocHandler) {
pAssocHandler->GetUIName(&pszName);
printf_s("%S \n", pszName);
}
}
if (pAssocHandler) {
pAssocHandler->Release();
}
} else {
HRESInfo::getErrorMsg(initAssocHRes);
}
if (pEnumHandlers) {
pEnumHandlers->Release();
}
system("PAUSE");
return 0;
}
Screenshot:

You don't say which call is actually failing (so please do so), but if you look at the documentation for IEnumAssocHandlers::Next, it doesn't say anywhere that the third parameter (pceltFetched) can be nullptr, so I would change your code to:
if (initAssocHRes == S_OK) {
ULONG handlers_retrieved = 0;
while (pEnumHandlers->Next(1, &assocHandler, &handlers_retrieved) == S_OK) {
...

Also first parameter to SHAssocEnumHandlers must not be null:
wchar_t *extension = L".jpg";
HRESULT initAssocHRes = SHAssocEnumHandlers(extension, ...

Related

Getting all services and their path to exe

Get list of windows services and print name, status, path to exe
the above statement needs to be solved, I am aware we enum services to find.....since I am beginner ,I don't understand how to retrieve all the path to exe.
this is what I knew
#include <Windows.h>
#include <iostream>
int main()
{
SC_HANDLE sHandle;
LPQUERY_SERVICE_CONFIG lpServiceConfig = NULL;
DWORD cbBufSize = 100;
LPDWORD bytesNeeded = NULL;
sHandle = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
sHandle = OpenService(sHandle, "YOU SERVICE NAME",SERVICE_ALL_ACCESS);
QueryServiceConfig(sHandle,lpServiceConfig,cbBufSize,bytesNeeded);
std::cout << lpServiceConfig->lpBinaryPathName << std::endl;
}
You need to use EnumServiceStatus() to query which services are installed. You can then open each service to query its EXE path.
Also, your code is leaking resources and memory.
Try something more like this:
#include <Windows.h>
#include <iostream>
#include <vector>
int main()
{
DWORD bytesNeeded = 0;
DWORD numServices = 0;
DWORD resumeHandle = 0;
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (!hSCManager) ...
EnumServicesStatus(hSCManager, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &bytesNeeded, &numServices, &resumeHandle);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ...
std::vector<BYTE> enumBuffer(bytesNeeded);
LPENUM_SERVICE_STATUS pEnum = reinterpret_cast<LPENUM_SERVICE_STATUS>(enumBuffer.data());
if (!EnumServicesStatus(hSCManager, SERVICE_WIN32, SERVICE_STATE_ALL, pEnum, bytesNeeded, &bytesNeeded, &numServices, &resumeHandle)) ...
for(DWORD idx = 0; idx < numServices; ++idx)
{
std::cout << pEnum[idx].lpServiceName << " (" << pEnum[idx].lpDisplayName << ")" << std::endl;
// use/display pEnum[idx].ServiceStatus as needed ...
SC_HANDLE hService = OpenService(hSCManager, pEnum[idx].lpServiceName, SERVICE_QUERY_CONFIG);
if (!hService) ...
QueryServiceConfig(hSerivce, NULL, 0, &bytesNeeded);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ...
std::vector<BYTE> configBuffer(bytesNeeded);
LPQUERY_SERVICE_CONFIG lpServiceConfig = reinterpret_cast<LPQUERY_SERVICE_CONFIG>(configBuffer.data());
if (!QueryServiceConfig(hSerivce, lpServiceConfig, bytesNeeded, &bytesNeeded)) ...
std::cout << lpServiceConfig->lpBinaryPathName << std::endl;
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
}

Windows SAPI error : 'GetVersionExA': was declared deprecated

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

How do you get the NamePropertyId of a UIAutomationElement by hovering the cursor?

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.

Passing a SAFEARRAY of bytes to load function of MSXML

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;
}

Program crashes when SetupDiGetDeviceInterfaceDetail is called

I'm trying to get the path of a device by using the SetupDiGetDeviceInterfaceDetail() function, but it crashes everytime I call it. I've have been working on this for over 12 hours but still couldn't find out what is wrong with it... Can someone see if they can find what is actually causing this to happen? Heres the code:
//DeviceManager.h
#include <windows.h>
//#include <hidsdi.h>
#include <setupapi.h>
#include <iostream>
#include <cfgmgr32.h>
#include <tchar.h>
#include <devpkey.h>
#include <string>
extern "C"{
#include <hidsdi.h>
}
//#pragma comment (lib, "setupapi.lib")
class DeviceManager
{
public:
DeviceManager();
~DeviceManager();
void ListAllDevices();
void GetDeviceHandler();
//HANDLE PSMove;
//byte reportBuffer[57];
GUID guid;
//private:
HDEVINFO deviceInfoSet; //A list of all the devices
SP_DEVINFO_DATA deviceInfoData; //A device from deviceInfoSet
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData;
};
//DeviceManager.cpp
#include"DeviceManager.h"
DeviceManager::DeviceManager()
{
//deviceInterfaceData = new SP_DEVICE_INTERFACE_DATA;
//deviceInterfaceDetailedData = new SP_DEVICE_INTERFACE_DETAIL_DATA;
HidD_GetHidGuid(&guid);
deviceInfoSet = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); //Gets all Devices
GetDeviceHandler();
}
DeviceManager::~DeviceManager()
{
}
void DeviceManager::ListAllDevices()
{
DWORD deviceIndex = 0;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
deviceInfoData.cbSize = sizeof(deviceInfoData);
ULONG tcharSize;
CM_Get_Device_ID_Size(&tcharSize, deviceInfoData.DevInst, 0);
TCHAR* deviceIDBuffer = new TCHAR[tcharSize]; //the device ID will be stored in this array, so the tcharSize needs to be big enough to hold all the info.
//Or we can use MAX_DEVICE_ID_LEN, which is 200
CM_Get_Device_ID(deviceInfoData.DevInst, deviceIDBuffer, MAX_PATH, 0); //gets the devices ID - a long string that looks like a file path.
std::cout << deviceIDBuffer << std::endl;
deviceIndex++;
}
}
void DeviceManager::GetDeviceHandler()
{
DWORD deviceIndex = 0;
SP_DEVINFO_DATA deviceInfoData;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData;
deviceInfoData.cbSize = sizeof(deviceInfoData);
while(SetupDiEnumDeviceInfo(deviceInfoSet, deviceIndex, &deviceInfoData))
{
TCHAR deviceID[MAX_DEVICE_ID_LEN];
CM_Get_Device_ID(deviceInfoData.DevInst, deviceID, MAX_DEVICE_ID_LEN, 0);
//std::cout << deviceID << std::endl;
deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(SetupDiEnumDeviceInterfaces(deviceInfoSet, &deviceInfoData, &guid, 0, &deviceInterfaceData))
{
DWORD bufferLength = 0;
//deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
deviceInterfaceData.cbSize = 2048;
//std::cout << "it works not" << std::endl;
if(SetupDiGetDeviceInterfaceDetail(deviceInfoSet, &deviceInterfaceData, NULL, 0, &bufferLength, NULL))
{
//deviceInterfaceData.cbSize = sizeof(bufferLength);
std::cout << "It works!" << std::endl;
}
else
{
std::cout << GetLastError() << std::endl;
}
}
else
{
//std::cout << GetLastError() << std::endl;
}
deviceIndex++;
}
}
//mainapp.cpp
#pragma once
int main()
{
DeviceManager deviceManager;
return 0;
}
The SetupDiGetDeviceInterfaceDetail function is called in the GetDeviceHandler() function of DeviceManager.
Please help. Thanks.
UPDATE: I have found out that it failed on the first SetupDiGetDeviceInterfaceDetail and is returning a 122 error (ERROR_INSUFFICIENT_BUFFER). But I am only trying to get the required buffer size, so how can this be??
UPDATE 2: right, I have changed the function a bit (see above code) by setting the deviceInterfaceData.cbsize to 2048 (a huge space for testing purposes) and now I'm getting a ERROR_INVALID_PARAMETER. This is getting more and more confusing... How can the parameters I've given is invalid? Just doesn't make sense. The only difference is I passed in References instead of Pointers because otherwise I will get a access violation error...
Having found this topic, I'd like to share my problem that using exactly the same source, I got ERROR_INVALID_USER_BUFFER from the call.
The reason was the line:
deviceInterfaceDetailedData->cbSize =
sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
which on my quadbyte aligned compiler set the value 8 instead of the required value 5.
You're not allocating memory properly for the SP_DEVICE_INTERFACE_DETAIL_DATA.
Remove SP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData; and try putting this inside your if block:
// Get the required bufferLength
SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
nullptr,
0,
&bufferLength,
nullptr);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
std::cout << "Failed to get bufferLength. Error "
<< GetLastError() << '\n';
return;
}
// Create device interface detailed information struct pointer
// and allocate memory to it.
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailedData(nullptr);
deviceInterfaceDetailedData =
static_cast<PSP_INTERFACE_DEVICE_DETAIL_DATA>(malloc(bufferLength));
if(deviceInterfaceDetailedData == nullptr)
{
std::cout << "Failed to allocate memory. Error "
<< GetLastError() << '\n';
return;
}
deviceInterfaceDetailedData->cbSize =
sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
// Get detailed information
if(SetupDiGetDeviceInterfaceDetail(deviceInfoSet,
&deviceInterfaceData,
deviceInterfaceDetailedData,
bufferLength,
&bufferLength,
nullptr))
{
//deviceInterfaceData.cbSize = sizeof(bufferLength);
std::cout << "It works!" << std::endl;
}
else
{
std::cout << GetLastError() << std::endl;
}
free(deviceInterfaceDetailedData);
I haven't looked at the rest of the code, it may have errors too, but this answers your original question.
This is according to MSDN definition:
Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with a NULLDeviceInterfaceDetailData pointer, a DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize variable. In response to such a call, this function returns the required buffer size at RequiredSize and fails with GetLastError returning ERROR_INSUFFICIENT_BUFFER.
So, after ERROR_INSUFFICIENT_BUFFER error just use requiredSize value.