Invalid access to memory location with ReadFile - c++

I have a file, C:\demo\Demo.txt, that has a simple "Hello, world" on it. I want to pass the path as argument to my app, open it with CreateFile, read it with ReadFile and show that line out on console. However, I am receiving an error code 998:
Invalid access to memory location.
This is my code:
int wmain(int argc, WCHAR **argv)
{
if (argc != 2)
{
fwprintf(stderr, L"\nWrong arguments. \n");
return 1;
}
// CreateFile function variables
HANDLE hSourceFile;
LPCWSTR fileName = (LPCWSTR)argv[1];
DWORD desiredAccess = FILE_GENERIC_READ;
DWORD shareMode = FILE_SHARE_READ;
DWORD creationDisposition = OPEN_EXISTING;
DWORD flagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
//---------------------------------------------------------------
// Opening file for reading data
hSourceFile = CreateFileW(
fileName,
desiredAccess,
shareMode,
NULL,
creationDisposition,
flagsAndAttributes,
NULL);
if (hSourceFile != INVALID_HANDLE_VALUE)
{
wprintf(L"\nThe source file, %s, is open. \n", fileName);
}
else
{
wprintf(L"Error code: %u\n", GetLastError());
}
// ReadFile function variables
LPVOID dataRead=NULL;
DWORD bytesToRead = 100;
DWORD bytesWritten = 0;
//-----------------------------------------------------------------
// Reading data from file
if (!ReadFile(
hSourceFile,
dataRead,
bytesToRead,
&bytesWritten,
NULL))
{
wprintf(L"Error code: %u\n", GetLastError());
return 1;
}
wprintf(L"%s. \n", (LPWSTR)dataRead);
CloseHandle(hSourceFile);
return 0;
}
First time I use ReadFile, so no idea what I am doing wrong.
Can you help me?

ReadFile wants a pointer to a buffer into which it can write the data. You are passing NULL, so you get the error you see.
I would change the code to
// ReadFile function variables
static const DWORD bytesToRead = 100;
unsigned char dataRead[bytesToRead];
DWORD bytesWritten = 0;
//-----------------------------------------------------------------
// Reading data from file
if (!ReadFile(
hSourceFile,
dataRead,
bytesToRead,
&bytesWritten,
NULL))
{
wprintf(L"Error code: %u\n", GetLastError());
return 1;
}
The next problem you have, is that you are casting your pointer to LPWSTR, that is a pointer to a null-terminated wide string. Does your file contain that null termination? or do you need to add it yourself? Assuming the file doesn't contain the termination, you probably want:
// ReadFile function variables
static const DWORD bufferSize = 50;
WCHAR buffer[bufferSize+1]; // Leave room for null.
DWORD bytesWritten = 0;
//-----------------------------------------------------------------
// Reading data from file
if (!ReadFile(
hSourceFile,
buffer,
bufferSize*sizeof(WCHAR),
&bytesWritten,
NULL))
{
wprintf(L"Error code: %u\n", GetLastError());
return 1;
}
buffer[bytesWritten/sizeof(WCHAR)] = 0; // Null terminate.
wprintf(L"%s. \n", buffer); // Look ma! No cast needed.

You must allocate a memory buffer where you want to place read bytes to. Now you pointer dataRead points to nullptr, in other words nowhere, but you pass the size 100, that states your pointer refers to 100 byte allocated buffer, it is not truth.

Related

Crash when calling ReadFile after LockFileEx

