瀏覽代碼

1、升级到VS2017
2、两个用例:一个是完成端口用例,一个是APC
3、封装成CNPServer类(未完成 。)

Jeff 6 年之前
父節點
當前提交
5e7485c92b

+ 25 - 0
基础应用/nps/nps - 2017.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.329
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nps", "nps\nps.vcxproj", "{5829E066-6EE8-4598-A57A-C8A42EC87D8E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{5829E066-6EE8-4598-A57A-C8A42EC87D8E}.Debug|Win32.ActiveCfg = Debug|Win32
+		{5829E066-6EE8-4598-A57A-C8A42EC87D8E}.Debug|Win32.Build.0 = Debug|Win32
+		{5829E066-6EE8-4598-A57A-C8A42EC87D8E}.Release|Win32.ActiveCfg = Release|Win32
+		{5829E066-6EE8-4598-A57A-C8A42EC87D8E}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {2BD993F1-295A-4623-BF54-D6797E58963C}
+	EndGlobalSection
+EndGlobal

+ 269 - 0
基础应用/nps/nps/NPServer.cpp

@@ -0,0 +1,269 @@
+#include "StdAfx.h"
+#include "NPServer.h"
+#include <process.h>
+
+CNPServer::CNPServer(LPCTSTR lpszPipename):m_hConnectEvent(NULL)
+{
+	ZeroMemory(&m_ovpConnect, sizeof(OVERLAPPED));
+	if ( lpszPipename != NULL)
+		_tcscpy_s(m_szPipename, lpszPipename);
+}
+
+CNPServer::~CNPServer(void)
+{
+}
+
+BOOL CNPServer::InitNPServer()
+{
+	if ( m_hConnectEvent != NULL )
+		return TRUE;
+	
+	// 创建连接操作的响应事件对象;
+	m_hConnectEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+	if (m_hConnectEvent == NULL)
+		return FALSE;
+
+	m_ovpConnect.hEvent = m_hConnectEvent;
+	// 创建接收客户端的线程;
+	HANDLE hThread = NULL;
+	unsigned int dwThreadId = 0;
+	hThread = (HANDLE)_beginthreadex(NULL, 0, AcceptThread, this, NULL, &dwThreadId);
+	if ( hThread == NULL)
+		return FALSE;
+
+	CloseHandle(hThread);
+
+	return TRUE;
+}
+
+unsigned CNPServer::AcceptThread(LPVOID lpParam)
+{
+	CNPServer *pthis = (CNPServer*)lpParam;
+	HANDLE hPipe = NULL; 
+	LPPIPEINST lpPipeInst;
+	DWORD dwWait, cbRet;
+	BOOL fSuccess, fPendingIO;
+
+	fPendingIO = pthis->CreateAndConnectInstance(&pthis->m_ovpConnect);
+
+	while (1)
+	{
+		// 等待客户端连接或读写操作完成;
+		dwWait = WaitForSingleObjectEx(pthis->m_hConnectEvent, INFINITE,TRUE); 
+		switch (dwWait)
+		{
+			// 连接完成;
+		case WAIT_OBJECT_0:
+			// If an operation is pending, get the result of the 
+			// connect operation. 
+
+			if (fPendingIO)
+			{
+				fSuccess = GetOverlappedResult(
+					hPipe,     // pipe handle 
+					&pthis->m_ovpConnect, // OVERLAPPED structure 
+					&cbRet,    // bytes transferred 
+					FALSE);    // does not wait 
+				if (!fSuccess)
+				{
+					printf("ConnectNamedPipe (%d)\n", GetLastError());
+					OutputDebugString(_T("ConnectNamedPipe GetOverlappedResult"));
+					return 0;
+				}
+			}
+
+			// Allocate storage for this instance. 
+
+			lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST));
+			if (lpPipeInst == NULL)
+			{
+				printf("GlobalAlloc failed (%d)\n", GetLastError());
+				return 0;
+			}
+
+			lpPipeInst->hPipeInst = hPipe;
+
+			// Start the read operation for this client. 
+			// Note that this same routine is later used as a 
+			// completion routine after a write operation. 
+
+			lpPipeInst->cbToWrite = 0;
+			CompletedWriteRoutine(pthis, 0, 0, (LPOVERLAPPED)lpPipeInst);
+
+			// Create new pipe instance for the next client. 
+
+			fPendingIO = pthis->CreateAndConnectInstance(&pthis->m_ovpConnect);
+			break;
+
+			// The wait is satisfied by a completed read or write 
+			// operation. This allows the system to execute the 
+			// completion routine. 
+
+		case WAIT_IO_COMPLETION:
+			break;
+
+			// An error occurred in the wait function. 
+
+		default:
+		{
+			printf("WaitForSingleObjectEx (%d)\n", GetLastError());
+			OutputDebugString(_T("WaitForSingleObjectEx\n"));
+			return 0;
+		}
+		}
+	}
+
+	return 0;
+}
+
+BOOL CNPServer::CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
+{
+	HANDLE hPipe = CreateNamedPipe( 
+		m_szPipename,             // pipe name 
+		PIPE_ACCESS_DUPLEX |      // read/write access 
+		FILE_FLAG_OVERLAPPED,     // overlapped mode 
+		PIPE_TYPE_MESSAGE |       // message-type pipe 
+		PIPE_READMODE_MESSAGE |   // message read mode 
+		PIPE_WAIT,                // blocking mode 
+		PIPE_UNLIMITED_INSTANCES, // unlimited instances 
+		BUFSIZE*sizeof(TCHAR),    // output buffer size 
+		BUFSIZE*sizeof(TCHAR),    // input buffer size 
+		PIPE_TIMEOUT,             // client time-out 
+		NULL);                    // default security attributes
+	if (hPipe == INVALID_HANDLE_VALUE) 
+	{
+		printf("CreateNamedPipe failed with %d.\n", GetLastError()); 
+		OutputDebugString(_T("CreateNamedPipe failed"));
+		return 0;
+	}
+
+	// Call a subroutine to connect to the new client. 
+
+	return ConnectToNewClient(hPipe, lpoOverlap); 
+}
+
+BOOL CNPServer::ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
+{
+	TCHAR szMsg[MAX_PATH] = {0};
+	BOOL fConnected, fPendingIO = FALSE; 
+
+	// Start an overlapped connection for this pipe instance. 
+	fConnected = ConnectNamedPipe(hPipe, lpo); 
+
+	// Overlapped ConnectNamedPipe should return zero. 
+	if (fConnected) 
+	{
+		_stprintf_s(szMsg, _T("ConnectNamedPipe failed with %d.\n"), GetLastError());
+		//printf("ConnectNamedPipe failed with %d.\n", GetLastError()); 
+		OutputDebugString(szMsg);
+		return 0;
+	}
+
+	switch (GetLastError()) 
+	{ 
+		// The overlapped connection in progress. 
+	case ERROR_IO_PENDING: 
+		//OutputDebugString(_T("The overlapped connection in progress\n"));
+		fPendingIO = TRUE; 
+		break; 
+
+		// Client is already connected, so signal an event. 
+
+	case ERROR_PIPE_CONNECTED: 
+		OutputDebugString(_T("Client is already connected, so signal an event\n"));
+		if (SetEvent(lpo->hEvent)) 
+			break; 
+
+		// If an error occurs during the connect operation... 
+	default: 
+		{
+			_stprintf_s(szMsg, _T("ConnectNamedPipe failed with %d.\n"), GetLastError());
+			OutputDebugString(szMsg);
+			//printf("ConnectNamedPipe failed with %d.\n", GetLastError());
+			return 0;
+		}
+	} 
+	return fPendingIO; 
+}
+
+void CNPServer::DisconnectAndClose(LPPIPEINST lpPipeInst)
+{
+	// Disconnect the pipe instance. 
+
+	if (! DisconnectNamedPipe(lpPipeInst->hPipeInst) ) 
+	{
+		printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
+	}
+
+	// Close the handle to the pipe instance. 
+
+	CloseHandle(lpPipeInst->hPipeInst); 
+
+	// Release the storage for the pipe instance. 
+
+	if (lpPipeInst != NULL) 
+		GlobalFree(lpPipeInst); 
+}
+
+void WINAPI CNPServer::CompletedWriteRoutine(CNPServer *pInstance, DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap)
+{
+	LPPIPEINST lpPipeInst; 
+	BOOL fRead = FALSE; 
+
+	// lpOverlap points to storage for this instance. 
+
+	lpPipeInst = (LPPIPEINST) lpOverLap; 
+
+	// The write operation has finished, so read the next request (if 
+	// there is no error). 
+
+	if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite)) 
+		fRead = ReadFileEx( 
+		lpPipeInst->hPipeInst, 
+		lpPipeInst->chRequest, 
+		BUFSIZE*sizeof(TCHAR), 
+		(LPOVERLAPPED) lpPipeInst, 
+		(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine); 
+
+	// Disconnect if an error occurred. 
+
+	if (! fRead) 
+		pInstance->DisconnectAndClose(lpPipeInst);
+}
+
+void WINAPI CNPServer::CompletedReadRoutine(CNPServer *pInstance, DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap)
+{
+	LPPIPEINST lpPipeInst; 
+	BOOL fWrite = FALSE; 
+
+	// lpOverlap points to storage for this instance. 
+
+	lpPipeInst = (LPPIPEINST) lpOverLap; 
+
+	// The read operation has finished, so write a response (if no 
+	// error occurred). 
+
+	if ((dwErr == 0) && (cbBytesRead != 0)) 
+	{ 
+		pInstance->GetAnswerToRequest(lpPipeInst);
+
+		fWrite = WriteFileEx( 
+			lpPipeInst->hPipeInst, 
+			lpPipeInst->chReply, 
+			lpPipeInst->cbToWrite, 
+			(LPOVERLAPPED) lpPipeInst, 
+			(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine); 
+	} 
+
+	// Disconnect if an error occurred. 
+
+	if (! fWrite) 
+		pInstance->DisconnectAndClose(lpPipeInst);
+}
+
+void CNPServer::GetAnswerToRequest(LPPIPEINST pipe)
+{
+	_tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
+	_tcscpy_s( pipe->chReply, BUFSIZE, TEXT("Default answer from server") );
+	pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
+}

+ 43 - 0
基础应用/nps/nps/NPServer.h

@@ -0,0 +1,43 @@
+#ifndef __NAMEPIPE_SERVER__
+#define __NAMEPIPE_SERVER__
+
+#pragma once
+
+#define PIPE_TIMEOUT	5000
+#define BUFSIZE			8092
+
+typedef struct 
+{ 
+	OVERLAPPED oOverlap;
+	DWORD dwProcessId;		// ½ø³ÌID;
+	HANDLE hPipeInst; 
+	TCHAR chRequest[BUFSIZE]; 
+	DWORD cbRead;
+	TCHAR chReply[BUFSIZE]; 
+	DWORD cbToWrite; 
+} PIPEINST, *LPPIPEINST; 
+
+class CNPServer
+{
+public:
+	CNPServer(LPCTSTR lpszPipename);
+	~CNPServer(void);
+
+public:
+	HANDLE			m_hConnectEvent;
+	OVERLAPPED		m_ovpConnect; 
+	TCHAR			m_szPipename[MAX_PATH];
+
+public:
+	BOOL InitNPServer();
+	static unsigned WINAPI AcceptThread(LPVOID lpParam);
+	BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap);
+	BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo);
+	void DisconnectAndClose(LPPIPEINST lpPipeInst); 
+	static void WINAPI CompletedWriteRoutine(CNPServer *pInstance, DWORD dwErr, DWORD cbWritten, LPOVERLAPPED lpOverLap);
+	static void WINAPI CompletedReadRoutine(CNPServer *pInstance, DWORD dwErr, DWORD cbBytesRead, LPOVERLAPPED lpOverLap);
+	void GetAnswerToRequest(LPPIPEINST pipe);
+};
+
+
+#endif //__NAMEPIPE_SERVER__

