WriteConsole access violation in function call but not from main() - c++

I am trying to use WriteConsole(..) in a function call but I get access violation. When I un-comment the code in main, it prints my text to the screen with no problem in the main function. When I try to print the string in the function call I get access violation even though it does print the text to the console.
void print(char *_charArray);
int _tmain(int argc, _TCHAR* argv[])
{
HWND hConsole;
// HANDLE hFile;
char myText[] = "This is my text";
char *pMyText = myText;
LPDWORD charsWriten;
// hFile = CreateFile("CONOUT$", GENERIC_WRITE, FILE_SHARE_READ, NULL,
// OPEN_EXISTING, 0, NULL);
print(pMyText);
// WriteConsole(hFile, myText, sizeof(myText), charsWriten, NULL);
getch();
return 0;
}
void print(char *text)
{
LPDWORD charsWriten;
HANDLE hFile;
hFile = CreateFile("CONOUT$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
OPEN_EXISTING, 0, NULL);
unsigned int strn = strlen(text) + 1;
if(!WriteConsole(hFile, text, (strlen(text) + 1), charsWriten,NULL))
{
printf("Write Failed\n");
}
}

This declaration is wrong:
LPDWORD charsWriten;
The CreateFile function expects the fourth parameter to be a pointer to a variable it can write into. You don't actually allocate memory, though; you just declare a pointer—an uninitialized one at that. That won't work. You need to do:
DWORD charsWritten;
...
WriteConsole(hFile, text, (strlen(text) + 1), &charsWritten, NULL)
That will fix the access violation problem, but it doesn't explain why you are writing one character past the end of your string. You don't need to add 1 to strlen; the terminating NUL doesn't need to be written.

LPDWORD charsWriten;
LPDWORD is DWORD*. So what you have there is an uninitialized pointer. You then pass this pointer to WriteConsole, which writes to the invalid location pointed to. Instead, declare charsWritten as type DWORD, and pass its address to WriteConsole with &charsWritten.
DWORD charsWritten;
WriteConsole(hFile, text, (strlen(text) + 1), &charsWritten, NULL);
If, as you say, it works as you have it in main. That is simply bad luck. It's undefined behavior, which doesn't always have predictable results.

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

WriteFile function retuns success but not able to view file in file system

I am trying to write the content of unsigned short and unsigned char array content to an .img file. I am using WriteFile method to do the same. it seems like WriteFile function successfully writing the array content to the file but the main problem is i am not able to view that file in file system. Following are the two methods I am using to Write the data to the file.
void createImageFile(unsigned short* src,int srcLength,const char* fileName)
{
DWORD dwBytesWritten = 0;
unsigned short *dest = new unsigned short[srcLength];
if(is_file_exist(fileName))
{
remove(fileName);
}
HANDLE hFile = CreateFile(LPCWSTR(fileName), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD e = GetLastError();
if(hFile)
{
memcpy(dest,src,srcLength*sizeof(unsigned short));
bool b = WriteFile(hFile,dest,srcLength,&dwBytesWritten,NULL);
if(!b)
{
DWORD e = GetLastError();
} CloseHandle(hFile);
}
if(dest)
{
delete[] dest;
dest = NULL;
}
}
void createImageFile(unsigned char* src,int srcLength,const char* fileName)
{
DWORD dwBytesWritten = 0;
unsigned short *dest = new unsigned short[srcLength];
if(is_file_exist(fileName))
{
remove(fileName);
}
HANDLE hFile = CreateFile(LPCWSTR(fileName), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD e = GetLastError();
if(hFile)
{
memcpy(dest,src,srcLength*sizeof(unsigned short));
bool b = WriteFile(hFile,dest,srcLength,&dwBytesWritten,NULL);
if(!b)
{
DWORD e = GetLastError();
} CloseHandle(hFile);
}
if(dest)
{
delete[] dest;
dest = NULL;
}
}
I am not sure what exactly I am doing wrong. I am not able to view those files on the specified path. Can somebody please help me in this?
Another thing I want to highlight is, the above code is the part of unmanaged code and supposed to be reside in the dll.
You cannot just cast fileName to a wide string.
Don't forget to close the file.
CreateFile returns INVALID_HANDLE_VALUE not zero on failure. So, your error checking condition is incorrect.
Copying src to dest is quite unnecessary. Nor do you need to set the pointer to NULL after deletion.
Also, you have a race condition between remove(fileName) and CreateFile. You don't need to remove — setting dwCreationDisposition is sufficient.
The whole function could be written as:
void createImageFile(unsigned short* src, int srcLength, const char* fileName)
{
using namespace std;
ofstream stream(fileName, ios_base::binary | ios_base::trunc);
stream.write(src, srcLength * sizeof(unsigned short));
}

lpData not get value after RegQueryValueEx

I'm not sure where problem is occur.
I have demo code get value from an registry:
using namespace std;
typedef struct REGKEYS
{
HKEY hKey;
LPCTSTR subKey;
LPCTSTR value;
LPCTSTR name;
LPCTSTR file;
LPCTSTR tag;
} REGKEYS;
REGKEYS regkeys = {HKEY_LOCAL_MACHINE,"Software\\Internet Download Manager", "Serial", "IDM", NULL, NULL};
HKEY hKey;
LPBYTE szDataBuf;
DWORD dwSize;
int _tmain(int argc, _TCHAR* argv[])
{
RegOpenKeyEx(regkeys.hKey, regkeys.subKey, 0, KEY_READ, &hKey);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, szDataBuf, &dwSize);
int lerr = GetLastError();
system("pause");
return 0;
}
When debug, I see regkeys.hKey not point to anything (it need point to "HKEY_LOCAL_MACHINE", is it?).
And szDataBuf is empty.
(GetLastError() not help me - it return 0)
Anyone tell me where is problem and how to fix it?
EDIT2:
I edited my code to :
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwSize = 0;
RegOpenKeyEx(regkeys.hKey, regkeys.subKey, 0, KEY_READ, &hKey);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, NULL, &dwSize);
char *szDataBuf = new char(dwSize);
RegQueryValueEx(hKey, regkeys.value, NULL, NULL, (LPBYTE)szDataBuf, &dwSize);
delete[] szDataBuf;
system("pause");
return 0;
}
I debug and see szDataBuf get right value, but my program break and get warning: warning C4244: 'initializing' : conversion from 'DWORD' to 'char', possible loss of data.
First of all, your error checking code is not correct. The registry functions all return Win32 error codes. You need to take notice of them and check for errors.
To be clear, GetLastError is no use because these functions do not call SetLastError. They return the error code directly. You must read the documentation carefully. There are often subtle differences in the way different parts of Win32 do error handling.
The code in your updated question is better, but it still fails to check for errors in the call to RegOpenKeyEx.
Now, beyond that you are not actually calling RegQueryValueEx correctly. You have not initialized dwSize, and you have not allocated szDataBuf. Since these are global variables, they will be zero initialised. So your call to RegQueryValueEx will indeed succeed if the value exists. But you cannot expect any value to arrive in the buffer since you did not allocate a buffer. You are passing NULL to the lpData parameter.
So, allocate a buffer. For instance:
char szDataBuf[128];
Initialise dwSize:
DWORD dwSize = sizeof(szDataBuf);
Then your call to RegQueryValueEx should be
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL,
(LPBYTE)szDataBuf, &dwSize);
Although you may wish to allocate the buffer dynamically:
dwSize = 0;
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL, NULL, &dwSize);
// check lerr here
vector<char> szDataBuf(dwSize);
int lerr = RegQueryValueEx(hKey, regkeys.value, NULL, NULL,
(LPBYTE)&szDataBuf[0], &dwSize);
// check lerr here
You might also consider avoiding the use of global variables here. All of the variables you use would be make more sense as locals.

