Open physical drive. Windows - c++

I try open physical drive like
ofstream * _fileWriter->open(_destPath, std::ofstream::out | std::ofstream::binary);
_destPath = \\.\PhysicalDrive1
But, when i try do
if (!(_fileWriter->is_open()))
return false;
It return false

You have to run the program with elevated access.
Request GENERIC_READ / GENERIC_WRITE
hdrive = CreateFile(L"\\\\.\\PhysicalDrive0", GENERIC_READ,
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
If you just want to get disk information, you can open the disk with no read/write access, the code below shouldn't need elevated access:
HANDLE hdrive;
hdrive = CreateFile(L"\\\\.\\PhysicalDrive0", 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (hdrive == INVALID_HANDLE_VALUE)
{
cout << "error " << GetLastError() << endl;
return 0;
}
cout << "open" << endl;
CloseHandle(hdrive);

Related

How can I read and write to pipes created for a child process in c++

I am making a tester program that opens a console application and reads it's standard input writes to it's standard output, but am having issues with the pipes. I am using named pipes since I might have to run this threaded or even open multiple executables to communicate with at once. These will need to remain running and continuously take input and give out put, as in a console calculator that asks if you if you want another calculation or to exit after each calculation.
Using error checking I have found that The pipes are created successfully, I apply them to the startupInfo struct and successfully open the executable. A note here, if I set a break point in visual studio just after the call to createProcess, the child process does show up in my task manager, the check STILL_ACTIVE is true and peaking at the pipe reveals an empty pipe. If no break point is set then I don't see it, and the check STILL_ACTIVE is false.
To simplify the problem I went back to basics, a simple hello world executable in c++. The calculator will be the next test. This prints hello world to the console and via a cin:get() waits for the enter key to be pressed. I ran this with the tester and tried to read the "Hello World" from the child process. I get nothing.
The end project will be open source, I don't want the user to have to download any other libraries to compile the project, and Boost::Process actually requires 2 install since process is not standard yet.
I know that I am close, here is my simple tester as one file with the process class extracted to be inline in the main. Note: I have enabled c++20 in my compiler.
// Tester.cpp
#include <string>
#include <string_view>
#include <vector>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
int main()
{
std::string data = "";
int id = 1;
std::string executable = "HelloWorld.exe";
if (_access((executable).c_str(), 0) != -1)
{
std::cerr << "Error: Executable file not found: " << executable << std::endl;
exit(0);
}
SECURITY_ATTRIBUTES saAttr{};
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
//Pipe names
std::wstring pipeErr = L"\\\\.\\pipe\\err_" + std::to_wstring(id);
std::wstring pipeOut = L"\\\\.\\pipe\\out_" + std::to_wstring(id);
std::wstring pipeIn = L"\\\\.\\pipe\\in_" + std::to_wstring(id);
// The Child error pipe for reading
CreateNamedPipeW(pipeErr.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, 0, NULL);
HANDLE err_pipe = CreateFileW(pipeErr.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
// The Child out pipe for reading
CreateNamedPipeW(pipeOut.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 1024, 1024, 0, NULL);
HANDLE out_pipe = CreateFileW(pipeOut.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
// The Child in pipe for writing
CreateNamedPipeW(pipeIn.c_str(), PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 1024, 1024, 0, NULL);
HANDLE in_pipe = CreateFileW(pipeIn.c_str(), GENERIC_READ | GENERIC_WRITE, 0, &saAttr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (in_pipe == INVALID_HANDLE_VALUE || out_pipe == INVALID_HANDLE_VALUE || err_pipe == INVALID_HANDLE_VALUE)
{
std::cout << "Error Creating Handles, Code: " << GetLastError() << std::endl;
return 0;
}
// Make sure the handles' inheritance is set correctly
if (!SetHandleInformation(in_pipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(out_pipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ||
!SetHandleInformation(err_pipe, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
{
std::cerr << "Error: Failed to set handle information for the child process" << std::endl;
return 0;
}
// Set up the startup info struct
STARTUPINFOA startupInfo;
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(STARTUPINFOA);
startupInfo.hStdInput = in_pipe;
startupInfo.hStdOutput = out_pipe;
startupInfo.hStdError = err_pipe;
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
// Set up the process info struct
PROCESS_INFORMATION processInfo;
memset(&processInfo, 0, sizeof(processInfo));
// Create the child process
if (CreateProcessA(NULL, executable.data(), NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &processInfo) == 0)
{
std::cerr << "Error: Failed to create the child process" << std::endl;
return 0;
}
// Set the pipes to non-blocking mode
DWORD mode = PIPE_NOWAIT;
SetNamedPipeHandleState(out_pipe, &mode, NULL, NULL);
SetNamedPipeHandleState(err_pipe, &mode, NULL, NULL);
SetNamedPipeHandleState(in_pipe, &mode, NULL, NULL);
Sleep(500); //wait for child to start, may not be neccesary
// Get the exit code of the child process
DWORD exitCode;
GetExitCodeProcess(processInfo.hProcess, &exitCode);
if (exitCode == STILL_ACTIVE) {
// Set up the read buffer
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
DWORD bytesRead = 0;
DWORD bytesAvail = 0;
// Check if there is data available to read from the pipe
if (!PeekNamedPipe(out_pipe, buffer, sizeof(buffer), &bytesRead, &bytesAvail, NULL)) {
std::cerr << "PeekNamedPipe failed (" << GetLastError() << ").\n";
return 0;
}
if (bytesAvail == 0)
{
std::cerr << "Pipe is empty" << std::endl;
}
if (!ReadFile(out_pipe, buffer, sizeof(buffer) - 1, &bytesRead, NULL))
{
std::cerr << "Failed to read from pipe. Error code: " << GetLastError() << std::endl;
return 0;
}
data = buffer;
}
if (data == "") {
std::cout << "Something went wrong. Code: " << GetLastError() << std::endl;
}
else {
std::cout << data << std::endl;
}
std::cout << "Press any key." << std::endl;
std::cin.get();
return 0;
}
and, for reference, here is helloworld.exe:
// HelloWorld.cpp
#include <iostream>
int main()
{
std::cout << "Hello World!" << std::endl;
std::cin.get();
}
Thanks to #Igor Tandetnik!
Here is the working Tester.cpp:
// Tester.cpp
#include <string>
#include <string_view>
#include <vector>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <io.h>
#include <fcntl.h>
#include <windows.h>
#include <aclapi.h>
constexpr auto BUFSIZE = 4096;
int main()
{
std::string data = "";
int id = 1;
std::wstring executable = L"HelloWorld.exe";
std::wstring argv = L"";
std::string name_c = "";
std::string path_c = "";
HANDLE hChildStd_IN_Rd = NULL;
HANDLE hChildStd_IN_Wr = NULL;
HANDLE hChildStd_OUT_Rd = NULL;
HANDLE hChildStd_OUT_Wr = NULL;
HANDLE hChildStd_ERR_Rd = NULL;
HANDLE hChildStd_ERR_Wr = NULL;
size_t size;
wcstombs_s(&size, nullptr, 0, executable.c_str(), executable.length());
name_c.resize(size);
wcstombs_s(&size, name_c.data(), name_c.size(), executable.c_str(), executable.length());
wchar_t current_dir[FILENAME_MAX];
if (_wgetcwd(current_dir, FILENAME_MAX) == nullptr) {
std::cerr << "Error getting current working directory. Code:" << GetLastError() << std::endl;
exit(0);
}
wchar_t path_exe[MAX_PATH];
GetModuleFileName(NULL, path_exe, MAX_PATH);
std::wstring path = path_exe;
path = std::filesystem::path(path).parent_path();
path += L"\\";
path += executable;
wcstombs_s(&size, nullptr, 0, path.c_str(), path.length());
path_c.resize(size);
wcstombs_s(&size, path_c.data(), path_c.size(), path.c_str(), path.length());
int found = _waccess_s(path.c_str(), 0);
if (found != 0)
{
std::cerr << "Error: Executable file not found: " << name_c << std::endl;
exit(0);
}
SECURITY_ATTRIBUTES sa_attr{};
sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
sa_attr.bInheritHandle = TRUE;
sa_attr.lpSecurityDescriptor = NULL;
// Create the pipes
if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &sa_attr, 0)
|| !CreatePipe(&hChildStd_IN_Rd, &hChildStd_IN_Wr, &sa_attr, 0)
|| !CreatePipe(&hChildStd_ERR_Rd, &hChildStd_ERR_Wr, &sa_attr, 0)) {
std::cout << "Error Creating Pipes, Code: " << GetLastError() << std::endl;
return 1;
}
if (hChildStd_OUT_Rd == INVALID_HANDLE_VALUE || hChildStd_OUT_Wr == INVALID_HANDLE_VALUE
|| hChildStd_IN_Rd == INVALID_HANDLE_VALUE || hChildStd_IN_Wr == INVALID_HANDLE_VALUE
|| hChildStd_ERR_Rd == INVALID_HANDLE_VALUE || hChildStd_ERR_Wr == INVALID_HANDLE_VALUE)
{
std::cout << "Error Creating Handles, Code: " << GetLastError() << std::endl;
return 1;
}
// Set up the startup info struct
STARTUPINFOW startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFOW));
startup_info.cb = sizeof(STARTUPINFOW);
startup_info.hStdOutput = hChildStd_OUT_Wr;
startup_info.hStdError = hChildStd_ERR_Wr;
startup_info.hStdInput = hChildStd_IN_Rd;
startup_info.dwFlags |= STARTF_USESTDHANDLES;
// Set up the process info struct
PROCESS_INFORMATION process_info;
memset(&process_info, 0, sizeof(process_info));
// Create the child process
if (!CreateProcess(path.data(), NULL, &sa_attr, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info))
{
std::cerr << "Error: Failed to create the child process. Code: " << GetLastError() << std::endl;
return 1;
}
// Get the exit code of the child process
DWORD exitCode;
GetExitCodeProcess(process_info.hProcess, &exitCode);
if (exitCode != STILL_ACTIVE) {
std::wcout << "Unable to Start Process: " << executable.c_str() << std::endl;
return 1;
}
std::wcout << "Started Process: " << executable.c_str() << std::endl;
Sleep(500); //wait for child to start, may not be neccesary
// Get the exit code of the child process
GetExitCodeProcess(process_info.hProcess, &exitCode);
if (exitCode == STILL_ACTIVE) {
// Set up the read buffer
DWORD bytesRead{}, dwWritten{};
CHAR buffer[BUFSIZE]{};
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
bSuccess = ReadFile(hChildStd_OUT_Rd, buffer, BUFSIZE, &bytesRead, NULL);
if (!bSuccess || bytesRead == 0)
{
std::cerr << "Failed to read from pipe. Error code: " << GetLastError() << std::endl;
return 1;
}
std::vector<char> v_data(buffer, buffer + bytesRead);
data = std::string(v_data.data(), v_data.size());
}
std::cout << "Recieved from Child: " << data << std::endl;
if (data == "") {
std::cout << "Something went wrong. Code: " << GetLastError() << std::endl;
return 1;
}
else {
std::cout << data << std::endl;
}
CloseHandle(process_info.hThread);
std::cout << "Press any key." << std::endl;
std::cin.get();
return 0;
}

C++ send data to parallel port in WinXP

I want to send mark to parallel port using C++ in winXP system. I checked the information and wrote the following code:
HANDLE parallelPort = CreateFile(L"LPT1", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(parallelPort == INVALID_HANDLE_VALUE)
std::cout << "handle error" << std::endl;
int *data = new int[1];
data[0] = 4;
WriteFile(parallelPort, data, sizeof(int), NULL, NULL);
std::cout << "send success!" << std::endl;
CloseHandle(parallelPort);
I run this code, find parallelPort != INVALID_HANDLE_VALUE . But it doesn't print send success!. What's wrong with this code?
If you have used the software named "E-prime", I want to do the same as it:
WritePort &H378, 0

Two processes handling their own lines of code in one main function (c++)

So my task goes like this:
The program needs 2 processes in one main function
First process creates or opens a file "log.txt" which is in the same directory where the program is located. Then it adds user input to this file.
Second process is a "monitor" of this file. It checks if the file exists, shows its size and shows how many characters were entered since the second process started.
Note that I am aware that the program itself is a process, but it needs to be done like that. There are some "tips" to use a file as mutex (CreateFile parameters) that would be the dsShareMode with FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE parameter.
Now my question is: how do you create 2 processes to handle its own line of code? I've seen many examples of CreateProcess function but I don't really understand the first two parameters of this function
lpApplicationName
and
lpCommandLine
What am I supposed to pass to it in order to run 2 processes, one to handle the user input and the other to be the "monitor"?
The first process is meant to handle those lines of code:
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);
While the second process should only care about this:
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 stringLength = 0;
for(int i=0; buffer[i]; i++)
stringLength++;
std::cout << "\nCharacters given since last startup: " << stringLength << std::endl;
Assuming you have a separate helper.exe, you can do:
CreateProcess(nullptr, "helper logger-mode", ...)
and
CreateProcess(nullptr, "helper monitor-mode", ...)
This will create two processes that see either logger-mode or monitor-mode in their second argument (argv[1]).
The question appears to demand having the same program being run as two separate processes. If that is the case, the program will need to handle command line arguments and tailor its functionality accordingly.
#Botje I've managed to do something like that. Could you take a look at tell me if such solution is acceptable?
int main(int argc, char *argv[])
{
std::string cmdline1 = "main Proc1";
std::string cmdline2 = "main Proc2";
std::string buffer;
HANDLE hFile;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
CreateProcess(argv[0], const_cast<char *>(cmdline1.c_str()), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
CreateProcess(argv[0], const_cast<char *>(cmdline2.c_str()), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if(strcmp(argv[1], "Proc1"))
{
while(1)
{
std::cout << "Enter your text:" << std::endl;
getline(std::cin, buffer);
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);
}
}
if(strcmp(argv[1], "Proc2"))
{
DWORD charactersGiven = 0;
while(1)
{
hFile = CreateFile("log.txt", GENERIC_READ, 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;
if(charactersGiven == 0)
charactersGiven = size;
std::cout << "Characters given since last startup: " << size - charactersGiven << std::endl;
}
Sleep(4000);
}
}
return 0;
}

I still have this issue: C++ get Partition Styles

I am new to C / C ++. This is an exercise. And I don't really understand it. The code above is that I copied on internet.
I'm learning C ++, so even though the code is C, I want to switch back to C ++.
I need to understand the code and output the screen:
is MBR disk/drive
is GPT disk/drive
or is RAW disk/drive
I am having trouble retrieving information about the Hard Drive Partition Types in C/C++.
I pressed F5 on Visual Studio 2013, and was notified:
The variable 'partitions_style' is being used without being initialized.
I still have another problem: I use the clean command in DiskPart for My Hard Drive. When I ran the test, I found IOCTL_DISK_GET_DRIVE_LAYOUT_EX did not recognize PartitionStyle RAW correctly, because this time my hard drive was RAW DISK (and certainly not PartitionStyle MBR or PartitionStyle GPT).
Please help me.
Thanks.
#include "windows.h"
#include <stdio.h>
#include <iostream>
using namespace std;
BOOL Get_Partition_Styles(LPWSTR wszPath, PDRIVE_LAYOUT_INFORMATION_EX p_LAYOUT_INFORMATION_EX)
{
DWORD partitionsSize = sizeof(DRIVE_LAYOUT_INFORMATION_EX)+127 * sizeof(PARTITION_INFORMATION_EX);
p_LAYOUT_INFORMATION_EX = (PDRIVE_LAYOUT_INFORMATION_EX)malloc(partitionsSize);
HANDLE hDevice = INVALID_HANDLE_VALUE;
BOOL bResult = FALSE;
DWORD junk = 0;
hDevice = CreateFileW(wszPath,
0,
FILE_SHARE_READ |
FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
return (FALSE);
}
bResult = DeviceIoControl(hDevice,
IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
NULL, 0,
p_LAYOUT_INFORMATION_EX, partitionsSize,
&junk,
(LPOVERLAPPED)NULL);
CloseHandle(hDevice);
return (bResult);
}
void enum_Partitions()
{
for (int i = 0;; i++)
{
WCHAR volume[MAX_PATH];
wsprintf(volume, L"\\\\.\\PhysicalDrive%d", i);
HANDLE h = CreateFile(volume, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
bool success = h != INVALID_HANDLE_VALUE;
if (!success)
break;
wcout << endl << endl << endl << L"Disk #" << i << endl;
PDRIVE_LAYOUT_INFORMATION_EX partitions_style; // disk drive geometry structure
BOOL bResult = FALSE; // generic results flag
bResult = Get_Partition_Styles(volume, partitions_style);
if (!bResult)
{
wcout << L"Partition Style: " << partitions_style->PartitionStyle << endl;
}
else
{
wcout << L"Get_Partition_Styles failed. Error: " << GetLastError() << endl;
}
CloseHandle(h);
}
free(partitions_style);
}
int main(int argc, char* argv[])
{
enum_Partitions();
bool success_nh;
cin >> success_nh;
return 0;
}
You pass a PDRIVE_LAYOUT_INFORMATION_EX to Get_Partition_Styles() but in the function you say p_LAYOUT_INFORMATION_EX = (PDRIVE_LAYOUT_INFORMATION_EX)malloc(partitionsSize); so you have just overridden the value you passed in.
Since you are passing by value, the updated version is not visible in the caller and so the one in the caller is never set to a value. (also the one in the called function is probably a memory leak since there is a malloc but no free).
As a side note: C or C++ ?
If you're in C++ you could pass a reference but then why are you using malloc ?
If your're in C then you could pass a pointer to be populated (the old version of passing a reference :-)

WinApi: Access denied when creating disk

I'm running the following code with administrator privileges:
HANDLE hDevice = INVALID_HANDLE_VALUE; // handle to the drive to be examined
BOOL bResult = FALSE; // results flag
DWORD junk = 0; // discard results
hDevice = CreateFileW(L"\\\\.\\PhysicalDrive0", // drive to open
0, // no access to the drive
FILE_SHARE_READ | // share mode
FILE_SHARE_WRITE,
NULL, // default security attributes
OPEN_EXISTING, // disposition
0, // file attributes
NULL); // do not copy file attributes
if (hDevice == INVALID_HANDLE_VALUE) // cannot open the drive
{
std::cout << "invalid handle" << std::endl;
return -1;
}
std::cout << "handle " << hDevice << std::endl;
DRIVE_LAYOUT_INFORMATION_EX drv_layout_info_ex;
CREATE_DISK disk;
INT n;
ZeroMemory(&disk, sizeof(CREATE_DISK));
disk.PartitionStyle = PARTITION_STYLE_MBR;
disk.Mbr.Signature = 0x7B060725;
bResult = ::DeviceIoControl(hDevice, IOCTL_DISK_CREATE_DISK, &disk,
sizeof(CREATE_DISK), NULL,
0, &junk, NULL);
if (!bResult)
{
std::cout << "IOCTL_DISK_CREATE_DISK failed due to " << GetLastError() << std::endl;
return FALSE;
}
I get the output:
handle 00000048
IOCTL_DISK_CREATE_DISK failed due to 5
Which is access denied. What is the problem?