I have several processes that try to read and write the same file. I want each of them to lock the file so that only one of them accesses it at a time.
I tried this (edit: this is a complete test code this time):
#include "stdafx.h"
#include "Windows.h"
bool test()
{
const char* path = "test.txt";
HANDLE hFile = CreateFileA(path,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf("ERROR: Cannot open file %s\n", path);
return false;
}
// Lock the file
{
OVERLAPPED overlapped = {0};
BOOL res = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, ~0, ~0, &overlapped);
if (!res)
{
printf("ERROR: Cannot lock file %s\n", path);
return false;
}
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (fileSize > 0)
{
char* content = new char[fileSize+1];
// Read the file
BOOL res = ReadFile(hFile, content, fileSize, NULL, NULL);
if (!res)
{
printf("ERROR: Cannot read file %s\n", path);
}
delete[] content;
}
const char* newContent = "bla";
int newContentSize = 3;
// Write the file
BOOL res = WriteFile(hFile, newContent, newContentSize, NULL, NULL);
if (!res)
{
//int err = GetLastError();
printf("ERROR: Cannot write to file\n");
}
// Unlock the file
{
OVERLAPPED overlapped = {0};
UnlockFileEx(hFile, 0, ~0, ~0, &overlapped);
}
CloseHandle(hFile);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool res = test();
return 0;
}
This works fine on my computer, which has Windows 8. But on my colleague's computer, which has Windows 7, it crashes. Specifically, the calls to ReadFile and WriteFile crash, always.
Note that it never enters the code paths with the error printfs. This code triggers no error except for a write at location 0x00000000 in ReadFile (when run on Windows 7).
We tried to also pass the overlapped struct to the ReadFile and WriteFile calls. It prevents the crash but the lock doesn't work anymore, the file is all scrambled (not with this test code, with the real code).
What am I doing wrong?
Looks like your problem is:
lpNumberOfBytesRead [out, optional] argument is null in your call.
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
Heres your problem :
You are missing a necessary struct-member and:
0 and ~0 and {0} are all bad code, constant expressions like these will always produce unepected results -- WINAPI doesnt work like libc, parameters are not always compared against constants, instead they are tested against/via macros and other preprocessor-definitions themselves so passing constant values or initializing WINAPI structs with constants will often lead to errors like these.
After years of experimenting i have found that there is only one surefire way of avoiding them, i will express it in corrected code :
OVERLAPPED overlapped;
overlapped.hEvent = CreateEvent( ........... ); // put valid parameters here!
UnlockFileEx(hFile, 0 /*"reserved"*/, ULONG_MAX, ULONG_MAX, &overlapped);
please read this carefully : http://msdn.microsoft.com/en-us/library/windows/desktop/aa365716%28v=vs.85%29.aspx

FILE_FLAG_NO_BUFFERING with overlapped I/O - bytes read zero

I observe a weird behavior while using the flag FILE_FLAG_NO_BUFFERING with overlapped I/O.
I invoke a series of ReadFile() function calls and query their statuses later using GetOverlappedResult().
The weird behavior that I am speaking of is that even though file handles were good and ReadFile() calls returned without any bad error(except ERROR_IO_PENDING which is expected), the 'bytes read' value returned from GetOverlappedResult() call is zero for some of the files, and each time I run the code - it is a different set of files.
If I remove the FILE_FLAG_NO_BUFFERING, things start working properly and no bytes read value is zero.
Here is how I have implemented overlapped I/O code with FILE_FLAG_NO_BUFFERING.
long overlappedIO(std::vector<std::string> &filePathNameVectorRef)
{
long totalBytesRead = 0;
DWORD bytesRead = 0;
DWORD bytesToRead = 0;
std::map<HANDLE, OVERLAPPED> handleMap;
HANDLE handle = INVALID_HANDLE_VALUE;
DWORD accessMode = GENERIC_READ;
DWORD shareMode = 0;
DWORD createDisposition = OPEN_EXISTING;
DWORD flags = FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING;
DWORD fileSize;
LARGE_INTEGER li;
char * buffer;
BOOL success = false;
for(unsigned int i=0; i<filePathNameVectorRef.size(); i++)
{
const char* filePathName = filePathNameVectorRef[i].c_str();
handle = CreateFile(filePathName, accessMode, shareMode, NULL, createDisposition, flags, NULL);
if(handle == INVALID_HANDLE_VALUE){
fprintf(stdout, "\n Error occured: %d", GetLastError());
fprintf(stdout," getting handle: %s",filePathName);
continue;
}
GetFileSizeEx(handle, &li);
fileSize = (DWORD)li.QuadPart;
bytesToRead = (fileSize/g_bytesPerPhysicalSector)*g_bytesPerPhysicalSector;
buffer = static_cast<char *>(VirtualAlloc(0, bytesToRead, MEM_COMMIT, PAGE_READWRITE));
OVERLAPPED overlapped;
ZeroMemory(&overlapped, sizeof(overlapped));
OVERLAPPED * lpOverlapped = &overlapped;
success = ReadFile(handle, buffer, bytesToRead, &bytesRead, lpOverlapped);
if(!success && GetLastError() != ERROR_IO_PENDING){
fprintf(stdout, "\n Error occured: %d", GetLastError());
fprintf(stdout, "\n reading file %s",filePathName);
CloseHandle(handle);
continue;
}
else
handleMap[handle] = overlapped;
}
// Status check and bytes Read value
for(std::map<HANDLE, OVERLAPPED>::iterator iter = handleMap.begin(); iter != handleMap.end(); iter++)
{
HANDLE handle = iter->first;
OVERLAPPED * overlappedPtr = &(iter->second);
success = GetOverlappedResult(handle, overlappedPtr, &bytesRead, TRUE);
if(success)
{
/* bytesRead value in some cases is unexpectedly zero */
/* no file is of size zero or lesser than 512 bytes(physical volume sector size) */
totalBytesRead += bytesRead;
CloseHandle(handle);
}
}
return totalBytesRead;
}
With FILE_FLAG_NO_BUFFERING absent, totalBytesRead value is 57 MB. With the flag present, totalBytesRead value is much lower than 57 MB and keeps changing each time I run the code ranging from 2 MB to 15 MB.
Your calculation of bytesToRead will produce 0 as a result when the file size is less than g_bytesPerPhysicalSector. So for small files you are requesting 0 bytes.

