技術:IPC,RPC,Windows General
主題:Named Pipe,Inter-process Communication
概要:
命名管道是一種進程間單工或雙工的通信機制。它可以在管道服務器和一個或多個管道客戶端間進行。客戶端可以位於本機或互聯網上的遠程計算機。
PIPE_ACCESS_INBOUND(呼入):
Client (GENERIC_WRITE) ---> Server (GENERIC_READ)
PIPE_ACCESS_OUTBOUND(外傳):
Client (GENERIC_READ) <--- Server (GENERIC_WRITE)
PIPE_ACCESS_DUPLEX(雙工):
Client (GENERIC_READ or GENERIC_WRITE, or both) <-->
Server (GENERIC_READ and GENERIC_WRITE)
GENERIC_READ(普通讀)
GENERIC_WRITE(普通寫)
下面的代碼示例演示了如何調用CreateNamedPipe來創建一個名稱為"\\.\pipe\SamplePipe", 的管道。支持全雙工連接。這樣客戶端和服務端都可以從管道中讀寫數據。自定義安全選項使得認證的用戶才具有對管道的讀寫權限。當有客戶端連接管道時,服務端嘗試調用ReadFile從管道中讀出客戶端的消息,並通過調用WriteFile寫入響應消息。
如何演示:
1.在VS2008中編譯CppNamedPipeClient 和CppNamedPipeServer 兩個工程,如果成功你會獲得兩個可執行文件CppNamedPipeClient.exe 和 CppNamedPipeServer.exe.
2.運行CppNamedPipeServer.exe。如果管道創建成功,程序會以命令行形式輸出以下信息:
Server:
The named pipe (\\.\pipe\SamplePipe) is created.
Waiting for the client's connection...
3.運行CppNamedPipeClient.exe。如果客戶端成功連接到命名管道會輸出下列信息:
Client:
The named pipe (\\.\pipe\SamplePipe) is connected.
同時服務器端會輸出下面的消息來指示有一個客戶端連接到管道
Server:
Client is connected.
4.接下來客戶端會嘗試寫入消息到命名管道,程序輸出:
Client:
Send 56 bytes to server: "Default request from client"
當服務端從客戶端讀取消息後打印出:
Server:
Receive 56 bytes from client: "Default request from client"
接下來,服務端寫入一個回應消息到管道。
Server:
Send 58 bytes to client: "Default response from server"
然後客戶端收到回應消息輸出:
Client:
Receive 58 bytes from server: "Default response from server"
最後斷開連接,關閉管道。
主要代碼邏輯:
1.調用CreateNamedPipe創建一個命名管道,指明管道的名稱,方向,傳輸模式,安全屬性等
[cpp] // Create the named pipe.
hNamedPipe = CreateNamedPipe(
FULL_PIPE_NAME, // Pipe name.
PIPE_ACCESS_DUPLEX, // The pipe is duplex; 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
BUFFER_SIZE, // Output buffer size in bytes
BUFFER_SIZE, // Input buffer size in bytes
NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval
pSa // Security attributes
);
// Create the named pipe.
hNamedPipe = CreateNamedPipe(
FULL_PIPE_NAME, // Pipe name.
PIPE_ACCESS_DUPLEX, // The pipe is duplex; 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
BUFFER_SIZE, // Output buffer size in bytes
BUFFER_SIZE, // Input buffer size in bytes
NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval
pSa // Security attributes
);
在這個事例中管道支持全雙工通信。安全屬性允許認證用戶具有讀寫管道權限,所有管理員組成員具有對管道的全部權限
[cpp] /
// FUNCTION: CreatePipeSecurity(PSECURITY_ATTRIBUTES *)
//
// PURPOSE: The CreatePipeSecurity function creates and initializes a new
// SECURITY_ATTRIBUTES structure to allow Authenticated Users read and
// write access to a pipe, and to allow the Administrators group full
// access to the pipe.
//
// PARAMETERS:
// * ppSa - output a pointer to a SECURITY_ATTRIBUTES structure that allows
// Authenticated Users read and write access to a pipe, and allows the
// Administrators group full access to the pipe. The structure must be
// freed by calling FreePipeSecurity.
//
// RETURN VALUE: Returns TRUE if the function succeeds..
//
// EXAMPLE CALL:
//
// PSECURITY_ATTRIBUTES pSa = NULL;
// if (CreatePipeSecurity(&pSa))
// {
// // Use the security attributes
// // ...
//
// FreePipeSecurity(pSa);
// }
//
BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *ppSa)
//
// FUNCTION: CreatePipeSecurity(PSECURITY_ATTRIBUTES *)
//
// PURPOSE: The CreatePipeSecurity function creates and initializes a new
// SECURITY_ATTRIBUTES structure to allow Authenticated Users read and
// write access to a pipe, and to allow the Administrators group full
// access to the pipe.
//
// PARAMETERS:
// * ppSa - output a pointer to a SECURITY_ATTRIBUTES structure that allows
// Authenticated Users read and write access to a pipe, and allows the
// Administrators group full access to the pipe. The structure must be
// freed by calling FreePipeSecurity.
//
// RETURN VALUE: Returns TRUE if the function succeeds..
//
// EXAMPLE CALL:
//
// PSECURITY_ATTRIBUTES pSa = NULL;
// if (CreatePipeSecurity(&pSa))
// {
// // Use the security attributes
// // ...
//
// FreePipeSecurity(pSa);
// }
//
BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *ppSa) 2.調用ConnectNamedPipe來等待客戶端連接
[cpp] if (!ConnectNamedPipe(hNamedPipe, NULL))
{
if (ERROR_PIPE_CONNECTED != GetLastError())
{
dwError = GetLastError();
wprintf(L"ConnectNamedPipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
}
if (!ConnectNamedPipe(hNamedPipe, NULL))
{
if (ERROR_PIPE_CONNECTED != GetLastError())
{
dwError = GetLastError();
wprintf(L"ConnectNamedPipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
}
3.通過調用ReadFile和WriteFile從管道中讀出客戶端請求並寫入響應數據[cpp] view plaincopyprint?//
// Receive a request from client.
//
BOOL fFinishRead = FALSE;
do
{
wchar_t chRequest[BUFFER_SIZE];
DWORD cbRequest, cbRead;
cbRequest = sizeof(chRequest);
fFinishRead = ReadFile(
hNamedPipe, // Handle of the pipe
chRequest, // Buffer to receive data
cbRequest, // Size of buffer in bytes
&cbRead, // Number of bytes read
NULL // Not overlapped I/O
);
if (!fFinishRead && ERROR_MORE_DATA != GetLastError())
{
dwError = GetLastError();
wprintf(L"ReadFile from pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Receive %ld bytes from client: \"%s\"\n", cbRead, chRequest);
} while (!fFinishRead); // Repeat loop if ERROR_MORE_DATA
//
// Send a response from server to client.
//
wchar_t chResponse[] = RESPONSE_MESSAGE;
DWORD cbResponse, cbWritten;
cbResponse = sizeof(chResponse);
if (!WriteFile(
hNamedPipe, // Handle of the pipe
chResponse, // Buffer to write
cbResponse, // Number of bytes to write
&cbWritten, // Number of bytes written
NULL // Not overlapped I/O
))
{
dwError = GetLastError();
wprintf(L"WriteFile to pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Send %ld bytes to client: \"%s\"\n", cbWritten, chResponse);
//
// Receive a request from client.
//
BOOL fFinishRead = FALSE;
do
{
wchar_t chRequest[BUFFER_SIZE];
DWORD cbRequest, cbRead;
cbRequest = sizeof(chRequest);
fFinishRead = ReadFile(
hNamedPipe, // Handle of the pipe
chRequest, // Buffer to receive data
cbRequest, // Size of buffer in bytes
&cbRead, // Number of bytes read
NULL // Not overlapped I/O
);
if (!fFinishRead && ERROR_MORE_DATA != GetLastError())
{
dwError = GetLastError();
wprintf(L"ReadFile from pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Receive %ld bytes from client: \"%s\"\n", cbRead, chRequest);
} while (!fFinishRead); // Repeat loop if ERROR_MORE_DATA
//
// Send a response from server to client.
//
wchar_t chResponse[] = RESPONSE_MESSAGE;
DWORD cbResponse, cbWritten;
cbResponse = sizeof(chResponse);
if (!WriteFile(
hNamedPipe, // Handle of the pipe
chResponse, // Buffer to write
cbResponse, // Number of bytes to write
&cbWritten, // Number of bytes written
NULL // Not overlapped I/O
))
{
dwError = GetLastError();
wprintf(L"WriteFile to pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Send %ld bytes to client: \"%s\"\n", cbWritten, chResponse);
4.調用FlushFileBuffers在斷開連接之前允許客戶端讀取管道內容。然後斷開客戶端連接
[cpp] FlushFileBuffers(hNamedPipe);
DisconnectNamedPipe(hNamedPipe);
FlushFileBuffers(hNamedPipe);
DisconnectNamedPipe(hNamedPipe);
5.關閉管道
[cpp] CloseHandle(hNamedPipe);
CloseHandle(hNamedPipe);
完整代碼:
CppNamedPipeServer.cpp
[cpp] #pragma region Includes
#include <stdio.h>
#include <windows.h>
#include <sddl.h>
#pragma endregion
// The full name of the pipe in the format of \\servername\pipe\pipename.
#define SERVER_NAME L"."
#define PIPE_NAME L"SamplePipe"
#define FULL_PIPE_NAME L"\\\\" SERVER_NAME L"\\pipe\\" PIPE_NAME
#define BUFFER_SIZE 1024
// Response message from client to server. '\0' is appended in the end
// because the client may be a native C++ application that expects NULL
// termiated string.
#define RESPONSE_MESSAGE L"Default response from server"
BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *);
void FreePipeSecurity(PSECURITY_ATTRIBUTES);
int wmain(int argc, wchar_t* argv[])
{
DWORD dwError = ERROR_SUCCESS;
PSECURITY_ATTRIBUTES pSa = NULL;
HANDLE hNamedPipe = INVALID_HANDLE_VALUE;
// Prepare the security attributes (the lpSecurityAttributes parameter in
// CreateNamedPipe) for the pipe. This is optional. If the
// lpSecurityAttributes parameter 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 of a pipe grant
// full control to the LocalSystem account, (elevated) administrators,
// and the creator owner. They also give only read access to members of
// the Everyone group and the anonymous account. However, if you want to
// customize the security permission of the pipe, (e.g. to allow
// Authenticated Users to read from and write to the pipe), you need to
// create a SECURITY_ATTRIBUTES structure.
if (!CreatePipeSecurity(&pSa))
{
dwError = GetLastError();
wprintf(L"CreatePipeSecurity failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
// Create the named pipe.
hNamedPipe = CreateNamedPipe(
FULL_PIPE_NAME, // Pipe name.
PIPE_ACCESS_DUPLEX, // The pipe is duplex; 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
BUFFER_SIZE, // Output buffer size in bytes
BUFFER_SIZE, // Input buffer size in bytes
NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval
pSa // Security attributes
);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
dwError = GetLastError();
wprintf(L"Unable to create named pipe w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"The named pipe (%s) is created.\n", FULL_PIPE_NAME);
// Wait for the client to connect.
wprintf(L"Waiting for the client's connection...\n");
if (!ConnectNamedPipe(hNamedPipe, NULL))
{
if (ERROR_PIPE_CONNECTED != GetLastError())
{
dwError = GetLastError();
wprintf(L"ConnectNamedPipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
}
wprintf(L"Client is connected.\n");
//
// Receive a request from client.
//
BOOL fFinishRead = FALSE;
do
{
wchar_t chRequest[BUFFER_SIZE];
DWORD cbRequest, cbRead;
cbRequest = sizeof(chRequest);
fFinishRead = ReadFile(
hNamedPipe, // Handle of the pipe
chRequest, // Buffer to receive data
cbRequest, // Size of buffer in bytes
&cbRead, // Number of bytes read
NULL // Not overlapped I/O
);
if (!fFinishRead && ERROR_MORE_DATA != GetLastError())
{
dwError = GetLastError();
wprintf(L"ReadFile from pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Receive %ld bytes from client: \"%s\"\n", cbRead, chRequest);
} while (!fFinishRead); // Repeat loop if ERROR_MORE_DATA
//
// Send a response from server to client.
//
wchar_t chResponse[] = RESPONSE_MESSAGE;
DWORD cbResponse, cbWritten;
cbResponse = sizeof(chResponse);
if (!WriteFile(
hNamedPipe, // Handle of the pipe
chResponse, // Buffer to write
cbResponse, // Number of bytes to write
&cbWritten, // Number of bytes written
NULL // Not overlapped I/O
))
{
dwError = GetLastError();
wprintf(L"WriteFile to pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Send %ld bytes to client: \"%s\"\n", cbWritten, chResponse);
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the client's connection.
FlushFileBuffers(hNamedPipe);
DisconnectNamedPipe(hNamedPipe);
Cleanup:
// Centralized cleanup for all allocated resources.
if (pSa != NULL)
{
FreePipeSecurity(pSa);
pSa = NULL;
}
if (hNamedPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(hNamedPipe);
hNamedPipe = INVALID_HANDLE_VALUE;
}
return dwError;
}
//
// FUNCTION: CreatePipeSecurity(PSECURITY_ATTRIBUTES *)
//
// PURPOSE: The CreatePipeSecurity function creates and initializes a new
// SECURITY_ATTRIBUTES structure to allow Authenticated Users read and
// write access to a pipe, and to allow the Administrators group full
// access to the pipe.
//
// PARAMETERS:
// * ppSa - output a pointer to a SECURITY_ATTRIBUTES structure that allows
// Authenticated Users read and write access to a pipe, and allows the
// Administrators group full access to the pipe. The structure must be
// freed by calling FreePipeSecurity.
//
// RETURN VALUE: Returns TRUE if the function succeeds.
//
// EXAMPLE CALL:
//
// PSECURITY_ATTRIBUTES pSa = NULL;
// if (CreatePipeSecurity(&pSa))
// {
// // Use the security attributes
// // ...
//
// FreePipeSecurity(pSa);
// }
//
BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *ppSa)
{
BOOL fSucceeded = TRUE;
DWORD dwError = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR pSd = NULL;
PSECURITY_ATTRIBUTES pSa = NULL;
// Define the SDDL for the security descriptor.
PCWSTR szSDDL = L"D:" // Discretionary ACL
L"(A;OICI;GRGW;;;AU)" // Allow read/write to authenticated users
L"(A;OICI;GA;;;BA)"; // Allow full control to administrators
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(szSDDL,
SDDL_REVISION_1, &pSd, NULL))
{
fSucceeded = FALSE;
dwError = GetLastError();
goto Cleanup;
}
// Allocate the memory of SECURITY_ATTRIBUTES.
pSa = (PSECURITY_ATTRIBUTES)LocalAlloc(LPTR, sizeof(*pSa));
if (pSa == NULL)
{
fSucceeded = FALSE;
dwError = GetLastError();
goto Cleanup;
}
pSa->nLength = sizeof(*pSa);
pSa->lpSecurityDescriptor = pSd;
pSa->bInheritHandle = FALSE;
*ppSa = pSa;
Cleanup:
// Clean up the allocated resources if something is wrong.
if (!fSucceeded)
{
if (pSd)
{
LocalFree(pSd);
pSd = NULL;
}
if (pSa)
{
LocalFree(pSa);
pSa = NULL;
}
SetLastError(dwError);
}
return fSucceeded;
}
//
// FUNCTION: FreePipeSecurity(PSECURITY_ATTRIBUTES)
//
// PURPOSE: The FreePipeSecurity function frees a SECURITY_ATTRIBUTES
// structure that was created by the CreatePipeSecurity function.
//
// PARAMETERS:
// * pSa - pointer to a SECURITY_ATTRIBUTES structure that was created by
// the CreatePipeSecurity function.
//
void FreePipeSecurity(PSECURITY_ATTRIBUTES pSa)
{
if (pSa)
{
if (pSa->lpSecurityDescriptor)
{
LocalFree(pSa->lpSecurityDescriptor);
}
LocalFree(pSa);
}
}
#pragma region Includes
#include <stdio.h>
#include <windows.h>
#include <sddl.h>
#pragma endregion
// The full name of the pipe in the format of \\servername\pipe\pipename.
#define SERVER_NAME L"."
#define PIPE_NAME L"SamplePipe"
#define FULL_PIPE_NAME L"\\\\" SERVER_NAME L"\\pipe\\" PIPE_NAME
#define BUFFER_SIZE 1024
// Response message from client to server. '\0' is appended in the end
// because the client may be a native C++ application that expects NULL
// termiated string.
#define RESPONSE_MESSAGE L"Default response from server"
BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *);
void FreePipeSecurity(PSECURITY_ATTRIBUTES);
int wmain(int argc, wchar_t* argv[])
{
DWORD dwError = ERROR_SUCCESS;
PSECURITY_ATTRIBUTES pSa = NULL;
HANDLE hNamedPipe = INVALID_HANDLE_VALUE;
// Prepare the security attributes (the lpSecurityAttributes parameter in
// CreateNamedPipe) for the pipe. This is optional. If the
// lpSecurityAttributes parameter 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 of a pipe grant
// full control to the LocalSystem account, (elevated) administrators,
// and the creator owner. They also give only read access to members of
// the Everyone group and the anonymous account. However, if you want to
// customize the security permission of the pipe, (e.g. to allow
// Authenticated Users to read from and write to the pipe), you need to
// create a SECURITY_ATTRIBUTES structure.
if (!CreatePipeSecurity(&pSa))
{
dwError = GetLastError();
wprintf(L"CreatePipeSecurity failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
// Create the named pipe.
hNamedPipe = CreateNamedPipe(
FULL_PIPE_NAME, // Pipe name.
PIPE_ACCESS_DUPLEX, // The pipe is duplex; 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
BUFFER_SIZE, // Output buffer size in bytes
BUFFER_SIZE, // Input buffer size in bytes
NMPWAIT_USE_DEFAULT_WAIT, // Time-out interval
pSa // Security attributes
);
if (hNamedPipe == INVALID_HANDLE_VALUE)
{
dwError = GetLastError();
wprintf(L"Unable to create named pipe w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"The named pipe (%s) is created.\n", FULL_PIPE_NAME);
// Wait for the client to connect.
wprintf(L"Waiting for the client's connection...\n");
if (!ConnectNamedPipe(hNamedPipe, NULL))
{
if (ERROR_PIPE_CONNECTED != GetLastError())
{
dwError = GetLastError();
wprintf(L"ConnectNamedPipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
}
wprintf(L"Client is connected.\n");
//
// Receive a request from client.
//
BOOL fFinishRead = FALSE;
do
{
wchar_t chRequest[BUFFER_SIZE];
DWORD cbRequest, cbRead;
cbRequest = sizeof(chRequest);
fFinishRead = ReadFile(
hNamedPipe, // Handle of the pipe
chRequest, // Buffer to receive data
cbRequest, // Size of buffer in bytes
&cbRead, // Number of bytes read
NULL // Not overlapped I/O
);
if (!fFinishRead && ERROR_MORE_DATA != GetLastError())
{
dwError = GetLastError();
wprintf(L"ReadFile from pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Receive %ld bytes from client: \"%s\"\n", cbRead, chRequest);
} while (!fFinishRead); // Repeat loop if ERROR_MORE_DATA
//
// Send a response from server to client.
//
wchar_t chResponse[] = RESPONSE_MESSAGE;
DWORD cbResponse, cbWritten;
cbResponse = sizeof(chResponse);
if (!WriteFile(
hNamedPipe, // Handle of the pipe
chResponse, // Buffer to write
cbResponse, // Number of bytes to write
&cbWritten, // Number of bytes written
NULL // Not overlapped I/O
))
{
dwError = GetLastError();
wprintf(L"WriteFile to pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Send %ld bytes to client: \"%s\"\n", cbWritten, chResponse);
// Flush the pipe to allow the client to read the pipe's contents
// before disconnecting. Then disconnect the client's connection.
FlushFileBuffers(hNamedPipe);
DisconnectNamedPipe(hNamedPipe);
Cleanup:
// Centralized cleanup for all allocated resources.
if (pSa != NULL)
{
FreePipeSecurity(pSa);
pSa = NULL;
}
if (hNamedPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(hNamedPipe);
hNamedPipe = INVALID_HANDLE_VALUE;
}
return dwError;
}
//
// FUNCTION: CreatePipeSecurity(PSECURITY_ATTRIBUTES *)
//
// PURPOSE: The CreatePipeSecurity function creates and initializes a new
// SECURITY_ATTRIBUTES structure to allow Authenticated Users read and
// write access to a pipe, and to allow the Administrators group full
// access to the pipe.
//
// PARAMETERS:
// * ppSa - output a pointer to a SECURITY_ATTRIBUTES structure that allows
// Authenticated Users read and write access to a pipe, and allows the
// Administrators group full access to the pipe. The structure must be
// freed by calling FreePipeSecurity.
//
// RETURN VALUE: Returns TRUE if the function succeeds.
//
// EXAMPLE CALL:
//
// PSECURITY_ATTRIBUTES pSa = NULL;
// if (CreatePipeSecurity(&pSa))
// {
// // Use the security attributes
// // ...
//
// FreePipeSecurity(pSa);
// }
//
BOOL CreatePipeSecurity(PSECURITY_ATTRIBUTES *ppSa)
{
BOOL fSucceeded = TRUE;
DWORD dwError = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR pSd = NULL;
PSECURITY_ATTRIBUTES pSa = NULL;
// Define the SDDL for the security descriptor.
PCWSTR szSDDL = L"D:" // Discretionary ACL
L"(A;OICI;GRGW;;;AU)" // Allow read/write to authenticated users
L"(A;OICI;GA;;;BA)"; // Allow full control to administrators
if (!ConvertStringSecurityDescriptorToSecurityDescriptor(szSDDL,
SDDL_REVISION_1, &pSd, NULL))
{
fSucceeded = FALSE;
dwError = GetLastError();
goto Cleanup;
}
// Allocate the memory of SECURITY_ATTRIBUTES.
pSa = (PSECURITY_ATTRIBUTES)LocalAlloc(LPTR, sizeof(*pSa));
if (pSa == NULL)
{
fSucceeded = FALSE;
dwError = GetLastError();
goto Cleanup;
}
pSa->nLength = sizeof(*pSa);
pSa->lpSecurityDescriptor = pSd;
pSa->bInheritHandle = FALSE;
*ppSa = pSa;
Cleanup:
// Clean up the allocated resources if something is wrong.
if (!fSucceeded)
{
if (pSd)
{
LocalFree(pSd);
pSd = NULL;
}
if (pSa)
{
LocalFree(pSa);
pSa = NULL;
}
SetLastError(dwError);
}
return fSucceeded;
}
//
// FUNCTION: FreePipeSecurity(PSECURITY_ATTRIBUTES)
//
// PURPOSE: The FreePipeSecurity function frees a SECURITY_ATTRIBUTES
// structure that was created by the CreatePipeSecurity function.
//
// PARAMETERS:
// * pSa - pointer to a SECURITY_ATTRIBUTES structure that was created by
// the CreatePipeSecurity function.
//
void FreePipeSecurity(PSECURITY_ATTRIBUTES pSa)
{
if (pSa)
{
if (pSa->lpSecurityDescriptor)
{
LocalFree(pSa->lpSecurityDescriptor);
}
LocalFree(pSa);
}
}CppNamedPipeClient.cpp
[cpp] #pragma region Includes
#include <stdio.h>
#include <windows.h>
#pragma endregion
// The full name of the pipe in the format of \\servername\pipe\pipename.
#define SERVER_NAME L"."
#define PIPE_NAME L"SamplePipe"
#define FULL_PIPE_NAME L"\\\\" SERVER_NAME L"\\pipe\\" PIPE_NAME
#define BUFFER_SIZE 1024
// Request message from client to server.
#define REQUEST_MESSAGE L"Default request from client"
int wmain(int argc, wchar_t* argv[])
{
HANDLE hPipe = INVALID_HANDLE_VALUE;
DWORD dwError = ERROR_SUCCESS;
// Try to open the named pipe identified by the pipe name.
while (TRUE)
{
hPipe = CreateFile(
FULL_PIPE_NAME, // Pipe name
GENERIC_READ | GENERIC_WRITE, // Read and write access
0, // No sharing
NULL, // Default security attributes
OPEN_EXISTING, // Opens existing pipe
0, // Default attributes
NULL // No template file
);
// If the pipe handle is opened successfully ...
if (hPipe != INVALID_HANDLE_VALUE)
{
wprintf(L"The named pipe (%s) is connected.\n", FULL_PIPE_NAME);
break;
}
dwError = GetLastError();
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (ERROR_PIPE_BUSY != dwError)
{
wprintf(L"Unable to open named pipe w/err 0x%08lx\n", dwError);
goto Cleanup;
}
// All pipe instances are busy, so wait for 5 seconds.
if (!WaitNamedPipe(FULL_PIPE_NAME, 5000))
{
dwError = GetLastError();
wprintf(L"Could not open pipe: 5 second wait timed out.");
goto Cleanup;
}
}
// Set the read mode and the blocking mode of the named pipe. In this
// sample, we set data to be read from the pipe as a stream of messages.
DWORD dwMode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(hPipe, &dwMode, NULL, NULL))
{
dwError = GetLastError();
wprintf(L"SetNamedPipeHandleState failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
//
// Send a request from client to server
//
wchar_t chRequest[] = REQUEST_MESSAGE;
DWORD cbRequest, cbWritten;
cbRequest = sizeof(chRequest);
if (!WriteFile(
hPipe, // Handle of the pipe
chRequest, // Message to be written
cbRequest, // Number of bytes to write
&cbWritten, // Number of bytes written
NULL // Not overlapped
))
{
dwError = GetLastError();
wprintf(L"WriteFile to pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Send %ld bytes to server: \"%s\"\n", cbWritten, chRequest);
//
// Receive a response from server.
//
BOOL fFinishRead = FALSE;
do
{
wchar_t chResponse[BUFFER_SIZE];
DWORD cbResponse, cbRead;
cbResponse = sizeof(chResponse);
fFinishRead = ReadFile(
hPipe, // Handle of the pipe
chResponse, // Buffer to receive the reply
cbResponse, // Size of buffer in bytes
&cbRead, // Number of bytes read
NULL // Not overlapped
);
if (!fFinishRead && ERROR_MORE_DATA != GetLastError())
{
dwError = GetLastError();
wprintf(L"ReadFile from pipe failed w/err 0x%08lx\n", dwError);
goto Cleanup;
}
wprintf(L"Receive %ld bytes from server: \"%s\"\n", cbRead, chResponse);
} while (!fFinishRead); // Repeat loop if ERROR_MORE_DATA
Cleanup:
// Centralized cleanup for all allocated resources.
if (hPipe != INVALID_HANDLE_VALUE)
{
CloseHandle(hPipe);
hPipe = INVALID_HANDLE_VALUE;
}
return dwError;
}