|
0xcdcdcdcd is a special value. In the Debug build, when memory is newly allocated, the C-runtime fills the memory with that value so that you can easily see that it has not been initialized.
If your pointer holds that value, then you can be fairly certain that it has not been assigned a meaningful value.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Re-design of a process launched with re-directed STD streams.
Process A creates two named pipes. One to write to the input of launched process B and one to read from process B. Standard stuff.
Process B launches process C and D and E etc.. In that order and each one runs synchronously. So, only one sub-process is active at any one time.
Process' C,D,E in turn connect to process A through the CreateFile() function - again standard stuff.
Now, the first pass runs just fine - process C reads and writes records from/to A and then ends. Then process D starts - but there is nothing in the pipe. Process A puts stuff in the pipe - it is active all the time - (until process B terminates), then it deals with process E and so on ..
I know that this a bit vague interms of detial - but I have tried every combination of CreateNamedPipe/ConnectNamedPipe/DisconnectNamedPipe on the server side and PeekNamePipe/ReadFile etc on the server side - with pipe busy and pipe closed returncodes.
If anyone has an example or knows of where I can get some idea of how to design a server side mechanism that lets multiple synchronous clients connect in-turn then you would be my friend.
I guess that I am missing something very simple - I hope.
|
|
|
|
|
Are you aware that every time a client connects to a pipe, that another client cannot connect until you create another instance of the pipe?
EDIT:
Let me clarify: You cannot have more than one client connected at once to the same pipe instance.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
OK that sounds interesting - can you spell it out for me! Sorry to come across a bit thick
|
|
|
|
|
Well, an ordinary pipe server follows these steps:
1. Create pipe instance
2. Wait for connection to pipe instance
3. When connection is detected,
A. Store handle of pipe in the array of connected pipes
B. Goto 1
However, I'm not sure if this is your problem because you said that the clients operate synchronously.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
There is never more than one client connected at any one time .. they serviced one at a time.
|
|
|
|
|
OK, perhaps if you could show your main server loop code, it might help.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Hiya.
The following code is bit of a mess - cos - I dont know how to submit stuff in a web friendly way - sorry about that - but if you can spot where I am going wrong in-terms of process control - especially in this server stuff - great - below - note - the peek before the read is for good reson!
UINT ReadWorker( LPVOID a_pParam )
{
// Get the pipeline and stage number for this worker.
CCallpipe *p = ( CCallpipe * )a_pParam;
#ifdef _PIPE_DIAG_MESSAGE_
CString szPrefix;
szPrefix.Format( "CCallpipe::ReadWorker(%d,%d)", p->Pipeline(), p->Stage() );
CApplMessage cons( true, true, ( LPCTSTR )szPrefix );
cons.Write( "Starting ReadWorker" );
#endif // _PIPE_DIAG_MESSAGE_
CHAR szReadBuffer[ _IO_BUFFSIZE_ ];
DWORD dwBytesWritten = 0;
DWORD dwRecCount = 0;
// Create the lock name.
p->m_szLock.Format( "CALLPIPE-%.5d", p->m_dwProcId );
// Connect to the IN stage input stream pipeline.
ConnectNamedPipe( p->m_hInputWrite, NULL );
// Ok, now lets read and process our input stream.
for( ;; )
{
// Read a record from the primary input stream.
if( !p->m_pManager->PeekRecord( *p->m_pProcess, 0, &p->m_szInRecord ) )
{
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "Read of stream: %d, failed", 0 );
#endif // _PIPE_DIAG_MESSAGE_
break;
}
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "I have read the following: >%s<", ( LPCTSTR )p->m_szInRecord );
#endif // _PIPE_DIAG_MESSAGE_
const char *pszRecord = ( LPCTSTR )p->m_szInRecord;
do
{
// Copy the input record to the buffer we will pass the WriteFile().
int nIndex;
for( nIndex = 0; nIndex < ( _IO_BUFFSIZE_ - 2 ) && *pszRecord; ++nIndex )
{
szReadBuffer[ nIndex ] = *pszRecord;
++pszRecord;
}
szReadBuffer[ nIndex ] = 0;
// If its the end of the record, tag on the newline character.
if( !*pszRecord )
{
szReadBuffer[ nIndex ] = _NEWLINE_;
++nIndex;
szReadBuffer[ nIndex ] = 0;
}
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "Writing: %s", szReadBuffer );
#endif // _PIPE_DIAG_MESSAGE_
if( !WriteFile( p->m_hInputWrite, szReadBuffer, ( DWORD )nIndex, &dwBytesWritten, NULL ) )
{
if( GetLastError() == ERROR_NO_DATA )
{
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "The pipe is now closed!" );
#endif // _PIPE_DIAG_MESSAGE_
break;
}
else
{
DWORD dwRetCode = GetLastError();
CString szMessage;
FormatMsg( dwRetCode, &szMessage );
p->m_pManager->StageMessage( *( p->m_pProcess ), 27, _ERROR_, dwRetCode, ( LPCTSTR )szMessage );
p->RaiseError();
return( _RC_FAIL_ );
}
}
// A stream number of -2 identifies the STDOUT stream.
if( p->m_pStage->Trace() )
{
++dwRecCount;
p->m_pManager->TraceMessage( *( p->m_pProcess ), _TRACE_WRITE_, -2, dwRecCount, szReadBuffer );
}
// Ensure that the operating system commits the data just written to the pipe.
FlushFileBuffers( p->m_hInputWrite );
// We must wait here for the potential IN stage of the called pipeline to release the lock
// signalling that it has read and consumed the record that we have just written. This
// will ensure that CALLPIPE does not delay the records.
HANDLE hLock = ::CreateEvent( 0, TRUE, FALSE, ( LPCTSTR )p->m_szLock );
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "Waiting for lock = %s", ( LPCTSTR )p->m_szLock );
#endif // _PIPE_DIAG_MESSAGE_
::WaitForSingleObject( hLock, INFINITE );
// Reset the lock.
::ResetEvent( hLock );
// Delete the handle.
::CloseHandle( hLock );
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "Wait complete for lock = %s", ( LPCTSTR )p->m_szLock );
#endif // _PIPE_DIAG_MESSAGE_
// Determine if the target pipeline has terminated.
DWORD dwExitCode = 0;
GetExitCodeProcess( p->m_pi.hProcess, &dwExitCode );
if( dwExitCode != STILL_ACTIVE )
{
// Disconnect this stages' primary input stream.
p->m_pManager->SeverInStream( *p, 0 );
CloseHandle( p->m_hInputWrite );
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "- done" );
#endif // _PIPE_DIAG_MESSAGE_
return( _RC_SUCCESS_ );
}
}
while( *pszRecord );
// Release the stage writing the record.
p->m_pManager->ConsumeRecord( *p->m_pProcess, 0 );
}
// Close the write end of the pipe, causing the input stage of the called pipeline to terminate
// as it will detect that its std input stream is at eof.
DisconnectNamedPipe( p->m_hInputWrite );
CloseHandle( p->m_hInputWrite );
#ifdef _PIPE_DIAG_MESSAGE_
cons.Write( "- done" );
#endif // _PIPE_DIAG_MESSAGE_
return( _RC_SUCCESS_ );
}
|
|
|
|
|
(Use the "Code Block" formatting to properly format code in the future.)
I'm assuming this is the server side. I see you are closing the pipe handle at the end of the function.
Can I assume you're recreating the pipe somewhere else in the program?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
As far as I understand - this is the server-side of the code - I cannot believe that it is so complicated to connect two process together .. with my application ..
|
|
|
|
|
Member 3852024 wrote: I cannot believe that it is so complicated to connect two process together
That's why we developers get the big bucks!
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
I wish I could get big bucks! I cannot get an IT job for love nor money!
|
|
|
|
|
Maybe you just have a simple race condition.
Maybe the process D is trying to connect before process A has a chance to re-open the pipe after process C disconnects.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
After some deliberation - I have decided to replace the whole mechanism with a shared file instead. It is a little ironic to say the least that I cannot get the pipe method to work for me - when my own application is called 'Pipelines'. Thank you for your help.
Regards.
James
|
|
|
|
|
Are you closing the pipe handle with CloseHandle() in process C before process D tries to connect?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
|
Thank you for looking into this for me. I am still at a loss as to why the process is not working. All the process' are synchronous - the mechanism I posted is one small part of a very big set of multi-threaded interlocked processes - however it is pretty much stand-alone - all it does is simulate the re-directed std handles of another process.
For the first time in years - I am stuck!
James.
|
|
|
|
|
I have read the entire thread so far and I think I see the problem here. The "Server" side of named pipes needs some magic in order to support multiple clients accessing it, even if those clients are "synchronized".
A named pipe is still a "one shot deal", that is, you create it, wait for a connection, accept the connection, and then close the pipe when you are all done. That means that a single "client" can access the pipe. In order for multiple clients to work, you have to have multiple instances of the "named pipe", in other words, you have lots of pipes with the same name all ready for use.
The easiest way to do this is demonstrated in the following pseudo-code (I cannot actually paste my working code as it belongs to my employer, as does my soul and first born
HANDLE P1 = create_a_named_pipe("Bob");
While (TRUE)
{
HANDLE P2 = create_a_named_pipe("Bob");
wait_for_a_connection(P1);
P1 = P2;
} ).
Anyway, you need to maintain at least one "unattached" pipe with the proper name so that clients have something to "connect to" while you are busy working with the other client or cleaning up after you are done with it.
Managing how one and only one application will have a pipe named "Bob" is an exercise for the student
|
|
|
|
|
Thank you very much for the update. I have already changed my code to use a shared file(s). Neverthless, after reading your comments - I can see exactly where my original design was wrong. I get it now. Thank you very much - this will be invaluable in other areas where I need to alter pipe processing connections.
|
|
|
|
|
Hello,
I have an application that uses a DLL but the DLL needs to access data provided by the application on runtime.
Tryng to make .exe objects visible to the DLL brings me to awful linking problems
The solution I tested is to use COM but this forces to use RPC for communication between the .DLL and the .EXE world. COM solution sounds complex and out-proc is slower than in-proc.
Please could you help me with a more simple solution?
Thank you in advance
|
|
|
|
|
What data is needed by the DLL?
You should export a function from the DLL that the EXE can call to pass in the data using function parameters.
|
|
|
|
|
Data is contained in arrays which objects are instances of classes of the application. I have tried to pass a reference of the object in the exported function but the parameter type is not known by the DLL.
I also tried to make the header file visible to the DLL and set a #include "myfile.h" in the DLL but this does not work.
|
|
|
|
|
I'm assuming you're getting compile time errors when compiling the DLL.
Please post the error messages and the relevant code.
|
|
|
|
|
Superman,
Please see the code posted to Albert Thread.
kind regards.
|
|
|
|
|
If you're going to pass by reference, your recipient (the DLL) needs the definition of what's enclosed, so it'll need the header file anyway. Just make sure it gets included into the DLL project as well.
|
|
|
|