Weird case of AccessViolation while using overlapped IO in Windows - winapi

I've been experimenting with Overlapped IO feature of Win32 API, namely ReadFileEx and WriteFileEx functions.
Here is a simplest example:
#include <iostream>
#include <string>
#include <Windows.h>
const DWORD blockSize = 512;
char buffer[blockSize];
bool done = false;
OVERLAPPED overlapped;
void Completion(DWORD error, DWORD read, LPOVERLAPPED overlapped) {
}
int _tmain(int argc, _TCHAR* argv[])
{
std::wstring fileName;
std::wcout << "Enter file name: ";
std::getline(std::wcin, fileName);
HANDLE file = CreateFile(
fileName.c_str(),
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (file == INVALID_HANDLE_VALUE) {
std::wcout << "Error while opening file: " << GetLastError() << std::endl;
std::cin.get();
return -1;
}
overlapped.Offset = overlapped.OffsetHigh = 0;
ReadFileEx(file, buffer, blockSize, &overlapped, (LPOVERLAPPED_COMPLETION_ROUTINE) &Completion);
while (!done)
SleepEx(1000, TRUE);
return 0;
}
As you can see, I'm starting overlapped reading with ReadFileEx and waiting for it to finish using SleepEx. Although Completion has empty body and the program should hang forever after reading first block, it does something completely different. In fact, it raises AccessViolation with code 0xC0000005 on the first call to SleepEx. This happens on Windows machines with Win 7 and Win Vista I've tried, including fresh 64 bit virtual machine with Windows 7. But, curiously, it does not fail on one Windows 8.1 machine and runs just as expected. This was compiled with Visual Studio 2010, but I don't think it matters.
I can not understand what have I done wrong, so if anyone knows the answer, please help me.

The callback must be of the following form, as stated clearly in the documentation:
VOID CALLBACK FileIOCompletionRoutine(
_In_    DWORD        dwErrorCode,
_In_    DWORD        dwNumberOfBytesTransfered,
_Inout_ LPOVERLAPPED lpOverlapped
);
Your function has the wrong calling convention. Your cast does not change that. It is simply a way for you to stop the compiler rejecting your ill-formed program. Don't lie to the compiler. Correct the function declaration by adding the CALLBACK calling convention.

Related

what is the Windows equivalent of unix's flock(h, LOCK_SH)?

how do you get a read-lock on Windows? like on Linux you'd do
#include <fcntl.h>
#include <sys/file.h>
int main(int argc, char **argv){
int h=open(argv[0],O_RDONLY);
flock(h,LOCK_SH);
flock(h,LOCK_UN);
close(h);
}
what's the Windows equivalent?
LockFileEx for basic locking. For a very soft lock there are also opportunistic locks.
expanding on #Anders's answer, the answer is LockFileEx, and the type of lock is decided by the dwFlags arguments,
linux=>windows
LOCK_SH => 0
LOCK_EX => LOCKFILE_EXCLUSIVE_LOCK
LOCK_NB => LOCKFILE_FAIL_IMMEDIATELY
the Windows API is quite a bit more complex (and powerful) than the Linux one, allowing you to lock "just parts" of the file, but you're free to effectively lock the whole file by just specifying that you want "the first 18446744073709551615 bytes locked" (meaning you want the first 18.45 exabytes of the file locked...), you're also able to "lock bytes that doesn't exist yet", hence a rough port of the code in the top post would be:
#include <cstdint>
#include <iostream>
#include <windows.h>
int main(int argc, char **argv){
HANDLE handle = CreateFileA(argv[0], GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
throw std::runtime_error("CreateFile failed with error " + std::to_string(GetLastError()) + " for " + std::string(argv[0]));
}
const DWORD allBitsSet = ~DWORD(0);
DWORD flags = 0; // LOCK_SH = 0, LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK, LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
_OVERLAPPED overlapped1 = {0};
_OVERLAPPED overlapped2 = {0};
if (!LockFileEx(handle, flags, 0, allBitsSet, allBitsSet, &overlapped1)) {
throw std::runtime_error("LockFileEx failed with error " + std::to_string(GetLastError()));
}
if(!UnlockFileEx(handle, 0, allBitsSet, allBitsSet, &overlapped2)) {
throw std::runtime_error("UnlockFileEx failed with error " + std::to_string(GetLastError()));
}
CloseHandle(handle);
}

Is there a way to detect changes in Focus Assist (formerly Quiet Hours) in Windows 10 from a Win32 App

I'd like to change the presence state in an App automatically to DND when Focus Assist is turned on.
So two questions basically:
Is it possible to check Focus Assist state through e.g. Windows 10 SDK?
There is a similar question for Quiet Hours in Windows 8 here: Get windows Quiet hours from Win32 or C# API, though it's not clear whether it also still applies to "Focus Assist" since this is no longer a true or false value.
Quiet hours had only ON/OFF state while Focus Assist can be OFF/PRIORITY/ALARMS.
The more interesting question though, which is not answered in the post mentioned above: is there an event I could register to, to get notified about state changes?
The goal is to get notified right away, when Focus Assist status changes in order to not have to query the registry on a regular basis.
As far as I know there is no officially documented way of getting the Focus assist status.
It still can be accessed by querying the WNF State of the feature, although this is completely undocumented and not officially supported.
The various states for WNF Data have been reverse engineered, so the one for Focus Assist is WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED.
The C++ sample below shows how to get the state of Focus Assist feature (mostly off, priority_only and alarm_only).
Once again, be wary that this is not officially supported by Microsoft:
#include <Windows.h>
#include <iostream>
#include <string>
#include <map>
// from ntdef.h
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
// from ntdef.h
typedef struct _WNF_STATE_NAME
{
ULONG Data[2];
} WNF_STATE_NAME;
typedef struct _WNF_STATE_NAME* PWNF_STATE_NAME;
typedef const struct _WNF_STATE_NAME* PCWNF_STATE_NAME;
typedef struct _WNF_TYPE_ID
{
GUID TypeId;
} WNF_TYPE_ID, *PWNF_TYPE_ID;
typedef const WNF_TYPE_ID* PCWNF_TYPE_ID;
typedef ULONG WNF_CHANGE_STAMP, *PWNF_CHANGE_STAMP;
enum FocusAssistResult
{
not_supported = -2,
failed = -1,
off = 0,
priority_only = 1,
alarms_only = 2
};
std::map<int, std::string> result_map = {
{-2, "Not Supported"},
{-1, "Failed"},
{0, "Off"},
{1, "Priority Only"},
{2, "Alarm Only"}
};
typedef NTSTATUS (NTAPI *PNTQUERYWNFSTATEDATA)(
_In_ PWNF_STATE_NAME StateName,
_In_opt_ PWNF_TYPE_ID TypeId,
_In_opt_ const VOID* ExplicitScope,
_Out_ PWNF_CHANGE_STAMP ChangeStamp,
_Out_writes_bytes_to_opt_(*BufferSize, *BufferSize) PVOID Buffer,
_Inout_ PULONG BufferSize);
int main(int argc, CHAR** argv)
{
// note: ntdll is guaranteed to be in the process address space.
const auto h_ntdll = GetModuleHandle(_T("ntdll"));
// get pointer to function
const auto pNtQueryWnfStateData = PNTQUERYWNFSTATEDATA(GetProcAddress(h_ntdll, "NtQueryWnfStateData"));
if (!pNtQueryWnfStateData)
{
std::cerr << "[-] Error: couldn't get pointer to NtQueryWnfStateData() function." << std::endl;
return -1;
}
// state name for active hours (Focus Assist)
WNF_STATE_NAME WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED{0xA3BF1C75, 0xD83063E};
// note: we won't use it but it's required
WNF_CHANGE_STAMP change_stamp = {0};
// on output buffer will tell us the status of Focus Assist
DWORD buffer = 0;
ULONG buffer_size = sizeof(buffer);
if (NT_SUCCESS(pNtQueryWnfStateData(&WNF_SHEL_QUIETHOURS_ACTIVE_PROFILE_CHANGED, nullptr, nullptr, &change_stamp,
&buffer, &buffer_size)))
{
// check if the result is one of FocusAssistResult
if (result_map.count(buffer) == 0)
{
std::cout << "Focus Assist result is unknown." << std::endl;
}
else
{
std::cout << "Focus assist state: " << result_map[buffer] << std::endl;
}
}
else
{
std::cerr << "[-] Error while calling NtQueryWnfStateData." << std::endl;
return -1;
}
return 0;
}

Format of the serial number of a physical harddrive retrieved using DeviceIoControl()

I retrieve the serial number of the physical hard-drive using the function DeviceIoControl following the suggestions from Blacktempel in this post. Getting the number works fine in principle, but I (still) have trouble with the format of the serial number as it keeps changing from computer to computer and with time. Also I experienced a format change on some computers between running the program as normal user or as admin.
For example, I retrieved a number with the following format:
WD-WCAZAF632086
when I tested the program first and after a few weeks it looks like:
2020202057202d4443575a414641333630323638
This is still the same number, only the characters have been replaced by their hex codes and swapped pair-wise. I've encountered different formats like a normal string with the characters exchanged pair-wise. Among other values, I need to check this number to verify if a software license is valid for a certain computer. Having an instable and unknown format is annoying and if the format changes to something I'm not yet aware of, I risk that the software license check fails although the license is still valid.
Does anyone know how to get the serial number in a stable format, or how to predict the format so it can be adapted for comparison?
Here is minimal C++ example of code that I used to retrieve the serial number of the first physical disc. I build it using Visual Studio 2015:
#include "stdafx.h"
#include "Windows.h"
#include <string>
#include <vector>
#include <iostream>
bool GetDeviceString(std::string &serialnumber)
{
HANDLE deviceHandle = CreateFileW(L"//./PhysicalDrive0", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); // Get Handle to device
if (deviceHandle == INVALID_HANDLE_VALUE) // Check if Handle is valid
return false;
STORAGE_PROPERTY_QUERY query{};
query.PropertyId = StorageDeviceProperty;
query.QueryType = PropertyStandardQuery;
STORAGE_DESCRIPTOR_HEADER storageDescriptorHeader = { 0 };
DWORD dwBytesReturned;
if (!DeviceIoControl(deviceHandle, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
&storageDescriptorHeader, sizeof(STORAGE_DESCRIPTOR_HEADER), &dwBytesReturned, NULL))
{
}
// Alloc the output buffer
const DWORD dwOutBufferSize = storageDescriptorHeader.Size;
std::vector<BYTE> pOutBuffer(dwOutBufferSize,0);
if (!DeviceIoControl(deviceHandle, IOCTL_STORAGE_QUERY_PROPERTY,
&query, sizeof(STORAGE_PROPERTY_QUERY),
pOutBuffer.data(), dwOutBufferSize,
&dwBytesReturned, NULL))
{
// handle error, do cleanup and return
}
STORAGE_DEVICE_DESCRIPTOR* pDeviceDescriptor = (STORAGE_DEVICE_DESCRIPTOR*)pOutBuffer.data();
const DWORD dwSerialNumberOffset = pDeviceDescriptor->SerialNumberOffset;
if (dwSerialNumberOffset != 0)
{
// Finally, get the serial number
serialnumber = (char*)(pOutBuffer.data() + dwSerialNumberOffset);
}
}
int main()
{
std::string serialnumber;
if (GetDeviceString(serialnumber))
{
std::cout << "serial number of first disc: " << serialnumber << std::endl;
}
else
{
std::cout << "Failed!" << std::endl;
}
std::cin.ignore();
return 0;
}

turn on LED using C

I want to turn on a LED using C, meaning that I want to write on parallel port.
but the code doesn't work.
I use char ledStatus instead of BYTE ledStatus. is there any difference??
what is the problem in this code?
#include <windows.h>
#include <conio.h>
#include <staio.h>
#define LED_ON 1
int main()
{
HANDLE h;
unsigned long dwSize=1;
int success;
h = CreateFile(
L"LPT1",
GENERIC_WRITE, // access (read-write) mode
0, // share mode
NULL, // pointer to security attributes
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL // handle to file with attributes to copy
);
if (INVALID_HANDLE_VALUE == h)
{
//Handle Error
printf("CreateFile failed with error %d\n", GetLastError());
exit(1);
}
else
{
printf("CreateFile1 Successful\n");
}
char ledStatus;
// turn on LED
ledStatus = LED_ON;
success = WriteFile(h, &ledStatus, 1, &dwSize, NULL);
if (success)
{
printf("File Write Successful - %i bytes\n", dwSize);
}
else
{
printf("File Write Failed\n");
}
// close port
CloseHandle(h);
return 0;
}
Your question is very poorly documented, you didn't describe what signal you used or how you wired the LED. Lots of ways to get that wrong. But you have no hope of making it work with the standard Windows parallel driver. It was written to interface parallel devices like printers. Which requires handshaking to clock a byte to the device. The driver turns on the STROBE signal, the device must turn on the ACK signal to acknowledge it copied the byte. That of course doesn't happen, the WriteFile() calls only fill a buffer in the driver.
You'll need another driver to directly control the output lines, Inpout32 is a common choice. Find essential advice in Jan Axelson's book, also includes a link to Inpout32.

How to remove file if application is not running?

Not sure whether this is possible, but I'm creating a file encoding applcation. When a file is decoded, it is saved temporarily in a temp directory, after which it can be opened regularly. However, I actually need to be certain the file is removed as soon as the application that has opened it, has closed it (e.g. has shut down). Otherwise, the decoded (secret) file is just hanging in the temp directory without supervision.
What's more, even when my application itself has been shut down for any reason, I'd like to pass this task on to Windows, if possible. So say the user decodes a file and opens it and then my application is shut down (either normally or abnormally), the decoded file in the temp directory should still be removed as soon as it's not used anymore.
How would I go about this? I've seen tips like FileSystemWatcher and a trivial 'check every second' idea, but if my application is not alive at the moment the decoded file is closed, I'd still like to have the file removed. So I guess I'd need to pass this responbility to Windows, but I'm not sure if that's possible and if so, how.
So how do I remove a file as soon as it's closed if my application isn't running at that particular moment?
Doing this may work:
In the process that creates the file, create it with FileOptions.DeleteOnClose, and with FileShare.ReadWrite (or FileShare.Read if only read access is required from other processes). You may also need FileShare.Delete.
DO NOT let the file close in the main application that created it until the application exits.
In other processes that consume the temporary file, open it with the same file options as the original.
This way, when the last process that has the file open closes, the file will be deleted.
UPDATE:
As noted in the comments, there doesn't seem to be a way in the .NET API to specify both the FIleShare options and the FileOptions.DeleteOnClose. It is possible using straight Win32. I have copied a sample that I tested below. There are 2 programs, one that creates the file, another that consumes it. The only notable difference between the 2 is that the consumer opens the file with OPEN_EXISTING.
Creator
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE fh = CreateFile(
L"yourFilePath\\tempFile.dat",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
NULL,
CREATE_NEW,
FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if(fh==INVALID_HANDLE_VALUE)
{
std::cerr << "Failed to create file. Error code = " << GetLastError() << std::endl;
return 1;
}
std::cout<< "Hit enter to close.";
std::string inp;
std::getline(std::cin,inp);
CloseHandle(fh);
return 0;
}
Consumer
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <string>
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE fh = CreateFile(
L"yourFilePath\\tempFile.dat",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_DELETE_ON_CLOSE,
NULL);
if(fh==INVALID_HANDLE_VALUE)
{
std::cerr << "Failed to create file. Error code = " << GetLastError() << std::endl;
return 1;
}
DWORD written;
if(!WriteFile(fh,"Test",4,&written,NULL))
{
std::cerr << "Failed to write data to file. Error code = " << GetLastError() << std::endl;
return 1;
}
std::cout<< "Hit enter to close.";
std::string inp;
std::getline(std::cin,inp);
CloseHandle(fh);
return 0;
}
Use FileOptions.DeleteOnClose.
Things like FileOptions.DeleteOnClose won't help if your media becomes unavailable or the machine gets shut down before the delete occurs. To me this looks very much like an exogenous condition.
Can you stream the decoding to a memory stream rather than to disk and take the whole problem away.

Resources