Solved

The procedure entry point could not be located

Posted on 2010-08-22
15
2,837 Views
Last Modified: 2012-05-10
Hi,

I am trying to run this process in VS2008, window xp OS, but I'm getting the following error:
The procedure entry point GetNamedPipeClientProcessId could not be located in the dynamic link library KERNEL32.dll. I'm new to window programming and don't have any idea why this is happening.
Can you please help with this error?

Thanks in advance.
/*  Chapter 11. ServerNP.
 *	Multi-threaded command line server. Named pipe version
 *	Usage:	Server [UserName GroupName]
 *	ONE THREAD AND PIPE INSTANCE FOR EVERY CLIENT. */

#include "Everything.h"
#include "ClientServer.h" /* Request and Response messages defined here */

typedef struct {				/* Argument to a server thread. */
	HANDLE hNamedPipe;			/* Named pipe instance. */
	DWORD threadNumber;
	TCHAR tempFileName[MAX_PATH]; /* Temporary file name. */
} THREAD_ARG;
typedef THREAD_ARG *LPTHREAD_ARG;

volatile static int shutDown = 0;
static DWORD WINAPI Server (LPTHREAD_ARG);
static DWORD WINAPI Connect (LPTHREAD_ARG);
static DWORD WINAPI ServerBroadcast (LPLONG);
static BOOL  WINAPI Handler (DWORD);
static TCHAR shutRequest[] = _T("$ShutDownServer");
static THREAD_ARG threadArgs[MAX_CLIENTS];

_tmain (int argc, LPTSTR argv[])
{
	/* MAX_CLIENTS is defined in ClientServer.h. */
	/* Currently limited to MAXIMUM_WAIT_OBJECTS WaitForMultipleObjects */
	/* is used by the main thread to wait for the server threads */

	HANDLE hNp, hMonitor, hSrvrThread[MAX_CLIENTS];
	DWORD iNp, monitorId, threadId;
	DWORD AceMasks[] =	/* Named pipe access rights - described in Chapter 15 */
		{STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0X1FF, 0, 0 };
	LPSECURITY_ATTRIBUTES pNPSA = NULL;

	if (!WindowsVersionOK (6, 0)) 
		ReportError (_T("This program requires Windows NT 6.0 or greater"), 1, FALSE);

	/* Console control handler to permit server shut down */
	if (!SetConsoleCtrlHandler (Handler, TRUE))
		ReportError (_T("Cannot create Ctrl handler"), 1, TRUE);

	/* Pipe security is commented out for simplicity - See chapter 16 */
//	if (argc == 4)		/* Optional pipe security - Uses a simpler function. */
//		pNPSA = InitializeAccessOnlySA (0440, argv[1], argv[2], AceMasks, &hSecHeap);
			
	/* Create a thread broadcast pipe name periodically. */
	hMonitor = (HANDLE) _beginthreadex (NULL, 0, ServerBroadcast, NULL, 0, &monitorId);

	/*	Create a pipe instance for every server thread.
	 *	Create a temp file name for each thread.
	 *	Create a thread to service that pipe. */

	for (iNp = 0; iNp < MAX_CLIENTS; iNp++) {
		hNp = CreateNamedPipe ( SERVER_PIPE, PIPE_ACCESS_DUPLEX,
				PIPE_READMODE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT,
				MAX_CLIENTS, 0, 0, INFINITE, pNPSA);

		if (hNp == INVALID_HANDLE_VALUE)
			ReportError (_T ("Failure to open named pipe."), 1, TRUE);
		threadArgs[iNp].hNamedPipe = hNp;
		threadArgs[iNp].threadNumber = iNp;
		GetTempFileName (_T ("."), _T ("CLP"), 0, threadArgs[iNp].tempFileName);
		hSrvrThread[iNp] = (HANDLE)_beginthreadex (NULL, 0, Server,
				&threadArgs[iNp], 0, &threadId);
		if (hSrvrThread[iNp] == NULL)
			ReportError (_T ("Failure to create server thread."), 2, TRUE);
	}
	
	/* Wait for all the threads to terminate. */

	WaitForMultipleObjects (MAX_CLIENTS, hSrvrThread, TRUE, INFINITE);
	_tprintf (_T ("All Server worker threads have shut down.\n"));

	WaitForSingleObject (hMonitor, INFINITE);
	_tprintf (_T ("Monitor thread has shut down.\n"));

	CloseHandle (hMonitor);
	for (iNp = 0; iNp < MAX_CLIENTS; iNp++) { 
		/* Close pipe handles and delete temp files */
		/* Closing temp files is redundant, as the worker threads do it */
		CloseHandle (hSrvrThread[iNp]);
		DeleteFile (threadArgs[iNp].tempFileName);
	}

	_tprintf (_T ("Server process will exit.\n"));
	return 0;
}


