WriteFile function C++ - c++

Im trying to use the WriteFile function. Ive been working off this example
http://msdn.microsoft.com/en-us/library/ms900134.aspx
Here the buffer that is passed to WriteFile is filled from ReadFile. But I dont want to do it that way. I just want to write a string like "Example text testing WriteFile" or something. But im not sure what values the parameters should have. Ive tried looking around on google but couldnt find anything. Anyone know how i do this?

From MSDN:
BOOL WINAPI WriteFile(
__in HANDLE hFile,
__in LPCVOID lpBuffer,
__in DWORD nNumberOfBytesToWrite,
__out_opt LPDWORD lpNumberOfBytesWritten,
__inout_opt LPOVERLAPPED lpOverlapped
);
The first argument is the handle to the file.
The second argument is a pointer to the data you want to write. In your case it's the string.
The third argument is the length of the data you want to write. In your case it will be something like strlen(str).
The fourth argument is a pointer to a DWORD variable that will receive the number of bytes actually written.
The fifth and last parameter can be NULL for now.
You use it like this:
char str[] = "Example text testing WriteFile";
DWORD bytesWritten;
WriteFile(fileHandle, str, strlen(str), &bytesWritten, NULL);
If WriteFile returns FALSE then there was an error. Use the GetLastError function to find out the error code.

A simple example of writing a string:
(hOutFile here is an open file handle from a call to CreateFile):
{
DWORD dwBytesWritten = 0;
char Str[] = "Example text testing WriteFile";
WriteFile( hOutFile, Str, strlen(Str), &dwBytesWritten, NULL );
}
EDIT: Check the MSDN function definition for what each parameter does.

Related

Read 'Binary' files with ReadFile WinAPI

When I try to open '.exe' files with ReadFile() Windows API, It's just return the 2 first character of file like : MZ
Here is my Code:
#define BUFFERSIZE 5000
VOID CALLBACK FileIOCompletionRoutine(
__in DWORD dwErrorCode,
__in DWORD dwNumberOfBytesTransfered,
__in LPOVERLAPPED lpOverlapped
);
VOID CALLBACK FileIOCompletionRoutine(
__in DWORD dwErrorCode,
__in DWORD dwNumberOfBytesTransfered,
__in LPOVERLAPPED lpOverlapped)
{
_tprintf(TEXT("Error code:\t%x\n"), dwErrorCode);
_tprintf(TEXT("Number of bytes:\t%x\n"), dwNumberOfBytesTransfered);
g_BytesTransferred = dwNumberOfBytesTransfered;
}
HANDLE hFile;
DWORD dwBytesRead = 0;
char ReadBuffer[BUFFERSIZE] = { 0 };
OVERLAPPED ol = { 0 };
hFile = CreateFile(fullFilePath.c_str(), // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // normal file
NULL); // no attr. template
ReadFileEx(hFile, ReadBuffer, BUFFERSIZE - 1, &ol, FileIOCompletionRoutine);
When I print ReadBuffer It's just MZ(exe file).
But Using:
std::ifstream file(argv[1], std::ios::in | std::ios::binary);
It's work perfectly.
How Can I Read Binary files With ReadFile?
The problem is not with reading, the problem is with printing.
You're not showing your code, but you're likely trying to print with printf or something similar. IOW, you're printing it as C string.
Well, binary data includes 0s, and in this case the first 3 bytes are 'M', 'Z', '\0' - and that prints as a null-terminated string "MZ".
You'd have to write a converter to per-byte hex numbers if you want to see meaningful printing of binary data: 4D 5A 00 and so on
How Can I Read Binary files With ReadFile?
ReadFile (and ReadFileEx ) works 'in binary mode'. You get exact file contents byte by byte without any translation.
You have problem with writing/printing. This mostly depends where you want to write, but for outputing (binary) data potentially containing nulls in C++ choose write method
some_output_stream.write( buffer_ptr, num_bytes_in_buffer );
some_output_stream should be set to binary mode (std::ios::binary). Without this flag all bytes with value 10 could be translated to pairs 13,10.
If C FILE functions are used
fwrite( buffer_ptr, 1, num_bytes_in_buffer, some_output_file );
Again some_output_file has to be in binary mode.
In some scenarios WriteFile can be used complementary to your usage of ReadFile.

