How do I get a specific TIME_ZONE_INFORMATION struct in Win32? - winapi

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

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.

Null when accessing the Access property of a Win32_Volume instance

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.

Building simple unix shell problems

I am new with unix and I've got an assignemnt on college to build a simple shell in c with built in cd and kill command..
This is my code which is not working..tbh I dont understand it the best so Im not suprised it is not working.. can you help me with it? Also have no idea how I would implement kill command. thank you!
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define BUF_SIZE 1024
const int ARGSIZE = 20;
void execute(char*args[])
{
int pid, status;
pid = fork();
if(pid<0)
{
perror("Error forking!");
}
else if(pid > 0)
{
while(wait(&status) != pid)
continue;
}
else if(pid == 0)
{
if (execvp(args[0], args) == -1)
{
perror("Error");
}
}
}
void cd(char*directory)
{
int ret = 0;
if(directory == '\0')
directory = getenv("HOME");
ret = chdir(directory);
if(ret != 0)
fprintf(stderr,"Failed to enter directory: %s\n",directory);
else
printf("%s\n",directory);
}
int main()
{
char line[BUF_SIZE];
char *args[ARGSIZE];
int argIndex = 0;
while(1){
printf("> ");
fgets(line, BUF_SIZE, stdin);
char *token;
token = strtok(line," ");
while(token!=NULL)
{
args[argIndex]=token;
token = strtok(NULL," ");
argIndex++;
}
args[argIndex]=NULL;
if(strcmp(args[0], "quit") == 0 || strcmp(args[0], "exit") == 0)
break;
if(line== "\n")
printf("> ");
else if ((strcmp(args[0], "cd") == 0))
cd(args[1]);
else
execute(args);
}
return 0;
}
You were on the right track. There were a few subtle issues where you were not accounting for the trailing '\n' that would remain in line as the last character following whatever was entered at the prompt. Including " \n" in the delimiters used to tokenize the input with strtok will remove it, allowing valid strcmp comparisons with the final token (e.g. that is why quit and exit would not quit the application).
Other than than, there were several additional things you could do a little different/better, you could handle directories entered as e.g. '~/somedir', and similar additional checks that could be employed. I have notated most below as comments to the code.
Look over the changes below and let me know if you have any questions. There are always additional checks that can be added, etc.., but on balance your approach to the problem was pretty good. (note: some of the changes made were non-substantive, e.g. "shell> " as the prompt, instead of "> ". Just handle any of those as you wish.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
enum {ARGSIZE = 20, BUF_SIZE = 1024};
void execute (char **args);
void cd (char *directory);
int killpid (char *pitstr, int sig);
int main (void)
{
char line[BUF_SIZE] = {0};
char *args[ARGSIZE] = {NULL};
char *token;
int i, argIndex = 0;
while (1) {
argIndex = 0; /* reinitialize variables */
for (i = 0; i < ARGSIZE; i++)
args[i] = NULL;
printf ("shell> "); /* prompt */
if (fgets (line, BUF_SIZE, stdin) == NULL) {
printf ("EOF received\n");
return 0;
}
if (*line == '\n') /* Enter alone */
continue;
token = strtok (line, " \n"); /* add \n to delimiters */
while (token != NULL) {
args[argIndex] = token;
token = strtok (NULL, " \n");
argIndex++;
}
if (!argIndex) continue; /* validate at least 1 arg */
if (strcmp (args[0], "quit") == 0 || strcmp (args[0], "exit") == 0)
break;
/* handle 'cd' or 'kill' separately */
if ((strcmp (args[0], "cd") == 0))
cd (args[1]);
else if ((strcmp (args[0], "kill") == 0)) {
if (args[1]) killpid (args[1], SIGTERM);
}
else
execute (args);
}
return 0;
}
void execute (char **args)
{
int pid, status;
pid = fork ();
if (pid < 0) {
perror ("Error forking!");
return;
}
else if (pid > 0) {
while (wait (&status) != pid)
continue;
}
else if (pid == 0) {
if (execvp (args[0], args) == -1) {
perror ("Error");
}
_exit (EXIT_FAILURE);
}
}
void cd (char *directory)
{
char dir[BUF_SIZE] = {0};
if (!directory) { /* handle 'cd' */
directory = getenv ("HOME");
if (chdir (directory))
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
return;
}
if (*directory == '~') { /* handle cd ~/stuff */
strcpy (dir, getenv ("HOME"));
strcat (dir, "/");
strcat (dir, directory + 2);
if (chdir (dir))
fprintf (stderr, "Failed to enter directory: %s\n", dir);
else
printf ("%s\n", dir);
return;
}
if (chdir (directory)) /* handle given directory */
fprintf (stderr, "Failed to enter directory: %s\n", directory);
else
printf ("%s\n", directory);
}
int killpid (char *pidstr, int sig)
{
pid_t pid = (pid_t)atoi (pidstr);
if (pid < 1) {
fprintf (stderr, "warning: requested pid < 1, ignoring\n");
return (int)pid;
}
printf (" killing pid '%d' with signal '%d'\n", (int)pid, sig);
// return kill (pid, sig);
return 0;
}
Sample Usage/Output
$ ./bin/ushell
shell> cd
/home/david
shell> cd ~/tmp
/home/david/tmp
shell> kill 18004
killing pid '18004' with signal '15'
shell>
shell> quit

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.

Resources