VC++ HeapAlloc inside function gives null pointer

I am trying to use HeapAlloc() to allocate a buffer used by SetupDiGetDeviceRegistryProperty().
Inside GetDeviceInformation() I have:
HANDLE hHeap = GetProcessHeap();
while (SetupDiEnumDeviceInfo(DeviceInfoSet, MemberIndex++, DeviceInfoData))
{
DWORD DataT;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
// port of device
DWORD portnum = 0;
GetRegistryProperty(DeviceInfoSet, DeviceInfoData, SPDRP_FRIENDLYNAME,
&DataT, buffer, &buffersize, &buffersize);
if (!buffer)
{
cerr << "Null Ptr!" << endl;
exit(1);
}
// Do stuff, uninstall device
if (buffer) HeapFree(hHeap, NULL, buffer);
}
}
And inside GetRegistryProperty() I have:
void GetRegistryProperty(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property, PDWORD DataT, LPTSTR buffer, PDWORD buffersize, PDWORD size)
{
HANDLE hHeap = GetProcessHeap();
while (!SetupDiGetDeviceRegistryProperty(
DeviceInfoSet,
DeviceInfoData,
Property, //SPDRP_FRIENDLYNAME or SPDRP_CLASS
DataT, //&DataT
(PBYTE)buffer,
*buffersize,
size)) //&buffersize
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) HeapFree(hHeap, NULL, buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (LPTSTR)HeapAlloc(hHeap, HEAP_ZERO_MEMORY |
HEAP_GENERATE_EXCEPTIONS, *buffersize * 2);
}
else
{
// error handling
break;
}
}
}
HeapAlloc() works as expected (the buffer is filled with the property) until GetRegistryProperty() returns. At this point, the buffer is always NULL. Is this also expected? How can I return a char * pointing to an array that lives past the life of the function that created it? I assume that I don't understand how HeapAlloc() works.
The reason I have it in a separate function is that I would like to call GetRegistryProperty() multiple times with different DWORD Propertys. Before I moved the code to a separate function it worked perfectly.
Pass the buffer by reference (note the LPTSTR&) :
void GetRegistryProperty(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
DWORD Property, PDWORD DataT, LPTSTR& buffer, PDWORD buffersize, PDWORD size)
You are passing buffer by value, so in GetRegistryProperty, when you reassign it, you simply overwrite the copy of the pointer in GetRegistryProperty.
Change the signature of GetRegistryProperty to:
void GetRegistryProperty(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, DWORD Property, PDWORD DataT, LPTSTR& buffer, PDWORD buffersize, PDWORD size)

Unable to open file using CreateFile function