static DWORD WINAPI Server (LPTHREAD_ARG pThArg)

/* Server thread function. There is a thread for every potential client. */
{
	/* Each thread keeps its own request, response,
		and bookkeeping data structures on the stack. 
		Also, each thread creates an additional "connect thread"
		so that the main worker thread can test the shut down flag
		periodically while waiting for a client connection. */

	HANDLE hNamedPipe, hTmpFile = INVALID_HANDLE_VALUE, hConTh = NULL, hClient;
	DWORD nXfer, conThStatus, clientProcessId;
	STARTUPINFO startInfoCh;
	SECURITY_ATTRIBUTES tempSA = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
	PROCESS_INFORMATION procInfo;
	FILE *fp;
	REQUEST request;
	RESPONSE response;
	TCHAR clientName[256];

	GetStartupInfo (&startInfoCh);
	hNamedPipe = pThArg->hNamedPipe;

	while (!shutDown) { 	/* Connection loop */

		/* Create a connection thread, and wait for it to terminate */
		/* Use a timeout on the wait so that the shut down flag can be tested */
		hConTh = (HANDLE)_beginthreadex (NULL, 0, Connect, pThArg, 0, NULL);
		if (hConTh == NULL) {
			ReportError (_T("Cannot create connect thread"), 0, TRUE);
			_endthreadex(2);
		}

		/* Wait for a client connection. */	
		while (!shutDown && WaitForSingleObject (hConTh, CS_TIMEOUT) == WAIT_TIMEOUT) 
			{ /* Empty loop body */};
		if (shutDown) _tprintf (_T("Thread %d received shut down\n"), pThArg->threadNumber);
		if (shutDown) continue;	/* Flag could also be set by a different thread */

		CloseHandle (hConTh); hConTh = NULL;
		/* A connection now exists */
        
		if (!GetNamedPipeClientComputerName(pThArg->hNamedPipe, clientName, sizeof(clientName))) {
			_tcscpy_s(clientName, sizeof(clientName)/sizeof(TCHAR)-1, _T("localhost"));
		}
        GetNamedPipeClientProcessId(pThArg->hNamedPipe, &clientProcessId);
		_tprintf(_T("Connect to client process id: %d on computer: %s\n"), clientProcessId, clientName);
        
		while (!shutDown && ReadFile (hNamedPipe, &request, RQ_SIZE, &nXfer, NULL)) {
			/* Receive new commands until the client disconnects */
			_tprintf(_T("Command from client thread: %d. %s\n"), clientProcessId, request.record);
			shutDown = shutDown || (_tcscmp (request.record, shutRequest) == 0);
			if (shutDown)  continue;

			/* Open the temporary results file used by all connections to this instance. */
			hTmpFile = CreateFile (pThArg->tempFileName, GENERIC_READ | GENERIC_WRITE,
				FILE_SHARE_READ | FILE_SHARE_WRITE, &tempSA,
				CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
			if (hTmpFile == INVALID_HANDLE_VALUE) { /* About all we can do is stop the thread */
				ReportError (_T("Cannot create temp file"), 0, TRUE);
				_endthreadex(1);
			}

			/* Main command loop */
			/* Create a process to carry out the command. */
			startInfoCh.hStdOutput = hTmpFile;
			startInfoCh.hStdError = hTmpFile;
			startInfoCh.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
			startInfoCh.dwFlags = STARTF_USESTDHANDLES;

			if (!CreateProcess (NULL, request.record, NULL,
				NULL, TRUE, /* Inherit handles. */
				0, NULL, NULL, &startInfoCh, &procInfo)) {
					PrintMsg (hTmpFile, _T("ERR: Cannot create process."));
					procInfo.hProcess = NULL;
			}

			CloseHandle(hTmpFile);  /* The child process is using the temp file, but the parent handle isn't needed */
			if (procInfo.hProcess != NULL ) { /* Server process is running */
				CloseHandle (procInfo.hThread);
				WaitForSingleObject (procInfo.hProcess, INFINITE);
				CloseHandle (procInfo.hProcess);
			}
			
			/* Respond a line at a time. It is convenient to use
				C library line-oriented routines at this point. */

			if (_tfopen_s (&fp, pThArg->tempFileName, _T("r")) != 0) {	
				_tprintf (_T("Temp output file is: %s.\n"), pThArg->tempFileName);
				_tperror (_T("Failure to open command output file."));
				break;  /* Try the next command. */
			}

			/* Avoid an "information discovery" security exposure. */
			/* ZeroMemory(&response, sizeof(response));  */
			while (_fgetts (response.record, MAX_RQRS_LEN, fp) != NULL) {
				response.rsLen = (LONG32)(strlen(response.record) + 1);
				WriteFile (hNamedPipe, &response, response.rsLen + sizeof(response.rsLen), &nXfer, NULL);
			}
			/* Write a terminating record. Messages use 8-bit characters, not UNICODE */
			response.record[0] = '\0';
			response.rsLen = 0;
			WriteFile (hNamedPipe, &response, sizeof(response.rsLen), &nXfer, NULL); 

			FlushFileBuffers (hNamedPipe);
			fclose (fp);

		}   /* End of main command loop. Get next command */

		/* Client has disconnected or there has been a shut down requrest */
		/* Terminate this client connection and then wait for another */
		FlushFileBuffers (hNamedPipe);
		DisconnectNamedPipe (hNamedPipe);
	}

	/*  Force the connection thread to shut down if it is still active */
    if (hConTh != NULL) {
        GetExitCodeThread (hConTh, &conThStatus);
	    if (conThStatus == STILL_ACTIVE) {
		    hClient = CreateFile (SERVER_PIPE, GENERIC_READ | GENERIC_WRITE, 0, NULL,
			    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		    if (hClient != INVALID_HANDLE_VALUE) CloseHandle (hClient);
		    WaitForSingleObject (hConTh, INFINITE);
        }
	}


/*	Comments about terminating the connection thread:
	There is an issue with the fact that the Connect thread
	could still be running. You would like to terminate it, but then 
	there would not be a clean thread shut down, and, for example, 
	DLL entry points would not be called, resulting in potential resource leaks.
	Now, in this case, the connection thread is minimal, so there should be
	no harm, but, here we've used a different approach:

	The connection thread can be resumed by having the server
	act like a client and perform a CreateFile to get a (very) short lived 
	connection, allowing the connection thread to shut down.

    Unfortunately, there is a problem here; any Connect thread could respond,
	not the one on the server instance we're interested in. We've ignored that
	here as there's only on connect thread.

	Nonetheless, here are a couple of other solutions that are tempting
	to try, but they both have problems.
	
	IDEA 1. Close the named pipe handle. Perhaps, that will cause the ConnectNamedPipe
	call to fail and the Connect thread can terminate. Unfortunately, CloseHandle 
	blocks while there is an active ConnectNamedPipe call.
		CloseHandle (hNamedPipe);  // Don't do this! It could block.
	
	IDEA 2. Terminate the thread. The problem is that DLL entry points will
	not be called, resulting in potential resource leaks mentioned above.

	NOTE: DLL entry points were discussed in Chapter 5 but have not been illustrated
	yet. There is an example in Chapter 12.

	IDEA 3. Use thread cancellation using asynch proc calls (Chapter 10).
	Unfortunately, the client may not be in an alertable wait state.

*/
	_tprintf (_T("Thread %d shutting down.\n"), pThArg->threadNumber);
	/* End of command processing loop. Free resources and exit from the thread. */
	CloseHandle (hTmpFile); hTmpFile = INVALID_HANDLE_VALUE;
	if (!DeleteFile (pThArg->tempFileName)) {
		ReportError (_T("Failed deleting temp file."), 0, TRUE);
	}
	_tprintf (_T ("Exiting server thread number %d.\n"), pThArg->threadNumber);
	return 0;
}


static DWORD WINAPI Connect (LPTHREAD_ARG pThArg)
{
	BOOL fConnect;
	/*	Pipe connection thread that allows the server worker thread 
		to poll the shut down flag. */
	fConnect = ConnectNamedPipe (pThArg->hNamedPipe, NULL);
	_endthreadex (0);
	return 0;	/* Suppress a compiler warning message. */ 
}


static DWORD WINAPI ServerBroadcast (LPLONG pNull)
{
	MS_MESSAGE MsNotify;
	DWORD nXfer, iNp;
	HANDLE hMsFile;

	/* Open the mailslot for the MS "client" writer. */
	while (!shutDown) { /* Run as long as there are server threads */
		/* Wait for another client to open a mailslot. */
		Sleep (CS_TIMEOUT);
		/* NOTE (Oct 12, 2001). The mailslot CreateFile uses GENERIC_WRITE
		   but not GENERIC_READ. GENERIC_READ will work on Windows NT/2000/XP,
		   but will fail ("BAD PARAMETER") on Windows 9x/Me. Now, this particular
		   program is not designed for 9x/Me since it is a named pipe server, but
		   there are many cases is which a mailslot client would run on 9x/Me, so
		   do not use GENERIC_READ when creating a mailslot client file */
		hMsFile = CreateFile (MS_CLTNAME, GENERIC_WRITE,
				FILE_SHARE_READ,
				NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hMsFile == INVALID_HANDLE_VALUE) continue;

		/* Send out the message to the mailslot. */

		MsNotify.msStatus = 0;
		MsNotify.msUtilization = 0;
		_tcsncpy_s (MsNotify.msName, sizeof(MsNotify.msName)/sizeof(TCHAR), SERVER_PIPE, _TRUNCATE);
		if (!WriteFile (hMsFile, &MsNotify, MSM_SIZE, &nXfer, NULL))
			ReportError (_T ("Server MS Write error."), 13, TRUE);
		CloseHandle (hMsFile);
	}

	/* Cancel all outstanding NP I/O commands. See Chapter 14 for CancelIoEx */
	_tprintf (_T("Shut down flag set. Cancel all outstanding I/O operations.\n"));
	/* This is an NT6 dependency. On Windows XP, outstanding NP I/O operations hang. */
	for (iNp = 0; iNp < MAX_CLIENTS; iNp++) {
		CancelIoEx (threadArgs[iNp].hNamedPipe, NULL);
	}
	_tprintf (_T ("Shuting down monitor thread.\n"));

	_endthreadex (0);
	return 0;
}


BOOL WINAPI Handler (DWORD CtrlEvent)
{
	/* shut down the system */
	_tprintf (_T("In console control handler\n"));
	InterlockedIncrement(&shutDown);
	return TRUE;
}

Open in new window

0
Comment
Question by:vielkacarolina1239
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 5
  • 2
15 Comments
 
LVL 62

Accepted Solution

by:
☠ MASQ ☠ earned 500 total points
ID: 33496947
The version of Kernel32.dll in XP doesn't support the function "GetNamedPipeClientProcessId"
This is found in Kernel32.dll from Vista onward
http://msdn.microsoft.com/en-us/library/aa365440(VS.85).aspx
0
 
LVL 32

Expert Comment

by:phoffric
ID: 33496948
I'm not a MS Windows programmer but I'll take a guess that you did not include all your headers that you may need. Try adding some of these if you haven't already done so.
#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <tchar.h>
0
 
LVL 32

Expert Comment

by:phoffric
ID: 33496962
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 62

Expert Comment

by:☠ MASQ ☠
ID: 33496981
This should work in a VS2008/Vista combination but won't with XP - as a learning exercise (which is what this appears to be) using XP is the wrong way to go unless your project is to produce a similar routine on XP using different function calls.
 
I guess that's the error explained.  The fix is use a different client OS unless you are forced to find a workaround - which would be a rewrite of the example code you posted.
0
 

Author Comment

by:vielkacarolina1239
ID: 33497020
This is a learning exercise, I was told to use xp.
0
 

Author Comment

by:vielkacarolina1239
ID: 33497042
Thanks for the info.
0
 
LVL 62

Expert Comment

by:☠ MASQ ☠
ID: 33497063
Are you running this one on XP? - it's the Server version.
2008 supports "GetNamedPipeClientProcessId"
For XP you run
http://fmgroup.polito.it/murciano/teachings/sp/CHAPTR11/clientNP.C 
0
 

Author Comment

by:vielkacarolina1239
ID: 33497113
xp professional, no the server version.
0
 

Author Comment

by:vielkacarolina1239
ID: 33497121
I meant to say, xp professional, no server 2008.
0
 

Author Comment

by:vielkacarolina1239
ID: 33497127
clientNP.c is the part of the project
0
 
LVL 62

Expert Comment

by:☠ MASQ ☠
ID: 33497130
The code in your question should run on Windows Server 2008, the code in my link is for XP (Client)
0
 

Author Comment

by:vielkacarolina1239
ID: 33497141
I was told to use both in xp. clientNP works fine.
0
 

Author Comment

by:vielkacarolina1239
ID: 33497159
I guess that I won’t be able to run serverNP.c on xp professional if there is not a way around it.
0
 
LVL 62

Assisted Solution

by:☠ MASQ ☠
☠ MASQ ☠ earned 500 total points
ID: 33497186
I would still say you can't call "GetNamedPipeClientProcessId" in XP's Kernel32.dll, unless VS2008 has installed another version which supports the function I'm afraid you might need to go back to your tutor with this.
Perhaps someone else can come up with another explanation ...
0
 

Author Comment

by:vielkacarolina1239
ID: 33497213
Thanks, I'll go back to him.
0

Featured Post

Salesforce Made Easy to Use

On-screen guidance at the moment of need enables you & your employees to focus on the core, you can now boost your adoption rates swiftly and simply with one easy tool.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
max float value 3 59
Embarcadero C++ Builder XE10.1 Berlin red arrow Indicator 2 74
Installshield for Embarcadero EX 10.1 Berlin 4 73
Android development question 2 80
Step by step guide to Clean and Sort your windows registry! Introduction: Always remember: A Clean registry = Better performance = Save your invaluable time In this article we're going to clear our registry manually! Yes, manually! The e…
Issue: Unstable cursor in Windows XP and Windows runs extremely slow in that any click will bring up the Hour glass (sometimes for several seconds before giving you what you want) . Troubleshooting Process and the FINAL FIX: This issue see…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question