Null when accessing the Access property of a Win32_Volume instance - windows

As a way to resolve GetVolumeInformation() not reporting FILE_READ_ONLY_VOLUME for a locked SD Card without any file-system, I found that the Win32_Volume class has an Access uint16 property that:
Describes whether the media is readable. This property is inherited from CIM_StorageExtent. This can be one of the following values.
I'm interacting with WMI from a C++ program, so when reading the Access property I get a VARIANT structure with the result.
According to the docs, a VARIANT contains an union, so I should first check the vt property to determine its type. vt is a VARTYPE, which is an int according to the docs. The vt value I get after accessing the Access property is 1, which again according to the docs, is null. I can confirm this result by trying to access most of the union members, which are not set at all.
Here's a complete runnable example (run with cl /EHsc test.cpp):
#include <iostream>
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main(int argc, char **argv) {
IWbemLocator *locator = NULL;
IWbemServices *services = NULL;
IEnumWbemClassObject* enumerator = NULL;
IWbemClassObject *classObject = NULL;
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) return 1;
if (FAILED(CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL))) return 1;
if (FAILED(CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *)&locator))) return 1;
if (FAILED(locator->ConnectServer(_bstr_t(L"ROOT\\CIMV2"), NULL, NULL, 0, NULL, 0, 0, &services))) return 1;
if (FAILED(CoSetProxyBlanket(services, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE))) return 1;
if (FAILED(services->ExecQuery(bstr_t("WQL"), bstr_t("SELECT * FROM Win32_Volume"), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &enumerator))) return 1;
while (enumerator) {
ULONG code = 0;
if (FAILED(enumerator->Next(WBEM_INFINITE, 1, &classObject, &code))) return 1;
if (code == 0) break;
VARIANT variant;
if (FAILED(classObject->Get(L"DriveLetter", 0, &variant, NULL, NULL))) return 1;
if (variant.bstrVal == NULL) {
VariantClear(&variant);
classObject->Release();
continue;
};
std::wcout << " DriveLetter : " << variant.bstrVal[0] << std::endl;
VariantClear(&variant);
if (FAILED(classObject->Get(L"Access", 0, &variant, NULL, NULL))) return 1;
std::wcout << "Access VARTYPE -> " << variant.vt << std::endl;
VariantClear(&variant);
classObject->Release();
}
enumerator->Release();
services->Release();
locator->Release();
CoUninitialize();
return 0;
}
This is an example output from my system (Windows 10 Pro x86_64):
DriveLetter : C
Access VARTYPE -> 1
DriveLetter : F
Access VARTYPE -> 1
DriveLetter : E
Access VARTYPE -> 1
I can access other string properties, like DriveLetter, just fine, which makes me think I'm doing something wrong with this particular property.
UPDATE 1: Looks like I get the same results with any uint16 property, but not with uint32, nor uint64, which seem to work just fine.

Related

Exact way to get permissions of a file in windows using C++ and api

