|
|
|
|
|
Peter has already given a partial answer to your question.
just consider the below example
class A
{
public:
A()
{
cout << "A::A\n";
}
};
class B : public A
{
public:
B()
{
cout << "B::B\n";
}
};
class C : public B
{
public:
C()
{
cout << "C::C\n";
}
};
int main()
{
A* a = new C();
return 0;
}
What will be the output
A::A
B::B
C::C
right??
means the order of object creation is like A->B->C
and C objects reference is being put into A's pointer
In your code
There are two object creation order
like A->B->D
and
like A->C->D
Here compler would be confused which D's reference comes to A's pointer???
That is why there is compilation error. c++ provides us something through which we can overcome this problem. Thats the virtual class.
You might have heard of diamond problem in c++. This what happens here.
you can change you code like below.
class A{};
class B : virtual public A{};
class C : virtual public A{};
class D : public B, public C{};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new D();
}
note the key word virtual.
Now the order of object creation will be like A->B->C->D. you can print some thing in constructure of each class and can see this.
In the second code snippet
class A{};
class B : public A{};
class C : public A{};
class D : public B, public C{};
int _tmain(int argc, _TCHAR* argv[])
{
B* b = new D();
}
There is no confusion for the compiler even though there are 2 object creation order.
One like A->B->D and another like A->C->D. But you have clearly mentioned that D objects refernce goes to B's pointer.
So complier will take A->B->D order and put this into B's pointer. But C object also will be created.
Now it is clear that why the third code snippet cause an error.
B's pointer stores a reference of D object being created in the order A->B->D. There is no Func() function on the way. Is there??
|
|
|
|
|
Resmi Anna wrote: That is why there is compilation error. c++ provides us something through which we can overcome this problem.
That's improper. virtual bases are not "the solution to ambiguity".
Are just "another thing".
If A is inherited twice because it must be inherited twice, it is not removing one of them that you "solve" THE problem. You actually soleve A problem, and introduce something else.
The layout of D in the first case is
D[B[A]C[A]]
and in the second case is
D[B[.]C[.]A]
(note: '.' is a pointer to A, internal to the compiler generated structure)
That's not equivalent to the first.
2 bugs found.
> recompile ...
65534 bugs found.
|
|
|
|
|
|
Hi,
I have created a checkbox using MFCRibbonCheckBox. Depending on certain conditions i want to disbale it.
But it does not have any property for disabling. Can anybody help me out?
thanx in advance
|
|
|
|
|
Please don't cross post.
CQ de W5ALT
Walt Fair, Jr., P. E.
Comport Computing
Specializing in Technical Engineering Software
|
|
|
|
|
Never used the MFC version of the ribbon bar but you probably need to use ON_UPDATE_COMMAND_UI[^], try googling for it if you don't know how it works.
> The problem with computers is that they do what you tell them to do and not what you want them to do. <
> //TODO: Implement signature here<
|
|
|
|
|
What does it mean when I see in the value for an object is set to + m_Bitmap 0xaf050c5e {unused=??? } HBITMAP__ * for a variable in my watch list? Is this telling me that this particular memory location is used? Also, I sometimes see a memory address of ,0xcdcdcdcd, is this correct?
Thanks, I am trying to track the value of a pointer that I think is bad.
|
|
|
|
|
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
|
|
|
|