// Click Start Client to start the NamedPipe Client void CDlgTestDlg::OnBnClickedOk() { CString szPipeName; szPipeName.Format(_T("%s//pipe//%s"),_T("."),_T("HelloWorld")); HANDLE hPipe; CString szShow; while (true) { // for the Client end, use CreateFile, while the Server end, use CreateNamePipe. hPipe=CreateFile(szPipeName, // Pipe Name GENERIC_READ|GENERIC_WRITE, //Read and Write access 0, //No sharing NULL, // Default security attributes OPEN_EXISTING, // Open existing pipe 0, // Default attributes NULL); // No template file if(hPipe!=INVALID_HANDLE_VALUE) break; // Open the pipe successful if( // Exit if an error other than ERROR_PIPE_BUSY occurs GetLastError()!=ERROR_PIPE_BUSY || !WaitNamedPipe(szPipeName,5000) //All pipes instances are busy, so wait for 5 seconds ) { //Unable to open the named pipe CString szDisplay; szDisplay.Format(_T("Unable to open named pipe %s w/err 0x%08lx/n"),szPipeName,GetLastError()); GetDlgItem(IDC_STATIC)->SetWindowText(szDisplay); return; } } szShow.Format(_T("The named pipe %s is connected. /n"),szPipeName); GetDlgItem(IDC_STATIC)->SetWindowText(szShow); // Set the read mode and the blocking mode of the specified named pipe. // set data to be read from the pipe as a stream of message DWORD dwMode=PIPE_READMODE_MESSAGE; BOOL bResult=SetNamedPipeHandleState(hPipe,&dwMode,NULL,NULL); if(!bResult) { CString szDisplay; szDisplay.Format(_T("SetNamedPipeHandleState failed w/err 0x%08lx/n"),GetLastError()); GetDlgItem(IDC_STATIC)->SetWindowText(szDisplay); return ; } // Send and receive message TCHAR szRequest[BUFFER_SIZE]; TCHAR szReply[BUFFER_SIZE]; DWORD dwBytesWritten,dwRequestBytes; DWORD dwBytesRead,dwReplyBytes; //send message to the pipe StringCchCopy(szRequest,BUFFER_SIZE,_T("Default request from client")); dwRequestBytes=sizeof(TCHAR)*(lstrlen(szRequest)+1); bResult=WriteFile(hPipe,szRequest,dwRequestBytes,&dwBytesWritten,NULL); if(! bResult || dwRequestBytes!=dwBytesWritten) //failed { CString szDisplay; szDisplay.Format(_T("WriteFile failed w/err 0x%08lx/n"), GetLastError()); GetDlgItem(IDC_STATIC)->SetWindowText(szDisplay); return; } CString szTemp; szTemp.Format(_T("/nSends %ld bytes; Message: /"%s/"/n"), dwBytesWritten, szRequest); szShow+=szTemp; GetDlgItem(IDC_STATIC)->SetWindowText(szShow); //Receive respond from server dwReplyBytes=sizeof(TCHAR)*BUFFER_SIZE; do { bResult=ReadFile(hPipe,szReply,dwReplyBytes,&dwBytesRead,NULL); if(!bResult && GetLastError()!=ERROR_MORE_DATA) { CString szDisplay; szDisplay.Format(_T("ReadFile failed w/err 0x%08lx/n"), GetLastError()); GetDlgItem(IDC_STATIC)->SetWindowText(szDisplay); break; } szTemp.Format(_T("Receives %ld bytes; Message: /"%s/"/n"),dwBytesRead,szReply); szShow+=szTemp; GetDlgItem(IDC_STATIC)->SetWindowText(szShow); } while (!bResult); CloseHandle(hPipe); // __super::OnOK(); } // Start the pipe server void CDlgServerDlg::OnBnClickedOk() { // TODO: Add your control notification handler code here //OnOK(); // Prepare the pipe name CString strPipeName; strPipeName.Format(_T("%s//pipe//%s"), _T("."), // Server name _T("HelloWorld") // Pipe name ); // Prepare the security attributes // If lpSecurityAttributes of CreateNamedPipe is NULL, the named pipe // gets a default security descriptor and the handle cannot be inherited. // The ACLs in the default security descriptor for a named pipe grant // full control to the LocalSystem account, administrators, and the // creator owner. They also grant read access to members of the Everyone // group and the anonymous account. In other words, with NULL as the // security attributes, the named pipe cannot be connected with the // WRITE permission across the network, or from a local client running // as a lower integiry level. Here, we fill the security attributes to // grant EVERYONE all access (not just the connect access) to the server // This solves the cross-network and cross-IL issues, but it creates // a security hole right there: the clients have WRITE_OWNER access and // then the server just lose the control of the pipe object. SECURITY_ATTRIBUTES sa; sa.lpSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); InitializeSecurityDescriptor(sa.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); // ACL is set as NULL in order to allow all access to the object. SetSecurityDescriptorDacl(sa.lpSecurityDescriptor, TRUE, NULL, FALSE); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; // Create the named pipe. HANDLE hPipe = CreateNamedPipe( strPipeName, // The unique pipe name. This string must // have the form of //./pipe/pipename PIPE_ACCESS_DUPLEX, // The pipe is bi-directional; both // server and client processes can read // from and write to the pipe PIPE_TYPE_MESSAGE | // Message type pipe PIPE_READMODE_MESSAGE | // Message-read mode PIPE_WAIT, // Blocking mode is enabled PIPE_UNLIMITED_INSTANCES, // Max. instances // These two buffer sizes have nothing to do with the buffers that // are used to read from or write to the messages. The input and // output buffer sizes are advisory. The actual buffer size reserved // for each end of the named pipe is either the system default, the // system minimum or maximum, or the specified size rounded up to the // next allocation boundary. The buffer size specified should be // small enough that your process will not run out of nonpaged pool, // but large enough to accommodate typical requests. BUFFER_SIZE, // Output buffer size in bytes BUFFER_SIZE, // Input buffer size in bytes NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval &sa // Security attributes ); if (hPipe == INVALID_HANDLE_VALUE) { CString szDisplay; szDisplay.Format(_T("Unable to create named pipe %s w/err 0x%08lx/n"), strPipeName, GetLastError()); GetDlgItem(IDC_STATIC)->SetWindowText(szDisplay); return; } CString szShow; szShow.Format(_T("The named pipe %s is created./n"),strPipeName); / // Wait for the client to connect. // szShow+=_T("/nWaiting for the client's connection.../n"); GetDlgItem(IDC_STATIC)->SetWindowText(szShow); //Enables a named pipe server process to wait for a client process to connect to an instance of a named pipe. //A client process connects by calling either the CreateFile or CallNamedPipe function. BOOL bConnected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (!bConnected) { CString szDisplay; szDisplay.Format(_T("Error occurred while connecting to the client: 0x%08lx/n"),GetLastError()); GetDlgItem(IDC_STATIC)->SetWindowText(szDisplay); CloseHandle(hPipe); return ; } / // Read client requests from the pipe and write the response. // // A char buffer of BUFFER_SIZE chars, aka BUFFER_SIZE * sizeof(TCHAR) // bytes. The buffer should be big enough for ONE request from a client. TCHAR szRequest[BUFFER_SIZE]; // Client -> Server DWORD dwBytesRead, dwRequestBytes; TCHAR szReply[BUFFER_SIZE]; // Server -> Client DWORD dwBytesWritten, dwReplyBytes; while (TRUE) { // Receive one message from the pipe. dwRequestBytes = sizeof(TCHAR) * BUFFER_SIZE; bool bResult = ReadFile( // Read from the pipe. hPipe, // Handle of the pipe szRequest, // Buffer to receive data dwRequestBytes, // Size of buffer in bytes &dwBytesRead, // Number of bytes read NULL); // Not overlapped I/O if (!bResult/*Failed*/ || dwBytesRead == 0/*Finished*/) break; CString szTmp; szTmp.Format(_T("/nReceives %ld bytes; Message: /"%s/"/n"),dwBytesRead,szRequest); szShow+=szTmp; GetDlgItem(IDC_STATIC)->SetWindowText(szShow); // Prepare the response. StringCchCopy( szReply, BUFFER_SIZE, _T("Default response from server")); dwReplyBytes = sizeof(TCHAR) * (lstrlen(szReply) + 1); // Write the response to the pipe. bResult = WriteFile( // Write to the pipe. hPipe, // Handle of the pipe szReply, // Buffer to write to dwReplyBytes, // Number of bytes to write &dwBytesWritten, // Number of bytes written NULL); // Not overlapped I/O if (!bResult/*Failed*/ || dwReplyBytes != dwBytesWritten/*Failed*/) { CString szText; szText.Format(_T("WriteFile failed w/err 0x%08lx/n"),GetLastError()); GetDlgItem(IDC_STATIC)->SetWindowText(szText); break; } CString szLast; szLast.Format(_T("/nReplies %ld bytes; Message: /"%s/"/n"),dwBytesWritten,szReply); szShow+=szLast; GetDlgItem(IDC_STATIC)->SetWindowText(szShow); } BOOL bResult; }