Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

315 lines
8.3 KiB

/*
copyright (c) 1992 Microsoft Corporation
Module Name:
modallp.cpp
Abstract:
This module contains the code to wait for reply on a remote call.
Author:
Johann Posch (johannp) 01-March-1993 modified to use CoRunModalLoop
*/
#include "ddeproxy.h"
#define DebWarn(x)
#define DebError(x)
#define DebAction(x)
#if DBG==1
static unsigned iCounter=0;
#endif
//
// Called after posting a message (call) to a server
//
#pragma SEG(CDdeObject_WaitForReply)
INTERNAL CDdeObject::SendMsgAndWaitForReply
(LPDDE_CHANNEL pChannel,
int iAwaitAck,
WORD wMsg,
long lparam,
BOOL fFreeOnError,
BOOL fStdCloseDoc,
BOOL fDetectTerminate,
BOOL fWait )
{
#ifdef _MAC
#else
DDECALLDATA DdeCD;
BOOL fPending;
HRESULT hres;
ULONG status = 0;
#if DBG == 1
unsigned iAutoCounter;
intrDebugOut((INTR_DDE,
"DdeObject::WaitForReply(%x) Call#(%x) awaiting %x\n",
this,
iAutoCounter=++iCounter,
iAwaitAck));
#endif
// make sure we have a call control. if OLE2 stuff has never been run,
// then we might not yet have a call control (since
// ChannelThreadInitialize may not have been be called).
COleTls tls;
CAptCallCtrl *pCallCtrl = tls->pCallCtrl;
if (pCallCtrl == NULL)
{
// OLE2 stuff has never been run and we dont yet have a CallCtrl
// for this thread. Go create one now. ctor adds it to the tls.
pCallCtrl = new CAptCallCtrl;
if (pCallCtrl == NULL)
{
intrDebugOut((DEB_ERROR,"SendRecieve2 couldn't alloc CallCtrl\n"));
return RPC_E_OUT_OF_RESOURCES;
}
}
// see if we can send the message, and then send it...
CALLCATEGORY CallCat = fWait ? CALLCAT_SYNCHRONOUS : CALLCAT_ASYNC;
if (pChannel->pCD != NULL)
{
// a DDE call is already in progress, dont let another DDE call out.
hres = E_UNEXPECTED;
}
else
{
// we dont know what interface is being called on, but we do
// know it is NOT IRemUnknown (IRundown) so it does not matter
// what we pass here as long as it is not IRemUnknown (IRundown).
hres = CanMakeOutCall(CallCat, IID_IUnknown);
}
if ( FAILED(hres) )
{
intrDebugOut((INTR_DDE, "CanMakeOutCall failed:%x\n", hres));
return hres;
}
// Note: this is to detect a premature DDE_TERMINATE
// here we care about if we receive a WM_DDE_TERMINATE instead ACK
// the next call to WaitForReply will detect this state and return
// since the terminate was send prematurly (Excel is one of this sucker)
//
if ( fDetectTerminate ) {
Assert(m_wTerminate == Terminate_None);
// if this flag is on terminate should not execute the default code
// in the window procedure
m_wTerminate = Terminate_Detect;
}
pChannel->iAwaitAck = iAwaitAck;
pChannel->dwStartTickCount = GetTickCount();
// start looking only for dde messages first
pChannel->msgFirst = WM_DDE_FIRST;
pChannel->msgLast = WM_DDE_LAST;
pChannel->msghwnd = pChannel->hwndCli;
pChannel->fRejected = FALSE;
// see if there is a thread window for lrpc communication
// if so we have to dispatch this messages as well
fPending = FALSE;
intrDebugOut((DEB_ITRACE,
"+++ Waiting for reply: server: %x, client %x Call#(%x) +++\n",
pChannel->hwndSvr,
pChannel->hwndCli,
iAutoCounter));
// prepare and enter the modal loop
DdeCD.hwndSvr = pChannel->hwndSvr;
DdeCD.hwndCli = pChannel->hwndCli;
DdeCD.wMsg = wMsg;
DdeCD.wParam = (WPARAM) pChannel->hwndCli,
DdeCD.lParam = lparam;
DdeCD.fDone = FALSE;
DdeCD.fFreeOnError = fFreeOnError;
DdeCD.pChannel = pChannel;
pChannel->pCD = &DdeCD;
//
// Setting this value tells DeleteChannel NOT to delete itself.
// If the value changes to Channel_DeleteNow while we are in
// the modal loop, this routine will delete the channel
//
pChannel->wChannelDeleted = Channel_InModalloop;
//
// hres will be the return code from the message
// handlers, or from the channel itself. The return
// code comes from calls to SetCallState. Most of the
// time, it will be things like RPC_E_DDE_NACK. However,
// it may also return OUTOFMEMORY, or other ModalLoop
// problems.
//
RPCOLEMESSAGE RpcOleMsg;
RpcOleMsg.Buffer = &DdeCD;
// Figure out the call category of this call by looking at the bit
// values in the rpc message flags.
DWORD dwMsgQInputFlag = gMsgQInputFlagTbl[CallCat];
// Now construct a modal loop object for the call that is about to
// be made. It maintains the call state and exits when the call has
// been completed, cancelled, or rejected.
CCliModalLoop CML(0, dwMsgQInputFlag);
do
{
hres = CML.SendReceive(&RpcOleMsg, &status, pChannel);
} while (hres == RPC_E_SERVERCALL_RETRYLATER);
if (hres != NOERROR)
{
intrDebugOut((DEB_ITRACE,
"**************** CallRunModalLoop returns %x ***\n",
hres));
}
if (m_wTerminate == Terminate_Received) {
intrAssert(fDetectTerminate);
//
// There really wasn't an error, its just that the server decided
// to terminate. If we return an error here, the app may decide
// that things have gone awry. Excel, for example, will decide
// that the object could not be activated, even though it has
// already updated its cache information.
//
hres = NOERROR;
intrDebugOut((DEB_ITRACE,
"::WaitForReply setting hres=%x\n",
hres));
intrDebugOut((DEB_ITRACE,
"::WaitForReply posting TERMINATE to self hwnd=%x\n",
DdeCD.hwndCli));
// set state to normal and repost message
Verify (PostMessage (DdeCD.hwndCli, WM_DDE_TERMINATE,
(WPARAM)DdeCD.hwndSvr, (LPARAM)0));
}
m_wTerminate = Terminate_None;
//
// If the channel is to be deleted, then do it now. This flag would
// have been set in the DeleteChannel routine.
//
if (pChannel->wChannelDeleted == Channel_DeleteNow)
{
intrDebugOut((INTR_DDE,
"::WaitForReply(%x) Channel_DeleteNow pChannel(%x)\n",
pChannel));
// If the channel is closed then its pointer in the DdeChannel must
// be NULL. This assumes that the passed in "pChannel" is always
// equal to either the "Doc" or "Sys" member channels.
// This code fragment is patterned after a code fragment
// found in CDdechannel::DeleteChannel().
if(0 == pChannel->ReleaseReference())
{
if(pChannel == m_pDocChannel)
{
m_pDocChannel = NULL;
}
else
{
Assert(pChannel == m_pSysChannel);
m_pSysChannel = NULL;
}
}
// Excel will send TERMINATE before sending an ACK to StdCloseDoc
return ResultFromScode (fStdCloseDoc ? DDE_CHANNEL_DELETED : RPC_E_DDE_POST);
}
pChannel->wChannelDeleted = 0;
pChannel->iAwaitAck = 0;
pChannel->pCD = NULL;
intrDebugOut((DEB_ITRACE,
"### Waiting for reply done: server: %x, client %x hres(%x)###\n",
pChannel->hwndSvr,
pChannel->hwndCli,
hres));
return hres;
#endif _MAC
}
// Provided IRpcChannelBuffer2 methods
HRESULT DDE_CHANNEL::SendReceive2(
/* [out][in] */ RPCOLEMESSAGE __RPC_FAR *pMessage,
/* [out] */ ULONG __RPC_FAR *pStatus)
{
pCD = (DDECALLDATA *) pMessage->Buffer;
if(!wPostMessageToServer(pCD->pChannel,
pCD->wMsg,
pCD->lParam,
pCD->fFreeOnError))
{
intrDebugOut((DEB_ITRACE, "SendRecieve2(%x)wPostMessageToServer failed", this));
return RPC_E_SERVER_DIED;
}
CAptCallCtrl *pCallCtrl = GetAptCallCtrl();
CCliModalLoop *pCML = pCallCtrl->GetTopCML();
hres = S_OK;
BOOL fWait = !pCD->fDone;
while (fWait)
{
HRESULT hr = OleModalLoopBlockFn(NULL, pCML, NULL);
if (pCD->fDone)
{
fWait = FALSE;
}
else if (hr != RPC_S_CALLPENDING)
{
fWait = FALSE;
hres = hr; // return result from OleModalLoopBlockFn()
}
}
if (FAILED(hres))
{
intrDebugOut((DEB_ITRACE, "**** CallRunModalLoop returns %x ***\n", hres));
}
return hres;
}
void DDE_CHANNEL::SetCallState(SERVERCALLEX ServerCall, HRESULT hr)
{
CallState = ServerCall;
hres = hr;
Win4Assert(pCD);
pCD->fDone = TRUE;
}