simple question, I have problem with memmove() and memcpy() when i'm using it. I really don't understand what wrong with my code. by the way i use QT.
HANDLE hFile;
HANDLE hMapFile;
HANDLE hMapView;
hFile = CreateFileW((const wchar_t*) objPath.constData(), GENERIC_READ , 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE){
hMapFile = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (hMapFile != INVALID_HANDLE_VALUE){
hMapView = MapViewOfFile(hMapFile, GENERIC_READ, 0, 0,0);
if (hMapView != INVALID_HANDLE_VALUE){
uint DefineWord;
memmove((void *) &DefineWord, hMapView,2); // <- always error right here
qDebug()<<DefineWord;
}
}
}
hMapView is not a pointer. memmove requires two pointers. Fix this by declaring hMapView properly. It should be a LPVOID.
MapViewOfFile returns a pointer, or NULL (0) when there is an error, not INVALID_HANDLE_VALUE (-1).
Edit: There was a lot of other problems with your code:
QString::constData() returns QChar*, not wchar_t*, you have to use QString::utf16() instead.
If CreateFileMappingW fails it returns NULL, not INVALID_HANDLE_VALUE.
MapViewOfFile access parameter is FILE_MAP_READ, not GENERIC_READ.
uint is often bigger than 2 bytes, so you should initialize the variable to 0 before memmove if you only read 2 bytes.
Here is a minimal code that should work (only tested on wineg++/wine):
#include <windows.h>
#include <QtCore/QString>
#include <QtCore/QDebug>
#include <QtCore/QTextStream>
int main(int argc, char const *argv[])
{
if (argc < 2) {
QTextStream(stdout) << "Usage :" << argv[0] << " filename" << endl;
return 1;
}
QString objPath(argv[1]);
// Qt source uses C-Style cast from utf16() to (wchar_t*),
// so it should be safe
HANDLE hFile = CreateFileW((const wchar_t *) objPath.utf16(), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
qDebug() << qt_error_string();
} else {
HANDLE hMapFile = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (!hMapFile) {
qDebug() << qt_error_string();
} else {
void *pMapView = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if (!pMapView) {
qDebug() << qt_error_string();
} else {
uint DefineWord = 0;
memmove((void *) &DefineWord, pMapView, 2);
qDebug() << DefineWord;
}
CloseHandle(hMapFile);
}
CloseHandle(hFile);
}
return 0;
}
PS: QString qt_error_string(int errorCode = -1) is an apparently undocumented Qt function that returns the error string of the last error (from the error code returned from GetLastError() or errno).
If you are using Qt, you can map a file to memory with QFile::map().
To do what your initial code was supposed to do, you only had to add 2 lines to the code sample you found (plus the error checking):
QFile file("foo");
if(!file.open(QFile::ReadOnly)) {
qDebug() << file.errorString();
} else {
uchar *memory = file.map(0, file.size());
if (!memory) {
qDebug() << file.errorString();
} else {
uint DefineWord = 0;
memmove(&DefineWord, memory, 2);
file.unmap();
}
}
by the way i use QT.
You aren't really using it in your example.
Qt has QFile::map method which can (and in my opinion should) be used instead of platform-specific MapViewOfFile.
Related
I've been given a task to create 2 processes. First one opens a file "log.txt" and adds the input given by user to it.
The second process is meant to be a "monitor" of that file. It checks if it exists, gives its size and gives the number of characters entered by user since the start of the second process. I'm using the GetFileSize() function to it so it's not a problem.
I'm slighty confused by the CreateProcess() and CreateFile() functions as I'm not sure how to connect it with one another.
I've read that the CreateFile() function can be used as a mutex by changing its flags. I've come up with something like this:
HANDLE hFile = CreateFile(
"log.txt",
FILE_APPEND_DATA,
FILE_SHARE_WRITE | FILE_SHARE_READ,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
Now I'm not really sure how to connect it to processes and where to start the processes from. And also I have no idea how to check how many characters were given since the start of the second process.
Can someone explain to me when to start those 2 processes and how to connect the CreateFile() function to them?
FILE_SHARE_WRITE | FILE_SHARE_READ will allow other processes to open and share the read and write access. You need to open the file exclusively (with dwShareMode = 0), but this requires process2 to try to open the file exclusively in a loop.
Instead, use CreateMutex to create a mutex, then process1 uses WaitForSingleObject to take up the mutex, do something and then ReleaseMutex, process2 uses WaitForSingleObject waits for released mutex, and then reads the file. (One synchronization is completed)
process 2:
#include <windows.h>
#include <iostream>
int wmain(int argc, wchar_t* argv[])
{
HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, false, L"MyMutex");
DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
if (dwWaitResult == WAIT_OBJECT_0)
{
HANDLE hFile = CreateFile(L"log.txt", FILE_READ_ATTRIBUTES, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "CreateFile error " << GetLastError() << std::endl;
ReleaseMutex(hMutex);
}
else
{
DWORD size = GetFileSize(hFile, NULL);
std::cout << "File Size: " << size << std::endl;
CloseHandle(hFile);
ReleaseMutex(hMutex);
}
}
return 0;
}
process 1:
#include <windows.h>
#include <iostream>
int wmain(int argc, wchar_t* argv[])
{
HANDLE hMutex = CreateMutex(NULL, false, L"MyMutex");
DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE);
if (dwWaitResult == WAIT_OBJECT_0)
{
STARTUPINFO si = { 0 };
si.cb = sizeof(si);
PROCESS_INFORMATION pi = { 0 };
CreateProcess(L"process2.exe",
NULL,
NULL,
NULL,
false,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi);
std::string buffer;
std::cin >> buffer;
HANDLE hFile = CreateFile(L"log.txt", FILE_APPEND_DATA, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DWORD written = 0;
WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);
CloseHandle(hFile);
ReleaseMutex(hMutex);
}
return 0;
}
But this is more troublesome, because you need to synchronize the two processes every time.
As #Remy Lebeau said, use ReadDirectoryChangesW in process2:
#include <windows.h>
#include <iostream>
int wmain(int argc, wchar_t* argv[])
{
FILE_NOTIFY_INFORMATION* pInfo = NULL;
HANDLE hFile = CreateFile(L"Directory of log.txt", GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
while (1)
{
DWORD returned = 0;
DWORD dwOffset = 0;
BYTE szBuffer[1024] = { 0 };
ReadDirectoryChangesW(hFile, szBuffer, sizeof(szBuffer), false, FILE_NOTIFY_CHANGE_SIZE, &returned, NULL, NULL);
do
{
pInfo = (FILE_NOTIFY_INFORMATION*)&szBuffer[dwOffset];
if (wcscmp(pInfo->FileName, L"log.txt") == 0)
{
HANDLE hFile = CreateFile(L"path\\log.txt", FILE_APPEND_DATA, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DWORD size = GetFileSize(hFile, NULL);
std::cout << "File Size: " << size << std::endl;
CloseHandle(hFile);
}
dwOffset += pInfo->NextEntryOffset;
} while (pInfo->NextEntryOffset != 0);
}
return 0;
}
And process 1 only need to get user input and write to the file:
#include <windows.h>
#include <iostream>
int wmain(int argc, wchar_t* argv[])
{
std::string buffer;
while (1)
{
std::cin >> buffer;
HANDLE hFile = CreateFile(L"log.txt", FILE_APPEND_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DWORD written = 0;
WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);
CloseHandle(hFile);
}
return 0;
}
It appears that you want to synchronize these two proccesses so that the second one waits for the first one to complete writing to "log.txt".
For that, you would need to open that file in the first process with exclusive access (no FILE_SHARE_WRITE | FILE_SHARE_READ), and close it when it's done writing.
The second process would try to open that same file, also with exclusive access. CreateFile() would fail with "access denied" error if that file is still in use by the first process. This is an essence of "mutually exclusive" concept of mutex. You would then wait a little and try again.
Contrary to synchronization objects, I am not aware of the way to wait for the file to become available (easily done with WaitForSingleObject for mutex).
So I've managed to make something out of your precious comments. I'm not sure if it is a right way to solve this task. It would be nice if someone could review my code and give me some additional tips.
Here is my code
int main(int argc, char *argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
CreateProcess("process2.exe",
NULL,
NULL,
NULL,
false,
CREATE_NEW_CONSOLE,
NULL,
NULL,
&si,
&pi);
std::string buffer;
std::cout << "Enter your text:" << std::endl;
getline(std::cin, buffer);
HANDLE hFile = CreateFile("log.txt", FILE_APPEND_DATA, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
DWORD written = 0;
WriteFile(hFile, buffer.c_str(), buffer.size(), &written, NULL);
hFile = CreateFile("log.txt", FILE_READ_ATTRIBUTES, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
std::cout << "CreateFile error " << GetLastError() << std::endl;
}
else
{
DWORD size = GetFileSize(hFile, NULL);
std::cout << "\nCurrent file size: " << size << std::endl;
CloseHandle(hFile);
}
int stringLenght = 0;
for(int i=0; buffer[i]; i++)
stringLenght++;
std::cout << "\nCharacters given since last startup: " << stringLenght << std::endl;
return 0;
}
I'm not sure if that was the point in this task or should it check the file size and ask user for input in a while loop and if it's possible to do without a mutex.
I'm trying to open a file on windows and check that the magic bytes match a windows PE32. If I run the code below and return just before the ReadFile call in the function problemFunction the code works fine and it prints 5a4d at the end of the main function. However if I return after the ReadFile call in problemFunction then I exit in the dos->e_magic != PIMAGE_DOS_HEADER check.
#include <Windows.h>
#include <winternl.h>
void problemFunction(HANDLE *fh) {
DWORD fileSize = GetFileSize(fh, NULL);
if (!fileSize) { CloseHandle(fh); exit(1); }
BYTE* pByte = new BYTE[fileSize];
DWORD dw;
ReadFile(*fh, pByte, fileSize, &dw, NULL);
// could be wrong but i think i need to run SetFilePointer here but not sure on what to do.
return;
}
int main() {
const char* filepath = "C:\\windows\\file\\path\\to\\exe";
HANDLE fh = CreateFileA(filepath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(fh == INVALID_HANDLE_VALUE) { CloseHandle(fh); exit(1); }
problemFunction(&fh);
DWORD fileSize = GetFileSize(fh, NULL);
if (!fileSize) { CloseHandle(fh); exit(1); }
BYTE* pByte = new BYTE[fileSize];
DWORD dw;
ReadFile(fh, pByte, fileSize, &dw, NULL);
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pByte;
if (dos->e_magic != IMAGE_DOS_SIGNATURE) { CloseHandle(fh); exit(1); }
// dos->e_magic should be 5a4d for MZ, windows PE
}
I assume i need to reset the file pointer after the problemFunction read call with something like
LONG reset = -sizeof(DWORD);
SetFilePointer(*fh, reset, NULL, FILE_END);
But i can't get it to work.
Thanks
There are a number of problems with your code.
problemFunction() is taking a HANDLE* pointer as input, but it is not dereferencing that pointer when passing it to GetFileSize() or CloseHandle(). But it is dereferencing the pointer when passing it to ReadFile().
You must be compiling your code with STRICT Type Checking turned off, otherwise your code would fail to compile. You should always compile with STRICT enabled.
HANDLE is a pointer type, so there is no need to pass it around by pointer, unless you are going to modify its value, which this code is not doing. So you should change problemFunction() to take a HANDLE as-is rather than taking a HANDLE* pointer.
Also, GetFileSize() does not return 0 on failure, like your code assumes. It actually returns INVALID_FILE_SIZE which is -1, ie 0XFFFFFFFF as a DWORD. This is clearly stated in the documentation:
If the function fails and lpFileSizeHigh is NULL, the return value is INVALID_FILE_SIZE. To get extended error information, call GetLastError.
But, most importantly, your 2nd call to ReadFile() inside of main() does not read what you are expecting because the 1st call to ReadFile() inside of problemFunction() has already read the data (and leaked it!), but you are not seeking the HANDLE back to the beginning of the file after that read so the 2nd call to ReadFile() can read it again. You are correct that you need to use SetFilePointer() for that.
With that said, try something more like this:
#include <Windows.h>
#include <winternl.h>
bool test(HANDLE fh) {
DWORD fileSize = GetFileSize(fh, NULL);
if (fileSize == INVALID_FILE_SIZE) {
return false;
}
BYTE* pByte = new BYTE[fileSize];
DWORD dw;
if (!ReadFile(fh, pByte, fileSize, &dw, NULL)) {
delete[] pByte;
return false;
}
// use pByte as needed...
delete[] pByte;
if (SetFilePointer(fh, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
return false;
}
return true;
}
int main() {
const char* filepath = "C:\\windows\\file\\path\\to\\exe";
HANDLE fh = CreateFileA(filepath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE) {
return 1;
}
if (!test(fh)) {
CloseHandle(fh);
return 1;
}
DWORD fileSize = GetFileSize(fh, NULL);
if (fileSize == INVALID_FILE_SIZE) {
CloseHandle(fh);
return 1;
}
BYTE* pByte = new BYTE[fileSize];
DWORD dw;
if (!ReadFile(fh, pByte, fileSize, &dw, NULL) || dw < sizeof(IMAGE_DOS_HEADER)) {
CloseHandle(fh);
return 1;
}
PIMAGE_DOS_HEADER dos = (PIMAGE_DOS_HEADER)pByte;
if (dos->e_magic != IMAGE_DOS_SIGNATURE) {
delete[] pByte;
CloseHandle(fh);
return 1;
}
...
delete[] pByte;
CloseHandle(fh);
return 0;
}
there's something wrong with this api. i already check return function. no error. but output nothing.
HANDLE hSnapProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
PROCESSENTRY32 process;
process.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnapProcess, &process);
do
{
if (process.th32ProcessID != 0)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process.th32ProcessID);
if (hProcess != NULL)
{
wchar_t filePath[MAX_PATH];
if (!GetModuleFileNameExW(hProcess, NULL, filePath, MAX_PATH))
{
std::wcout << filePath << std::endl;
}
}
CloseHandle(hProcess);
}
} while (Process32Next(hSnapProcess, &process));
CloseHandle(hSnapProcess);
Two clear mistakes can be seen in your code, both can be understood by reading the documentation.
Firstly, in GetModuleFileNameEx:
The handle must have the PROCESS_QUERY_INFORMATION and PROCESS_VM_READ access rights.
Your handle only has PROCESS_QUERY_INFORMATION.
Secondly, again in GetModuleFileNameEx:
If the function succeeds, the return value specifies the length of the string copied to the buffer.
If the function fails, the return value is zero.
Your logic is back-to-front. Replace:
if (!GetModuleFileNameExW(hProcess, NULL, filePath, MAX_PATH))
with
if (GetModuleFileNameExW(hProcess, NULL, filePath, MAX_PATH))
Nothing is wrong with this API, the only thing that's wrong here is your code.
The documentation clearly states that the return value of GetModuleFileNameExW is the length of the string copied to the buffer.
If the return value is 0, the function has failed.
So you simply need to write this:
...
if (GetModuleFileNameExW(hProcess, NULL, filePath, MAX_PATH) != 0)
{
// handle "success" case
}
...
BTW CloseHandle(hProcess); should be inside the if (hProcess != NULL) block.
Full working example with error checks
#include <iostream>
#include <windows.h>
#include <tlhelp32.h>
#include <psapi.h>
int main()
{
HANDLE hSnapProcess = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (hSnapProcess != INVALID_HANDLE_VALUE)
{
PROCESSENTRY32 process;
process.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnapProcess, &process);
do
{
if (process.th32ProcessID != 0)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, process.th32ProcessID);
if (hProcess != NULL)
{
wchar_t filePath[MAX_PATH];
if (GetModuleFileNameExW(hProcess, NULL, filePath, MAX_PATH))
{
std::wcout << filePath << std::endl;
}
else
{
std::wcout << L"GetModuleFileNameExW failed with error" << GetLastError() << std::endl;
}
CloseHandle(hProcess);
}
}
} while (Process32Next(hSnapProcess, &process));
CloseHandle(hSnapProcess);
}
else
{
std::wcout << L"CreateToolhelp32Snapshot failed with error" << GetLastError() << std::endl;
}
}
please help me with reading memory mapped file. I open file in code below. And then i want to read bytes from 8 to 16. How can i do that?
// 0. Handle or create and handle file
m_hFile = CreateFile(file_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (m_hFile == INVALID_HANDLE_VALUE)
{
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
m_hFile = createNewFile(file_path.c_str());
}
else throw GetLastError();
}
// 1. Create a file mapping object for the file
m_hMapFile = CreateFileMapping(m_hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
if (m_hMapFile == NULL) throw GetLastError();
// 2. Map the view.
m_lpMapAddress = MapViewOfFile(m_hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
// to map
if (m_lpMapAddress == NULL) throw GetLastError();
You can access it like any other memory block. Here's an example that prints those bytes interpreted as unsigned chars:
unsigned char *mappedDataAsUChars = (unsigned char*)m_lpMapAddress;
for(int k = 8; k < 16; k++)
std::cout << "Byte at " << k << " is " << mappedDataAsUChars[k] << std::endl;
Here is my code. I have attached wininet.lib to additional dependencies.
#include <iostream>
#include <Windows.h>
#include <WinInet.h>
using namespace std;
int main()
{
HINTERNET hSession, hURL;
char* Buffer = new char[1024];
DWORD BufferLen, BytesWritten;
HANDLE FileHandle;
hSession = InternetOpen(NULL, 0, NULL, NULL, 0);
hURL = InternetOpenUrl(hSession, "http://www.google.co.uk", NULL, 0, 0, 0);
FileHandle = CreateFile("C:\temp.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
if (FileHandle == NULL) { cout << "FileHandle == NULL" << endl; }
BytesWritten = 0;
do
{
InternetReadFile(hURL, Buffer, 1024, &BufferLen);
WriteFile(FileHandle, Buffer, BufferLen, &BytesWritten, NULL);
} while (BufferLen != 0);
CloseHandle(FileHandle);
InternetCloseHandle(hURL);
InternetCloseHandle(hSession);
ShellExecute(0, "open", "C:\\temp.txt", NULL, NULL, 1);
cout << "Operation complete!" << endl;
system("PAUSE");
return 0;
}
My output file C:\temp.txt is not created even though the handle is non-null. I would like to know why this is the case and if the rest of my code is correct. Thank you.