Ok so I've been following this tutorial: http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=4422&lngWId=3
And so far I've gotten everything to work, up until I need the program to load in a .raw audio file.
Here's the relevant code:
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD size = 0;
DWORD readBytes = 0;
void* block = NULL;
//open the file
if((hFile = CreateFile((LPCWSTR)filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// get it's size, allocate memory, and then read it into memory
size = GetFileSize(hFile, NULL);
block = HeapAlloc(GetProcessHeap(), 0, size);
ReadFile(hFile, block, size, &readBytes, NULL);
CloseHandle(hFile);
*blockSize = size;
return (LPSTR)block;
}
And then my main function which calls it:
int _tmain(int argc, _TCHAR* argv[])
{
HWAVEOUT hWaveOut; //device handle
WAVEFORMATEX wfx; //struct for format info
MMRESULT result; // for waveOut return values
LPSTR block;
DWORD blockSize;
// first let's set up the wfx format struct
wfx.nSamplesPerSec = 44100; // rate of the sample
wfx.wBitsPerSample = 16; //sample size
wfx.nChannels = 2; // 2 channels = stereo
wfx.cbSize = 0; // no extra info
wfx.wFormatTag = WAVE_FORMAT_PCM; //PCM format
wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
// then let's open the device
if(waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
{
fprintf(stderr, "unable to open Wave Mapper device.\n");
Sleep(1000);
ExitProcess(1);
}
// if no errors then close it
printf("The Wave Mapper device was opened successfully!\n");
//load and play file
if((block = loadAudioBlock("ding.raw", &blockSize)) == NULL)
{
fprintf(stderr, "Unable to load file\n");
Sleep(1000);
ExitProcess(1);
}
writeAudioBlock(hWaveOut, block, blockSize);
Sleep(1000);
waveOutClose(hWaveOut);
return 0;
}
Everytime I run the program I get the: "Unable to load file" output. I've got the "ding.raw" file in the same directory as my exe. I've also tried doing the full path as "C://path" and "C:/path" but then the compiler just gives me more errors about being unable to load a pdb file.
Any ideas? I'm using the Visual Studio 2012 Professional IDE and compiler.
Instead of using the standard char you should be using e.g. _TCHAR and LPCTSTR everywhere. This will make all string and string pointers you pass around be correct.
Look at the argv argument to _tmain and you will see that it uses _TCHAR instead of char. This is because Windows support both normal characters and Unicode characters depending on a couple of macros. See e.g. here for some more information.
So to solve what is likely your problem (since you don't get the actual error code, see my comment about GetLastError) you should change the function like this:
void *loadAudioBlock(LPCTSTR filename, DWORD* blockSize)
{
// ...
if((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
// ...
}
And call it like this:
// ...
void *block;
if((block = loadAudioBlock(_T("C:\\path\\ding.raw"), &blockSize)) == NULL)
{
fprintf(stderr, "unable to open Wave Mapper device, error code %ld.\n", GetLastError());
Sleep(1000);
ExitProcess(1);
}
// ...
As you can see I also changed the return type, as the file is binary and won't have any readable text.
LPSTR loadAudioBlock(const char* filename, DWORD* blockSize)
{
if((hFile = CreateFile(CA2T(filename), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE)
return NULL;
}
See ATL conversion macros: http://msdn.microsoft.com/en-us/library/87zae4a3%28v=vs.80%29.aspx Just casting const char* LPCWSTR doesn't work.

Reading a Text File w/ WIN32

I'm trying to parse a text file with a win32 program in c++. Is there a simple method of reading a text file line by line? My text file consists of strings that I would like to store in a char array(const char* cArray[67]). Here is what I have so far. I am using CreateFile and ReadFile. I get an access violation error(0x000003e6) from readfile:
CDECK::CDECK():filename(".\\Deck/list.txt")
{
LPVOID data = NULL;
hFile = CreateFileA(filename, GENERIC_READ,FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
MessageBox(NULL, L"Failed to CreateFile - 'hFile'", L"CDECK::CDECK()", MB_OK);
DWORD fileSize = GetFileSize(hFile, &fileSize);
DWORD read = -1;
if(!ReadFile(hFile, data, fileSize, &read, NULL))
{
DWORD err = GetLastError();
MessageBox(NULL, L"Failed to ReadFile - 'hFile'", L"CDECK::CDECK()", MB_OK);
}
return;
}
Is there a simple method of reading a text file line by line?
Yes:
{
std::ifstream hFile(filename);
std::vector<std::string> lines;
std::string line;
while(std::getline(hFile, line))
lines.push_back(line);
return lines;
}
Consider this code:
LPVOID data = NULL;
if(!ReadFile(hFile, data, fileSize, &read, NULL))
Here data is null, and the following argument is the size of the entire file. You are supposed to allocate a buffer, and then pass a pointer to such buffer and its size to it. There is where the ReadFile function will write the readed bytes.
Here is a simple way of getting it to work with a statically sized buffer:
char data[4096] = {};
if(!ReadFile(hFile, static_cast< LPVOID >( &data ), 4096, &read, NULL))
Your problem is that you are reading the bytes of the file, to read the string you need to alloc a string location using SysAllocStringByteLen and then use the ReadFile
You forgot to allocate a buffer space before reading your data :
LPVOID data = NULL;
Before reading you must allocate a fileSize buffer space :
data = malloc(fileSize);
And probably must also declare your data variable as char* instead of void*