DeviceIoControl with input unsigned char buffer C++

I have a problem with using DeviceIOControl to put 128 byte buffer to my driver, i use this code:
int Initialize(unsigned char* public_signature, int size)
{
int ret = DeviceIoControl(
DeviceFileHandle,
2236440,
public_signature,
size,
NULL,
0,
NULL,
NULL);
if(ret != 0)
return 0;
wprintf(L"Format message failed with 0x%x\n", GetLastError()); // always error 0x6!
return 1;
}
I always get 0x6 error, what i'm doing wrong?
upd
My handle creating function:
int CreateFileHandle()
{
DeviceFileHandle = CreateFile( L"\Device\test",
GENERIC_WRITE,
GENERIC_READ | GENERIC_WRITE,
NULL,
OPEN_EXISTING,
0,
0);
if(DeviceFileHandle)
return 0;
return 1;
}
The error is in the 1st parameter of CreateFile. In your example, it would try to open a file, not a device. In addition, you didn't escape backslashes in the string. \t and similar are interpreted as special characters in C++.
The device name should be "\\\\.\\Device\\test".

Trouble using ReadFile() to read a string from a text file

How can I make the code below to read correct text. In my text file has Hello welcome to C++, however at the end of the text, it has a new line. With the code below, my readBuffer always contains extra characters.
DWORD byteWritten;
int fileSize = 0;
//Use CreateFile to check if the file exists or not.
HANDLE hFile = CreateFile(myFile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
BOOL readSuccess;
DWORD byteReading;
char readBuffer[256];
readSuccess = ReadFile(hFile, readBuffer, byteReading, &byteReading, NULL);
if(readSuccess == TRUE)
{
TCHAR myBuffer[256];
mbstowcs(myBuffer, readBuffer, 256);
if(_tcscmp(myBuffer, TEXT("Hello welcome to C++")) == 0)
{
FindClose(hFile);
CloseHandle(hFile);
WriteResultFile(TRUE, TEXT("success!"));
}
}
}
Thanks,
There are a few problems:
You're passing uninitialized data (byteReading) as the "# of bytes to read" parameter to ReadFile().
Depending on how you created the file, the file's contents may not have a terminating 0 byte. The code assumes that the terminator is present.
FindClose(hFile) doesn't make sense. CloseHandle(hFile) is all you need.
You need to call CloseHandle if CreateFile() succeeds. Currently, you call it only if you find the string you're looking for.
This isn't a bug, but it's helpful to zero-initialize your buffers. That makes it easier to see in the debugger exactly how much data is being read.
HANDLE hFile = CreateFile(myfile, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
BOOL readSuccess;
DWORD byteReading = 255;
char readBuffer[256];
readSuccess = ReadFile(hFile, readBuffer, byteReading, &byteReading, NULL);
readBuffer[byteReading] = 0;
if(readSuccess == TRUE)
{
TCHAR myBuffer[256];
mbstowcs(myBuffer, readBuffer, 256);
if(_tcscmp(myBuffer, TEXT("Hello welcome to C++")) == 0)
{
rv = 0;
}
}
CloseHandle(hFile);
}
I see two things:
byteReading isn't initialized
you are reading bytes so you have to terminate the string by 0.
CloseHandle is sufficient
Either remove the new line character from the file or use _tcsstr for checking the existence of the string "Hello Welcome to C++".