C++ how to find last (offset - adress) used in processmemory with use readprocessmemory

i use this code to readprocessmemory :
BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);
char value[5];
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, 6500);
{
ReadProcessMemory(hProcess, (LPVOID)105477, value, 5, 0);
}
its work 100%
but i want to know how know last Offset used in processmemory - before i read it
see the picture : enter image description here
the last offset in this processmemory is 7FFE0FFF - but how can i get it before i read the processmemory
Well it MAY work if you are absolutely sure that you CAN read the memory of the other process... anyway it is a quite dangerous method, there are much better IPC APIs to do these things!
Unless you are writing a debugger yourself... in fact ReadProcessMemory is cited here "Process Functions for Debugging" https://msdn.microsoft.com/it-it/library/windows/desktop/ms680549(v=vs.85).aspx

WriteFile throws Access Violation when 4th (optional) parameter is NULL

Thought that it may be helpful to someone because it was a kind of surprise for me.
WriteFile function tries to write into its 4th (optional) parameter, and if it is NULL it causes Access Violation exception... But not on Windows 8(.1).
This is the function definition from msdn:
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten, // Optional
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
lpNumberOfBytesWritten [out, optional]
...
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
I created short example that reproduces the error. The code is Win32 console application created in Visual Studio 2008 SP1:
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hFile = CreateFile(L"N:\\Test\\Test.tmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
return -1;
}
unsigned int testValue = 32;
//-----------------------------------------------
// Next line generates AV exception on Windows 7,
// On Windows 8 it works fine:
//-----------------------------------------------
WriteFile(hFile, &testValue, sizeof(unsigned int), NULL, NULL);
CloseHandle(hFile);
return 0;
}
And, finally, if I change the call to WriteFile() by the following two lines, this solves the problem and works on all platforms:
// Now it does not generate AV:
DWORD written = 0;
WriteFile(hFile, &testValue, sizeof(unsigned int), &written, NULL);
The code generates Access Violation on Windows 7 and on Windows XP SP3 (did not test it on Vista). On Windows 8(.1) it works, even when I pass NULL in 4th parameter (lpNumberOfBytesWritten).
The actual problem was that I developed a module that writes into a temporary file, but I ignored the 4th parameter (I read "optional" but misread the rest and thought that it may be ignored). I developed and tested it on Windows 8.1, so the code worked fine, but the client machine was on Windows 7 and code failed.
The lessons I learned: I should be more attentive (to details) and don't be smug (and test carefully).
The documentation for lpNumberOfBytesWritten says:
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
In other words, the lpNumberOfBytesWritten parameter is only optional when you are using overlapped IO. You are passing NULL for lpOverlapped, and therefore not using overlapped IO, the lpNumberOfBytesWritten is not optional and cannot be NULL.

How to copy a file but touch the timestamp on the new copy?

