I am currently trying to get the full filepath from my executable by providing a process ID, and this works "fine" in the since that its able to return some of the information needed, however for some reason it becomes corrupted and this can be seen when trying to return it as a plain string: C and if you iterate over each char and print each letter you get even more of a mess. Where is my current coding wrong when attempting allocate my buffer?
std::string User::getFullPath() {
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());
char buffer[MAX_PATH];
if (hProcess != NULL)
{
GetModuleFileNameEx(hProcess, NULL, (LPWSTR)buffer, MAX_PATH);
CloseHandle(hProcess);
}
for (char i : buffer) {
std::cout << i<<std::endl;
}
return buffer;
}
How do I properly allocate the memory in this case to prevent corruption
First off, the contents of your array are uninitialized if OpenProcess() fails. There is no need to use OpenProcess() on the calling process ID. Use GetCurrentProcess() instead, or simply use GetModuleFileName() instead.
That said, the real problem is not with memory allocation, but rather is that you are mixing ANSI and Unicode incorrectly. You are typecasting a char[] buffer to wchar_t*, which won't work.
You need to either:
use a wchar_t[] instead:
std::wstring User::getFullPath() {
wchar_t buffer[MAX_PATH] = {};
GetModuleFileNameW(NULL, buffer, MAX_PATH);
std::wcout << buffer << std::endl;
return buffer;
}
use GetModuleFileName(Ex)A() instead:
std::string User::getFullPath() {
char buffer[MAX_PATH] = {};
GetModuleFileNameA(NULL, buffer, MAX_PATH);
std::cout << buffer << std::endl;
return buffer;
}
Related
I'm using this function to add my program to startup. But it doesn't work and I don't know why weird ascii characters and words are showing up in startup applications. What am I doing wrong?
Instead this is being added to starup. U㫅萹㐀蠀渐晁Ɉ U㫆萺㝈耀 U㫆萺㝈耀 and C. Which has no file location and also no details.
HKEY NewVal;
char loggeduser[UNLEN + 1];
std::ostringstream fileinhome;
GetUserNameA(loggeduser, &len);
fileinhome << "C:\\Users\\" << loggeduser << "\\AppData\\Roaming\\snetwork\\snetwork.exe";
std::string fp = fileinhome.str();
const char* file = fp.c_str();
if (RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), &NewVal) != ERROR_SUCCESS)
{
return;
}
if (RegSetValueEx(NewVal, _T("CLI-Social-Network"), 0, REG_SZ, (LPBYTE)file, sizeof(file)) != ERROR_SUCCESS)
{
return;
}
else {
// std::cout << "Program added to Startup.\n";
// Do nothing, Program was added to Startup
}
RegCloseKey(NewVal);
A possibility: You have UNICODE and/or _UNICODE defined, so RegSetValueEx is actually RegSetValueExW. Therefore, this function passes Unicode data into the buffer file. But file is an ASCII buffer, so the otherwise-valid Unicode data is incorrectly parsed as ASCII, leading to the strange output.
To fix, use std::wstring and W functions explicitly.
Unicode considerations aside, you can't use a const char * as a buffer for receiving data. You must allocate sufficient memory for the buffer first.
I want to replace a specific character wchar_t. as a result it return memory address. is there a way to return replaced wchar_t?
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <Psapi.h>
using namespace std;
int main()
{
wchar_t processPath[MAX_PATH];
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, 3820);
GetProcessImageFileName(hProcess, processPath, MAX_PATH);
CloseHandle(hProcess);
wchar_t * pwc;
pwc = wcsstr(processPath, L"\\Device\\HardiskVolume1");
wcscpy_s(pwc, 100, L"C:", 100);
wcout << processPath;
return 0;
}
Thank you
I suggest that you use std::wstring, and then .replace, there isn't really a good 'replace' function when using c-strings:
LPCWSTR pwszReplace = L"string-of-interest";
std::size_t len = wcslen(pwszReplace);
std::wstring path(processPath),
std::size_t ndx = path.find(pwszReplace);
if(std::wstring::npos!=ndx)
{
path.replace(ndx, len, L"new-string");
}
std::wcout << L"path is now: " << path << std::endl;
Use GetModuleFileNameEx Windows XP and higher. Or QueryFullProcessImageName for Vista and higher.
Otherwise, you can't assume "\\Device\\HardiskVolume1" is always "C:"
See also this SO Q&A: Convert HarddiskVolume path to normal path
Start by changing "\Device" to "\\?":
`"\\Device\\HardiskVolume1\\path.exe"` //to
`"\\\\?\\HardiskVolume1\\path.exe"`
wchar_t buf[MAX_PATH];
wchar_t *ptr = wcsstr(processPath, L"\\Device");
if(ptr)
{
wcscpy_s(buf, L"\\\\?");
wcscat_s(buf, ptr + wcslen(L"\\Device"));
}
Now you can open buf in CreateFile, then use GetFinalPathNameByHandle to get
`"\\\\?\\C:\\path.exe"`
Note that wcsstr returns NULL if search string is not found. If search string was found and copy was successful, you end up overwriting processPath the way you have done that. Moreover, wcscpy_s is the secure version of wcscpy. If you don't want to use wcscpy_s correctly then just use wcscpy without using a random number like 100 as the argument.
I need to read file asynchroneously
string read(string path) {
DWORD readenByte;
int t;
char* buffer = new char[512];
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, "read");
OVERLAPPED overlap;
overlap.hEvent = hEvent;
HANDLE hFile = CreateFile(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(!hFile) {
Debug::error(GetLastError(), "fileAsync.cpp::read - ");
}
t = ReadFile(hFile, buffer, MAX_READ - 1, &readenByte, &overlap);
if(!t) {
Debug::error(GetLastError(), "fileAsync.cpp::read - ");
}
t = WaitForSingleObject(hEvent, 5000);
if(t == WAIT_TIMEOUT) {
Debug::error("fail to read - timeout, fileAsync.cpp::read");
}
buffer[readenByte] = '\0';
string str = buffer;
return str;
}
I've got the error at ReadFile - 38: reached the end of the file
How to read asynchroneusly file in c++ with use of winapi?
There are several bugs in your code that need to be addressed, some cause failure, others catastrophic failure.
The first bug leads to the error code you get: You have an uninitialized OVERLAPPED structure, instructing the following ReadFile call to read from the random file position stored in the Offset and OffsetHigh members. To fix this, initialize the data: OVERLAPPED overlap = {0};.
Next, you aren't opening the file for asynchronous access. To subsequently read asynchronously from a file, you need to call CreateFile passing FILE_FLAG_OVERLAPPED for dwFlagsAndAttributes. If you don't you're off to hunting a bug for months (see What happens if you forget to pass an OVERLAPPED structure on an asynchronous handle?).
The documentation for ReadFile explains, that lpNumberOfBytesRead parameter is not used for asynchronous I/O, and you should pass NULL instead. This should be immediately obvious, since an asynchronous ReadFile call returns, before the number of bytes transferred is known. To get the size of the transferred payload, call GetOverlappedResult once the asynchronous I/O has finished.
The next bug only causes a memory leak. You are dynamically allocating buffer, but never call delete[] buffer;. Either delete the buffer, or allocate a buffer with automatic storage duration (char buffer[MAX_READ] = {0};), or use a C++ container (e.g. std::vector<char> buffer(MAX_READ);).
Another bug is, where you try to construct a std::string from your buffer: The constructor you chose cannot deal with what would be an embedded NUL character. It'll just truncate whatever you have. You'd need to call a std::string constructor taking an explicit length argument. But even then, you may wind up with garbage, if the character encoding of the file and std::string do not agree.
Finally, issuing an asynchronous read, followed by WaitForSingleObject is essentially a synchronous read, and doesn't buy you anything. I'm assuming this is just for testing, and not your final code. Just keep in mind when finishing this up, that the OVERLAPPED structure need to stay alive for as long as the asynchronous read operation is in flight.
Additional recommendations, that do not immediately address bugs:
You are passing a std::string to your read function, that is used in the CreateFile call. Windows uses UTF-16LE encoding throughout, which maps to wchar_t/std::wstring when using Visual Studio (and likely other Windows compilers as well). Passing a std::string/const char* has two immediate drawbacks:
Calling the ANSI API causes character strings to be converted from MBCS to UTF-16 (and vice versa). This both needlessly wastes resources, as well as fails in very subtle ways, as it relies on the current locale.
Not every Unicode code point can be expressed using MBCS encoding. This means, that some files cannot be opened when using MBCS character encoding.
Use the Unicode API (CreateFileW) and UTF-16 character strings (std::wstring/wchar_t) throughout. You can also define the preprocessor symbols UNICODE (for the Windows API) and _UNICODE (for the CRT) at the compiler's command line, to not accidentally call into any ANSI APIs.
You are creating an event object that is only ever accessed through its HANDLE value, not by its name. You can pass NULL as the lpName argument to CreateEvent. This prevents potential name clashes, which is all the more important with a name as generic as "read".
1) You need to include the flag FILE_FLAG_OVERLAPPED in the 6th argument (dwFlagsAndAttributes) of the call to CreateFile. That is why most likely the overlapped read fails.
2) What is the value of MAX_READ? I hope it's less than 513 otherwise if the file is bigger than 512 bytes bad things will happen.
3) ReadFile with the overlapped structure pointer being not NULL will give you the error code 997 (ERROR_IO_PENDING) which is expected and thus you cannot evaluate the t after calling ReadFile.
4) In the case of asynchronous operation the ReadFile function does not store the bytes read in the pointer you pass in the call, you must query the overlapped result yourself after the operation is completed.
Here is a small working snippet, I hope you can build up from that:
#include <Windows.h>
#include <iostream>
#include <sstream>
class COverlappedCompletionEvent : public OVERLAPPED
{
public:
COverlappedCompletionEvent() : m_hEvent(NULL)
{
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_hEvent == NULL)
{
auto nError = GetLastError();
std::stringstream ErrorStream;
ErrorStream << "CreateEvent() failed with " << nError;
throw std::runtime_error(ErrorStream.str());
}
ZeroMemory(this, sizeof(OVERLAPPED));
hEvent = m_hEvent;
}
~COverlappedCompletionEvent()
{
if (m_hEvent != NULL)
{
CloseHandle(m_hEvent);
}
}
private:
HANDLE m_hEvent;
};
int main(int argc, char** argv)
{
try
{
if (argc != 2)
{
std::stringstream ErrorStream;
ErrorStream << "usage: " << argv[0] << " <filename>";
throw std::runtime_error(ErrorStream.str());
}
COverlappedCompletionEvent OverlappedCompletionEvent;
char pBuffer[512];
auto hFile = CreateFileA(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (hFile == NULL)
{
auto nError = GetLastError();
std::stringstream ErrorStream;
ErrorStream << "CreateFileA() failed with " << nError;
throw std::runtime_error(ErrorStream.str());
}
if (ReadFile(hFile, pBuffer, sizeof(pBuffer), nullptr, &OverlappedCompletionEvent) == FALSE)
{
auto nError = GetLastError();
if (nError != ERROR_IO_PENDING)
{
std::stringstream ErrorStream;
ErrorStream << "ReadFile() failed with " << nError;
throw std::runtime_error(ErrorStream.str());
}
}
::WaitForSingleObject(OverlappedCompletionEvent.hEvent, INFINITE);
DWORD nBytesRead = 0;
if (GetOverlappedResult(hFile, &OverlappedCompletionEvent, &nBytesRead, FALSE))
{
std::cout << "Read " << nBytesRead << " bytes" << std::endl;
}
CloseHandle(hFile);
}
catch (const std::exception& Exception)
{
std::cout << Exception.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I am trying to load the name of an image using its VM address by calling GetModuleFileName() which seems to return the value correctly into a TCHAR[] array. I am able to display the data correctly using MessageBox() but cout << seems to display some funky hexadecimal number.
TCHAR buf[MAX_PATH];
HMODULE hProc = LoadLibrary(TEXT("kernel32.dll"));
GetModuleFileName(hProc, buf, MAX_PATH);
cout << buf; //Produces the odd number
MessageBox(NULL, buf, NULL, MB_OK); //Produces correct filepath
FreeLibrary(hProc);
Am I supposed to set a flag for cout so it knows to print it correctly? Thank you!
Probably you need to use wcout, because your TCHAR might be unicodish. Or convert it.
Maybe you will have better luck with
std::wcout << buf;
I'm trying to copy some binary data from my IStream instance (since Gdiplus::Image only saves to IStream-deriving objects, or a file path) to a char pointer from which I can read simply by knowing the allocated binary size and have access to the pointer.
My class is as follows:
Upload::Upload(Gdiplus::Bitmap* bitmap, CLSID clsEncoderId)
{
int result;
STATSTG statResult;
result = CreateStreamOnHGlobal(0, TRUE, &m_hBufferStream);
if (result != S_OK)
MessageBoxW(NULL, _T("Upload::Upload(): Could not create stream"), _T("Point"), MB_OK | MB_ICONERROR);
else
{
if (bitmap->Save(m_hBufferStream, &clsEncoderId, NULL) != Gdiplus::Ok)
MessageBoxW(NULL, _T("Upload::Upload(): Could not save() image"), _T("Point"), MB_OK | MB_ICONERROR);
}
if (m_hBufferStream->Stat(&statResult, STATFLAG_NONAME) != S_OK)
return;
Gdiplus::Image test(m_hBufferStream, TRUE);
test.Save(_T("hejs.png"), &clsEncoderId, NULL);
m_iSize = statResult.cbSize.LowPart;
}
char* Upload::GetBinaryData()
{
char* buffer = (char*)malloc(m_iSize);
ULONG size = 0;
m_hBufferStream->Read(buffer, m_iSize, &size);
return buffer;
}
In my function that processes the Upload instance I do this:
char* pBuffer = upload->GetBinaryData();
buffer.write(pBuffer, upload->GetSize());
But the memory stored is wrong (oddly it seems like a pattern though).
What am I doing wrong?
Thanks in advance.
P.S.:
The test Image-instance successfully saves to the file after reading from m_hBufferStream.
First of all, IStream::Read() is not required to read exactly the specified number of bytes - it is required to read no more than that number. Actual number is stored inside the veriable pointed to by the third parameter.
Second, you don't check the HRESULT returned by Read().
A much better strategy would be to call Read() in a loop, check its return value and adjust the pointer to the buffer according to how many bytes have been actually read.
i faced the same problem - matter is
bitmap->Save
write bytes and moves offset to the end of the stream, and when you try to get bytes it starts to read from the end of stream and thus would read 0 bytes. So you need point read offset from begin of the stream:
LARGE_INTEGER li = {0};
m_hBufferStream->Seek(li, STREAM_SEEK_SET, NULL);