CreateFile error trying to open pipe - c++

I am trying to create a demonstration client/server application using named pipes on two Windows 7 machines, but cannot get this to work. The two machines, let's call them server and laptop, are both connected to an ethernet switch which is in turn connected to a cable modem. Both machines can see the internet, and both machines show up in the Windows network map. So I think they are correctly networked.
I am writing in Visual C++ and am basically copying the sample code on MSDN for a named pipe server and client. On my server, I call CreateNamedPipe() using the pipe name:
\\.\pipe\MyServerName
On the client, I call CreateFile with the pipe name of:
\\<machine>\pipe\MyServerName
where "machine" is configurable. If I run the server and client on the same machine, and for machine use either "." or "POWEREDGE" (the name of my server machine according to Windows), the two programs communicate fine.
Now I go to my laptop and run the client software. I use "POWEREDGE" as the machine name. CreateFile fails with GetLastError=1 ("Incorrect Function" apparently).
Any ideas about what could be going wrong here?
In response to requests, here is the actual code:
// CLIENT SIDE
// note: value of gLKServer is "POWEREDGE"
char PipeName[256]="";
wsprintf(PipeName,"\\\\%s\\pipe\\LKServer", gLKServerName);
while (TRUE) {
hPipe = CreateFile(
PipeName, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (hPipe != INVALID_HANDLE_VALUE) {
break;
}
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (err=GetLastError() != ERROR_PIPE_BUSY)
{
printf("CreateFile error %lu\n", err);
}
...
// SERVER SIDE
char PipeName[256]="\\\\.\\pipe\\LKServer";
hPipe = CreateNamedPipe(
PipeName, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0, // client time-out
NULL); // default security attribute

Related

Named pipe: ReadFile after ConnectNamedPipe return ERROR_BROKEN_PIPE

I reactivated code that I am sure used to work some months ago. It drives me crazy but it does not anymore. I could not find an answer in other questions.
On the server side, I create a pipe using
#define MAX_MESSAGE_LENGTH 1024
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE);
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
auto pipe_name = _T("\\\\.\\pipe\\") + _serviceName;
HANDLE pipe = CreateNamedPipe(
pipe_name.c_str(),
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1,
MAX_MESSAGE_LENGTH, MAX_MESSAGE_LENGTH, // buffer lengths (advisory)
0, // default timeout of 50ms when WaitNamedPipe uses NMPWAIT_USE_DEFAULT_WAIT
&sa));
Then a thread waits for incoming clients with ConnectNamedPipe. ConnectNamedPipe blocks until a client connects with
HANDLE pipe = CreateFile(
pipe_name.c_str(), // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
FILE_ATTRIBUTE_NORMAL, // default attributes
NULL); // no template file
ConnectNamedPipe on the server then returns with TRUE and GetLastError == 0. But when it tries to call ReadFile to read incoming data on the pipe, ReadFile immediately returns FALSE and GetLastError==ERROR_BROKEN_PIPE.
On client side, CreateFile has returned GetLastError==231, "All pipe instances are busy". Although it is the only client! A call to WaitNamedPipe(pipe, 2000)returns with error code 121, "The semaphore timeout period has expired".
Increasing the number of allowed clients in CreateNamedPipe does not change anything.
It seems the pipe got completely broken in the moment the client tries to connect. But why? Both client and server run on the same machine with same user and even same session.
Another call to ConnectNamedPipe then failed with GLE=232:"The pipe is being closed".
I also had other SECURITY_ATTRIBUTES for CreateNamedPipe, which shall allow for non-elevated users to connect, but that makes no difference.
Also I tried to use CallNamedPipe on the client with the same result.
PathFileExists is the pipe killer! After hours of trying I finally found what breaks the pipe: a simple call to PathFileExists on the pipe name! This was added recently on the client side to check whether the pipe is already created. I had a look at the code changes but I totally missed that. PathFileExists correctly returns true or false but seems to mess up the pipe (as I told it did not help to allow more than one client to connect). Argh!!!

C++ USB communication

