I am trying to make a handler class for dealing with a pipe in c++. I may start by saying I'm used to c#, and quite new to c++ and the concept of pointers.
The only field in the class is a variable, of type HANDLE (void *), pipeHandle
, which stores the value returned by CreateFile()
.
I have a method, ConnectPipe()
, which uses CreateFile()
to get the handle of the pipe, as well as some error checking. It stores the handle in pipeHandle
and then finishes execution. This appears to be problematic, as after research and debugging I have found that the value of pipeHandle
changes after ConnectPipe()
finishes executing. I think this is due to the way that the pointer references something instantiated in ConnectPipe()
which then gets deleted after ConnectPipe()
finishes.
Code:
PipeManager.h:
#ifndef PIPE_MANAGER_H
#define PIPE_MANAGER_H
#include <Windows.h>
#include <string>
class PipeManager
{
private:
HANDLE pipeHandle;
void PipeConnect(LPCWSTR pipeFullName);
void PipeReceive(BYTE* outBuffer);
public:
PipeManager(std::string pipeName);
void Testing();
};
#endif
PipeManager.cpp:
#include "PipeManager.h"
#include <iostream>
void PipeManager::PipeConnect(LPCWSTR pipeFullName)
{
const int ATTEMPT_LIMIT = 10;
int attempts = 0;
do {
if (attempts > ATTEMPT_LIMIT) {
break;
}
pipeHandle = CreateFile(pipeFullName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (pipeHandle == INVALID_HANDLE_VALUE) {
std::cerr << "Failed to connect to the named pipe, error code " << GetLastError() << ". Trying again." << std::endl;
attempts++;
}
} while (pipeHandle == INVALID_HANDLE_VALUE);
}
void PipeManager::PipeReceive(BYTE* outBuffer)
{
DWORD read = 0; // Number of bytes read in each ReadFile() call
int index = 0;
do {
if (!ReadFile(pipeHandle, outBuffer + index, 1, &read, NULL)) {
std::cerr << "Failed to read from the named pipe, error code " << GetLastError() << std::endl;
break;
}
} while (outBuffer[index - 1] != 0); // Stop if the most recent byte was null-termination.
}
// Constructor for a named pipe, yet to be connected to
PipeManager::PipeManager(std::string pipeName) {
std::string fullName = "\\\\.\\pipe\\" + pipeName;
PipeConnect(std::wstring(fullName.begin(), fullName.end()).c_str());
}
void PipeManager::Testing()
{
BYTE buffer[1024];
PipeReceive(buffer);
}
CPPClient.cpp (application entry point):
int main()
{
//return HandlePipe("TestingPipe", false);
PipeManager pipeManager = new PipeManager(std::string("TestingPipe"));
pipeManager.Testing();
}
I have a pipe server running (written in c#) that creates "TestingPipe", that I know works and have tested. I have also managed to get a pipe client (written in c++) working but not inside a class - just a load of function calls and things in the main()
method.
When I run the above program, the c# server initially accepts the connection but then fails when the client tries to read saying "pipe is broken", and the c++ client fails with code 6 invalid handle when it tries to read from the pipe.
How can I keep pipeHandle
constant throughout the lifetime of the object, or at least stop it changing after ConnectPipe
finishes initialising?
Unless this isn't possible, in which case I'll have to reconnect to the pipe every time I want to read or write to it.
Edit: Removing code that wasn't relevant
Many thanks to Igor Tandetnik - in my main()
function I had used the new
keyword, which creates an object and copies it into a new object. It was this that caused the pipeHandle
to change, not a referencing issue as I first thought.