+ 13 - 296
基础应用/nps/nps/nps.cpp

@@ -3,36 +3,14 @@
 
 #include "stdafx.h"
 #include "nps.h"
-///////////////////////
-#include <windows.h> 
-#include <stdio.h>
-#include <tchar.h>
-#include <strsafe.h>
-
-#define PIPE_TIMEOUT 5000
-#define BUFSIZE 4096
-
-typedef struct 
-{ 
-	OVERLAPPED oOverlap; 
-	HANDLE hPipeInst; 
-	TCHAR chRequest[BUFSIZE]; 
-	DWORD cbRead;
-	TCHAR chReply[BUFSIZE]; 
-	DWORD cbToWrite; 
-} PIPEINST, *LPPIPEINST; 
-
-VOID DisconnectAndClose(LPPIPEINST); 
-BOOL CreateAndConnectInstance(LPOVERLAPPED); 
-BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED); 
-VOID GetAnswerToRequest(LPPIPEINST); 
-
-VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED); 
-VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED); 
-
-HANDLE hPipe; 
 
 
+#define EXAMPLE 1
+#if EXAMPLE
+#include "nps_example2.h"
+#else
+#include "NPServer.h"
+#endif
 
 #ifdef _DEBUG
 #define new DEBUG_NEW