My project is like i need to modify the file permissions from a web application. I'm using java for backend and emberjs for client side. To get the file permissions I'm using C++ native code with windows api with JNI. Here is my problem,
I need to get the permissions of the files in a directory in windows using api. I'm new to windows api so I've googled and got the below code and modified it to my needs. Now the problem is when i run this, it gives me the results when the file has "Full Control" as permission otherwise the permissions are not showing. Please help me with this. What need to be modified in here or if there are any other possible solutions, please suggest me that too. Thanks in advance.
Here is my code,
#include <Windows.h>
#include <vector>
#include <map>
#include <iostream>
#include <aclapi.h>
#include <windows.h>
#include <string>
#include <memory>
#include <tchar.h>
using namespace std;
bool CanAccessFolder(LPCTSTR folderName, DWORD genericAccessRights,DWORD& grantedRights)
{
bool bRet = false;
DWORD length = 0;
if (!::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION, NULL, NULL, &length) &&
ERROR_INSUFFICIENT_BUFFER == ::GetLastError()) {
PSECURITY_DESCRIPTOR security = static_cast< PSECURITY_DESCRIPTOR >(::malloc(length));
if (security && ::GetFileSecurity(folderName, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION, security, length, &length)) {
HANDLE hToken = NULL;
if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_IMPERSONATE | TOKEN_QUERY |
TOKEN_DUPLICATE | STANDARD_RIGHTS_READ, &hToken)) {
HANDLE hImpersonatedToken = NULL;
if (::DuplicateToken(hToken, SecurityImpersonation, &hImpersonatedToken)) {
GENERIC_MAPPING mapping = { 0xFFFFFFFF };
PRIVILEGE_SET privileges = { 0 };
DWORD grantedAccess = 0, privilegesLength = sizeof(privileges);
BOOL result = FALSE;
mapping.GenericRead = FILE_GENERIC_READ;
mapping.GenericWrite = FILE_GENERIC_WRITE;
mapping.GenericExecute = FILE_GENERIC_EXECUTE;
mapping.GenericAll = FILE_ALL_ACCESS;
::MapGenericMask(&genericAccessRights, &mapping);
if (::AccessCheck(security, hImpersonatedToken, genericAccessRights,
&mapping, &privileges, &privilegesLength, &grantedAccess, &result))
{
bRet = (result == TRUE);
grantedRights = grantedAccess;
}
::CloseHandle(hImpersonatedToken);
}
::CloseHandle(hToken);
}
::free(security);
}
}
return bRet;
}
vector<string> printMasks(DWORD Mask)
{
// This evaluation of the ACCESS_MASK is an example.
// Applications should evaluate the ACCESS_MASK as necessary.
vector<string> access;
std::wcout << "Effective Allowed Access Mask : "<< Mask << std::hex << std::endl;
if (((Mask & GENERIC_ALL) == GENERIC_ALL)
|| ((Mask & FILE_ALL_ACCESS) == FILE_ALL_ACCESS))
{
// wprintf_s(L"Full Control\n");
access.push_back("Full Control");
// return access;
}
if (((Mask & GENERIC_READ) == GENERIC_READ)
|| ((Mask & FILE_GENERIC_READ) == FILE_GENERIC_READ))
// wprintf_s(L"Read\n");
access.push_back("Read");
if (((Mask & GENERIC_WRITE) == GENERIC_WRITE)
|| ((Mask & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE))
// wprintf_s(L"Write\n");
access.push_back("Write");
if (((Mask & GENERIC_EXECUTE) == GENERIC_EXECUTE)
|| ((Mask & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE))
// wprintf_s(L"Execute\n");
access.push_back("Execute");
return access;
}
std::map<std::string, std::vector<std::string>>
list_directory(const std::string &directory)
{
DWORD access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_ALL_ACCESS;
std::map<std::string, std::vector<std::string>> files;
WIN32_FIND_DATAA findData;
HANDLE hFind = INVALID_HANDLE_VALUE;
std::string full_path = directory + "\\*";
hFind = FindFirstFileA(full_path.c_str(), &findData);
if (hFind == INVALID_HANDLE_VALUE)
throw std::runtime_error("Invalid handle value! Please check your path...");
while (FindNextFileA(hFind, &findData) != 0)
{
std::string file = findData.cFileName;
std::string filepath = directory + "/" + file;
DWORD grant = 0;
bool b = CanAccessFolder(filepath.c_str(), access_mask, grant);
files[file] = printMasks(grant);
}
FindClose(hFind);
return files;
}
int main() {
std::map<std::string, std::vector<std::string>> files;
files = list_directory("C:/Users/Vicky/Desktop/samples");
int i = 1;
map<string, vector<string>> :: iterator it=files.begin();
//iteration using traditional for loop
for(it=files.begin();it!=files.end();it++)
{
//accessing keys
cout << it->first << " : \t";
//accessing values (vectors)
for (auto &&i : it->second)
{
cout << i << "\t";
}
cout << endl;
}
}
Here are the results,
sample1.txt permissions
sample2.txt permissions
When you are performing the access check the line
DWORD access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | FILE_ALL_ACCESS;
Is specifying that you are checking that the if you have read/write/execute/full control access to each item you are checking.
As a result when you call AccessCheck on sample2.txt where you don't have all those permissions AccessCheck reports in its last parameter that you don't have access. In that case MSDN for the GrantedAccess parameter states
[out] GrantedAccess
A pointer to an access mask that receives the granted access rights. If >AccessStatus is set to FALSE, the function sets the access mask to zero. If
the function fails, it does not set the access mask.
That access mask of all zero's is what you are printing out for sample2.txt
If you want to see what you can actually do for each file change the line above to
DWORD access_mask = MAXIMUM_ALLOWED;
This causes the file to be checked for whatever access it can get hold of rather than full control which it does not have.

GetRawInputDeviceInfo indicates a buffer size of 1 character for RIDI_DEVICENAME

I'm getting ridiculous behavior from RIDI_DEVICENAME. According to the documentation,
Return value
Type: UINT
If successful, this function returns a non-negative number indicating the number of bytes copied to pData.
If pData is not large enough for the data, the function returns -1. If pData is NULL, the function returns a value of zero. In both of these cases, pcbSize is set to the minimum size required for the pData buffer.
Call GetLastError to identify any other errors.
Ignoring the obvious problem that -1 is not a representable value in the UINT return type, it seems that the function should tell me the required size of the buffer, and if I supply a buffer of this size, the function should either succeed or at least follow its own rules for failure.
However, I'm not seeing this at all. On Windows 10, the Unicode version of the function sets pcbSize to 1 when pData is null and leaves it alone otherwise, failing in all cases. The ANSI version of the function sets pcbSize to 2 when pData is null, and otherwise doubles whatever value was passed in, and still fails.
Headers used for either version of test code:
#define WIN32_EXTRA_LEAN 1
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
#include <windows.h>
ANSI test code:
std::string GetRawInputDeviceName( HANDLE hRaw )
{
UINT numChars = 0u;
INT validChars;
validChars = static_cast<INT>(::GetRawInputDeviceInfoA(hRaw, RIDI_DEVICENAME, nullptr, &numChars));
auto lasterror = ::GetLastError();
if (lasterror != ERROR_INSUFFICIENT_BUFFER) {
std::wcerr << L"Failed to get length of name of raw input device, retcode = " << validChars << L", last error = " << lasterror << L"\n";
return {};
}
std::string name;
name.resize(numChars);
validChars = static_cast<INT>(::GetRawInputDeviceInfoA(hRaw, RIDI_DEVICENAME, &name[0], &numChars));
lasterror = ::GetLastError();
if (validChars > 0) {
name.resize(validChars);
return name;
}
else {
std::wcerr << L"Failed to get name of raw input device, retcode = " << validChars << L", last error = " << lasterror << L"\n";
return {};
}
}
Unicode test code:
std::wstring GetRawInputDeviceName( HANDLE hRaw )
{
UINT numChars = 0u;
INT validChars;
validChars = static_cast<INT>(::GetRawInputDeviceInfoW(hRaw, RIDI_DEVICENAME, nullptr, &numChars));
auto lasterror = ::GetLastError();
if (lasterror != ERROR_INSUFFICIENT_BUFFER) {
std::wcerr << L"Failed to get length of name of raw input device, retcode = " << validChars << L", last error = " << lasterror << L"\n";
return {};
}
std::wstring name;
name.resize(numChars);
validChars = static_cast<INT>(::GetRawInputDeviceInfoW(hRaw, RIDI_DEVICENAME, &name[0], &numChars));
lasterror = ::GetLastError();
if (validChars > 0) {
name.resize(validChars);
return name;
}
else {
std::wcerr << L"Failed to get name of raw input device, retcode = " << validChars << L", last error = " << lasterror << L"\n";
return {};
}
}
On Windows 10 through RDP I'm getting ERROR_INSUFFICIENT_BUFFER consistently.
On Windows 8.1 running as a local user, I get ERROR_INSUFFICIENT_BUFFER if pData is null, and when I provide a buffer I get back failure ((UINT)-1) and GetLastError() returns zero.
I've also just tried proposing a likely-large-enough buffer size, and got failures as well.
What is going on, what is the right way to get the interface path name, and do I need administrative rights or to call some other APIs first? I don't seem to be having any problems calling GetRawInputDeviceList or using RIDI_DEVICEINFO mode of GetRawInputDeviceInfo... but I need the interface path in order to go further.
Windows HID Device Name Format
https://stackoverflow.com/a/64320052/103167
the GetRawInputDeviceName have several errors in declaration / implementation / documentation
by fact more correct declare return value as signed ( LONG or INT) but not UINT
exist 3 case:
1. function return negative value (or if want -1) : this is error
case, and by design - last error must be set. but really it not
always set (implementation error).
most common errors:
pcbSize or pData point to invalid or read only memory location. usual error in this case ERROR_NOACCESS (translated from
STATUS_ACCESS_VIOLATION)
hDevice not valid handle - ERROR_INVALID_HANDLE is returned
uiCommand not valid RIDI_XXX constant - ERROR_INVALID_PARAMETER
*pcbSize is not large enough for the data - in this case *pcbSize is set to the minimum size required for the pData buffer. ERROR_INSUFFICIENT_BUFFER
again - only in this case (-1) exist sense call GetLastError();
2. function return 0 this possible only in case when pData is NULL.
*pcbSize is set to the minimum size required for the pData buffer.
3. function return positive value ( > 0) this mean that this count of
bytes (in case RIDI_PREPARSEDDATA or RIDI_DEVICEINFO ) or
characters (in case RIDI_DEVICENAME) written to buffer
so documentation is wrong here:
pcbSize
[in, out]
Pointer to a variable that contains the size, in bytes, of the data in
pData.
in case RIDI_DEVICENAME in characters
so already visible very serious problems with design (type of return value - unsigned) and mixed bytes/characters. many different cases.
but then exist critical error in implementation. in begin of function handle hDevice converted to pointer.
PDEVICEINFO pDeviceInfo = HMValidateHandle(hDevice, TYPE_DEVICEINFO);
(if 0 returned - we got -1 on exit with ERROR_INVALID_HANDLE).
in DEVICEINFO exist UNICODE_STRING ustrName - this name and copied to user mode
switch (uiCommand) {
case RIDI_DEVICENAME:
/*
* N.b. UNICODE_STRING counts the length by the BYTE count, not by the character count.
* Our APIs always treat the strings by the character count. Thus, for RIDI_DEVICNAME
* only, cbOutSize holds the character count, not the byte count, in spite of its
* name. Confusing, but cch is the way to be consistent.
*/
cbOutSize = pDeviceInfo->ustrName.Length / sizeof(WCHAR) + 1; // for Null terminator
break;
//...
}
required cbOutSize compared with cbBufferSize = *pcbSize;
and if (cbBufferSize >= cbOutSize) api begin copy operation
exist next code
case RIDI_DEVICENAME:
if (cbOutSize <= 2) { // !!!! error !!!!
retval = -1;
goto leave;
}
RtlCopyMemory(pData, pDeviceInfo->ustrName.Buffer, pDeviceInfo->ustrName.Length);
((WCHAR*)pData)[1] = '\\'; // convert nt prefix ( \??\ ) to win32 ( \\?\ )
((WCHAR*)pData)[cbOutSize - 1] = 0; // make it null terminated
break;
cbOutSize here - is (len + 1) of device name (which we not control). so if name is zero length - always -1 is returned (error #1) but last error not set ( error #2 )
of course exist and error #3 - why is device name is 0 length ? this must not be. but in case terminal service devices - (virtual mouse/ keyboard device created on UMB bus ) - exist this result.
full code for api ( in kernel)
UINT NtUserGetRawInputDeviceInfo(
HANDLE hDevice,
UINT uiCommand,
LPVOID pData,
PUINT pcbSize)
{
UINT cbOutSize = 0;
UINT cbBufferSize;
int retval = 0;
EnterCrit(0, UserMode);
UserAtomicCheck uac;
try {
ProbeForRead(pcbSize, sizeof(UINT), sizeof(DWORD));
cbBufferSize = *pcbSize;
} except (EXCEPTION_EXECUTE_HANDLER) {
UserSetLastError(RtlNtStatusToDosError(GetExceptionCode()));// ERROR_NOACCESS
retval = -1;
goto leave1;
}
EnterDeviceInfoListCrit_();
PDEVICEINFO pDeviceInfo = HMValidateHandle(hDevice, TYPE_DEVICEINFO);
if (pDeviceInfo == NULL) {
UserSetLastError(ERROR_INVALID_HANDLE);
retval = -1;
goto leave;
}
/*
* Compute the size of the output and evaluate the uiCommand.
*/
switch (uiCommand) {
case RIDI_PREPARSEDDATA:
if (pDeviceInfo->type == DEVICE_TYPE_HID) {
cbOutSize = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.DescriptorSize;
} else {
cbOutSize = 0;
}
break;
case RIDI_DEVICENAME:
/*
* N.b. UNICODE_STRING counts the length by the BYTE count, not by the character count.
* Our APIs always treat the strings by the character count. Thus, for RIDI_DEVICNAME
* only, cbOutSize holds the character count, not the byte count, in spite of its
* name. Confusing, but cch is the way to be consistent.
*/
cbOutSize = pDeviceInfo->ustrName.Length / sizeof(WCHAR) + 1; // for Null terminator
break;
case RIDI_DEVICEINFO:
cbOutSize = sizeof(RID_DEVICE_INFO);
break;
default:
UserSetLastError(ERROR_INVALID_PARAMETER);
retval = -1;
goto leave;
}
if (pData == NULL) {
/*
* The app wants to get the required size.
*/
try {
ProbeForWrite(pcbSize, sizeof(UINT), sizeof(DWORD));
*pcbSize = cbOutSize;
} except (EXCEPTION_EXECUTE_HANDLER) {
UserSetLastError(RtlNtStatusToDosError(GetExceptionCode()));// ERROR_NOACCESS
retval = -1;
goto leave;
}
retval = 0;
} else {
if (cbBufferSize >= cbOutSize) {
try {
ProbeForWrite(pData, cbBufferSize, sizeof(DWORD));
switch (uiCommand) {
case RIDI_PREPARSEDDATA:
if (pDeviceInfo->type == DEVICE_TYPE_HID) {
RtlCopyMemory(pData, pDeviceInfo->hid.pHidDesc->pPreparsedData, cbOutSize);
}
break;
case RIDI_DEVICENAME:
if (cbOutSize <= 2) { // !!!!
retval = -1;
goto leave;
}
RtlCopyMemory(pData, pDeviceInfo->ustrName.Buffer, pDeviceInfo->ustrName.Length);
((WCHAR*)pData)[1] = '\\'; // make it null terminated
((WCHAR*)pData)[cbOutSize - 1] = 0; // make it null terminated
break;
case RIDI_DEVICEINFO:
{
PRID_DEVICE_INFO prdi = (PRID_DEVICE_INFO)pData;
ProbeForRead(prdi, sizeof(UINT), sizeof(DWORD));
if (prdi->cbSize != cbOutSize) {
MSGERRORCLEANUP(ERROR_INVALID_PARAMETER);
}
ProbeForWrite(prdi, sizeof(RID_DEVICE_INFO), sizeof(DWORD));
RtlZeroMemory(prdi, sizeof(RID_DEVICE_INFO));
prdi->cbSize = cbOutSize;
switch (pDeviceInfo->type) {
case DEVICE_TYPE_HID:
prdi->dwType = RIM_TYPEHID;
prdi->hid.dwVendorId = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.VendorID;
prdi->hid.dwProductId = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.ProductID;
prdi->hid.dwVersionNumber = pDeviceInfo->hid.pHidDesc->hidCollectionInfo.VersionNumber;
prdi->hid.usUsagePage = pDeviceInfo->hid.pHidDesc->hidpCaps.UsagePage;
prdi->hid.usUsage = pDeviceInfo->hid.pHidDesc->hidpCaps.Usage;
break;
case DEVICE_TYPE_MOUSE:
prdi->dwType = RIM_TYPEMOUSE;
prdi->mouse.dwId = pDeviceInfo->mouse.Attr.MouseIdentifier;
prdi->mouse.dwNumberOfButtons = pDeviceInfo->mouse.Attr.NumberOfButtons;
prdi->mouse.dwSampleRate = pDeviceInfo->mouse.Attr.SampleRate;
break;
case DEVICE_TYPE_KEYBOARD:
prdi->dwType = RIM_TYPEKEYBOARD;
prdi->keyboard.dwType = GET_KEYBOARD_DEVINFO_TYPE(pDeviceInfo);
prdi->keyboard.dwSubType = GET_KEYBOARD_DEVINFO_SUBTYPE(pDeviceInfo);
prdi->keyboard.dwKeyboardMode = pDeviceInfo->keyboard.Attr.KeyboardMode;
prdi->keyboard.dwNumberOfFunctionKeys = pDeviceInfo->keyboard.Attr.NumberOfFunctionKeys;
prdi->keyboard.dwNumberOfIndicators = pDeviceInfo->keyboard.Attr.NumberOfIndicators;
prdi->keyboard.dwNumberOfKeysTotal = pDeviceInfo->keyboard.Attr.NumberOfKeysTotal;
break;
}
}
break;
default:
__assume(false);
}
} except (EXCEPTION_EXECUTE_HANDLER) {
UserSetLastError(RtlNtStatusToDosError(GetExceptionCode()));// ERROR_NOACCESS
retval = -1;
goto leave;
}
retval = cbOutSize;
} else {
/*
* The buffer size is too small.
* Returns error, storing the required size in *pcbSize.
*/
retval = -1;
try {
ProbeForWrite(pcbSize, sizeof(UINT), sizeof(DWORD));
*pcbSize = cbOutSize;
UserSetLastError(ERROR_INSUFFICIENT_BUFFER);
} except (EXCEPTION_EXECUTE_HANDLER) {
UserSetLastError(RtlNtStatusToDosError(GetExceptionCode()));// ERROR_NOACCESS
retval = -1;
goto leave;
}
}
}
leave:
LeaveDeviceInfoListCrit_();
leave1:
UserSessionSwitchLeaveCrit();
return retval;
}
then GetRawInputDeviceInfoA add additional errors compare GetRawInputDeviceInfoW - the value from *pcbSize by some reason multiple on 2. but again - this error in all case.
note that DeviceName (formatted from strings returned from driver on IRP_MN_QUERY_ID have very strict restrictions:
If a driver returns an ID with an illegal character, the system will
bug check. Characters with the following values are illegal in an ID
for this IRP:
Less than or equal to 0x20 (' ')
Greater than 0x7F
Equal to 0x2C (',')
so even after covert unicode to ansi - length of device name will be the same ( all symbols < 0x80 ). so not need *2 buffer size for Ansi version.
then i already view error in your code - you call ::GetLastError(); unconditionally after GetRawInputDeviceInfoW - but returned value have sense only in case api return -1
explain for observed behavior:
for local devices api in general work correct (if no mistakes in our code)
for terminal service devices - was 0 length ustrName. as result if we pass NULL in pData - return value will be
pDeviceInfo->ustrName.Length / sizeof(WCHAR) + 1;
because pDeviceInfo->ustrName.Length == 0 - 1 will be returned inside *pcbSize
in case A version - -by mistake - 2*1==2 will be returned.
but when e pass not NULL in pData - we trap in this
if (cbOutSize <= 2) { // !!!! error !!!!
retval = -1;
goto leave;
}
so you can pass any by size buffer, anyway, because (cbOutSize <= 2) - -1 will be returned and last error not set
possible solution - at first - never use ansi version - GetRawInputDeviceInfoA
use this wrapper function.
ULONG GetRawInputDeviceInfoExW(_In_opt_ HANDLE hDevice,
_In_ UINT uiCommand,
_Inout_updates_bytes_to_opt_(*pcbSize, *pcbSize) LPVOID pData,
_Inout_ PUINT pcbSize)
{
switch (int i = GetRawInputDeviceInfoW(hDevice, uiCommand, pData, pcbSize))
{
case 0:
return ERROR_INSUFFICIENT_BUFFER;
case 1:
return ERROR_INVALID_NAME;
default:
if (0 > i)
{
return GetLastError();
}
*pcbSize = i;
return NOERROR;
}
}
example of usage: (/RTCs must be disabled )
void Demo()
{
PRAWINPUTDEVICELIST pRawInputDeviceList = 0;
UINT uiNumDevices = 0;
UINT cch, cchAllocated = 0;
union {
PVOID buf;
PWSTR name;
};
buf = 0;
while (0 <= (int)GetRawInputDeviceList(pRawInputDeviceList, &uiNumDevices, sizeof(RAWINPUTDEVICELIST)))
{
if (pRawInputDeviceList)
{
do
{
HANDLE hDevice = pRawInputDeviceList->hDevice;
ULONG dwError;
while (ERROR_INSUFFICIENT_BUFFER == (dwError =
GetRawInputDeviceInfoExW(hDevice, RIDI_DEVICENAME, name, &(cch = cchAllocated))))
{
if (cch > cchAllocated)
{
cchAllocated = RtlPointerToOffset(buf = alloca((cch - cchAllocated) * sizeof(WCHAR)),
pRawInputDeviceList) / sizeof(WCHAR);
}
else
{
__debugbreak();
}
}
if (dwError == NOERROR)
{
DbgPrint("[%p, %x %S]\n", hDevice, pRawInputDeviceList->dwType, name);
}
else
{
DbgPrint("error = %u\n", dwError);
}
} while (pRawInputDeviceList++, --uiNumDevices);
break;
}
pRawInputDeviceList = (PRAWINPUTDEVICELIST)alloca(uiNumDevices * sizeof(RAWINPUTDEVICELIST));
}
}
This code is working fine on my PC. Not sure, but it indeed could be RDP issue.
UINT result = ::GetRawInputDeviceInfoW(m_Handle, RIDI_DEVICENAME, nullptr, &size);
if (result == static_cast<UINT>(-1))
{
//PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
return false;
}
DCHECK_EQ(0u, result);
std::wstring buffer(size, 0);
result = ::GetRawInputDeviceInfoW(m_Handle, RIDI_DEVICENAME, buffer.data(), &size);
if (result == static_cast<UINT>(-1))
{
//PLOG(ERROR) << "GetRawInputDeviceInfo() failed";
return false;
}
DCHECK_EQ(size, result);

How to use the GetLastError function in a Win32 Console Application?

I am trying to open a Registry Key using the RegOpenKeyEx function from the Windows API, and have this code:
#include <windows.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int wmain(int argc, wchar_t*argv [])
{
HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = L"Demo";
DWORD ulOptions = 0;
REGSAM samDesired = KEY_ALL_ACCESS;
HKEY phkResult;
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
cout << "The registry key has been opened." << endl;
}
else //How can I retrieve the standard error message using GetLastError() here?
{
}
}
How do I use the GetLastError() function to show a generic error message instead of valid any Error Message ID into the else?
Edit: I know there is a FormatMessage function but have the same problem, I don't know how to use it on my code.
The Registry functions do not use GetLastError(). They return the actual error codes directly:
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
cout << "The registry key has been created." << endl;
}
else
{
cout << "The registry key has not been created. Error: " << R << endl;
}
If you want to display a system error message, use FormatMessage() for that:
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
cout << "The registry key has been created." << endl;
}
else
{
char *pMsg = NULL;
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
R,
0,
(LPSTR)&pMsg,
0,
NULL
);
cout << "The registry key has not been created. Error: (" << R << ") " << pMsg << endl;
LocalFree(pMsg);
}
Try this
HKEY hKey = HKEY_CURRENT_USER;
LPCTSTR lpSubKey = L"Demo";
DWORD ulOptions = 0;
REGSAM samDesired = KEY_ALL_ACCESS;
HKEY phkResult;
char *ErrorMsg= NULL;
long R = RegOpenKeyEx(hKey, lpSubKey, ulOptions, samDesired, &phkResult);
if (R == ERROR_SUCCESS)
{
printf("The registry key has been opened.");
}
else //How can I retrieve the standard error message using GetLastError() here?
{
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL,
R,
0,
(LPSTR)&ErrorMsg,
0,
NULL
);
printf("Error while creating Reg key.");
}