I am using ::CopyFile() to make a copy of a file. It appears the original file's timestamp is being preserved and I would like the copy to set the current timestamp on the copy, i.e. 'touching' it.
Is there a WinAPI way to do this easily?
If you read the MSDN documentation for CopyFile(), there are comments at the bottom that say the following:
File times semantics
This article should document semantics with respect to file creation/modification/access times.
Creation time: if the target file already exists, its' creation time is preserved, otherwise it is set to the current system time.
Last Modification time: always copied from modification time of the source file.
Last Access time: always set to the current system time.
and
Mod-time not always preserved
The modification time is not guaranteed to be set. CopyFileEx does try to set the modification time, but it does NO error checking on it. This means if setting modification time fails internally in CopyFileEx (e.g. with access denied), latter will still returns successful!
So if modification time is important for your scenario (it is for my synchronization program), you have to explicitly call SetFileTime() and check it's return value to be sure.
You should use SetFileTime() to update the copied file's timestamp(s) yourself to make sure they are set to what you want them to be set to. There is an example on MSDN:
Changing a File Time to the Current Time
#include <windows.h>
// SetFileToCurrentTime - sets last write time to current system time
// Return value - TRUE if successful, FALSE otherwise
// hFile - must be a valid file handle
BOOL SetFileToCurrentTime(HANDLE hFile)
{
FILETIME ft;
SYSTEMTIME st;
BOOL f;
GetSystemTime(&st); // Gets the current system time
SystemTimeToFileTime(&st, &ft); // Converts the current system time to file time format
f = SetFileTime(hFile, // Sets last-write time of the file
(LPFILETIME) NULL, // to the converted current system time
(LPFILETIME) NULL,
&ft);
return f;
}
::CopyFile is actually part of windows:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363851%28v=vs.85%29.aspx
It is a convenience function that does copy metadata. There is another way, though less convenient, to copy files using windows. Check out these functions:
ReadFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
CreateFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
WriteFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747%28v=vs.85%29.aspx
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
BOOL WINAPI ReadFile(
_In_ HANDLE hFile,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfBytesToRead,
_Out_opt_ LPDWORD lpNumberOfBytesRead,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
So you would open the file with something like this:
CreateFile(<File>, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)
Check for a invalid return handle,
Create the new file with something like this:
CreateFile(<File>, GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL)
Check for a invalid return handle,
read the file into a buffer:
ReadFile(handle for file 1, buffer, Buffer size, Destination file,OUT for Bytes Read, NULL)
Then write out the Buffer:
WriteFile(outfile handle,buffer,number of bytes,NULL)
Close your handles.
Make sure to read CreateFiles details, it can be used to open files too.

Visual C++ RegGetValue() fails in program where it shouldn't

I'm making a C++ program using Visual C++ 2008 Express that gets the paths to specific apps from the registry, display a list of those that are installed, allows the user to pick one to configure, then launch the selected app.
This program is supposed to retrieve the paths to (currently) three apps by using RegGetValue (from windows.h).
While it works with Apps n°1 and 3, it fails with app n°2.
The part of the source that handles the registry is available on Pastebin: http://pastebin.com/9X2hjGqh.
I get error n°234 (ERROR_MORE_DATA) when I add a cout to get the function's return.
RegGetValue syntax:
LONG WINAPI RegGetValue(
_In_ HKEY hkey,
_In_opt_ LPCTSTR lpSubKey,
_In_opt_ LPCTSTR lpValue,
_In_opt_ DWORD dwFlags,
_Out_opt_ LPDWORD pdwType,
_Out_opt_ PVOID pvData,
_Inout_opt_ LPDWORD pcbData
);
Full reference here: http://msdn.microsoft.com/en-us/library/ms724875(v=VS.85).aspx
One thing that stands out are all the calls where you do this:
RegGetValue(hKey, NULL, "PATH", RRF_RT_ANY, NULL, (PVOID)&ValueBuffer, &BufferSize);
Notice the last parameter is &BufferSize. This is an [in, out] parameter. You set it to the size of your buffer before going in and it changes the value to the number of characters read into the buffer on the way out. This is what the docs say about RegGetValue (and other similar Reg) functions:
pcbData [in, out, optional]
A pointer to a variable that specifies the size of the buffer pointed to by the pvData parameter, in bytes. When the function returns, this variable contains the size of the data copied to pvData.
So when you call RegGetValue it started at 8192 (BUFFER) but after the first call it was overwritten by the the number of characters read.
Before each RegGetValue call where you pass a &BufferSize you should do this:
BufferSize = BUFFER
As well I notice you have:
#define BUFFER 8192
char ValueBuffer[255];
DWORD BufferSize = BUFFER;
Shouldn't you be setting ValueBuffer to be at least ValueBuffer[BUFFER] instead of ValueBuffer[255]?
As well your code as it is only supports an 8192 byte buffer. If the Value key from the registry is longer than that then it would return ERROR_MORE_DATA. I assume that your code is not anticipating anything beyond 8192. You can determine the size up front for a Value key by using RegQueryInfoKey and dynamically allocating enough space ahead of time.
ERROR_MORE_DATA means that one of the buffers you passed to RegGetValue is not large enough to store the data you asked RegGetValue to give you. You need to loop and reallocate the buffers supplied here when you get this exit code.
For example:
LONG result = ERROR_MORE_DATA;
DWORD dataLength = /* some reasonable default size */ 255;
unique_ptr<char[]> buffer;
while (result == ERROR_MORE_DATA)
{
buffer.reset(new char[dataLength]);
result = RegGetValueW(
hKey,
L"Subkey",
L"Value",
0,
nullptr,
buffer.get(),
&dataLength
);
}
if (result != ERROR_SUCCESS)
{
// Handle the error
}