@@ -59,275 +37,14 @@ int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
 	else
 	{
 		// TODO: 在此处为应用程序的行为编写代码。
-		HANDLE hConnectEvent; 
-		OVERLAPPED oConnect; 
-		LPPIPEINST lpPipeInst; 
-		DWORD dwWait, cbRet; 
-		BOOL fSuccess, fPendingIO; 
-
-		// Create one event object for the connect operation. 
-
-		hConnectEvent = CreateEvent( 
-			NULL,    // default security attribute
-			TRUE,    // manual reset event 
-			TRUE,    // initial state = signaled 
-			NULL);   // unnamed event object 
-
-		if (hConnectEvent == NULL) 
-		{
-			printf("CreateEvent failed with %d.\n", GetLastError()); 
-			return 0;
-		}
-
-		oConnect.hEvent = hConnectEvent; 
-
-		// Call a subroutine to create one instance, and wait for 
-		// the client to connect. 
-
-		fPendingIO = CreateAndConnectInstance(&oConnect); 
-
-		while (1) 
-		{ 
-			// Wait for a client to connect, or for a read or write 
-			// operation to be completed, which causes a completion 
-			// routine to be queued for execution. 
-
-			dwWait = WaitForSingleObjectEx( 
-				hConnectEvent,  // event object to wait for 
-				INFINITE,       // waits indefinitely 
-				TRUE);          // alertable wait enabled 
-
-			switch (dwWait) 
-			{ 
-				// The wait conditions are satisfied by a completed connect 
-				// operation. 
-			case 0: 
-				// If an operation is pending, get the result of the 
-				// connect operation. 
-
-				if (fPendingIO) 
-				{ 
-					fSuccess = GetOverlappedResult( 
-						hPipe,     // pipe handle 
-						&oConnect, // OVERLAPPED structure 
-						&cbRet,    // bytes transferred 
-						FALSE);    // does not wait 
-					if (!fSuccess) 
-					{
-						printf("ConnectNamedPipe (%d)\n", GetLastError()); 
-						return 0;
-					}
-				} 
-
-				// Allocate storage for this instance. 
-
-				lpPipeInst = (LPPIPEINST) GlobalAlloc(GPTR, sizeof(PIPEINST)); 
-				if (lpPipeInst == NULL) 
-				{
-					printf("GlobalAlloc failed (%d)\n", GetLastError()); 
-					return 0;
-				}
-
-				lpPipeInst->hPipeInst = hPipe; 
-
-				// Start the read operation for this client. 
-				// Note that this same routine is later used as a 
-				// completion routine after a write operation. 
-
-				lpPipeInst->cbToWrite = 0; 
-				CompletedWriteRoutine(0, 0, (LPOVERLAPPED) lpPipeInst); 
-
-				// Create new pipe instance for the next client. 
-
-				fPendingIO = CreateAndConnectInstance( &oConnect); 
-				break; 
-
-				// The wait is satisfied by a completed read or write 
-				// operation. This allows the system to execute the 
-				// completion routine. 
-
-			case WAIT_IO_COMPLETION: 
-				break; 
-
-				// An error occurred in the wait function. 
-
-			default: 
-				{
-					printf("WaitForSingleObjectEx (%d)\n", GetLastError()); 
-					return 0;
-				}
-			} 
-		} 
-		return 0; 
-
+#if EXAMPLE
+		example();
+#else
+		CNPServer nps(_T("\\\\.\\pipe\\mynamedpipe"));
+		nps.InitNPServer();
+		system("pause");
+#endif
 	}
 
 	return nRetCode;
 }
