202 lines
5.4 KiB
C++
202 lines
5.4 KiB
C++
/*
|
|
|
|
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)
|
|
|
|
|
|
|
|
#ifdef _CHICAGO_
|
|
//POSTPPC
|
|
INTERNAL_(BOOL) CDdeObject::CanMakeOutCall(LPDDE_CHANNEL pChannel)
|
|
{
|
|
intrDebugOut((DEB_ITRACE,"::CanMakeOutCall (%x) returns %d \n",pChannel,
|
|
(pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) ? FALSE : TRUE));
|
|
return (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) ? FALSE : TRUE;
|
|
}
|
|
#endif
|
|
|
|
|
|
INTERNAL CDdeObject::WaitForReply
|
|
(LPDDE_CHANNEL pChannel, int iAwaitAck, BOOL fStdCloseDoc, BOOL fDetectTerminate)
|
|
{
|
|
#ifdef _MAC
|
|
#else
|
|
CALLDATA CD;
|
|
IID iid = CLSID_NULL;
|
|
DDECALLDATA DdeCD;
|
|
MSG PrevMsg;
|
|
BOOL fPending;
|
|
HRESULT hres;
|
|
|
|
|
|
|
|
#if DBG == 1
|
|
unsigned iAutoCounter;
|
|
intrDebugOut((INTR_DDE,
|
|
"DdeObject::WaitForReply(%x) Call#(%x) awaiting %x\n",
|
|
this,
|
|
iAutoCounter=++iCounter,
|
|
iAwaitAck));
|
|
#endif
|
|
|
|
if (pChannel->pCD && (pChannel->pCD->id != CALLDATAID_UNUSED)) {
|
|
// this callinfo is in use
|
|
intrDebugOut((DEB_ERROR,
|
|
"DdeObject::WaitForReply(%x)ERROR: DDE: callinfo is used\n", this));
|
|
return ResultFromScode (E_UNEXPECTED);
|
|
}
|
|
|
|
|
|
// 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;
|
|
PrevMsg.message = 0;
|
|
PrevMsg.time = 0;
|
|
|
|
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 = pChannel->wMsg;
|
|
DdeCD.wParam = (WPARAM) pChannel->hwndCli,
|
|
DdeCD.lParam = pChannel->lParam;
|
|
DdeCD.fInitialSend = TRUE;
|
|
|
|
CD.id = CALLDATAID_UNUSED;
|
|
CD.lid = iid;
|
|
CD.TIDCallee = 0;
|
|
CD.pRpcMsg = (LPVOID) &DdeCD;
|
|
CD.CallCat = CALLCAT_SYNCHRONOUS;
|
|
CD.Event = 0;
|
|
|
|
pChannel->pCD = &CD;
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
hres = pChannel->pCallCont->CallRunModalLoop(&CD);
|
|
|
|
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));
|
|
|
|
pChannel->ReleaseReference();
|
|
|
|
// Excel will send TERMINATE before sending an ACK to StdCloseDoc
|
|
return ResultFromScode (fStdCloseDoc ? S_OK : 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
|
|
}
|