I'm trying to implement named pipes in C++, but either my reader isn't reading anything, or my writer isn't writing anything (or both). Here's my reader:
int main()
{
HANDLE pipe = CreateFile(GetPipeName(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
char data[1024];
DWORD numRead = 1;
while (numRead >= 0)
{
ReadFile(pipe, data, 1024, &numRead, NULL);
if (numRead > 0)
cout << data;
}
return 0;
}
LPCWSTR GetPipeName()
{
return L"\\\\.\\pipe\\LogPipe";
}
And here's my writer:
int main()
{
HANDLE pipe = CreateFile(GetPipeName(), GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
string message = "Hi";
WriteFile(pipe, message.c_str(), message.length() + 1, NULL, NULL);
return 0;
}
LPCWSTR GetPipeName()
{
return L"\\\\.\\pipe\\LogPipe";
}
Does that look right? numRead in the reader is always 0, for some reason, and it reads nothing but 1024 -54's (some weird I character).
Solution:
Reader (Server):
while (true)
{
HANDLE pipe = CreateNamedPipe(GetPipeName(), PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND , PIPE_WAIT, 1, 1024, 1024, 120 * 1000, NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
cout << "Error: " << GetLastError();
}
char data[1024];
DWORD numRead;
ConnectNamedPipe(pipe, NULL);
ReadFile(pipe, data, 1024, &numRead, NULL);
if (numRead > 0)
cout << data << endl;
CloseHandle(pipe);
}
Writer (client):
HANDLE pipe = CreateFile(GetPipeName(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (pipe == INVALID_HANDLE_VALUE)
{
cout << "Error: " << GetLastError();
}
string message = "Hi";
cout << message.length();
DWORD numWritten;
WriteFile(pipe, message.c_str(), message.length(), &numWritten, NULL);
return 0;
The server blocks until it gets a connected client, reads what the client writes, and then sets itself up for a new connection, ad infinitum. Thanks for the help, all!
You must use CreateNamedPipe() to create the server end of a named pipe. Be sure to specify a non-zero buffer size, zero (documented by MSDN as 'use system default buffer size') doesn't work. MSDN has decent samples for a multi-threaded client&server.
A named pipe client can open the named pipe with CreateFile -- but the named pipe server needs to use CreateNamedPipe to create the named pipe. After it's created the named pipe, the server uses ConnectNamedPipe to wait for a client to connect. Only after the client has connected should the server do a blocking read like your call to ReadFile.
Related
I am opening and reading a port from a USB device (thermal printer):
HANDLE hUsb = CreateFile(symbolicName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
ReadFile(hUsb, buffer, bytes, &read, NULL);
I need to setup timeout to read, but it's an USB port, not a COM port, so I can't use the function SetCommTimeouts.
Is there any function that I can use and has the same effect of SetCommTimeouts?
If there's a simply way, I prefer to not use thread.
I am using Visual Studio 2010 with Windows 10.
Grateful.
first of all any Visual Studio here absolute unrelated.
general solution - use asynchronous io, which never block. and you can yourself cancel io operation by some timeout. good way of course set timer (via CreateTimerQueueTimer) and cancel io in timer callback. or if io will complete before this - cancel timer. but if want simplest implementation, which do synchronous io in place - possible do next:
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
//------------------------------------------------------------------------
HANDLE hFile = CreateFileW(symbolicName, FILE_GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
FILE_FLAG_OVERLAPPED, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
OVERLAPPED ov = {};
if (ov.hEvent = CreateEventW(0, 0, 0, 0))
{
char buf[16];
ULONG NumberOfBytesRead = 0;
ULONG err = BOOL_TO_ERROR(ReadFile(hFile, buf, sizeof(buf), 0, &ov));
switch (err)
{
case ERROR_IO_PENDING:
if (WaitForSingleObject(ov.hEvent, timeout) != WAIT_OBJECT_0)
{
CancelIo(hFile);
}
case NOERROR:
err = BOOL_TO_ERROR(GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE));
break;
}
CloseHandle(ov.hEvent);
}
CloseHandle(hFile);
}
this is my code:
int main(int argc, CHAR* argv[]) {
using namespace std;
PVOID data[1024];
DWORD dwBytesRead = 0;
DWORD dwBytesWrite = 512;
HANDLE hFile = CreateFile(L"\\\\.\\E:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);//open usb
if (hFile == INVALID_HANDLE_VALUE) {
printf("Error %x", GetLastError());
return 1;
}
printf ("created usb hendle\n");
LARGE_INTEGER a = { 50688 };
SetFilePointerEx(hFile, a,NULL,0); //set the pointer to c600
printf("got usb pointer set\n");
PVOID ToBe = ":) hello this is our file -> ";
if (WriteFile(hFile,ToBe,512 ,&dwBytesWrite, NULL) == 0)
{
printf("writeFile error: %x", GetLastError());
CloseHandle(hFile);
return 1;
}
printf("write the first string in isb\n");
HANDLE aFile = CreateFile(L"C:\\Users\\h7080y_dxlq\\Downloads\\Video\\88250.mp4", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); //open the file handle
printf("created mp4 hendle\n");
if (aFile == INVALID_HANDLE_VALUE) {
printf("Error %x", GetLastError());
return 1;
}
if (ReadFile(aFile, &data, 512, &dwBytesRead, NULL) == 0) {
printf("ReadFile error: %x", GetLastError());
return 1;
}
DWORD dwPos;
printf("checked for read errors in mp4 passed o.k.\n");
while (ReadFile(aFile, data,512, &dwBytesRead, NULL) && dwBytesRead > 0) //read file
{
dwPos = SetFilePointerEx(hFile, a, NULL, 0);
LockFile(hFile, dwPos, 0, dwBytesRead, 0);
WriteFile(hFile, data, 512, &dwBytesWrite, NULL); // write 512 bit chunk at the time to usb
UnlockFile(hFile, dwPos, 0, dwBytesRead, 0);
a = { 50688+512 }; // promot
}
printf("write all mp4 to the usb directtly\n");
ToBe = "<- this is the end of file , see you soon :)";
if (WriteFile(hFile, ToBe, 512, &dwBytesWrite, NULL) == 0)
{
printf("writeFile error: %x", GetLastError());
CloseHandle(hFile);
return 1;
}
printf("after end massage \n");
CloseHandle(hFile);
system("pause");
return 0;
}
I try to take a file (mp4 in this case) , and read it chunk by chunk (512 bit at the time) , take the chunk and write it to usb and so on till end of file .
Now, the problem is:
A the loop never ends.
B that it don't write the file to the USB, it looks like its write on the same spot again and again...
How can I fix it?
LARGE_INTEGER a = { 50688 };
while (ReadFile(aFile, data,512, &dwBytesRead, NULL) && dwBytesRead > 0)
{
dwPos = SetFilePointerEx(hFile, a, NULL, 0);
LockFile(hFile, dwPos, 0, dwBytesRead, 0);
WriteFile(hFile, data, 512, &dwBytesWrite, NULL);
UnlockFile(hFile, dwPos, 0, dwBytesRead, 0);
a = { 50688+512 };
}
The first time round the loop you set the file pointer to 50688 and write there. Each subsequent time round the loop you set the file pointer to 50688+512 and write there.
It looks like it writes to the same spot again and again.
Yes indeed. That's exactly what your code specifies. Your should set the file pointer on aFile outside the loop, and let it advance naturally as the file is written. Something like this:
dwPos = 50688;
LARGE_INTEGER a = { dwPos };
if (!SetFilePointerEx(hFile, a, NULL, 0))
{
// handle error
}
while (ReadFile(aFile, data, 512, &dwBytesRead, NULL) && dwBytesRead > 0)
{
LockFile(hFile, dwPos, 0, dwBytesRead, 0);
WriteFile(hFile, data, 512, &dwBytesWrite, NULL);
UnlockFile(hFile, dwPos, 0, dwBytesRead, 0);
dwPos += 512;
}
Note that your calls to LockFile, and the use of a DWORD for dwPos, means that you cannot write a file larger than 4GB.
It is also far from clear to me that the calls to LockFile are needed. Since your original code got the handling of dwPos wrong, it's clear that you weren't locking the parts of the file you intended to. It is my belief that you should simply remove them. In which case the code will become:
LARGE_INTEGER a = { 50688 };
if (!SetFilePointerEx(hFile, a, NULL, 0))
{
// handle error
}
while (ReadFile(aFile, data, 512, &dwBytesRead, NULL) && dwBytesRead > 0)
{
if (!WriteFile(hFile, data, 512, &dwBytesWrite, NULL))
{
// handle error
}
}
You have also omitted large amounts of error checking in this code. I would not be surprised to find that there are a number of other problems with it. I don't particularly want to try to find every single error in your code, and hope that what I have written is enough to help you on your way.
I have the following code as part of another module that sends messages to the client. This was for IPC. Two dll's are loaded by the exe and these two need to communicate
In DLL-1 I have the following line of code as the server named pipe.
pipe = CreateNamedPipe("\\\\.\\pipe\\S2D8",PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED /**1-way, send only with overlapped IO*/,
PIPE_TYPE_MESSAGE,1,0,0, 0, NULL);
if( INVALID_HANDLE_VALUE != pipe )
{
log("Created Named Pipe as Serverl\n");
}
else
{
log("Cannot create Named Pipe as Server\n");
}
And somewhere else in the DLL-1 I have the following for the server
bool result = ConnectNamedPipe(pipe, NULL);
if (!result)
{
CloseHandle(pipe); // close the pipe
}
else
{
DWORD numWritten;
WriteFile(pipe,KeyBoardBuffer,strlen(KeyBoardBuffer) * sizeof(char),&numWritten,0);
log("Bytes writtern to pipe:%d\n",numWritten);
}
When I look at the logs, I can see the that named pipe. Good so far.
While in DLL-2 I have the following as the client part
log("Connecting to named pipe at client\n");
if(pipe2 == NULL || pipe2 == INVALID_HANDLE_VALUE)
{
pipe2 = CreateFile("\\\\.\\pipe\\S2D8", GENERIC_READ ,
FILE_SHARE_READ | FILE_SHARE_WRITE,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
if (pipe2 == INVALID_HANDLE_VALUE)
{
log("Cannot connect to named pipe at client%x\n", GetLastError());
CloseHandle(pipe2);
}
else
{
log("Connected to named pipe at client! Going to read!!!\n");
char buffer[256] = {'\0'};
DWORD numBytesRead = 0;
BOOL result = ReadFile(
pipe2,
buffer, // the data from the pipe will be put here
sizeof(buffer) * sizeof(char), // number of bytes allocated
&numBytesRead, // this will store number of bytes actually read
NULL // not using overlapped IO
);
if (result)
{
kbBuffer[numBytesRead / sizeof(char)] = '\0'; // null terminate the string
log( "Number of bytes read: %d\n",numBytesRead);
log(kbBuffer );
}
else
{
log("Failed to read data from the pipe.\n");
}
}
}
And in my logs, I can see the line "Connecting to named pipe at client" and then "Connected to named pipe at client! Going to read!!!", after that there is nothing in the log, everything seems stuck.
Is the naming convention of pipe correct? Or is there any security settings I have to define?
I am using VS2010, Win7 x64.
Any guidance is much appreciated.
You're calling the wrong method. The pipe is supposed to pre-exist, so you should be calling OpenFile(), not CreateFile().
Ah, I found the answer to the hang, I had to do a PeekNamedPipe(pipe2, NULL, 0, NULL, &bytesAvailable, NULL); and then check for the bytesAvailable to be greater than zero before I did a ReadFile()
I have a problem with using DeviceIOControl to put 128 byte buffer to my driver, i use this code:
int Initialize(unsigned char* public_signature, int size)
{
int ret = DeviceIoControl(
DeviceFileHandle,
2236440,
public_signature,
size,
NULL,
0,
NULL,
NULL);
if(ret != 0)
return 0;
wprintf(L"Format message failed with 0x%x\n", GetLastError()); // always error 0x6!
return 1;
}
I always get 0x6 error, what i'm doing wrong?
upd
My handle creating function:
int CreateFileHandle()
{
DeviceFileHandle = CreateFile( L"\Device\test",
GENERIC_WRITE,
GENERIC_READ | GENERIC_WRITE,
NULL,
OPEN_EXISTING,
0,
0);
if(DeviceFileHandle)
return 0;
return 1;
}
The error is in the 1st parameter of CreateFile. In your example, it would try to open a file, not a device. In addition, you didn't escape backslashes in the string. \t and similar are interpreted as special characters in C++.
The device name should be "\\\\.\\Device\\test".
I'm trying to use MapViewOfFile in a 64 bit process on a file that is already mapped to memory of another 32 bit process. It fails and gives me an "access denied" error. Is this a known Windows limitation or am I doing something wrong? Same code works fine with 2 32bit processes.
The code sort of looks like this:
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szShmName);
if (NULL == hMapFile)
{ /* failed to open - create new (this happens in the 32 bit app) */
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = FALSE;
/* give access to members of administrators group */
BOOL success = ConvertStringSecurityDescriptorToSecurityDescriptor(
"D:(A;OICI;GA;;;BA)",
SDDL_REVISION_1,
&(sa.lpSecurityDescriptor),
NULL);
HANDLE hShmFile = CreateFile(FILE_XXX_SHM,
FILE_ALL_ACCESS, 0,
&sa,
OPEN_ALWAYS, 0, NULL);
hMapFile = CreateFileMapping(hShmFile, &sa, PAGE_READWRITE,
0,
SHM_SIZE,
szShmName);
CloseHandle(hShmFile);
}
// this one fails in 64 bit app
pShm = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, SHM_SIZE);
When you call CreateFile in the 32-bit application, you're passing 0 for the sharing parameter, which means no sharing is allowed. Changing that to FILE_SHARE_READ | FiLE_SHARE_WRITE would probably be a step in the right direction.
Edit: I just whipped together a demo that works (at least for me):
#include <windows.h>
#include <iostream>
static const char map_name[] = "FileMapping1";
static const char event1_name[] = "EventName1";
static const char event2_name[] = "EventName2";
int main() {
HANDLE mapping = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, map_name);
if (NULL == mapping) {
std::cout << "Calling CreateFile\n";
HANDLE file = CreateFile("MappedFile",
FILE_ALL_ACCESS,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
0,
NULL);
std::cout << "Creating File mapping\n";
mapping = CreateFileMapping(file, NULL, PAGE_READWRITE, 0, 65536, map_name);
std::cout << "Closing file handle\n";
CloseHandle(file);
}
std::cout << "Mapping view of file\n";
char *memory = (char *)MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, 65536);
if (memory == NULL) {
std::cerr << "Mapping Failed.\n";
return 1;
}
std::cout << "Mapping succeeded\n";
HANDLE event = CreateEvent(NULL, false, false, event1_name);
if (GetLastError()==ERROR_ALREADY_EXISTS) {
std::cout <<"Waiting to receive string:\n";
WaitForSingleObject(event, INFINITE);
std::cout << "Received: " << memory;
HANDLE event2 = CreateEvent(NULL, false, false, event2_name);
SetEvent(event2);
}
else {
char string[] = "This is the shared string";
std::cout << "Sending string: " << string << "\n";
strncpy(memory, string, sizeof(string));
SetEvent(event);
HANDLE event2 = CreateEvent(NULL, false, false, event2_name);
WaitForSingleObject(event2, INFINITE);
}
return 0;
}
Any combination of 32- or 64-bit executables seems to work fine.
Edit2: Note, however, that this is purely demo-level code. Just for example, the name of each shared object should normally contain a GUID-string to ensure against accidental collision with other programs. I've also skipped quite a bit of error checking, not to mention the minor detail that this code doesn't accomplish anything useful.