-
-// CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED) 
-// This routine is called as a completion routine after writing to 
-// the pipe, or when a new client has connected to a pipe instance.
-// It starts another read operation. 
-
-VOID WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten, 
-								  LPOVERLAPPED lpOverLap) 
-{ 
-	LPPIPEINST lpPipeInst; 
-	BOOL fRead = FALSE; 
-
-	// lpOverlap points to storage for this instance. 
-
-	lpPipeInst = (LPPIPEINST) lpOverLap; 
-
-	// The write operation has finished, so read the next request (if 
-	// there is no error). 
-
-	if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite)) 
-		fRead = ReadFileEx( 
-		lpPipeInst->hPipeInst, 
-		lpPipeInst->chRequest, 
-		BUFSIZE*sizeof(TCHAR), 
-		(LPOVERLAPPED) lpPipeInst, 
-		(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedReadRoutine); 
-
-	// Disconnect if an error occurred. 
-
-	if (! fRead) 
-		DisconnectAndClose(lpPipeInst); 
-} 
-
-// CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED) 
-// This routine is called as an I/O completion routine after reading 
-// a request from the client. It gets data and writes it to the pipe. 
-
-VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead, 
-								 LPOVERLAPPED lpOverLap) 
-{ 
-	LPPIPEINST lpPipeInst; 
-	BOOL fWrite = FALSE; 
-
-	// lpOverlap points to storage for this instance. 
-
-	lpPipeInst = (LPPIPEINST) lpOverLap; 
-
-	// The read operation has finished, so write a response (if no 
-	// error occurred). 
-
-	if ((dwErr == 0) && (cbBytesRead != 0)) 
-	{ 
-		GetAnswerToRequest(lpPipeInst); 
-
-		fWrite = WriteFileEx( 
-			lpPipeInst->hPipeInst, 
-			lpPipeInst->chReply, 
-			lpPipeInst->cbToWrite, 
-			(LPOVERLAPPED) lpPipeInst, 
-			(LPOVERLAPPED_COMPLETION_ROUTINE) CompletedWriteRoutine); 
-	} 
-
-	// Disconnect if an error occurred. 
-
-	if (! fWrite) 
-		DisconnectAndClose(lpPipeInst); 
-} 
-
-// DisconnectAndClose(LPPIPEINST) 
-// This routine is called when an error occurs or the client closes 
-// its handle to the pipe. 
-
-VOID DisconnectAndClose(LPPIPEINST lpPipeInst) 
-{ 
-	// Disconnect the pipe instance. 
-
-	if (! DisconnectNamedPipe(lpPipeInst->hPipeInst) ) 
-	{
-		printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
-	}
-
-	// Close the handle to the pipe instance. 
-
-	CloseHandle(lpPipeInst->hPipeInst); 
-
-	// Release the storage for the pipe instance. 
-
-	if (lpPipeInst != NULL) 
-		GlobalFree(lpPipeInst); 
-} 
-
-// CreateAndConnectInstance(LPOVERLAPPED) 
-// This function creates a pipe instance and connects to the client. 
-// It returns TRUE if the connect operation is pending, and FALSE if 
-// the connection has been completed. 
-
-BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap) 
-{ 
-	LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe"); 
-
-	hPipe = CreateNamedPipe( 
-		lpszPipename,             // pipe name 
-		PIPE_ACCESS_DUPLEX |      // read/write access 
-		FILE_FLAG_OVERLAPPED,     // overlapped mode 
-		PIPE_TYPE_MESSAGE |       // message-type pipe 
-		PIPE_READMODE_MESSAGE |   // message read mode 
-		PIPE_WAIT,                // blocking mode 
-		PIPE_UNLIMITED_INSTANCES, // unlimited instances 
-		BUFSIZE*sizeof(TCHAR),    // output buffer size 
-		BUFSIZE*sizeof(TCHAR),    // input buffer size 
-		PIPE_TIMEOUT,             // client time-out 
-		NULL);                    // default security attributes
-	if (hPipe == INVALID_HANDLE_VALUE) 
-	{
-		printf("CreateNamedPipe failed with %d.\n", GetLastError()); 
-		return 0;
-	}
-
-	// Call a subroutine to connect to the new client. 
-
-	return ConnectToNewClient(hPipe, lpoOverlap); 
-}
-
-BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo) 
-{ 
-	BOOL fConnected, fPendingIO = FALSE; 
-
-	// Start an overlapped connection for this pipe instance. 
-	fConnected = ConnectNamedPipe(hPipe, lpo); 
-
-	// Overlapped ConnectNamedPipe should return zero. 
-	if (fConnected) 
-	{
-		printf("ConnectNamedPipe failed with %d.\n", GetLastError()); 
-		return 0;
-	}
-
-	switch (GetLastError()) 
-	{ 
-		// The overlapped connection in progress. 
-	case ERROR_IO_PENDING: 
-		fPendingIO = TRUE; 
-		break; 
-
-		// Client is already connected, so signal an event. 
-
-	case ERROR_PIPE_CONNECTED: 
-		if (SetEvent(lpo->hEvent)) 
-			break; 
-
-		// If an error occurs during the connect operation... 
-	default: 
-		{
-			printf("ConnectNamedPipe failed with %d.\n", GetLastError());
-			return 0;
-		}
-	} 
-	return fPendingIO; 
-}
-
-VOID GetAnswerToRequest(LPPIPEINST pipe)
-{
-	_tprintf( TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
-	StringCchCopy( pipe->chReply, BUFSIZE, TEXT("Default answer from server") );
-	pipe->cbToWrite = (lstrlen(pipe->chReply)+1)*sizeof(TCHAR);
-}
-

+ 8 - 0
基础应用/nps/nps/nps.vcproj

@@ -176,6 +176,10 @@
 				RelativePath=".\nps.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\NPServer.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\stdafx.cpp"
 				>
@@ -206,6 +210,10 @@
 				RelativePath=".\nps.h"
 				>
 			</File>
+			<File
+				RelativePath=".\NPServer.h"
+				>
+			</File>
 			<File
 				RelativePath=".\Resource.h"
 				>

+ 117 - 0
基础应用/nps/nps/nps.vcxproj

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{5829E066-6EE8-4598-A57A-C8A42EC87D8E}</ProjectGuid>
+    <RootNamespace>nps</RootNamespace>
+    <Keyword>Win32Proj</Keyword>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v141</PlatformToolset>
+    <UseOfMfc>Dynamic</UseOfMfc>
+    <CharacterSet>Unicode</CharacterSet>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v141</PlatformToolset>
+    <UseOfMfc>Dynamic</UseOfMfc>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup>
+    <_ProjectFileVersion>15.0.28127.55</_ProjectFileVersion>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>..\..\..\..\bin\$(SolutionName)\</OutDir>
+    <IntDir>$(OutDir)$(ProjectName)\$(Configuration)\</IntDir>
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>..\..\..\..\bin\$(SolutionName)\</OutDir>
+    <IntDir>$(OutDir)$(ProjectName)\$(Configuration)\</IntDir>
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <Optimization>Disabled</Optimization>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <MinimalRebuild>true</MinimalRebuild>
+      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <Optimization>MaxSpeed</Optimization>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <OptimizeReferences>true</OptimizeReferences>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <TargetMachine>MachineX86</TargetMachine>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="nps.cpp" />
+    <ClCompile Include="NPServer.cpp" />
+    <ClCompile Include="stdafx.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="nps.h" />
+    <ClInclude Include="NPServer.h" />
+    <ClInclude Include="nps_example.h" />
+    <ClInclude Include="nps_example2.h" />
+    <ClInclude Include="Resource.h" />
+    <ClInclude Include="stdafx.h" />
+    <ClInclude Include="targetver.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="nps.rc" />
+  </ItemGroup>
+  <ItemGroup>
+    <Text Include="ReadMe.txt" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 59 - 0
基础应用/nps/nps/nps.vcxproj.filters

@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="源文件">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="头文件">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="资源文件">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="nps.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="NPServer.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="stdafx.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="nps.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="NPServer.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="Resource.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="stdafx.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="targetver.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="nps_example.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="nps_example2.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <ResourceCompile Include="nps.rc">
+      <Filter>资源文件</Filter>
+    </ResourceCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <Text Include="ReadMe.txt" />
+  </ItemGroup>
+</Project>

+ 313 - 0
基础应用/nps/nps/nps_example.h

@@ -0,0 +1,313 @@
+#pragma once
+
+///////////////////////
+#include <windows.h> 
+#include <stdio.h>
+#include <tchar.h>
+#include <strsafe.h>
+
+#define PIPE_TIMEOUT 5000
+#define BUFSIZE 4096
+
+typedef struct
+{
+	OVERLAPPED oOverlap;
+	HANDLE hPipeInst;
+	TCHAR chRequest[BUFSIZE];
+	DWORD cbRead;
+	TCHAR chReply[BUFSIZE];
+	DWORD cbToWrite;
+} PIPEINST, *LPPIPEINST;
+
+VOID DisconnectAndClose(LPPIPEINST);
+BOOL CreateAndConnectInstance(LPOVERLAPPED);
+BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED);
+VOID GetAnswerToRequest(LPPIPEINST);
+
+VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
+VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
+
+HANDLE hPipe;
+
+
+int example()
+{
+	HANDLE hConnectEvent;
+	OVERLAPPED oConnect;
+	LPPIPEINST lpPipeInst;
+	DWORD dwWait, cbRet;
+	BOOL fSuccess, fPendingIO;
+
+	// Create one event object for the connect operation. 
+
+	hConnectEvent = CreateEvent(
+		NULL,    // default security attribute
+		TRUE,    // manual reset event 
+		TRUE,    // initial state = signaled 
+		NULL);   // unnamed event object 
+
+	if (hConnectEvent == NULL)
+	{
+		printf("CreateEvent failed with %d.\n", GetLastError());
+		return 0;
+	}
+
+	oConnect.hEvent = hConnectEvent;
+
+	// Call a subroutine to create one instance, and wait for 
+	// the client to connect. 
+
+	fPendingIO = CreateAndConnectInstance(&oConnect);
+
+	while (1)
+	{
+		// Wait for a client to connect, or for a read or write 
+		// operation to be completed, which causes a completion 
+		// routine to be queued for execution. 
+
+		dwWait = WaitForSingleObjectEx(
+			hConnectEvent,  // event object to wait for 
+			INFINITE,       // waits indefinitely 
+			TRUE);          // alertable wait enabled 
+
+		switch (dwWait)
+		{
+			// The wait conditions are satisfied by a completed connect 
+			// operation. 
+		case WAIT_OBJECT_0:
+			// If an operation is pending, get the result of the 
+			// connect operation. 
+
+			if (fPendingIO)
+			{
+				fSuccess = GetOverlappedResult(
+					hPipe,     // pipe handle 
+					&oConnect, // OVERLAPPED structure 
+					&cbRet,    // bytes transferred 
+					FALSE);    // does not wait 
+				if (!fSuccess)
+				{
+					printf("ConnectNamedPipe (%d)\n", GetLastError());
+					OutputDebugString(_T("ConnectNamedPipe GetOverlappedResult"));
+					return 0;
+				}
+			}
+
+			// Allocate storage for this instance. 
+
+			lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST));
+			if (lpPipeInst == NULL)
+			{
+				printf("GlobalAlloc failed (%d)\n", GetLastError());
+				return 0;
+			}
+
+			lpPipeInst->hPipeInst = hPipe;
+
+			// Start the read operation for this client. 
+			// Note that this same routine is later used as a 
+			// completion routine after a write operation. 
+
+			lpPipeInst->cbToWrite = 0;
+			CompletedWriteRoutine(0, 0, (LPOVERLAPPED)lpPipeInst);
+
+			// Create new pipe instance for the next client. 
+
+			fPendingIO = CreateAndConnectInstance(&oConnect);
+			break;
+
+			// The wait is satisfied by a completed read or write 
+			// operation. This allows the system to execute the 
+			// completion routine. 
+
+		case WAIT_IO_COMPLETION:
+			break;
+
+			// An error occurred in the wait function. 
+
+		default:
+		{
+			printf("WaitForSingleObjectEx (%d)\n", GetLastError());
+			OutputDebugString(_T("WaitForSingleObjectEx\n"));
+			return 0;
+		}
+		}
+	}
+	return 0;
+
+}
+
+// CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED) 
+// This routine is called as a completion routine after writing to 
+// the pipe, or when a new client has connected to a pipe instance.
+// It starts another read operation. 
+
+VOID WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten,
+	LPOVERLAPPED lpOverLap)
+{
+	LPPIPEINST lpPipeInst;
+	BOOL fRead = FALSE;
+
+	// lpOverlap points to storage for this instance. 
+
+	lpPipeInst = (LPPIPEINST)lpOverLap;
+
+	// The write operation has finished, so read the next request (if 
+	// there is no error). 
+
+	if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite))
+		fRead = ReadFileEx(
+			lpPipeInst->hPipeInst,
+			lpPipeInst->chRequest,
+			BUFSIZE * sizeof(TCHAR),
+			(LPOVERLAPPED)lpPipeInst,
+			(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine);
+
+	// Disconnect if an error occurred. 
+
+	if (!fRead)
+		DisconnectAndClose(lpPipeInst);
+}
+
+// CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED) 
+// This routine is called as an I/O completion routine after reading 
+// a request from the client. It gets data and writes it to the pipe. 
+
+VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead,
+	LPOVERLAPPED lpOverLap)
+{
+	LPPIPEINST lpPipeInst;
+	BOOL fWrite = FALSE;
+
+	// lpOverlap points to storage for this instance. 
+
+	lpPipeInst = (LPPIPEINST)lpOverLap;
+
+	// The read operation has finished, so write a response (if no 
+	// error occurred). 
+
+	if ((dwErr == 0) && (cbBytesRead != 0))
+	{
+		GetAnswerToRequest(lpPipeInst);
+
+		fWrite = WriteFileEx(
+			lpPipeInst->hPipeInst,
+			lpPipeInst->chReply,
+			lpPipeInst->cbToWrite,
+			(LPOVERLAPPED)lpPipeInst,
+			(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);
+	}
+
+	// Disconnect if an error occurred. 
+
+	if (!fWrite)
+		DisconnectAndClose(lpPipeInst);
+}
+
+// DisconnectAndClose(LPPIPEINST) 
+// This routine is called when an error occurs or the client closes 
+// its handle to the pipe. 
+
+VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
+{
+	// Disconnect the pipe instance. 
+
+	if (!DisconnectNamedPipe(lpPipeInst->hPipeInst))
+	{
+		printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
+	}
+
+	// Close the handle to the pipe instance. 
+
+	CloseHandle(lpPipeInst->hPipeInst);
+
+	// Release the storage for the pipe instance. 
+
+	if (lpPipeInst != NULL)
+		GlobalFree(lpPipeInst);
+}
+
+// CreateAndConnectInstance(LPOVERLAPPED) 
+// This function creates a pipe instance and connects to the client. 
+// It returns TRUE if the connect operation is pending, and FALSE if 
+// the connection has been completed. 
+
+BOOL CreateAndConnectInstance(LPOVERLAPPED lpoOverlap)
+{
+	LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");
+
+	hPipe = CreateNamedPipe(
+		lpszPipename,             // pipe name 
+		PIPE_ACCESS_DUPLEX |      // read/write access 
+		FILE_FLAG_OVERLAPPED,     // overlapped mode 
+		PIPE_TYPE_MESSAGE |       // message-type pipe 
+		PIPE_READMODE_MESSAGE |   // message read mode 
+		PIPE_WAIT,                // blocking mode 
+		PIPE_UNLIMITED_INSTANCES, // unlimited instances 
+		BUFSIZE * sizeof(TCHAR),    // output buffer size 
+		BUFSIZE * sizeof(TCHAR),    // input buffer size 
+		PIPE_TIMEOUT,             // client time-out 
+		NULL);                    // default security attributes
+	if (hPipe == INVALID_HANDLE_VALUE)
+	{
+		printf("CreateNamedPipe failed with %d.\n", GetLastError());
+		OutputDebugString(_T("CreateNamedPipe failed"));
+		return 0;
+	}
+
+	// Call a subroutine to connect to the new client. 
+
+	return ConnectToNewClient(hPipe, lpoOverlap);
+}
+
+BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo)
+{
+	TCHAR szMsg[MAX_PATH] = { 0 };
+	BOOL fConnected, fPendingIO = FALSE;
+
+	// Start an overlapped connection for this pipe instance. 
+	fConnected = ConnectNamedPipe(hPipe, lpo);
+
+	// Overlapped ConnectNamedPipe should return zero. 
+	if (fConnected)
+	{
+		_stprintf_s(szMsg, _T("ConnectNamedPipe failed with %d.\n"), GetLastError());
+		//printf("ConnectNamedPipe failed with %d.\n", GetLastError()); 
+		OutputDebugString(szMsg);
+		return 0;
+	}
+
+	switch (GetLastError())
+	{
+		// The overlapped connection in progress. 
+	case ERROR_IO_PENDING:
+		//OutputDebugString(_T("The overlapped connection in progress\n"));
+		fPendingIO = TRUE;
+		break;
+
+		// Client is already connected, so signal an event. 
+
+	case ERROR_PIPE_CONNECTED:
+		OutputDebugString(_T("Client is already connected, so signal an event\n"));
+		if (SetEvent(lpo->hEvent))
+			break;
+
+		// If an error occurs during the connect operation... 
+	default:
+	{
+		_stprintf_s(szMsg, _T("ConnectNamedPipe failed with %d.\n"), GetLastError());
+		OutputDebugString(szMsg);
+		//printf("ConnectNamedPipe failed with %d.\n", GetLastError());
+		return 0;
+	}
+	}
+	return fPendingIO;
+}
+
+VOID GetAnswerToRequest(LPPIPEINST pipe)
+{
+	_tprintf(TEXT("[%d] %s\n"), pipe->hPipeInst, pipe->chRequest);
+	StringCchCopy(pipe->chReply, BUFSIZE, TEXT("Default answer from server"));
+	pipe->cbToWrite = (lstrlen(pipe->chReply) + 1) * sizeof(TCHAR);
+}
+