ATA command device IDENTIFY

I am trying to identify a device using ATA_PASS_THROUGH_EX.
When I see the output buffer, it has all invalid data. Can someone help me what I am doing wrong?
#include <Windows.h>
#include <ntddscsi.h>
#include <iostream>
void main() {
WCHAR *fileName = (WCHAR * ) "\\.\PhysicalDrive0";
HANDLE handle = CreateFile(
fileName,
GENERIC_READ | GENERIC_WRITE, //IOCTL_ATA_PASS_THROUGH requires read-write
FILE_SHARE_READ,
NULL, //no security attributes
OPEN_EXISTING,
0, //flags and attributes
NULL //no template file
);
ATA_PASS_THROUGH_EX inputBuffer;
inputBuffer.Length = sizeof(ATA_PASS_THROUGH_EX);
inputBuffer.AtaFlags = ATA_FLAGS_DATA_IN;
inputBuffer.DataTransferLength = 0;
inputBuffer.DataBufferOffset = 0;
IDEREGS *ir = (IDEREGS *) inputBuffer.CurrentTaskFile;
ir->bCommandReg = 0xEC; //identify device
ir->bSectorCountReg = 1;
unsigned int inputBufferSize = sizeof(ATA_PASS_THROUGH_EX);
UINT8 outputBuffer[512];
UINT32 outputBufferSize = 512;
LPDWORD bytesReturned = 0;
DeviceIoControl( handle, IOCTL_ATA_PASS_THROUGH_DIRECT, &inputBuffer, inputBufferSize, &outputBuffer, outputBufferSize, bytesReturned, NULL);
DWORD error = GetLastError();
std::cout << outputBuffer << std::endl;
system("pause");
}
update:
When I check the error value, it is 5, which means it is an access violation. I am running in admin mode. Am I doing something wrong?
-Nick
I've done this using code that looks like this:
int foo()
{
int iRet( 0 );
// Open handle to disk.
HANDLE hDevice( ::CreateFileW( L"\\\\.\\PhysicalDrive0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ) );
if( hDevice == INVALID_HANDLE_VALUE )
{
std::wcout << L"CreateFileW( " << sPath << L" ) failed. LastError: " << GetLastError() << std::endl;
return -1;
}
//
// Use IOCTL_ATA_PASS_THROUGH
//
std::vector< UCHAR > vBuffer( sizeof( ATA_PASS_THROUGH_EX ) + sizeof( IDENTIFY_DEVICE_DATA ), 0 );
PATA_PASS_THROUGH_EX pATARequest( reinterpret_cast< PATA_PASS_THROUGH_EX >( &vBuffer[0] ) );
pATARequest->AtaFlags = ATA_FLAGS_DATA_IN | ATA_FLAGS_DRDY_REQUIRED;
pATARequest->Length = sizeof( ATA_PASS_THROUGH_EX );
pATARequest->DataBufferOffset = sizeof( ATA_PASS_THROUGH_EX );
pATARequest->DataTransferLength = sizeof( IDENTIFY_DEVICE_DATA );
pATARequest->TimeOutValue = 2;
pATARequest->CurrentTaskFile[6] = ID_CMD;
ULONG ulBytesRead;
if( DeviceIoControl( hDevice, IOCTL_ATA_PASS_THROUGH,
&vBuffer[0], ULONG( vBuffer.size() ),
&vBuffer[0], ULONG( vBuffer.size() ),
&ulBytesRead, NULL ) == FALSE )
{
std::cout << "DeviceIoControl(IOCTL_ATA_PASS_THROUGH) failed. LastError: " << GetLastError() << std::endl;
iRet = -1;
}
else
{
// Fetch identity blob from output buffer.
PIDENTIFY_DEVICE_DATA pIdentityBlob( reinterpret_cast< PIDENTIFY_DEVICE_DATA >( &vBuffer[ sizeof( ATA_PASS_THROUGH_EX ) ] ) );
}
CloseHandle( hDevice );
return iRet;
}
Note that this must be run from an administrator account or elevated context.

How do I get a specific TIME_ZONE_INFORMATION struct in Win32?

The Win32 GetTimeZoneInformation function returns your systems local time zone as set up in the control panel. How do I get another specific time zone? Is there a call that does this?
Tony
According to this the information for the different timezones is stored in the registry, so you will have to retrieve the information from there and populate the TIME_ZONE_INFORMATION struct yourself.
Quote from the msdn article
Remarks
Settings for each time zone are stored in the following registry key:
HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
Windows NT
CurrentVersion
Time Zones
time_zone_name
code:
#include <stdio.h>
#include <windows.h>
#define pWin32Error(dwSysErr, sMsg )
typedef struct _REG_TZI_FORMAT
{
LONG Bias;
LONG StandardBias;
LONG DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
} REG_TZI_FORMAT;
#define REG_TIME_ZONES "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"
#define REG_TIME_ZONES_LEN (sizeof(REG_TIME_ZONES)-1)
#define REG_TZ_KEY_MAXLEN (REG_TIME_ZONES_LEN + (sizeof(((TIME_ZONE_INFORMATION*)0)->StandardName)/2) -1)
int GetTimeZoneInformationByName(TIME_ZONE_INFORMATION *ptzi, const char StandardName[]) {
int rc;
HKEY hkey_tz;
DWORD dw;
REG_TZI_FORMAT regtzi;
char tzsubkey[REG_TZ_KEY_MAXLEN+1] = REG_TIME_ZONES;
strncpy(tzsubkey + REG_TIME_ZONES_LEN, StandardName, sizeof(tzsubkey) - REG_TIME_ZONES_LEN);
if (tzsubkey[sizeof(tzsubkey)-1] != 0) {
fprintf(stderr, "timezone name too long\n");
return -1;
}
if (ERROR_SUCCESS != (dw = RegOpenKey(HKEY_LOCAL_MACHINE, tzsubkey, &hkey_tz))) {
fprintf(stderr, "failed to open: HKEY_LOCAL_MACHINE\\%s\n", tzsubkey);
pWin32Error(dw, "RegOpenKey() failed");
return -1;
}
rc = 0;
#define X(param, type, var) \
do if ((dw = sizeof(var)), (ERROR_SUCCESS != (dw = RegGetValueW(hkey_tz, NULL, param, type, NULL, &var, &dw)))) { \
fprintf(stderr, "failed to read: HKEY_LOCAL_MACHINE\\%s\\%S\n", tzsubkey, param); \
pWin32Error(dw, "RegGetValue() failed"); \
rc = -1; \
goto ennd; \
} while(0)
X(L"TZI", RRF_RT_REG_BINARY, regtzi);
X(L"Std", RRF_RT_REG_SZ, ptzi->StandardName);
X(L"Dlt", RRF_RT_REG_SZ, ptzi->DaylightName);
#undef X
ptzi->Bias = regtzi.Bias;
ptzi->DaylightBias = regtzi.DaylightBias;
ptzi->DaylightDate = regtzi.DaylightDate;
ptzi->StandardBias = regtzi.StandardBias;
ptzi->StandardDate = regtzi.StandardDate;
ennd:
RegCloseKey(hkey_tz);
return rc;
}
#define ZONE "Russian Standard Time"
int main(int argc, char* argv[])
{
DWORD dw;
TIME_ZONE_INFORMATION tzi;
dw = GetTimeZoneInformationByName(&tzi, ZONE);
if (dw != 0) return 1;
SYSTEMTIME lt;
SYSTEMTIME ut = {
2000, /*WORD wYear;*/
1, /*WORD wMonth;*/
0, /*WORD wDayOfWeek;*/
1, /*WORD wDay;*/
12, /*WORD wHour;*/
0, /*WORD wMinute;*/
0, /*WORD wSecond;*/
0 /*WORD wMilliseconds;*/
};
SystemTimeToTzSpecificLocalTime(&tzi, &ut, &lt);
printf("%d-%02d-%02d %02d:%02d:%02d UTC\n", ut.wYear, ut.wMonth, ut.wDay, ut.wHour, ut.wMinute, ut.wSecond);
printf("=\n");
printf("%d-%02d-%02d %02d:%02d:%02d Europe/Moscow\n", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond);
return 0;
}

Resources