I am implementing a named pipe IPC scheme in C running on windows, which is mostly working.
On the client side I create the pipe like this
void CreatePipex(const LPCWSTR pipename, InteruptHandler interruptHandler, unsigned char *USARTData)
{
while (1)
{
pipes [_pipeIndex].handle = CreateFile(
pipename,
GENERIC_READ |
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
// break if pipe was created
if (pipes[_pipeIndex].handle != INVALID_HANDLE_VALUE)
{
wprintf(L"created pipe %s\n", pipename);
break;
}
if (GetLastError() == ERROR_FILE_NOT_FOUND)
{
}
// exit if pipe not created and not busy
if (GetLastError() != ERROR_PIPE_BUSY)
{
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
wprintf(L"Could not create %s : %s %d\n",pipename, buf,GetLastError());
//printf("could not create pipe %d\n", lastError);
exit(-1);
}
if (!WaitNamedPipe(pipename, 20000))
{
wprintf(L"Could not open %s: 20 second wait timed out.\n",pipename);
exit(-1);
}
}
DWORD mode = PIPE_NOWAIT;
if (!SetNamedPipeHandleState(pipes[_pipeIndex].handle, &mode, 0, 0))
{
wchar_t buf[256];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
wprintf(L"Could not set mode for %s : %s\n", pipename, buf);
exit(-1);
}
But if I run the client without the server the client pipe cannot be created
Could not create \\.\pipe\F0 : The system cannot find the file specified.
Is there a way of getting my client to wait for the server?
You could loop (and sleep) until CreateFile returns something different from ERROR_FILE_NOT_FOUND.
Related
Just when I thought I finally understood threads, I got a problem.
In the main thread, I create a mutex using this:
Mutex = CreateMutex(NULL, FALSE, Mutex_Name);
Then, in one of the worker threads (the first one to reach), I have a function that returns a handle to a file by creating it like this:
file_h = CreateFile("The_File.txt",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
The other threads have functions that return a handle to the file by this:
file_h = CreateFile("The_File.txt",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
At the last part, both threads try to write to the file using this function:
int W_to_f(char* str_to_w, HANDLE file)
{
HANDLE mutex = NULL;
DWORD waitcode1;
DWORD dwBytesWrite;
char line[Line_Len];
mutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, LOCK);
if (mutex == NULL)
{
printf("Failed at opening LOCK in write file\n");
return -1;
}
waitcode1 = WaitForSingleObject(mutex, 15000);
if (WAIT_OBJECT_0 != waitcode1)
{
printf("Error when waiting for LOCK in file\n");
return -1;
}
strcpy(line, str_to_w);
while ((Line_Len - (strlen(line) + 1)) > 0)
{
strcat(line, "#");
}
SetFilePointer(file, 0, NULL, FILE_END); //problem?
WriteFile(file, line, strlen(line), &dwBytesWrite, NULL);
WriteFile(file, "\n", 2, &dwBytesWrite, NULL);
if(!ReleaseMutex(mutex))
{
printf("failed release mutex in write_file fun\n");
return -1;
}
return 0;
}
All I want them to do is to write to the file like this:
firststring############
secondstring###########
But, after checking with breakpoints, what I get is that the first one manages to write to file:
firststring###########
But then after the second one writes to the file, it becomes:
癡慩㩤㈱㐳䁀䁀䁀䁀䁀䁀䁀䁀䁀幀搀湩楤㩮㘵㠷䁀䁀䁀䁀䁀䁀䁀䁀䁀
Just one line, it doesn't even write the Chinese after the firststring####.
Should I somehow use SetFilePointer?
Should I CreateFile() in the function using OPEN_EXISTING for each thread?
So I have a service which starts at boot time, and I have an application which I have placed in the startup folder.
So the client sometimes connects very late to the server of the named pipe.
Here is my code in my service.
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\popupPipe"),
PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_WAIT,
1, 1024 * 16, 1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
HRESULT
SendMessage(){
if (ConnectNamedPipe(hPipe, NULL) != FALSE) { // wait for someone to connect to the pipe
WriteFile(hPipe, (char *)message->buffer, sizeof(message->buffer), &dwWritten, NULL);
return S_OK;
}
return E_FAIL;
}
and here is the application
hPipe = CreateFile(TEXT("\\\\.\\pipe\\popupPipe"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPipe == INVALID_HANDLE_VALUE)
return -1;
while (hPipe != INVALID_HANDLE_VALUE)
{
DWORD dwRead;
char buffer[100] = { 0 };
while (ReadFile(hPipe, buffer, sizeof(buffer), &dwRead, NULL) != FALSE);
if (dwRead == sizeof(buffer)) {
dwRead = 0;
buffer[100] = '\0';
temp = &buffer[1];
DisplayPopup(hInstance, cmdShow);
}
}
return 0;
but at the clients end the application always returns INVALID_HANDLE_VALUE
In the service SendMessage is called multiple times so even if it fails the first times it should succeed when the client connects shouldn't it.
You don't check if the creation of the pipe suceeds. Looking at the Microsoft documentation, it probably does not succeed because you mix parameters:
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\popupPipe"),
PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_WAIT,
1, 1024 * 16, 1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
should be:
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\popupPipe"),
PIPE_ACCESS_DUPLEX, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
1, 1024 * 16, 1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
I'm using overlapped IO to read and write a single Windows pipe in C code simultantiously. I want to write a synchronous function to read and write data from seperate threads. If you are using synchronous IO you cannot read and write the pipe simultaniously. My client and my server are using the same write/read functions. Time by time my client sends data that is never received by the server. Does anyone have an idea how this could happen? If I use synchronous IO in the client everything works as expected.
The server pipe is opened by the following cmd:
CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
instances, PIPE_BUF_SIZE, PIPE_BUF_SIZE, 0, NULL);
The client pipe is opend this way:
CreateFile(pipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
I'm using these read function:
int readBytesPipeCommChannel(PipeCommChannelData* comm, uint32_t* amount)
OVERLAPPED osRead;
memset(&osRead, 0, sizeof(osRead));
osRead.hEvent = comm->readAsyncIOEvent;
int err = 0;
if(!ReadFile(comm->pipeH, comm->receiveBuffer, sizeof(comm->receiveBuffer), amount, &osRead))
{
err = GetLastError();
if (err == ERROR_IO_PENDING)
{
if(WaitForSingleObject(osRead.hEvent, INFINITE))
{
GetOverlappedResult(comm->pipeH, &osRead, amount, TRUE);
}
else
{
CancelIo(comm->pipeH);
return PIPE_EVENT_ERROR;
}
}
else if(err != ERROR_BROKEN_PIPE)
{
return PIPE_READ_ERROR;
}
}
if(err == ERROR_BROKEN_PIPE)
return PIPE_BROKEN_ERR;
return PIPE_OK;
}
And last but not least the write function:
int sendBytesPipeCommChannel(PipeCommChannelData* comm, const uint8_t* bytes, uint32_t amount)
{
OVERLAPPED osWrite;
memset(&osWrite, 0, sizeof(osWrite));
osWrite.hEvent = comm->writeAsyncIOEvent;
uint32_t bytesWritten = 0;
for(uint32_t curPos = 0; curPos < amount; curPos += bytesWritten)
{
if(!WriteFile(comm->pipeH, &bytes[curPos], (amount - curPos), &bytesWritten, &osWrite))
{
if (GetLastError() != ERROR_IO_PENDING)
return PIPE_WRITE_ERR;
if(!WaitForSingleObject(osWrite.hEvent, INFINITE))
{
CancelIo(comm->pipeH);
return PIPE_EVENT_ERROR;
}
}
}
return PIPE_OK;
}
The documentation for ReadFile says:
If hFile was opened with FILE_FLAG_OVERLAPPED, the following conditions are in effect:
The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to get the actual number of bytes read.
This applies even if the operation completes synchronously.
I want to send message to server and read it using named pipes. When I use WriteFile function, the message gets to the server, but TransactNamedPipe fails with error 230 (ERROR_BAD_PIPE) and CallNamedPipe fails with error 87 (INVALID_PARAMETER) or 231 (PIPE_BUSY). I've tried MSDN examples, a lot of other stuff, but still no results. Please help.
Client:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <tchar.h>
#include <string>
#define BUFSIZE 512
int _tmain(int argc, TCHAR *argv[])
{
OVERLAPPED ov;
ZeroMemory(&ov, sizeof(OVERLAPPED));
HANDLE hPipe;
// Try to open a named pipe; wait for it, if necessary.
while (1)
{
hPipe = CreateFile(
L"\\\\.\\pipe\\PipeTest", // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
FILE_FLAG_OVERLAPPED,
NULL); // no template file
// Break if the pipe handle is valid.
if (hPipe != INVALID_HANDLE_VALUE)
break;
DWORD lastErr = GetLastError();
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (GetLastError() != ERROR_PIPE_BUSY)
{
printf("Could not open pipe\n");
return 0;
}
// All pipe instances are busy, so wait for 2 seconds.
if (!WaitNamedPipe(L"\\\\.\\pipe\\PipeTest", 2000))
{
printf("Could not open pipe\n");
return 0;
}
}
std::wstring s;
s.resize(1024);
DWORD cbRead;
BOOL fSuccess = TransactNamedPipe(
hPipe, // pipe handle
L"Hello", // message to server
sizeof(wchar_t) * 5, // message length
&s[0],
s.size() * sizeof(wchar_t),
&cbRead, // bytes read
&ov); // not overlapped
DWORD lastErr = GetLastError();
GetOverlappedResult(hPipe, &ov, &cbRead, TRUE);
DWORD lastErr2 = GetLastError();
CloseHandle(hPipe);
return 0;
}
Server:
#include <iostream>
#include <string>
#include <Windows.h>
const std::wstring pipeName = L"\\\\.\\pipe\\PipeTest";
int main(void)
{
HANDLE hPipe;
wchar_t buffer[256];
DWORD dwRead;
OVERLAPPED ov;
ZeroMemory(&ov, sizeof(OVERLAPPED));
hPipe = CreateNamedPipe(pipeName.c_str(),
PIPE_ACCESS_DUPLEX | PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
PIPE_WAIT,
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, &ov) != FALSE) // wait for someone to connect to the pipe
{
while (ReadFile(hPipe, buffer, 255, &dwRead, &ov) != FALSE)
{
WriteFile(hPipe, L"lalala", 6 * sizeof(wchar_t), &dwRead, &ov);
DWORD lastErr1 = GetLastError();
GetOverlappedResult(hPipe, &ov, &dwRead, TRUE);
DWORD lastrr2 = GetLastError();
printf("%s", buffer);
}
}
DisconnectNamedPipe(hPipe);
}
return 0;
}
if you read about TransactNamedPipe
TransactNamedPipe fails if the server did not create the pipe as a
message-type pipe or if the pipe handle is not in message-read mode.
and CallNamedPipe
Calling CallNamedPipe is equivalent to calling the CreateFile (or
WaitNamedPipe, if CreateFile cannot open the pipe immediately),
TransactNamedPipe, and CloseHandle functions
so this functions work only message-type pipe
but when you create server pipe you use PIPE_TYPE_BYTE | PIPE_READMODE_BYTE
so CallNamedPipe and/or TransactNamedPipe and must fail.
you need use ReadFile/WriteFile instead. or create server with flags PIPE_TYPE_MESSAGE|PIPE_READMODE_MESSAGE and call SetNamedPipeHandleState for client handle for set it message-read mode (use PIPE_READMODE_MESSAGE)
I am fairly new to C, and I am trying to write a small application that will read the entire raw contents of a drive.
Here is my code;
int main(int argc, char *argv[]) {
HANDLE hFile;
DWORD dwBytesRead;
char buff[512];
hFile = CreateFile("\\\\.\\PhysicalDrive2", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
if(hFile == INVALID_HANDLE_VALUE){
printf("%d",GetLastError());
return;
}
SetFilePointer(hFile, 512*0, NULL, FILE_BEGIN);
ReadFile(hFile, buff, 512, &dwBytesRead, NULL);
CloseHandle(hFile);
return 0;
}
How do I put the ReadFile into a loop to read all the data on the drive? I eventually need to save the contents of the buffer to the disk.
Thanks
The loop might look like this:
hFile = CreateFile(...);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
while (true)
{
unsigned char buff[32768]; // needs to be a multiple of sector size
DWORD dwBytesRead;
if (!ReadFile(hFile, buff, sizeof buff, &dwBytesRead, NULL))
{
// handle error
}
if (dwBytesRead == 0)
{
break; // we reached the end
}
// do something with the dwBytesRead that were read
}
CloseHandle(hFile);