+ 319 - 0
基础应用/nps/nps/nps_example2.h

@@ -0,0 +1,319 @@
+#pragma once
+
+#include <windows.h> 
+#include <stdio.h>
+#include <tchar.h>
+#include <strsafe.h>
+enum enum_op_type {
+	OP_ACCEPT,
+	OP_SEND,
+	OP_RECV,
+	OP_MAX,
+};
+const char *op_names[] = {
+ "ACCEPT",
+ "SEND",
+ "RECV"
+};
+#define PIPE_TIMEOUT 5000
+#define BUFSIZE 4096
+
+typedef struct
+{
+	OVERLAPPED oOverlap;
+	DWORD opType;
+	HANDLE hPipeInst;
+	TCHAR chRequest[BUFSIZE];
+	DWORD cbRead;
+	TCHAR chReply[BUFSIZE];
+	DWORD cbToWrite;
+} PIPEINST, *LPPIPEINST;
+
+VOID DisconnectAndClose(LPPIPEINST);
+BOOL CreateAndConnectInstance();
+BOOL ConnectToNewClient(HANDLE);
+VOID GetAnswerToRequest(LPPIPEINST);
+
+VOID WINAPI CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED);
+VOID WINAPI CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED);
+
+// HANDLE hPipe;
+HANDLE hIocp;
+
+int example(VOID)
+{
+	DWORD dwErr;
+	BOOL fSuccess;
+	DWORD dwNoOfBytes = 0;
+	ULONG_PTR ulKey = 0;
+	OVERLAPPED* pov = NULL;
+
+	// Create one event object for the connect operation. 
+	hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
+
+	// Call a subroutine to create one instance, and wait for 
+	// the client to connect. 
+
+	CreateAndConnectInstance();
+
+	while (1)
+	{
+		// Wait for a completion notification.  
+		pov = NULL;
+		fSuccess = GetQueuedCompletionStatus(
+			hIocp,         // Completion port handle  
+			&dwNoOfBytes,  // Bytes transferred  
+			&ulKey,
+			&pov,          // OVERLAPPED structure  
+			INFINITE       // Notification time-out interval  
+		);
+
+		if (FALSE == fSuccess) {
+			dwErr = GetLastError();
+			printf("GetQueuedCompletionStatus: dwErr=%x.\n", dwErr);
+		}
+		// Get the base address of the RECEIVE_CONTEXT structure   
+		// containing the OVERLAPPED structure received.  
+		LPPIPEINST ppi = CONTAINING_RECORD(pov, PIPEINST, oOverlap);
+		DWORD opType = ppi->opType;
+		printf("GetQueuedCompletionStatus: opType=%s,dwNoOfBytes=%d.\n", op_names[opType], dwNoOfBytes);
+
+		if (OP_ACCEPT == opType) {
+			// Allocate storage for this instance. 
+
+			ppi->cbToWrite = 0;
+			CompletedWriteRoutine(0, 0, (LPOVERLAPPED)ppi);
+
+			// Create new pipe instance for the next client. 
+
+			CreateAndConnectInstance();
+
+			// The wait is satisfied by a completed read or write 
+			// operation. This allows the system to execute the 
+			// completion routine. 
+		}
+		else if (OP_RECV == opType) {
+			if (!dwNoOfBytes) {
+				DisconnectAndClose(ppi);
+			}
+			else {
+				CompletedReadRoutine(0, dwNoOfBytes, (LPOVERLAPPED)ppi);
+			}
+		}
+		else {
+			CompletedWriteRoutine(0, dwNoOfBytes, (LPOVERLAPPED)ppi);
+		}
+	}
+	return 0;
+}
+
+// CompletedWriteRoutine(DWORD, DWORD, LPOVERLAPPED) 
+// This routine is called as a completion routine after writing to 
+// the pipe, or when a new client has connected to a pipe instance.
+// It starts another read operation. 
+
+VOID WINAPI CompletedWriteRoutine(DWORD dwErr, DWORD cbWritten,	LPOVERLAPPED lpOverLap)
+{
+	LPPIPEINST lpPipeInst;
+	BOOL fRead = FALSE;
+
+	// lpOverlap points to storage for this instance. 
+
+	lpPipeInst = (LPPIPEINST)lpOverLap;
+
+	// The write operation has finished, so read the next request (if 
+	// there is no error). 
+	if ((dwErr == 0) && (cbWritten == lpPipeInst->cbToWrite)) {
+		DWORD dwRead;
+		lpPipeInst->opType = OP_RECV;
+
+		fRead = ReadFile(
+			lpPipeInst->hPipeInst,
+			lpPipeInst->chRequest,
+			BUFSIZE * sizeof(TCHAR),
+			&dwRead,
+			(LPOVERLAPPED)lpPipeInst);
+		//(LPOVERLAPPED_COMPLETION_ROUTINE)CompletedReadRoutine);
+		if (!fRead && ERROR_IO_PENDING != GetLastError()) {
+			printf("ReadFile: dwRead=%d,GLE=%d\n", dwRead, GetLastError());
+		}
+	}
+
+	// Disconnect if an error occurred. 
+	printf("%s: PipInst=%x,dwErr=%x,cbWritten=%d,fRead=%d.\n",
+		__func__, (int)lpPipeInst->hPipeInst, dwErr, cbWritten, fRead);
+
+	/*
+	if (!fRead) {
+	 DisconnectAndClose(lpPipeInst);
+	}
+	*/
+}
+
+// CompletedReadRoutine(DWORD, DWORD, LPOVERLAPPED) 
+// This routine is called as an I/O completion routine after reading 
+// a request from the client. It gets data and writes it to the pipe. 
+
+VOID WINAPI CompletedReadRoutine(DWORD dwErr, DWORD cbBytesRead,LPOVERLAPPED lpOverLap)
+{
+	LPPIPEINST lpPipeInst;
+	BOOL fWrite = FALSE;
+
+	// lpOverlap points to storage for this instance. 
+	/*
+	ERROR_BROKEN_PIPE
+	109 (0x6D)
+	The pipe has been ended.
+	*/
+	lpPipeInst = (LPPIPEINST)lpOverLap;
+	if (0x6d == dwErr) {
+		printf("%s: PipInst=%x, the pipe has been ended.\n",
+			__func__, (int)lpPipeInst->hPipeInst);
+	}
+	else {
+		printf("%s: PipInst=%x,dwErr=%x,cbBytesRead=%d.\n",
+			__func__, (int)lpPipeInst->hPipeInst, dwErr, cbBytesRead);
+	}
+
+	// The read operation has finished, so write a response (if no 
+	// error occurred). 
+
+	if ((dwErr == 0) && (cbBytesRead != 0))
+	{
+		DWORD dwWritten;
+		GetAnswerToRequest(lpPipeInst);
+		lpPipeInst->opType = OP_SEND;
+
+		fWrite = WriteFile(
+			lpPipeInst->hPipeInst,
+			lpPipeInst->chReply,
+			lpPipeInst->cbToWrite,
+			&dwWritten,
+			(LPOVERLAPPED)lpPipeInst);
+		// (LPOVERLAPPED_COMPLETION_ROUTINE)CompletedWriteRoutine);
+		if (!fWrite) {
+			printf("WriteFie: dwWritten=%d,GLE=%d\n", dwWritten, GetLastError());
+		}
+	}
+
+	// Disconnect if an error occurred. 
+
+	/*
+	if (!fWrite) {
+	 DisconnectAndClose(lpPipeInst);
+	}
+	*/
+}
+
+// DisconnectAndClose(LPPIPEINST) 
+// This routine is called when an error occurs or the client closes 
+// its handle to the pipe. 
+
+VOID DisconnectAndClose(LPPIPEINST lpPipeInst)
+{
+	// Disconnect the pipe instance. 
+
+	if (!DisconnectNamedPipe(lpPipeInst->hPipeInst))
+	{
+		printf("DisconnectNamedPipe failed with %d.\n", GetLastError());
+	}
+
+	// Close the handle to the pipe instance. 
+
+	CloseHandle(lpPipeInst->hPipeInst);
+
+	// Release the storage for the pipe instance. 
+
+	if (lpPipeInst != NULL)
+		GlobalFree(lpPipeInst);
+}
+
+// CreateAndConnectInstance(LPOVERLAPPED) 
+// This function creates a pipe instance and connects to the client. 
+// It returns TRUE if the connect operation is pending, and FALSE if 
+// the connection has been completed. 
+
+BOOL CreateAndConnectInstance()
+{
+	LPCWSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe");
+
+	HANDLE hPipe = CreateNamedPipe(
+		lpszPipename,             // pipe name 
+		PIPE_ACCESS_DUPLEX |      // read/write access 
+		FILE_FLAG_OVERLAPPED,     // overlapped mode 
+		PIPE_TYPE_MESSAGE |       // message-type pipe 
+		PIPE_READMODE_MESSAGE |   // message read mode 
+		PIPE_WAIT,                // blocking mode 
+		PIPE_UNLIMITED_INSTANCES, // unlimited instances 
+		BUFSIZE * sizeof(TCHAR),    // output buffer size 
+		BUFSIZE * sizeof(TCHAR),    // input buffer size 
+		PIPE_TIMEOUT,             // client time-out 
+		NULL);                    // default security attributes
+
+	printf("CreateNamedPipe, hPipe=%llx.\n", (INT64)hPipe);
+	if (hPipe == INVALID_HANDLE_VALUE)
+	{
+		printf("CreateNamedPipe failed with %d.\n", GetLastError());
+		return 0;
+	}
+	HANDLE hRet = CreateIoCompletionPort(hPipe, hIocp, NULL, 0);
+	// Call a subroutine to connect to the new client. 
+
+	return ConnectToNewClient(hPipe);
+}
+
+BOOL ConnectToNewClient(HANDLE hPipe)
+{
+	BOOL fConnected, fPendingIO = FALSE;
+
+	LPPIPEINST lpPipeInst = (LPPIPEINST)GlobalAlloc(GPTR, sizeof(PIPEINST));
+	if (lpPipeInst == NULL)
+	{
+		printf("GlobalAlloc failed (%d)\n", GetLastError());
+		return 0;
+	}
+	ZeroMemory(&lpPipeInst->oOverlap, sizeof(OVERLAPPED));
+	lpPipeInst->hPipeInst = hPipe;
+	lpPipeInst->opType = OP_ACCEPT;
+
+	// Start an overlapped connection for this pipe instance. 
+	fConnected = ConnectNamedPipe(hPipe, &lpPipeInst->oOverlap);
+
+	// Overlapped ConnectNamedPipe should return zero. 
+	if (fConnected)
+	{
+		printf("ConnectNamedPipe failed with %d.\n", GetLastError());
+		return 0;
+	}
+
+	switch (GetLastError())
+	{
+		// The overlapped connection in progress. 
+	case ERROR_IO_PENDING:
+		fPendingIO = TRUE;
+		break;
+
+		// Client is already connected, so signal an event. 
+
+	case ERROR_PIPE_CONNECTED:
+	{
+		CreateAndConnectInstance();
+	}
+	break;
+
+	// If an error occurs during the connect operation... 
+	default:
+	{
+		printf("ConnectNamedPipe failed with %d.\n", GetLastError());
+		return 0;
+	}
+	}
+	return fPendingIO;
+}
+
+VOID GetAnswerToRequest(LPPIPEINST pipe)
+{
+	_tprintf(TEXT("[%llx] %s\n"), (INT64)pipe->hPipeInst, pipe->chRequest);
+	StringCchCopy(pipe->chReply, BUFSIZE, TEXT("Default answer from server"));
+	pipe->cbToWrite = (lstrlen(pipe->chReply) + 1) * sizeof(TCHAR);
+}