I have a problem regarding communication with a USB device on Windows. I can't use libusb or WinUSB as I have a specific driver for that (Silabs USB to UART, which is a USB-to-serial bridge). This is how I initialize a device file, send&read data and close the handle.
HANDLE hDevFile = CreateFile(L"\\??\\USB#VID_10C4&PID_EA60#0001#{a5dcbf10-6530-11d2-901f-00c04fb951ed}",
GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
PurgeComm(hDevFile, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
DCB dcbInitState;
GetCommState(hDevFile, &dcbInitState);
DCB dcbNewState = dcbInitState;
dcbNewState.BaudRate = 57600;
dcbNewState.Parity = NOPARITY;
dcbNewState.ByteSize = 8;
dcbNewState.StopBits = ONESTOPBIT;
if (SetCommState(hDevFile, &dcbNewState) == 0)
{
printf("Could not set COM state. Error: %i", GetLastError());
return -1;
}
Sleep(60);
BYTE outData[8];
outData[0] = 0x53;
outData[1] = 0x10;
outData[2] = 0x04;
outData[3] = 0x10;
outData[4] = 0x40;
outData[5] = outData[3] ^ outData[4];
outData[6] = 0xAA;
outData[7] = 0x00;
DWORD dwWritten;
if (!WriteData(hDevFile, outData, 8, &dwWritten))
{
printf("Could not write data. Error: %i", GetLastError());
return -1;
}
BYTE inData[8];
DWORD dwRead;
if (!ReadData(hDevFile, inData, 8, &dwRead, 2000))
{
printf("Could not read data. Error: %i", GetLastError());
return -1;
}
SetCommState(hDevFile, &dcbInitState);
Sleep(60);
CloseHandle(hDevFile);
hDevFile = INVALID_HANDLE_VALUE;
(I get the device symbolic name from the registry but I've skipped that part to make my question concise. WriteData() and ReadData() are custom functions that write and read accordingly.)
The problem is that SetCommState() returns a zero-value. GetLastError() returns 122, which is ERROR_INSUFFICIENT_BUFFER.
The problem now is that PurgeComm() generates ERROR_INSUFFICIENT_BUFFER, too. CreateFile() gives ERROR_SUCCESS, so it must be opened properly.
What's wrong? Did I miss something?
Edit: I tried enumerating COM ports and found an interesting thing - there are no COM ports on my computer. Even though the device is connected and enabled, with the driver present and all that stuff. I also tried forcefully putting \\.\COM1, \\.\COM2, and so on as the file name for CreateFile, but with no luck. Everytime got an ERROR_FILE_NOT_FOUND.
Please, help. This is very important to me.
Because this is a CP210x device, it's a virtual COM port, so you should be opening it as such in CreateFile. You had it right when you said that you tried using \.\COMx, you just need to find out which COM port your CP210x device has been assigned and you will not get the ERROR_FILE_NOT_FOUND error. You can find this by looking in device manager:
Take a look a the Serial Communications Guide for the CP210x, this explains how to make these types of calls to your device, there's even a COM port discovery function that will help you find the COMxx name dynamically. It also has accompanying software, AN197SW.zip.
You can use the Win32 Communication Functions just fine with a handle gotten from passing the device interface path to CreateFile. I do this all the time. Ignore the people telling you that you must use COMx.
However, it is important that you use the device interface path corresponding to the (virtual) serial port device (GUID_DEVINTERFACE_COMPORT). Many drivers are implemented as a pair of (USB device, serial port device), where the serial port is a child of the USB device. Opening the USB device (GUID_DEVINTERFACE_USB_DEVICE) will not give you working communication functions, such as PurgeCommState. (And this is exactly what you're trying now, note that the tail end of your device interface path exactly matches the GUID documented on MSDN)
If you don't have anything listed under the Ports section in Device Manager, you either don't have the driver correctly installed, or the device is not connected.
Once you get a port device found, you can use CM_Get_Parent to pair up the GUID_DEVINTERFACE_COMPORT instance with the GUID_DEVINTERFACE_USB_DEVICE, solving your question of "What serial port is attached to USB in this particular way?"

CreateFile: direct write operation to raw disk "Access is denied" - Vista, Win7

The relevant Microsoft doc is:
Blocking Direct Write Operations to Volumes and Disks
CreateFile, remarks on Physical Disks and Volumes
The executable is written in C++ and it calls CreateFile() to open an SD card that has no filesystem. The CreateFile() and consecutive ReadFile() calls are successful for GENERIC_READ without Administrator privileges.
CreateFile fails for GENERIC_WRITE even with Administrator privileges. In the explorer, I set Run as Administrator under Properties > Compatibility > Privilege Level. I also tried to run the executable from an Administrator cmd (started with Ctrl+Shift+Enter, "Administrator:" is in the window title, properly elevated). Still, I get ERROR_ACCESS_DENIED (0x5).
Do I have to pass something else to CreateFile? I have no idea what security attributes are, I just pass NULL, relevant code is here at line 92, and here at line 48.
Or is there anything else that should be set to run the process with Administrator privileges?
A related questions:
Can I get write access to raw disk sectors under Vista and Windows 7 in user mode?
Raw partition access in Windows Vista
How to obtain direct access to raw HD data in C?
Is there a clean way to obtain exclusive access to a physical partition under Windows?
While the answer of #MSalters makes sense, it is not how my code works. In fact it is so counter-intuitive, I spent several days making sure the code does in fact work.
These code snippets are in a proven, mass consumer market software product. When it needs to modify an on-disk structure, it dismounts the win32 volume so it can modify NTFS or FAT filesystem structures. Interestingly, the volume access handle is read-only:
char fn [30];
snprintf (fn, sizeof fn, "\\\\.\\%s:", vol -> GetVolName ());
vol_handle = CreateFile (fn, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING | FILE_FLAG_RANDOM_ACCESS,
NULL);
if (vol_handle == INVALID_HANDLE_VALUE)
{
// show error message and exit
}
If unable to get write access to a volume or partition, this code forces a dismount if the user authorizes such after a stern warning:
if (!DeviceIoControl (vol_handle, FSCTL_DISMOUNT_VOLUME,
NULL, 0, NULL, 0, &status, NULL))
{
DWORD err = GetLastError ();
errormsg ("Error %d attempting to dismount volume: %s",
err, w32errtxt (err));
}
// lock volume
if (!DeviceIoControl (vol_handle, FSCTL_LOCK_VOLUME,
NULL, 0, NULL, 0, &status, NULL))
{
// error handling; not sure if retrying is useful
}
Writing is then fairly straightforward, except for positioning the file pointer by 512-byte sector:
long hipart = sect >> (32-9);
long lopart = sect << 9;
long err;
SetLastError (0); // needed before SetFilePointer post err detection
lopart = SetFilePointer (vol_handle, lopart, &hipart, FILE_BEGIN);
if (lopart == -1 && NO_ERROR != (err = GetLastError ()))
{
errormsg ("HWWrite: error %d seeking drive %x sector %ld: %s",
err, drive, sect, w32errtxt (err));
return false;
}
DWORD n;
if (!WriteFile (vol_handle, buf, num_sects*512, &n, NULL))
{
err = GetLastError ();
errormsg ("WriteFile: error %d writing drive %x sectors %lu..%lu: %s",
err, drv, sect, sect + num_sects - 1,
w32errtxt (err));
return false;
}
It's quite rare to want only GENERIC_WRITE. You most likely want GENERIC_READ|GENERIC_WRITE.
There is note in MSDN in documentation of CreateFile:
Direct access to the disk or to a volume is restricted. For more information, see "Changes to the file system and to the storage stack to restrict direct disk access and direct volume access in Windows Vista and in Windows Server 2008" in the Help and Support Knowledge Base at http://support.microsoft.com/kb/942448.
It refers to Vista/2008, but maybe apply to Win7 also.
I had a similar issue when porting from x86 to x64 code. You mention that you are passing null for your SECURITY_ATTRIBUTES parameter; I was getting access-denied errors myself using this approach until I actually began creating/passing this parameter.

About pipe behavior in windows

hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
0,
I have two questions about this:
what if the above code is run twice,how many pipes will get created,1 or 2?
if 2,suppose one of the pipe get connected by A,then B tries to connect lpszPipename, is it guaranteed that B will connect to the one that no one has connected?
The second call to CreateNamedPipe with the same name fails, if FILE_FLAG_FIRST_PIPE_INSTANCE flag is used, or connects to the same pipe, if this flag is not used. In the case the second CreateNamedPipe call succeeds, it returns another handle to the same kernel object.
In the fourth parameter of CreateNamedPipe function you can limit how many named pipe instances can be created. If you set it to PIPE_UNLIMITED_INSTANCE as in your example and call the CreateNamedPipe function twice with the same parameters, two instances will be created (they'll share the same pipe name) and two clients will be able to connect to your named pipe server (each of them to one named pipe instance).
For more information look at http://msdn.microsoft.com/en-us/library/aa365594%28v=VS.85%29.aspx

Open a socket using CreateFile

We've got some old serial code which checks whether a serial port is available simply by opening it and then closing it. Now we are adding network support to the app I want to reuse the function by supplying the ip address as a string.
/**
* So far I have tried:
* A passed in portPath normally looks like:
\\?\acpi#pnp0501#1#1#{GUID}
10.2.0.155:2001
//10.2.0.155:2001/
\\.\10.2.0.155:2001\
\\?\10.2.0.155:2001\
* all without success.
*/
bool PortIsAvailable( const CString& portPath )
{
HANDLE hCom = ::CreateFile( portPath,
GENERIC_READ | GENERIC_WRITE,
0, // comm devices must be opened with exclusive-access
NULL, // no security attributes
OPEN_EXISTING, // comm devices must use OPEN_EXISTING
FILE_FLAG_OVERLAPPED, // not overlapped I/O
NULL ); // hTemplate must be NULL for comm devices
if (INVALID_HANDLE_VALUE != hCom )
{
::CloseHandle( hCom );
return true;
}
return false;
}
I know I could use connect followed by shutdown but I want to reuse the function with minimal changes. If I can reuse the function so much the better. If not then I will have to write code that determines whether it is a socket or not.
I was wondering what the correct way of opening a socket via CreateFile is?
You can not create a socket via CreateFile. You should use the windows socket API for this purpose. For creating the SOCKET handle, you use WSASocket. Note that the SOCKET returned by this function can be used as a Windows Handle with some Windows functions, such as ReadFile and WriteFile.
I don't believe you can manipulate sockets with CreateFile(). Sockets are an abstraction imported from BSD (iirc) and implemented in a name-compatible way (originally via winsock.h, and currently winsock2.h). I don't think MS ever added support for sockets to CreateFile().
More rationale: Most (everything?) CreateFile() manipulates returns a native Windows handle. Because sockets are a non-native abstraction, they don't have a native handle in the OS, so it wouldn't make sense for CreateFile() to handle them.