Getting all services and their path to exe - c++

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

Related

LSALogonUser fails to authenticate domain users using AD issued certificates

I am working on a certificate-based authentication project for domain users against Active Directory without the use of smartcards. I am trying to access the issued domain user certificate container and pass the value in a serialized format to LsaLogonUser for authentication.
First, I am enrolling the domain user certificate by creating a new certificate template described below:-
Duplicate a new certificate template from "User" certificate template.
In the Properties of new certificate template window, go to the General tab and change the following settings:
Check the "Publish certificate in Active Directory" box and enter a template name.
Go to the Request Handling tab and change the following settings:
Change "Purpose" to "Signature and encryption".
Check the box "Allow private key to be exported".
Select "Prompt the user during enrollment".
Go to the Subject Name tab and change the following settings:
Select "Build from this Active Directory information".
Change "Subject name format" to "None".
Check the "User principal name (UPN)" box.
Go to the Extensions tab and edit "Application Policies" so that the only listed policies are "Client Authentication" and "Smart Card Logon". (Remove any default policies as necessary.)
Go to the Cryptography tab and change the following settings:
Change "Minimum key size" to 2048.
Select "Requests must use one of the following providers: "
Select "Microsoft Enhanced Cryptographic Provider v1.0" as "Providers".
After making the above changes, issue/publish the new certificate template in Active Directory Certificate Authority.
The domain user enrolls using the new certificate template and the user certificate is stored in the current user's Certificate Store.
After the enrollment process is complete, I am trying to access the CSP container handle of the user certificate and using it for KERB_CERTIFICATE_LOGON structure for packing and serializing the authentication data specified by LsaLogonUser. Here is the code:
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <Ntsecapi.h>
#include <iostream>
#include <intsafe.h>
#include <WinCred.h>
#include <winbase.h>
#pragma comment(lib, "Crypt32")
#define NEGOSSP_NAME_A "Negotiate"
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
#include <vcruntime_exception.h>
#pragma comment(lib, "Secur32.lib")
using namespace std;
// 1-Byte packing for this structure
#pragma pack(push, KerbCspInfo, 1)
typedef struct _KERB_SMARTCARD_CSP_INFO {
DWORD dwCspInfoLen;
DWORD MessageType;
union {
PVOID ContextInformation;
ULONG64 SpaceHolderForWow64;
};
DWORD flags;
DWORD KeySpec;
ULONG nCardNameOffset;
ULONG nReaderNameOffset;
ULONG nContainerNameOffset;
ULONG nCSPNameOffset;
TCHAR bBuffer[sizeof(DWORD)];
} KERB_SMARTCARD_CSP_INFO, * PKERB_SMARTCARD_CSP_INFO;
#pragma pack(pop, KerbCspInfo)
HRESULT UnicodeStringInitWithString(
_In_ PWSTR pwz,
_Out_ UNICODE_STRING* pus
)
{
HRESULT hr;
if (pwz)
{
size_t lenString = wcslen(pwz);
USHORT usCharCount;
hr = SizeTToUShort(lenString, &usCharCount);
if (SUCCEEDED(hr))
{
USHORT usSize;
hr = SizeTToUShort(sizeof(wchar_t), &usSize);
if (SUCCEEDED(hr))
{
hr = UShortMult(usCharCount, usSize, &(pus->Length)); // Explicitly NOT including NULL terminator
if (SUCCEEDED(hr))
{
pus->MaximumLength = pus->Length;
pus->Buffer = pwz;
hr = S_OK;
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
}
}
}
}
else
{
hr = E_INVALIDARG;
}
return hr;
}
static void _UnicodeStringPackedUnicodeStringCopy(
__in const UNICODE_STRING& rus,
__in PWSTR pwzBuffer,
__out UNICODE_STRING* pus
)
{
pus->Length = rus.Length;
pus->MaximumLength = rus.Length;
pus->Buffer = pwzBuffer;
std::CopyMemory(pus->Buffer, rus.Buffer, pus->Length);
}
// Set the SeTcbPrivilege of the current process
BOOL SetSeTcbPrivilege()
{
TOKEN_PRIVILEGES tp;
LUID luid;
HANDLE hProcessToken;
int x;
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&hProcessToken))
{
_tprintf(_T("OpenProcessToken failed with error 0x%.8X\n"), GetLastError());
cin >> x;
return FALSE;
}
if (!LookupPrivilegeValue(
NULL,
SE_TCB_NAME,
&luid))
{
_tprintf(_T("LookupPrivilegeValue failed with error 0x%.8X\n"), GetLastError());
CloseHandle(hProcessToken);
cin >> x;
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Enable the privilege
if (!AdjustTokenPrivileges(
hProcessToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
_tprintf(_T("AdjustTokenPrivileges failed with error 0x%.8X\n"), GetLastError());
CloseHandle(hProcessToken);
cin >> x;
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
_tprintf(_T("The token does not have the privilege \"SeTcbPrivilege\". \n"));
CloseHandle(hProcessToken);
cin >> x;
return FALSE;
}
CloseHandle(hProcessToken);
return TRUE;
}
// Build the authentication data used by LsaLogonUser
BOOL ConstructAuthCertInfo(const KERB_CERTIFICATE_UNLOCK_LOGON& rkiulIn,LPBYTE* ppbAuthInfo, ULONG* pulAuthInfoLen)
{
UNICODE_STRING DomainName;
UNICODE_STRING UserName;
UNICODE_STRING Password;
NTSTATUS Status;
ULONG_PTR Ptr;
ULONG AuthInfoLength;
wstring WProvName;
DWORD ProvSize = 0;
wstring containerName;
DWORD contSize = 0;
HCRYPTPROV hProv;
DWORD dwKeySpec;
// Fetching the certificate context from the certificate store
// and recieving the CSP handle for the user certificate
HCERTSTORE hStoreHandle = NULL;
PCCERT_CONTEXT pCertContext = NULL;
LPCTSTR pszStoreName = _T("MY");
CERT_CREDENTIAL_INFO certInfo;
HCRYPTHASH hHash;
BOOL bStatus;
DWORD dwHashLen = CERT_HASH_LENGTH;
LPWSTR szMarshaledCred = NULL;
HANDLE hToken;
hStoreHandle = CertOpenSystemStore(NULL, pszStoreName);
if (hStoreHandle)
{
// Since my certificate store has only one user certificate, tring to retrieve PCERT_CONTEXT for it
pCertContext = CertFindCertificateInStore(
hStoreHandle,
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
0,
CERT_FIND_ANY,
NULL,
NULL);
if (pCertContext)
{
BOOL bFreeHandle;
// acquire private key container to this certificate
if (CryptAcquireCertificatePrivateKey(pCertContext, CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG, NULL, &hProv, &dwKeySpec, &bFreeHandle))
{
cout << "The private key container handle is accessed.. "<<endl<<"The dwKeySpec Value is: "<<dwKeySpec<<endl;
//Fetching the container name where the certificate is stored
if (CryptGetProvParam(hProv, PP_CONTAINER, NULL, &contSize, 0))
{
BYTE* contName = (BYTE*)malloc(contSize);
if (CryptGetProvParam(hProv, PP_CONTAINER, contName, &contSize, 0))
{
containerName = wstring(contName, contName + contSize);
wcout << "The container name is: " << containerName << endl;
}
else
{
cout << "Could not get the container name. Exiting.."<<endl;
return FALSE;
}
}
else
{
cout << "Could not get the container size. Exiting.."<<endl;
return FALSE;
}
//Fetching the CSP name where the certificate is stored
if (CryptGetProvParam(hProv, PP_NAME, NULL, &ProvSize, 0))
{
BYTE* ProvName = (BYTE*)malloc(ProvSize);
if (CryptGetProvParam(hProv, PP_NAME, ProvName, &ProvSize, 0))
{
WProvName = wstring(ProvName, ProvName + ProvSize);
wcout << "The name of the CSP is: " << WProvName << endl;
}
else
{
cout << "The CSP name could not be retrieved. Exiting.." << endl;
return FALSE;
}
}
else
{
cout << "The CSP name size could not be retrieved. Exiting.." << endl;
return FALSE;
}
}
else
{
cout << "Could not get the Private Key Container handle. Exiting...";
return FALSE;
}
}
else
{
cout << "Could not find the user certificate in the Certificate store. Exiting.." << endl;
return FALSE;
}
}
// Creating and initializing a PKERB_SMARTCARD_CSP_INFO struct for passing as an argument to KERB_CERTIFICATE_LOGON struct
// This struct stores information regarding the CSP and container of the user certs
DWORD dwReaderLen = (DWORD)_tcslen(L"") + 1;
DWORD dwCardLen = (DWORD)_tcslen(L"") + 1;
DWORD dwProviderLen = (DWORD)_tcslen(WProvName.c_str()) + 1;
DWORD dwContainerLen = (DWORD)_tcslen(containerName.c_str()) + 1;
DWORD dwBufferSize = dwReaderLen + dwCardLen + dwProviderLen + dwContainerLen;
PKERB_SMARTCARD_CSP_INFO CspInfo = (PKERB_SMARTCARD_CSP_INFO)malloc(sizeof(KERB_SMARTCARD_CSP_INFO) + dwBufferSize * sizeof(TCHAR));
std::memset(CspInfo, 0, sizeof(KERB_SMARTCARD_CSP_INFO));
CspInfo->dwCspInfoLen = sizeof(KERB_SMARTCARD_CSP_INFO) + dwBufferSize * sizeof(TCHAR);
CspInfo->MessageType = 1;
CspInfo->KeySpec = dwKeySpec;
CspInfo->nCardNameOffset = ARRAYSIZE(CspInfo->bBuffer);
CspInfo->nReaderNameOffset = CspInfo->nCardNameOffset + dwCardLen;
CspInfo->nContainerNameOffset = CspInfo->nReaderNameOffset + dwReaderLen;
CspInfo->nCSPNameOffset = CspInfo->nContainerNameOffset + dwContainerLen;
std::memset(CspInfo->bBuffer, 0, sizeof(CspInfo->bBuffer));
_tcscpy_s(&CspInfo->bBuffer[CspInfo->nCardNameOffset], dwBufferSize + 4 - CspInfo->nCardNameOffset, L"");
_tcscpy_s(&CspInfo->bBuffer[CspInfo->nReaderNameOffset], dwBufferSize + 4 - CspInfo->nReaderNameOffset, L"");
_tcscpy_s(&CspInfo->bBuffer[CspInfo->nContainerNameOffset], dwBufferSize + 4 - CspInfo->nContainerNameOffset, containerName.c_str());
_tcscpy_s(&CspInfo->bBuffer[CspInfo->nCSPNameOffset], dwBufferSize + 4 - CspInfo->nCSPNameOffset, WProvName.c_str());
const KERB_CERTIFICATE_LOGON* pkilIn = &rkiulIn.Logon;
// alloc space for struct plus extra for the three strings
DWORD cb = sizeof(rkiulIn) +
pkilIn->DomainName.Length +
pkilIn->UserName.Length +
pkilIn->Pin.Length +
CspInfo->dwCspInfoLen;
KERB_CERTIFICATE_UNLOCK_LOGON* pkiulOut = (KERB_CERTIFICATE_UNLOCK_LOGON*)CoTaskMemAlloc(cb);
if (pkiulOut)
{
std::ZeroMemory(&pkiulOut->LogonId, sizeof(LUID));
//
// point pbBuffer at the beginning of the extra space
//
BYTE* pbBuffer = (BYTE*)pkiulOut + sizeof(*pkiulOut);
//
// set up the Logon structure within the KERB_CERTIFICATE_UNLOCK_LOGON
//
KERB_CERTIFICATE_LOGON* pkilOut = &pkiulOut->Logon;
pkilOut->MessageType = pkilIn->MessageType;
pkilOut->Flags = pkilIn->Flags;
//
// copy each string,
// fix up appropriate buffer pointer to be offset,
// advance buffer pointer over copied characters in extra space
//
_UnicodeStringPackedUnicodeStringCopy(pkilIn->DomainName, (PWSTR)pbBuffer, &pkilOut->DomainName);
pkilOut->DomainName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->DomainName.Length;
_UnicodeStringPackedUnicodeStringCopy(pkilIn->UserName, (PWSTR)pbBuffer, &pkilOut->UserName);
pkilOut->UserName.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->UserName.Length;
_UnicodeStringPackedUnicodeStringCopy(pkilIn->Pin, (PWSTR)pbBuffer, &pkilOut->Pin);
pkilOut->Pin.Buffer = (PWSTR)(pbBuffer - (BYTE*)pkiulOut);
pbBuffer += pkilOut->Pin.Length;
pkilOut->CspData = (PUCHAR)(pbBuffer - (BYTE*)pkiulOut);
pkilOut->CspDataLength = CspInfo->dwCspInfoLen;
std::memcpy(pbBuffer,CspInfo, CspInfo->dwCspInfoLen);
*ppbAuthInfo = (BYTE*)pkilOut;
*pulAuthInfoLen = cb;
return TRUE;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
NTSTATUS nStatus;
CHAR szProcName[] = "LsaTestLogonProcess";
CHAR szPackageName[] = NEGOSSP_NAME_A;
CHAR szOriginName[] = "LsaSmartCardLogonTest";
LSA_STRING lsaProcName = { strlen(szProcName), strlen(szProcName) + 1, szProcName };
LSA_STRING lsaPackageName = { strlen(szPackageName), strlen(szPackageName) + 1, szPackageName };
LSA_STRING lsaOriginName = { strlen(szOriginName), strlen(szOriginName) + 1, szOriginName };
HANDLE lsaHandle;
ULONG ulAuthPackage;
LPBYTE pbAuthInfo = NULL;
ULONG ulAuthInfoLen = 0;
LSA_OPERATIONAL_MODE dummy;
TOKEN_SOURCE tokenSource;
LPVOID pProfileBuffer = NULL;
ULONG ulProfileBufferLen = 0;
LUID logonId;
HANDLE hLogonToken;
QUOTA_LIMITS quotas;
NTSTATUS subStatus;
HANDLE hToken = NULL;
int x;
wchar_t doman[] = L"TECNICS";
wchar_t usernme[] = L"";
wchar_t pn[] = L"";
PWSTR domain = doman;
PWSTR username = usernme;
PWSTR pin = pn;
//Certificate Based Auth
KERB_CERTIFICATE_UNLOCK_LOGON ckiul;
KERB_CERTIFICATE_LOGON* ckil = &ckiul.Logon;
ckil->MessageType = KerbCertificateLogon;
ckil->Flags = 2;
// Converting Domain Name to Unicode Format
UnicodeStringInitWithString(domain, &ckil->DomainName);
// Passing empty UserName as per https://learn.microsoft.com/en-us/windows/win32/api/ntsecapi/ns-ntsecapi-kerb_certificate_logon
UnicodeStringInitWithString(username, &ckil->UserName);
// Passing empty PIN since no PIN asked during enrollment
UnicodeStringInitWithString(pin, &ckil->Pin);
//End
if (!SetSeTcbPrivilege())
{
cin >> x;
return 0;
}
std::memcpy(tokenSource.SourceName, "LsaTest", 8);
AllocateLocallyUniqueId(&tokenSource.SourceIdentifier);
nStatus = LsaRegisterLogonProcess(&lsaProcName,
&lsaHandle,
&dummy);
if (nStatus == STATUS_SUCCESS)
{
nStatus = LsaLookupAuthenticationPackage(lsaHandle,
&lsaPackageName,
&ulAuthPackage);
if (nStatus == STATUS_SUCCESS)
{
if (!ConstructAuthCertInfo(ckiul, &pbAuthInfo, &ulAuthInfoLen))
{
cout << "Could not serialize the authentication data. Exiting...";
cin >> x;
return 0;
}
nStatus = LsaLogonUser(lsaHandle,
&lsaOriginName,
Interactive,
ulAuthPackage,
pbAuthInfo,
ulAuthInfoLen,
NULL,
&tokenSource,
&pProfileBuffer,
&ulProfileBufferLen,
&logonId,
&hLogonToken,
&quotas,
&subStatus);
if (nStatus == STATUS_SUCCESS)
{
if (pProfileBuffer)
LsaFreeReturnBuffer(pProfileBuffer);
_tprintf(_T("User logged on successfully!!\n"));
cin >> x;
CloseHandle(hLogonToken);
}
else
{
_tprintf(_T("LsaLogonUser failed with error 0x%.8X. SubStatus = 0x%.8X\n"), LsaNtStatusToWinError(nStatus), LsaNtStatusToWinError(subStatus));
cin >> x;
}
HeapFree(GetProcessHeap(), 0, pbAuthInfo);
}
else
{
_tprintf(_T("LsaLookupAuthenticationPackage failed with error 0x%.8X\n"), LsaNtStatusToWinError(nStatus));
cin >> x;
}
LsaDeregisterLogonProcess(lsaHandle);
}
else
{
_tprintf(_T("LsaRegisterLogonProcess failed with error 0x%.8X\n"), LsaNtStatusToWinError(nStatus));
cin >> x;
}
return 0;
}
NOTE: The user needs to have SeTcbPriveledge and admin rights to run the program. You can refer to this article to set the SeTcbPriveledge for the domain user.
After running the above code in the domain user's environment, LSALogonUser fails and I get the following status values:
- Status: 0x0000052E/ERROR_LOGON_FAILURE (The user name or password is incorrect.)
- SubStatus: 0x8009000d/NTE_NO_KEY (Key does not exist.)
I have also pushed a repo on Github which consists of the code in with Visual Studio extensions. You can clone the repo from here.
Can someone suggest a better approach or hints to make this work?

Enumerate all file type associations

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, ...

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

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.

How to read a value from the Windows registry

Given the key for some registry value (e.g. HKEY_LOCAL_MACHINE\blah\blah\blah\foo) how can I:
Safely determine that such a key exists.
Programmatically (i.e. with code) get its value.
I have absolutely no intention of writing anything back to the registry (for the duration of my career if I can help it). So we can skip the lecture about every molecule in my body exploding at the speed of light if I write to the registry incorrectly.
Prefer answers in C++, but mostly just need to know what the special Windows API incantation to get at the value is.
Here is some pseudo-code to retrieve the following:
If a registry key exists
What the default value is for that registry key
What a string value is
What a DWORD value is
Example code:
Include the library dependency: Advapi32.lib
HKEY hKey;
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Perl", 0, KEY_READ, &hKey);
bool bExistsAndSuccess (lRes == ERROR_SUCCESS);
bool bDoesNotExistsSpecifically (lRes == ERROR_FILE_NOT_FOUND);
std::wstring strValueOfBinDir;
std::wstring strKeyDefaultValue;
GetStringRegKey(hKey, L"BinDir", strValueOfBinDir, L"bad");
GetStringRegKey(hKey, L"", strKeyDefaultValue, L"bad");
LONG GetDWORDRegKey(HKEY hKey, const std::wstring &strValueName, DWORD &nValue, DWORD nDefaultValue)
{
nValue = nDefaultValue;
DWORD dwBufferSize(sizeof(DWORD));
DWORD nResult(0);
LONG nError = ::RegQueryValueExW(hKey,
strValueName.c_str(),
0,
NULL,
reinterpret_cast<LPBYTE>(&nResult),
&dwBufferSize);
if (ERROR_SUCCESS == nError)
{
nValue = nResult;
}
return nError;
}
LONG GetBoolRegKey(HKEY hKey, const std::wstring &strValueName, bool &bValue, bool bDefaultValue)
{
DWORD nDefValue((bDefaultValue) ? 1 : 0);
DWORD nResult(nDefValue);
LONG nError = GetDWORDRegKey(hKey, strValueName.c_str(), nResult, nDefValue);
if (ERROR_SUCCESS == nError)
{
bValue = (nResult != 0) ? true : false;
}
return nError;
}
LONG GetStringRegKey(HKEY hKey, const std::wstring &strValueName, std::wstring &strValue, const std::wstring &strDefaultValue)
{
strValue = strDefaultValue;
WCHAR szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer);
ULONG nError;
nError = RegQueryValueExW(hKey, strValueName.c_str(), 0, NULL, (LPBYTE)szBuffer, &dwBufferSize);
if (ERROR_SUCCESS == nError)
{
strValue = szBuffer;
}
return nError;
}
const CString REG_SW_GROUP_I_WANT = _T("SOFTWARE\\My Corporation\\My Package\\Group I want");
const CString REG_KEY_I_WANT= _T("Key Name");
CRegKey regKey;
DWORD dwValue = 0;
if(ERROR_SUCCESS != regKey.Open(HKEY_LOCAL_MACHINE, REG_SW_GROUP_I_WANT))
{
m_pobLogger->LogError(_T("CRegKey::Open failed in Method"));
regKey.Close();
goto Function_Exit;
}
if( ERROR_SUCCESS != regKey.QueryValue( dwValue, REG_KEY_I_WANT))
{
m_pobLogger->LogError(_T("CRegKey::QueryValue Failed in Method"));
regKey.Close();
goto Function_Exit;
}
// dwValue has the stuff now - use for further processing
Since Windows >=Vista/Server 2008, RegGetValue is available, which is a safer function than RegQueryValueEx. No need for RegOpenKeyEx, RegCloseKey or NUL termination checks of string values (REG_SZ, REG_MULTI_SZ, REG_EXPAND_SZ).
#include <iostream>
#include <string>
#include <exception>
#include <windows.h>
/*! \brief Returns a value from HKLM as string.
\exception std::runtime_error Replace with your error handling.
*/
std::wstring GetStringValueFromHKLM(const std::wstring& regSubKey, const std::wstring& regValue)
{
size_t bufferSize = 0xFFF; // If too small, will be resized down below.
std::wstring valueBuf; // Contiguous buffer since C++11.
valueBuf.resize(bufferSize);
auto cbData = static_cast<DWORD>(bufferSize * sizeof(wchar_t));
auto rc = RegGetValueW(
HKEY_LOCAL_MACHINE,
regSubKey.c_str(),
regValue.c_str(),
RRF_RT_REG_SZ,
nullptr,
static_cast<void*>(valueBuf.data()),
&cbData
);
while (rc == ERROR_MORE_DATA)
{
// Get a buffer that is big enough.
cbData /= sizeof(wchar_t);
if (cbData > static_cast<DWORD>(bufferSize))
{
bufferSize = static_cast<size_t>(cbData);
}
else
{
bufferSize *= 2;
cbData = static_cast<DWORD>(bufferSize * sizeof(wchar_t));
}
valueBuf.resize(bufferSize);
rc = RegGetValueW(
HKEY_LOCAL_MACHINE,
regSubKey.c_str(),
regValue.c_str(),
RRF_RT_REG_SZ,
nullptr,
static_cast<void*>(valueBuf.data()),
&cbData
);
}
if (rc == ERROR_SUCCESS)
{
cbData /= sizeof(wchar_t);
valueBuf.resize(static_cast<size_t>(cbData - 1)); // remove end null character
return valueBuf;
}
else
{
throw std::runtime_error("Windows system error code: " + std::to_string(rc));
}
}
int main()
{
std::wstring regSubKey;
#ifdef _WIN64 // Manually switching between 32bit/64bit for the example. Use dwFlags instead.
regSubKey = L"SOFTWARE\\WOW6432Node\\Company Name\\Application Name\\";
#else
regSubKey = L"SOFTWARE\\Company Name\\Application Name\\";
#endif
std::wstring regValue(L"MyValue");
std::wstring valueFromRegistry;
try
{
valueFromRegistry = GetStringValueFromHKLM(regSubKey, regValue);
}
catch (std::exception& e)
{
std::cerr << e.what();
}
std::wcout << valueFromRegistry;
}
Its parameter dwFlags supports flags for type restriction, filling the value buffer with zeros on failure (RRF_ZEROONFAILURE) and 32/64bit registry access (RRF_SUBKEY_WOW6464KEY, RRF_SUBKEY_WOW6432KEY) for 64bit programs.
The pair RegOpenKey and RegQueryKeyEx will do the trick.
If you use MFC CRegKey class is even more easier solution.
RegQueryValueEx
This gives the value if it exists, and returns an error code ERROR_FILE_NOT_FOUND if the key doesn't exist.
(I can't tell if my link is working or not, but if you just google for "RegQueryValueEx" the first hit is the msdn documentation.)
Typically the register key and value are constants in the program. If so, here is an example how to read a DWORD registry value Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled:
#include <windows.h>
DWORD val;
DWORD dataSize = sizeof(val);
if (ERROR_SUCCESS == RegGetValueA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\FileSystem", "LongPathsEnabled", RRF_RT_DWORD, nullptr /*type not required*/, &val, &dataSize)) {
printf("Value is %i\n", val);
// no CloseKey needed because it is a predefined registry key
}
else {
printf("Error reading.\n");
}
To adapt for other value types, see https://learn.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-reggetvaluea for complete spec.
This console app will list all the values and their data from a registry key for most of the potential registry values. There's some weird ones not often used. If you need to support all of them, expand from this example while referencing this Registry Value Type documentation.
Let this be the registry key content you can import from a .reg file format:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\added\subkey]
"String_Value"="hello, world!"
"Binary_Value"=hex:01,01,01,01
"Dword value"=dword:00001224
"QWord val"=hex(b):24,22,12,00,00,00,00,00
"multi-line val"=hex(7):4c,00,69,00,6e,00,65,00,20,00,30,00,00,00,4c,00,69,00,\
6e,00,65,00,20,00,31,00,00,00,4c,00,69,00,6e,00,65,00,20,00,32,00,00,00,00,\
00
"expanded_val"=hex(2):25,00,55,00,53,00,45,00,52,00,50,00,52,00,4f,00,46,00,49,\
00,4c,00,45,00,25,00,5c,00,6e,00,65,00,77,00,5f,00,73,00,74,00,75,00,66,00,\
66,00,00,00
The console app itself:
#include <Windows.h>
#include <iostream>
#include <string>
#include <locale>
#include <vector>
#include <iomanip>
int wmain()
{
const auto hKey = HKEY_CURRENT_USER;
constexpr auto lpSubKey = TEXT("added\\subkey");
auto openedKey = HKEY();
auto status = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &openedKey);
if (status == ERROR_SUCCESS) {
auto valueCount = static_cast<DWORD>(0);
auto maxNameLength = static_cast<DWORD>(0);
auto maxValueLength = static_cast<DWORD>(0);
status = RegQueryInfoKey(openedKey, NULL, NULL, NULL, NULL, NULL, NULL,
&valueCount, &maxNameLength, &maxValueLength, NULL, NULL);
if (status == ERROR_SUCCESS) {
DWORD type = 0;
DWORD index = 0;
std::vector<wchar_t> valueName = std::vector<wchar_t>(maxNameLength + 1);
std::vector<BYTE> dataBuffer = std::vector<BYTE>(maxValueLength);
for (DWORD index = 0; index < valueCount; index++) {
DWORD charCountValueName = static_cast<DWORD>(valueName.size());
DWORD charBytesData = static_cast<DWORD>(dataBuffer.size());
status = RegEnumValue(openedKey, index, valueName.data(), &charCountValueName,
NULL, &type, dataBuffer.data(), &charBytesData);
if (type == REG_SZ) {
const auto reg_string = reinterpret_cast<wchar_t*>(dataBuffer.data());
std::wcout << L"Type: REG_SZ" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData : " << reg_string << std::endl;
}
else if (type == REG_EXPAND_SZ) {
const auto casted = reinterpret_cast<wchar_t*>(dataBuffer.data());
TCHAR buffer[32000];
ExpandEnvironmentStrings(casted, buffer, 32000);
std::wcout << L"Type: REG_EXPAND_SZ" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData: " << buffer << std::endl;
}
else if (type == REG_MULTI_SZ) {
std::vector<std::wstring> lines;
const auto str = reinterpret_cast<wchar_t*>(dataBuffer.data());
auto line = str;
lines.emplace_back(line);
for (auto i = 0; i < charBytesData / sizeof(wchar_t) - 1; i++) {
const auto c = str[i];
if (c == 0) {
line = str + i + 1;
const auto new_line = reinterpret_cast<wchar_t*>(line);
if (wcsnlen_s(new_line, 1024) > 0)
lines.emplace_back(new_line);
}
}
std::wcout << L"Type: REG_MULTI_SZ" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData: " << std::endl;
for (size_t i = 0; i < lines.size(); i++) {
std::wcout << L"\t\tLine[" << i + 1 << L"]: " << lines[i] << std::endl;
}
}
if (type == REG_DWORD) {
const auto dword_value = reinterpret_cast<unsigned long*>(dataBuffer.data());
std::wcout << L"Type: REG_DWORD" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData : " << std::to_wstring(*dword_value) << std::endl;
}
else if (type == REG_QWORD) {
const auto qword_value = reinterpret_cast<unsigned long long*>(dataBuffer.data());
std::wcout << L"Type: REG_DWORD" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData : " << std::to_wstring(*qword_value) << std::endl;
}
else if (type == REG_BINARY) {
std::vector<uint16_t> bins;
for (auto i = 0; i < charBytesData; i++) {
bins.push_back(static_cast<uint16_t>(dataBuffer[i]));
}
std::wcout << L"Type: REG_BINARY" << std::endl;
std::wcout << L"\tName: " << valueName.data() << std::endl;
std::wcout << L"\tData:";
for (size_t i = 0; i < bins.size(); i++) {
std::wcout << L" " << std::uppercase << std::hex << \
std::setw(2) << std::setfill(L'0') << std::to_wstring(bins[i]);
}
std::wcout << std::endl;
}
}
}
}
RegCloseKey(openedKey);
return 0;
}
Expected console output:
Type: REG_SZ
Name: String_Value
Data : hello, world!
Type: REG_BINARY
Name: Binary_Value
Data: 01 01 01 01
Type: REG_DWORD
Name: Dword value
Data : 4644
Type: REG_DWORD
Name: QWord val
Data : 1188388
Type: REG_MULTI_SZ
Name: multi-line val
Data:
Line[1]: Line 0
Line[2]: Line 1
Line[3]: Line 2
Type: REG_EXPAND_SZ
Name: expanded_val
Data: C:\Users\user name\new_stuff
#include <windows.h>
#include <map>
#include <string>
#include <stdio.h>
#include <string.h>
#include <tr1/stdint.h>
using namespace std;
void printerr(DWORD dwerror) {
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dwerror,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Process any inserts in lpMsgBuf.
// ...
// Display the string.
if (isOut) {
fprintf(fout, "%s\n", lpMsgBuf);
} else {
printf("%s\n", lpMsgBuf);
}
// Free the buffer.
LocalFree(lpMsgBuf);
}
bool regreadSZ(string& hkey, string& subkey, string& value, string& returnvalue, string& regValueType) {
char s[128000];
map<string,HKEY> keys;
keys["HKEY_CLASSES_ROOT"]=HKEY_CLASSES_ROOT;
keys["HKEY_CURRENT_CONFIG"]=HKEY_CURRENT_CONFIG; //DID NOT SURVIVE?
keys["HKEY_CURRENT_USER"]=HKEY_CURRENT_USER;
keys["HKEY_LOCAL_MACHINE"]=HKEY_LOCAL_MACHINE;
keys["HKEY_USERS"]=HKEY_USERS;
HKEY mykey;
map<string,DWORD> valuetypes;
valuetypes["REG_SZ"]=REG_SZ;
valuetypes["REG_EXPAND_SZ"]=REG_EXPAND_SZ;
valuetypes["REG_MULTI_SZ"]=REG_MULTI_SZ; //probably can't use this.
LONG retval=RegOpenKeyEx(
keys[hkey], // handle to open key
subkey.c_str(), // subkey name
0, // reserved
KEY_READ, // security access mask
&mykey // handle to open key
);
if (ERROR_SUCCESS != retval) {printerr(retval); return false;}
DWORD slen=128000;
DWORD valuetype = valuetypes[regValueType];
retval=RegQueryValueEx(
mykey, // handle to key
value.c_str(), // value name
NULL, // reserved
(LPDWORD) &valuetype, // type buffer
(LPBYTE)s, // data buffer
(LPDWORD) &slen // size of data buffer
);
switch(retval) {
case ERROR_SUCCESS:
//if (isOut) {
// fprintf(fout,"RegQueryValueEx():ERROR_SUCCESS:succeeded.\n");
//} else {
// printf("RegQueryValueEx():ERROR_SUCCESS:succeeded.\n");
//}
break;
case ERROR_MORE_DATA:
//what do I do now? data buffer is too small.
if (isOut) {
fprintf(fout,"RegQueryValueEx():ERROR_MORE_DATA: need bigger buffer.\n");
} else {
printf("RegQueryValueEx():ERROR_MORE_DATA: need bigger buffer.\n");
}
return false;
case ERROR_FILE_NOT_FOUND:
if (isOut) {
fprintf(fout,"RegQueryValueEx():ERROR_FILE_NOT_FOUND: registry value does not exist.\n");
} else {
printf("RegQueryValueEx():ERROR_FILE_NOT_FOUND: registry value does not exist.\n");
}
return false;
default:
if (isOut) {
fprintf(fout,"RegQueryValueEx():unknown error type 0x%lx.\n", retval);
} else {
printf("RegQueryValueEx():unknown error type 0x%lx.\n", retval);
}
return false;
}
retval=RegCloseKey(mykey);
if (ERROR_SUCCESS != retval) {printerr(retval); return false;}
returnvalue = s;
return true;
}