diff options
Diffstat (limited to 'svl/source/svdde/ddeml1.cxx')
-rw-r--r-- | svl/source/svdde/ddeml1.cxx | 2661 |
1 files changed, 2661 insertions, 0 deletions
diff --git a/svl/source/svdde/ddeml1.cxx b/svl/source/svdde/ddeml1.cxx new file mode 100644 index 000000000000..9d1351b17f16 --- /dev/null +++ b/svl/source/svdde/ddeml1.cxx @@ -0,0 +1,2661 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: ddeml1.cxx,v $ + * $Revision: 1.5 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svl.hxx" + +/* + ToDo / Bugs: + + - DdeInitiate: Eigener Thread? + - Timeout bei Disconnects (IBM:nicht auf Ack warten!) + - Konzept Errorhandling (globale/lokale Fehler) + - Bedeutung/Anwendung Conversation-Contexte + - Bei Zugriffen auf ConversationHandles WindowHandles checken + - Namen der Partner-App ermitteln + - Codepage-Geraffel +*/ +#define INCL_DOSPROCESS + +#include "ddemlimp.hxx" + +#define LOGFILE +#define STATUSFILE +#define DDEDATAFILE +#include "ddemldeb.hxx" + + +#if defined (OS2) && defined (__BORLANDC__) +#pragma option -w-par +#endif + +// static +inline BOOL ImpDdeMgr::MyWinDdePostMsg( HWND hWndTo, HWND hWndFrom, + USHORT nMsg, PDDESTRUCT pData, ULONG nFlags ) +{ + BOOL bSuccess = WinDdePostMsg( hWndTo,hWndFrom,nMsg,pData,nFlags); + if( !bSuccess ) + { + WRITELOG("WinDdePostMsg:Failed!") + if ( !(nFlags & DDEPM_NOFREE) ) + { + MyDosFreeMem( pData,"MyWinDdePostMsg" ); + } + } + return bSuccess; +} + + +// ********************************************************************* +// ImpDdeMgr +// ********************************************************************* + +USHORT ImpDdeMgr::nLastErrInstance = 0; + +// +// Conversation-WndProc +// Steuert Transaktionen eines Conversationhandles +// +MRESULT EXPENTRY ConvWndProc(HWND hWnd,ULONG nMsg,MPARAM nPar1,MPARAM nPar2) +{ +#if defined(DBG_UTIL) && defined(OV_DEBUG) + if( nMsg >= WM_DDE_FIRST && nMsg <= WM_DDE_LAST) + { + ////WRITELOG("::ConvWndProc:DDE-Msg received") + } +#endif + ImpConvWndData* pObj = (ImpConvWndData*)WinQueryWindowULong( hWnd, 0 ); + return pObj->pThis->ConvWndProc( hWnd, nMsg, nPar1, nPar2 ); +} + +// +// Server-WndProc +// DDE-Server-Window der App +// +MRESULT EXPENTRY ServerWndProc(HWND hWnd,ULONG nMsg,MPARAM nPar1,MPARAM nPar2) +{ +#if defined(DBG_UTIL) && defined(OV_DEBUG) + if( nMsg >= WM_DDE_FIRST && nMsg <= WM_DDE_LAST) + { + ////WRITELOG("::ServerWndProc:DDE-Msg received") + } +#endif + ImpDdeMgr* pObj = (ImpDdeMgr*)WinQueryWindowULong( hWnd, 0 ); + return pObj->SrvWndProc( hWnd, nMsg, nPar1, nPar2 ); +} + + +inline HDDEDATA ImpDdeMgr::Callback( USHORT nTransactionType, + USHORT nClipboardFormat, HCONV hConversationHandle, HSZ hsz1, + HSZ hsz2, HDDEDATA hData, ULONG nData1, ULONG nData2 ) +{ + HDDEDATA hRet = (HDDEDATA)0; + if( pCallback ) + hRet = (*pCallback)(nTransactionType, nClipboardFormat, + hConversationHandle, hsz1, hsz2, hData, nData1, nData2); + return hRet; +} + + + +ImpDdeMgr::ImpDdeMgr() +{ + nLastErrInstance = DMLERR_NO_ERROR; + pCallback = 0; + nTransactFilter = 0; + nServiceCount = 0; + pServices = 0; + pAppTable = 0; + pConvTable = 0; + pTransTable = 0; + bServFilterOn = TRUE; + bInSyncTrans = FALSE; + + CreateServerWnd(); + pData = InitAll(); + if ( !pData ) + nLastErrInstance = DMLERR_MEMORY_ERROR; + else + RegisterDDEMLApp(); +} + +ImpDdeMgr::~ImpDdeMgr() +{ + CleanUp(); + DestroyServerWnd(); +// Named Shared Mem vom BS loeschen lassen, da nicht bekannt ist, +// wieviele DDEML-Instanzen die App erzeugt hat, und OS/2 +// keinen App-Referenzzaehler fuer shared mem fuehrt. +// if ( pData ) +// DosFreeMem( pData ); +} + + +BOOL ImpDdeMgr::IsSameInstance( HWND hWnd ) +{ + TID tid; PID pid; + WinQueryWindowProcess( hWnd, &pid, &tid ); + return (BOOL)(pid == pidThis); +} + +HSZ ImpDdeMgr::GetAppName( HWND hWnd ) +{ + return 0; +} + +// static +ImpDdeMgr* ImpDdeMgr::GetImpDdeMgrInstance( HWND hWnd ) +{ + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + if( !pData ) + return 0; + + ImpDdeMgr* pResult = 0; + TID tid; PID pidApp; + WinQueryWindowProcess( hWnd, &pidApp, &tid ); + HWND* pApp = ImpDdeMgr::GetAppTable( pData ); + USHORT nCurApp = 0; + while( nCurApp < pData->nMaxAppCount ) + { + HWND hCurWin = *pApp; + if( hCurWin ) + { + PID pidCurApp; + WinQueryWindowProcess( hCurWin, &pidCurApp, &tid ); + if( pidCurApp == pidApp ) + { + pResult = (ImpDdeMgr*)WinQueryWindowULong( hCurWin, 0 ); + break; + } + } + pApp++; + nCurApp++; + } + return pResult; +} + + + + + +void ImpDdeMgr::CleanUp() +{ + DisconnectAll(); + ImpService* pPtr = pServices; + if( pPtr ) + { + for( USHORT nIdx = 0; nIdx < nServiceCount; nIdx++, pPtr++ ) + { + HSZ hStr = pPtr->hBaseServName; + if( hStr ) + DdeFreeStringHandle( hStr ); + hStr = pPtr->hInstServName; + if( hStr ) + DdeFreeStringHandle( hStr ); + } + nServiceCount = 0; + delete pServices; + pServices = 0; + } + bServFilterOn = TRUE; // default setting DDEML + UnregisterDDEMLApp(); +} + +void ImpDdeMgr::RegisterDDEMLApp() +{ + HWND* pPtr = pAppTable; + HWND hCur; + USHORT nPos = 0; + while( nPos < pData->nMaxAppCount ) + { + hCur = *pPtr; + if (hCur == (HWND)0 ) + { + // in Tabelle stellen + *pPtr = hWndServer; + break; + } + nPos++; + pPtr++; + } +} + +void ImpDdeMgr::UnregisterDDEMLApp() +{ + HWND* pPtr = pAppTable; + USHORT nPos = 0; + while( nPos < pData->nMaxAppCount ) + { + if (*pPtr == hWndServer ) + { + *pPtr = 0; + break; + } + nPos++; + pPtr++; + } +} + +// static +ImpDdeMgrData* ImpDdeMgr::AccessMgrData() +{ + ImpDdeMgrData* pData = 0; + APIRET nRet = DosGetNamedSharedMem((PPVOID)&pData,DDEMLDATA,PAG_READ|PAG_WRITE); + DBG_ASSERT(!nRet,"DDE:AccessMgrData failed"); + return pData; +} + +USHORT ImpDdeMgr::DdeGetLastError() +{ + USHORT nErr; + if ( !pData ) + nErr = DMLERR_DLL_NOT_INITIALIZED; + else if ( nLastErrInstance ) + nErr = nLastErrInstance; + else + nErr = pData->nLastErr; + + nLastErrInstance = 0; + pData->nLastErr = 0; + return nErr; +} + + + +USHORT ImpDdeMgr::DdeInitialize( PFNCALLBACK pCallbackProc, ULONG nTransactionFilter ) +{ + if ( !nLastErrInstance ) + { + if ( !pCallbackProc ) + { + nLastErrInstance = DMLERR_INVALIDPARAMETER; + return nLastErrInstance; + } + pCallback = pCallbackProc; + nTransactFilter = nTransactionFilter; + nTransactFilter |= CBF_FAIL_SELFCONNECTIONS; + } + return nLastErrInstance; +} + + +// static +HWND ImpDdeMgr::NextFrameWin( HENUM hEnum ) +{ + char aBuf[ 10 ]; + + HWND hWnd = WinGetNextWindow( hEnum ); + while( hWnd ) + { + WinQueryClassName( hWnd, sizeof(aBuf)-1, (PCH)aBuf ); + // Frame-Window ? + if( !strcmp( aBuf, "#1" ) ) // #define WC_FRAME ((PSZ)0xffff0001L) + break; + hWnd = WinGetNextWindow( hEnum ); + } + return hWnd; +} + + +HCONV ImpDdeMgr::DdeConnectImp( HSZ hszService,HSZ hszTopic,CONVCONTEXT* pCC) +{ + hCurConv = 0; + if( !pCC ) + pCC = &aDefaultContext; + + ULONG nBufLen; + PSZ pService = AllocAtomName( (ATOM)hszService, nBufLen ); + PSZ pTopic = AllocAtomName( (ATOM)hszTopic, nBufLen ); +#if 0 && defined(OV_DEBUG) + String aStr("DdeConnectImp Service:"); + aStr += pService; + aStr += " Topic:"; + aStr += pTopic; + WRITELOG((char*)(const char*)aStr) +#endif + +#if defined(OV_DEBUG) + if( !strcmp(pService,"oliver voeltz") ) + { + WRITESTATUS("Table of connections"); + MyDosFreeMem( pTopic,"DdeConnectImp" ); + MyDosFreeMem( pService,"DdeConnectImp" ); + return 0; + } +#endif + +#if 0 + // original pm-fkt benutzen + HWND hWndCurClient = CreateConversationWnd(); + WinDdeInitiate( hWndCurClient, pService, pTopic, pCC ); + if( GetConversationWndRefCount(hWndCurClient) == 0) + DestroyConversationWnd( hWndCurClient ); +#else + // eigener Verbindungsaufbau + HENUM hEnum = WinBeginEnumWindows( HWND_DESKTOP ); + HWND hWndCurSrv = NextFrameWin( hEnum ); + HWND hWndCurClient = CreateConversationWnd(); + while( hWndCurSrv && !hCurConv ) + { + if( hWndCurSrv != hWndServer || + ((nTransactFilter & CBF_FAIL_SELFCONNECTIONS)==0 )) + { + // pro DDE-Server ein Conversation-Window erzeugen + if( GetConversationWndRefCount(hWndCurClient) >= 2) + { + DestroyConversationWnd( hWndCurClient ); + hWndCurClient = CreateConversationWnd(); + } + MyInitiateDde(hWndCurSrv,hWndCurClient,hszService,hszTopic,pCC); + if( !bListConnect && hCurConv ) + break; + } + hWndCurSrv = NextFrameWin( hEnum ); + } + + if( GetConversationWndRefCount(hWndCurClient) == 0) + DestroyConversationWnd( hWndCurClient ); + WinEndEnumWindows( hEnum ); +#endif + + if( !hCurConv ) + nLastErrInstance = DMLERR_NO_CONV_ESTABLISHED; + +#if 0 && defined(OV_DEBUG) + String aCStr( "DdeConnectImp:End "); + if( nLastErrInstance != DMLERR_NO_CONV_ESTABLISHED ) + aCStr += "(Success)"; + else + aCStr += "(Failed)"; + WRITELOG((char*)aCStr.GetStr()) +#endif + + MyDosFreeMem( pTopic,"DdeConnectImp" ); + MyDosFreeMem( pService,"DdeConnectImp" ); + return hCurConv; +} + +HCONV ImpDdeMgr::DdeConnect( HSZ hszService, HSZ hszTopic, CONVCONTEXT* pCC) +{ + ////WRITELOG("DdeConnect:Start") + bListConnect = FALSE; + HCONV hResult = DdeConnectImp( hszService, hszTopic, pCC ); + ////WRITELOG("DdeConnect:End") + ////WRITESTATUS("DdeConnect:End") + return hResult; +} + + +HCONVLIST ImpDdeMgr::DdeConnectList( HSZ hszService, HSZ hszTopic, + HCONVLIST hConvList, CONVCONTEXT* pCC ) +{ + nPrevConv = 0; + ////WRITESTATUS("Before DdeConnectList") + if( hConvList ) + { + HCONV hLastConvInList; + + hCurListId = hConvList; + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConvList; + if( (USHORT)hConvList >= pData->nMaxConvCount ||pConv->hWndThis==0 ) + { + nLastErrInstance = DMLERR_INVALIDPARAMETER; + return 0; + } + GetLastServer(pData, hConvList, hLastConvInList); + nPrevConv = (USHORT)hLastConvInList; + } + else + hCurListId = (HCONVLIST)WinCreateWindow( HWND_OBJECT, WC_FRAME, + CONVLISTNAME, 0,0,0,0,0, HWND_DESKTOP, HWND_BOTTOM, 0,0,0); + + bListConnect = TRUE; + DdeConnectImp( hszService, hszTopic, pCC ); +#if 0 && defined(OV_DEBUG) + WRITELOG("DdeConnectList:ConnectionList:") + HCONV hDebug = 0; + do + { + hDebug = DdeQueryNextServer( hCurListId, hDebug); + String aStr( (ULONG)hDebug ); + WRITELOG((char*)(const char*)aStr) + } while( hDebug ); +#endif + ////WRITESTATUS("After DdeConnectList") + return (HCONVLIST)hCurListId; +} + +DDEINIT* ImpDdeMgr::CreateDDEInitData( HWND hWndDestination, HSZ hszService, + HSZ hszTopic, CONVCONTEXT* pCC ) +{ + ULONG nLen1 = 0, nLen2 = 0; + HATOMTBL hAtomTable = WinQuerySystemAtomTable(); + + if( hszService ) + nLen1 = WinQueryAtomLength( hAtomTable, hszService ); + if( hszTopic ) + nLen2 = WinQueryAtomLength( hAtomTable, hszTopic ); + nLen1++; nLen2++; + + DDEINIT* pBuf = 0; + + ULONG nLen = sizeof(DDEINIT) + nLen1+ nLen2 + sizeof(CONVCONTEXT); + if( !(MyDosAllocSharedMem((PPVOID)&pBuf, NULL, nLen, + PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE | OBJ_ANY, + "CreateDDEInitData"))) + { + memset( pBuf, 0, nLen ); + + /* + PID pid; TID tid; + WinQueryWindowProcess( hWndDestination, &pid, &tid ); + APIRET nRet = DosGiveSharedMem( pBuf, pid, PAG_READ | PAG_WRITE ); + */ + + pBuf->cb = nLen; + pBuf->offConvContext = sizeof( DDEINIT ); + char* pBase = (char*)pBuf; + pBase += sizeof(DDEINIT); + if( pCC ) + memcpy( pBase, pCC, sizeof(CONVCONTEXT) ); + pBase += sizeof(CONVCONTEXT); + pBuf->pszAppName = pBase; + if( hszService ) + WinQueryAtomName( hAtomTable, hszService, pBase, nLen1 ); + pBase += nLen1; + pBuf->pszTopic = pBase; + if( hszTopic ) + WinQueryAtomName( hAtomTable, hszTopic, pBase, nLen2 ); + } + return pBuf; +} + + + +void ImpDdeMgr::MyInitiateDde( HWND hWndSrv, HWND hWndClient, + HSZ hszService, HSZ hszTopic, CONVCONTEXT* pCC ) +{ + DDEINIT* pBuf = CreateDDEInitData( hWndSrv, hszService, hszTopic, pCC ); + if( pBuf ) + { + PID pid; TID tid; + WinQueryWindowProcess( hWndSrv, &pid, &tid ); + APIRET nRet = DosGiveSharedMem( pBuf, pid, PAG_READ | PAG_WRITE ); + WinSendMsg( hWndSrv,WM_DDE_INITIATE,(MPARAM)hWndClient,(MPARAM)pBuf); + MyDosFreeMem( pBuf,"MyInitiateDde" ); + } +} + +// static +ImpHCONV* ImpDdeMgr::GetFirstServer(ImpDdeMgrData* pData, HCONVLIST hConvList, + HCONV& rhConv ) +{ + ImpHCONV* pPtr = GetConvTable( pData ); + HCONV hConv; + if( !rhConv ) + { + pPtr++; + hConv = 1; + } + else + { + // Startposition + pPtr += (USHORT)rhConv; + hConv = rhConv; + pPtr++; hConv++; // auf den naechsten + } + while( hConv < pData->nMaxConvCount ) + { + if( pPtr->hConvList == hConvList ) + { + rhConv = hConv; + return pPtr; + } + pPtr++; + hConv++; + } + rhConv = 0; + return 0; +} + +// static +ImpHCONV* ImpDdeMgr::GetLastServer(ImpDdeMgrData* pData, HCONVLIST hConvList, + HCONV& rhConv ) +{ + ImpHCONV* pPtr = GetConvTable( pData ); + pPtr += pData->nMaxConvCount; + pPtr--; + HCONV hConv = pData->nMaxConvCount; + hConv--; + while( hConv > 0 ) + { + if( pPtr->hConvList == hConvList ) + { + rhConv = hConv; + return pPtr; + } + pPtr--; + hConv--; + } + rhConv = 0; + return 0; +} + +// static +BOOL ImpDdeMgr::CheckConvListId( HCONVLIST hConvListId ) +{ + HAB hAB = WinQueryAnchorBlock( (HWND)hConvListId ); + if( hAB ) + return WinIsWindow( hAB, (HWND)hConvListId ); + return FALSE; + /* + HAB hAB = WinQueryAnchorBlock( (HWND)hConvListId ); + if( hAB ) + { + char aBuf[ 16 ]; + WinQueryWindowText( (HWND)hConvListId, sizeof(aBuf), aBuf ); + if( strcmp(aBuf, CONVLISTNAME ) == 0 ) + return TRUE; + } + return FALSE; + */ +} + +// static +HCONV ImpDdeMgr::DdeQueryNextServer(HCONVLIST hConvList, HCONV hConvPrev) +{ + if( !CheckConvListId( hConvList ) ) + return (HCONV)0; + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + GetFirstServer( pData, hConvList, hConvPrev ); + return hConvPrev; +} + +// static + +// Idee: DisconnectAll uebergibt das ServerWindow. Zu jedem HCONV +// wird das Creator-Server-Wnd gespeichert. Disconnect braucht +// dann nur noch die Window-Handles zu vergleichen +BOOL ImpDdeMgr::DdeDisconnect( HCONV hConv ) +{ + WRITELOG("DdeDisconnect:Start") + ////WRITESTATUS("DdeDisconnect:Start") + + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + if ( !pData ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_DLL_NOT_INITIALIZED; + return FALSE; + } + ImpHCONV* pConv = GetConvTable(pData) + (USHORT)hConv; + + if( (USHORT)hConv >= pData->nMaxConvCount || pConv->hWndThis==0 ) + { + nLastErrInstance = DMLERR_NO_CONV_ESTABLISHED; + return FALSE; + } + + PID pidApp; TID tid; + HWND hWndDummy = WinCreateWindow( HWND_OBJECT, WC_FRAME, + "Bla", 0, 0,0,0,0, HWND_DESKTOP, HWND_BOTTOM, 0, 0, 0 ); + WinQueryWindowProcess( hWndDummy, &pidApp, &tid ); + WinDestroyWindow( hWndDummy ); + PID pidThis; PID pidPartner; + + HWND hWndThis = pConv->hWndThis; + HWND hWndPartner = pConv->hWndPartner; + + WinQueryWindowProcess( hWndThis, &pidThis, &tid ); + WinQueryWindowProcess( hWndPartner, &pidPartner, &tid ); + if( pidApp != pidThis && pidApp != pidPartner ) + return TRUE; // gehoert nicht der App -> ueberspringen + + HCONV hConvPartner = pConv->hConvPartner; + + // die App benachrichtigen, dass alle offenen Advise-Loops + // beendet werden, egal ob sie vom Server oder Client + // initiiert wurden. Die Dinger aber nicht loeschen, da sie evtl. + // noch vom Partner gebraucht werden. + ImpConvWndData* pObj = + (ImpConvWndData*)WinQueryWindowULong( pConv->hWndThis, 0 ); + ImpDdeMgr* pThis = pObj->pThis; + pThis->SendUnadvises( hConv, 0, FALSE ); // alle Formate & NICHT loeschen + pThis->SendUnadvises( hConvPartner, 0, FALSE ); // alle Formate & NICHT loeschen + + pConv->nStatus |= ST_TERMINATED; + + HAB hAB = WinQueryAnchorBlock( pConv->hWndThis ); + // um die MessageQueue inne Gaenge zu halten + ULONG nTimerId = WinStartTimer( hAB, 0, 0, 50 ); + + /* + Die Partner-App muss ein DDE_TERMINATE posten, auf das + wir warten muessen, um alle Messages zu bearbeiten, die + _vor_ dem DdeDisconnect von der Partner-App gepostet + wurden. + */ + WRITELOG("DdeDisconnect:Waiting for acknowledge...") + WinDdePostMsg( hWndPartner, hWndThis, WM_DDE_TERMINATE, + (PDDESTRUCT)0,DDEPM_RETRY); + + QMSG aQueueMsg; + BOOL bContinue = TRUE; + while( bContinue ) + { + if( WinGetMsg( hAB, &aQueueMsg, 0, 0, 0 )) + { + WinDispatchMsg( hAB, &aQueueMsg ); + if( (!WinIsWindow( hAB, hWndPartner)) || + (pConv->nStatus & ST_TERMACKREC) ) + { + bContinue = FALSE; + if( pConv->nStatus & ST_TERMACKREC ) + { + WRITELOG("DdeDisconnect: TermAck received") + } + else + { + WRITELOG("DdeDisconnect: Partner died") + } + } + } + else + bContinue = FALSE; + } + + WinStopTimer( hAB, 0, nTimerId ); + + // WRITELOG("DdeDisconnect:Freeing data") + // Transaktionstabelle aufraeumen + FreeTransactions( pData, hConv ); + if( hConvPartner ) + FreeTransactions( pData, hConvPartner ); + + FreeConvHandle( pData, hConv ); + + WRITELOG("DdeDisconnect:End") + //WRITESTATUS("DdeDisconnect:End") + return TRUE; +} + +// static +BOOL ImpDdeMgr::DdeDisconnectList( HCONVLIST hConvList ) +{ + if( !CheckConvListId( hConvList ) ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_INVALIDPARAMETER; + return FALSE; + } + + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + if ( !pData ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_DLL_NOT_INITIALIZED; + return FALSE; + } + HCONV hConv = 0; + GetFirstServer( pData, hConvList, hConv ); + while( hConv ) + { + DdeDisconnect( hConv ); + GetFirstServer( pData, hConvList, hConv ); + } + WinDestroyWindow( (HWND)hConvList ); + return TRUE; +} + + + +// static +HCONV ImpDdeMgr::DdeReconnect(HCONV hConv) +{ + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + if ( !pData ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_DLL_NOT_INITIALIZED; + return 0; + } + return 0; +} + +// static +USHORT ImpDdeMgr::DdeQueryConvInfo(HCONV hConv, ULONG nTransId, CONVINFO* pCI) +{ + if( !pCI || pCI->nSize == 0) + return 0; + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + if ( !pData ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_DLL_NOT_INITIALIZED; + return 0; + } + Transaction* pTrans; + if( nTransId != QID_SYNC ) + { + pTrans = ImpDdeMgr::GetTransTable( pData ); + pTrans += nTransId; + if( nTransId >= pData->nMaxTransCount || pTrans->hConvOwner == 0 ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_UNFOUND_QUEUE_ID; + return 0; + } + } + else + pTrans = 0; + + ImpHCONV* pConv = ImpDdeMgr::GetConvTable( pData ); + pConv += (ULONG)hConv; + if( hConv >= pData->nMaxConvCount || pConv->hWndThis == 0 ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_NO_CONV_ESTABLISHED; + return 0; + } + + USHORT nSize = pCI->nSize; + if( nSize > sizeof(CONVINFO) ) + nSize = sizeof(CONVINFO); + CONVINFO aTempInfo; + memset( &aTempInfo, 0, sizeof(CONVINFO) ); + aTempInfo.nSize = pCI->nSize; + aTempInfo.hConvPartner = pConv->hConvPartner; + aTempInfo.hszPartner = pConv->hszPartner; + aTempInfo.hszServiceReq = pConv->hszServiceReq; + aTempInfo.hszTopic = pConv->hszTopic; + aTempInfo.nStatus = pConv->nStatus; + aTempInfo.hConvList = pConv->hConvList; + aTempInfo.aConvCtxt = pConv->aConvContext; + if( pTrans ) + { + aTempInfo.nUser = pTrans->nUser; + aTempInfo.hszItem = pTrans->hszItem; + aTempInfo.nFormat = pTrans->nFormat; + aTempInfo.nType = pTrans->nType; + aTempInfo.nConvst = pTrans->nConvst; + aTempInfo.nLastError= pTrans->nLastError; + } + memcpy( pCI, &aTempInfo, nSize ); + + return nSize; +} + +// static +BOOL ImpDdeMgr::DdeSetUserHandle(HCONV hConv, ULONG nTransId, ULONG hUser) +{ + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + if ( !pData ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_DLL_NOT_INITIALIZED; + return FALSE; + } + Transaction* pTrans = GetTransTable( pData ); + pTrans += nTransId; + if( !nTransId || !hConv || nTransId >= pData->nMaxTransCount || + pTrans->hConvOwner != hConv ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_INVALIDPARAMETER; + return FALSE; + } + if( !pTrans->hConvOwner) + { + ImpDdeMgr::nLastErrInstance = DMLERR_UNFOUND_QUEUE_ID; + return FALSE; + } + pTrans->nUser = hUser; + return TRUE; +} + +BOOL ImpDdeMgr::DdeAbandonTransaction( HCONV hConv, ULONG nTransId ) +{ + ////WRITELOG("DdeAbandonTransaction:Start") + if( !pData ) + { + nLastErrInstance = DMLERR_DLL_NOT_INITIALIZED; + return FALSE; + } + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + if( nTransId < 1 || nTransId >= pData->nMaxTransCount || + hConv < 1 || hConv >= pData->nMaxConvCount || !pConv->hWndThis) + { + nLastErrInstance = DMLERR_INVALIDPARAMETER; + return FALSE; + } + if( !hConv ) + { + DBG_ASSERT(0,"DdeAbandonTransaction:NULL-hConv not supported"); + nLastErrInstance = DMLERR_INVALIDPARAMETER; + return FALSE; + } + Transaction* pTrans = pTransTable; + pTrans += (USHORT)nTransId; + if( pTrans->hConvOwner != hConv ) + { + nLastErrInstance = DMLERR_UNFOUND_QUEUE_ID; + return FALSE; + } + + if( bInSyncTrans && nTransId == nSyncTransId ) + { + bSyncAbandonTrans = TRUE; + return TRUE; + } + USHORT nTempType = pTrans->nType; + nTempType &= (~XTYPF_MASK); + if( nTempType == (XTYP_ADVREQ & ~(XTYPF_NOBLOCK))) + { + ////WRITELOG("DdeAbandTrans:Advise Loop") + +// ---------------------------------------------------------------------- +// Der von der Deutschen Bank eingesetzte DDE-Server +// "Invision V2.71 Build 36 Mar 12 1999 V4.8.2" hat einen Bug, der +// dazu fuehrt, dass auf per WM_DDE_TERMINATE geschlossene Verbindungen +// nicht mit einem WM_DDE_TERMINATE geantwortet wird, wenn der +// entsprechende Link vorher per WM_DDE_UNADVISE beendet wurde. Dieser +// Bug tritt ab zwei parallel laufenden Links auf. Auf Wunsch der DB +// wurde das folgende Workaround eingebaut. +// ---------------------------------------------------------------------- +#define DEUTSCHE_BANK +#ifndef DEUTSCHE_BANK + +// Acknowledge ist beim Unadvise nicht ueblich +//#define SO_DDE_ABANDON_TRANSACTION_WAIT_ACK +#ifdef SO_DDE_ABANDON_TRANSACTION_WAIT_ACK + DDESTRUCT* pOutDDEData = MakeDDEObject( pConv->hWndPartner, + pTrans->hszItem, DDE_FACKREQ, 0 /*pTrans->nFormat*/, 0, 0); +#else + DDESTRUCT* pOutDDEData = MakeDDEObject( pConv->hWndPartner, + pTrans->hszItem, 0, 0 /*pTrans->nFormat*/, 0, 0); +#endif + WRITELOG("DdeAbandTrans:Waiting for acknowledge...") + pTrans->nConvst = XST_UNADVSENT; + if ( !MyWinDdePostMsg( pConv->hWndPartner, pConv->hWndThis, + WM_DDE_UNADVISE, pOutDDEData, DDEPM_RETRY ) ) + { + WRITELOG("DdeAbandTrans:PostMsg Failed") + return FALSE; + } +#ifdef SO_DDE_ABANDON_TRANSACTION_WAIT_ACK + WaitTransState( pTrans, nTransId, XST_UNADVACKRCVD, 0 ); +#else + pTrans->nConvst = XST_UNADVACKRCVD; +#endif + +#endif // DEUTSCHE_BANK + + WRITELOG("DdeAbandTrans:Ack received->Freeing transaction") + FreeTransaction( pData, nTransId ); + } + WRITELOG("DdeAbandonTransaction:End") + return TRUE; +} + +// wird von einem Server aufgerufen, wenn sich die Daten des +// Topic/Item-Paars geaendert haben. Diese Funktion fordert +// dann den Server auf, die Daten zu rendern (bei Hotlinks) und +// benachrichtigt die Clients +BOOL ImpDdeMgr::DdePostAdvise( HSZ hszTopic, HSZ hszItem) +{ + ////WRITELOG("DdePostAdvise:Start") + ////WRITESTATUS("DdePostAdvise:Start") + +#if 0 && defined( OV_DEBUG ) + String aDebStr("DdePostAdvise:Item "); + aDebStr += (ULONG)hszItem; + WRITELOG((char*)(const char*)aDebStr) +#endif + + Transaction* pTrans = pTransTable; + pTrans++; + USHORT nCurTrans = 1; + USHORT nUsedTransactions = pData->nCurTransCount; + while( nUsedTransactions && nCurTrans < pData->nMaxTransCount ) + { + HCONV hOwner = pTrans->hConvOwner; + if( hOwner ) + { + nUsedTransactions--; + USHORT nTempType = pTrans->nType; + nTempType &= (~XTYPF_MASK); + if( nTempType == (XTYP_ADVREQ & (~XTYPF_NOBLOCK) ) ) + { + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hOwner; + if(hszItem == pTrans->hszItem && pConv->hszTopic == hszTopic) + { + if( pConv->hConvPartner ) + { + // Transaktionen werden immer vom Client erzeugt + // -> auf Server-HCONV umschalten + hOwner = pConv->hConvPartner; + pConv = pConvTable; + pConv += (USHORT)hOwner; + } + HWND hWndClient = pConv->hWndPartner; + HWND hWndServer = pConv->hWndThis; +#if 0 && defined( OV_DEBUG ) + String aDebStr("DdePostAdvise: Server:"); + aDebStr += (ULONG)hWndServer; + aDebStr += " Client:"; + aDebStr += (ULONG)hWndClient; + WRITELOG((char*)(const char*)aDebStr) +#endif + DDESTRUCT* pOutDDEData; + if ( pTrans->nType & XTYPF_NODATA ) + { + // Warm link + ////WRITELOG("DdePostAdvise:Warm link found") + pOutDDEData = MakeDDEObject( hWndClient, hszItem, + DDE_FNODATA, pTrans->nFormat, 0, 0 ); + } + else + { + // Hot link + ////WRITELOG("DdePostAdvise:Hot link found") + pOutDDEData = Callback( XTYP_ADVREQ, + pTrans->nFormat, hOwner, hszTopic, + hszItem, (HDDEDATA)0, 1, 0 ); + } + if( pOutDDEData ) + { + // todo: FACK_REQ in Out-Data setzen, wenn pTrans->nType & XTYPF_ACKREQ + ////WRITELOG("DdePostAdvise:Sending data/notification") + BOOL bSuccess = MyWinDdePostMsg( hWndClient, + hWndServer,WM_DDE_DATA, pOutDDEData, DDEPM_RETRY); + if( bSuccess ) + { + // auf Acknowledge des Partners warten ? + if( pTrans->nType & XTYPF_ACKREQ ) + { + pTrans->nConvst = XST_ADVDATASENT; + // Impl. ist falsch! => korrekt: XST_ADVDATAACKRCVD + WaitTransState(pTrans, nCurTrans, + XST_UNADVACKRCVD, 0); + } + } + else + { + ////WRITELOG("DdePostAdvise:PostMsg failed") + nLastErrInstance = DMLERR_POSTMSG_FAILED; + } + } + else + { + ////WRITELOG("DdePostAdvise:No data to send") + } + } + } + } + nCurTrans++; + pTrans++; + } + ////WRITELOG("DdePostAdvise:End") + return TRUE; +} + +BOOL ImpDdeMgr::DdeEnableCallback( HCONV hConv, USHORT wCmd) +{ + return FALSE; +} + +// Rueckgabe: 0==Service nicht registriert; sonst Pointer auf Service-Eintrag +ImpService* ImpDdeMgr::GetService( HSZ hszService ) +{ + ImpService* pPtr = pServices; + if( !pPtr || !hszService ) + return 0; + for( ULONG nIdx = 0; nIdx < nServiceCount; nIdx++, pPtr++ ) + { + if(( hszService == pPtr->hBaseServName ) || + ( hszService == pPtr->hInstServName ) ) + return pPtr; + } + return 0; +} + + +// legt Service in Service-Tabelle ab. Tabelle wird ggf. expandiert +ImpService* ImpDdeMgr::PutService( HSZ hszService ) +{ + if( !pServices ) + { + DBG_ASSERT(nServiceCount==0,"DDE:Bad ServiceCount"); + pServices = new ImpService[ DDEMLSERVICETABLE_INISIZE ]; + memset( pServices, 0, DDEMLSERVICETABLE_INISIZE* sizeof(ImpService)); + nServiceCount = DDEMLSERVICETABLE_INISIZE; + } + ImpService* pPtr = pServices; + USHORT nCurPos = 0; + while( pPtr ) + { + if( pPtr->hBaseServName == 0 ) + break; + nCurPos++; + if( nCurPos < nServiceCount ) + pPtr++; + else + pPtr = 0; + } + if( !pPtr ) + { + // Tabelle vergroessern + pPtr = new ImpService[ nServiceCount + DDEMLSERVICETABLE_INISIZE ]; + memset( pPtr, 0, DDEMLSERVICETABLE_INISIZE* sizeof(ImpService)); + memcpy( pPtr, pServices, nServiceCount * sizeof(ImpService) ); +#ifdef DBG_UTIL + memset( pServices, 0, nServiceCount * sizeof(ImpService) ); +#endif + delete pServices; + pServices = pPtr; + pPtr += nServiceCount; // zeigt auf erste neue Position + nServiceCount += DDEMLSERVICETABLE_INISIZE; + } + DBG_ASSERT(pPtr->hBaseServName==0,"DDE:Service not empty"); + DBG_ASSERT(pPtr->hInstServName==0,"DDE:Service not empty"); + + DdeKeepStringHandle( hszService ); + + USHORT nStrLen = (USHORT)DdeQueryString( hszService, 0, 0, 0); + char* pBuf = new char[ nStrLen + 1 ]; + DdeQueryString(hszService, pBuf, nStrLen, 850 /* CodePage*/ ); + pBuf[ nStrLen ] = 0; + String aStr( (ULONG)hWndServer ); + aStr += pBuf; + HSZ hszInstServ = DdeCreateStringHandle( (PSZ)(const char*)pBuf, 850 ); + delete [] pBuf; + + pPtr->hBaseServName = hszService; + pPtr->hInstServName = hszInstServ; + return pPtr; +} + +void ImpDdeMgr::BroadcastService( ImpService* pService, BOOL bRegistered ) +{ + DBG_ASSERT(pService,"DDE:No Service"); + if( !pService ) + return; + MPARAM aMp1 = (MPARAM)(pService->hBaseServName); + MPARAM aMp2 = (MPARAM)(pService->hInstServName); + ULONG nMsg; + if( bRegistered ) + nMsg = WM_DDEML_REGISTER; + else + nMsg = WM_DDEML_UNREGISTER; + + HWND* pPtr = pAppTable; + for( USHORT nPos = 0; nPos < pData->nMaxAppCount; nPos++, pPtr++ ) + { + HWND hWndCurWin = *pPtr; + if ( hWndCurWin && hWndCurWin != hWndServer ) + WinSendMsg( hWndCurWin, nMsg, aMp1, aMp2 ); + } +} + +HDDEDATA ImpDdeMgr::DdeNameService( HSZ hszService, USHORT afCmd ) +{ + HDDEDATA hRet = (HDDEDATA)1; + + if( afCmd & DNS_FILTERON ) + bServFilterOn = TRUE; + else if( afCmd & DNS_FILTEROFF ) + bServFilterOn = FALSE; + ImpService* pService = GetService( hszService ); + BOOL bRegister = (BOOL)(afCmd & DNS_REGISTER); + if( bRegister ) + { + if( !pService ) + { + pService = PutService( hszService ); + BroadcastService( pService, TRUE ); + } + } + else + { + if( pService ) + { + BroadcastService( pService, FALSE ); + DdeFreeStringHandle( pService->hBaseServName ); + pService->hBaseServName = 0; + DdeFreeStringHandle( pService->hInstServName ); + pService->hInstServName = 0; + } + hRet = (HDDEDATA)0; // Service nicht gefunden + } + return hRet; +} + + +// static +HDDEDATA ImpDdeMgr::DdeClientTransaction(void* pDdeData, ULONG cbData, + HCONV hConv, HSZ hszItem, USHORT nFormat, USHORT nType, + ULONG nTimeout, ULONG* pResult) +{ + //WRITELOG("DdeClientTransaction:Start") + +#if 0 && defined(OV_DEBUG) + if( nType == XTYP_REQUEST ) + { + WRITELOG("Start XTYP_REQUEST"); + WinMessageBox(HWND_DESKTOP,HWND_DESKTOP, + "Start XTYP_REQUEST","DdeClientTransaction", + HWND_DESKTOP,MB_OK); + } +#endif + + if( pResult ) + *pResult = 0; + + ImpDdeMgrData* pData = ImpDdeMgr::AccessMgrData(); + if ( !pData ) + { + ImpDdeMgr::nLastErrInstance = DMLERR_DLL_NOT_INITIALIZED; + return (HDDEDATA)0; + } + + BOOL bIsDdeHandle = (BOOL)(pDdeData && cbData==0xffffffff); + BOOL bAppOwnsHandle = (BOOL)( bIsDdeHandle && + (((DDESTRUCT*)pDdeData)->fsStatus & IMP_HDATAAPPOWNED) ); + + BOOL bNoData = (BOOL)(nType & XTYPF_NODATA)!=0; + BOOL bAckReq = (BOOL)(nType & XTYPF_ACKREQ)!=0; + USHORT nTypeFlags = nType & XTYPF_MASK; + nType &= (~XTYPF_MASK); + + BOOL bSync = (BOOL)( nTimeout != TIMEOUT_ASYNC ) != 0; + if( nType == XTYP_ADVSTART ) + bSync = TRUE; + + // Mapping transaction -> OS/2-Message + USHORT nTimeoutErr, nMsg; + switch ( nType ) + { + case XTYP_ADVSTART: + nMsg = WM_DDE_ADVISE; + nTimeoutErr = DMLERR_ADVACKTIMEOUT; +{ + nTimeout = 60000; +#if 0 && defined(OV_DEBUG) + char aBuf[ 128 ]; + ImpDdeMgr::DdeQueryString( hszItem,aBuf,127,850); + String aXXStr("Establishing hotlink "); + aXXStr += aBuf; + WRITELOG((char*)aXXStr.GetStr()); +#endif + +} + break; + + case XTYP_ADVSTOP: + nMsg = WM_DDE_UNADVISE; + nTimeoutErr = DMLERR_UNADVACKTIMEOUT; + break; + + case XTYP_REQUEST: + nMsg = WM_DDE_REQUEST; + nTimeoutErr = DMLERR_DATAACKTIMEOUT; + break; + + case XTYP_POKE: + nMsg = WM_DDE_POKE; + nTimeoutErr = DMLERR_POKEACKTIMEOUT; + break; + + case XTYP_EXECUTE: + nMsg = WM_DDE_EXECUTE; + nTimeoutErr = DMLERR_EXECACKTIMEOUT; + break; + + default: + nMsg = 0; + } + if(!hConv || (USHORT)hConv>= pData->nMaxConvCount || !nType || !nMsg || + (nType != XTYP_EXECUTE && (!hszItem || !nFormat)) ) + { + WRITELOG("DdeClientTransaction:Invalid parameter") + ImpDdeMgr::nLastErrInstance = DMLERR_INVALIDPARAMETER; + if( bIsDdeHandle && !bAppOwnsHandle ) + DdeFreeDataHandle( (HDDEDATA)pDdeData ); + return (HDDEDATA)0; + } + + // ueber den Conversation handle das ImpDdeMgr-Objekt holen + ImpHCONV* pConv = GetConvTable( pData ); + pConv += (USHORT)hConv; + ImpConvWndData* pObj = + (ImpConvWndData*)WinQueryWindowULong( pConv->hWndThis, 0 ); + ImpDdeMgr* pThis = pObj->pThis; + + if( bSync && pThis->bInSyncTrans ) + { + WRITELOG("DdeClientTransaction:Already in sync. transaction") + ImpDdeMgr::nLastErrInstance = DMLERR_REENTRANCY; + if( bIsDdeHandle && !bAppOwnsHandle ) + DdeFreeDataHandle( (HDDEDATA)pDdeData ); + return (HDDEDATA)0; + } + + Transaction* pTrans; + + BOOL bReqOnAdvLoop = FALSE; + ULONG nTransId = GetTransaction( pData, hConv, hszItem, nFormat ); + if( nTransId ) + { + // WRITELOG("DdeClientTransaction:Transaction found") + pTrans = GetTransTable( pData ); + pTrans += (USHORT)nTransId; + USHORT nTransType = pTrans->nType; + nTransType &= (~XTYPF_MASK); + if( (nType != XTYP_REQUEST && nTransType == nType) || + // wird Advise-Loop schon zum requesten missbraucht ? + (nType == XTYP_REQUEST && + nTransType == XTYP_ADVREQ && + pTrans->nConvst == XST_WAITING_REQDATA)) + { + // dieser Kanal ist dicht! + WRITELOG("DdeClientTransaction:Transaction already used") + ImpDdeMgr::nLastErrInstance = DMLERR_REENTRANCY; + if( bIsDdeHandle && !bAppOwnsHandle ) + DdeFreeDataHandle( (HDDEDATA)pDdeData ); + return (HDDEDATA)0; + } + else if( nTransType == XTYP_ADVREQ ) + { + switch( nType ) + { + case XTYP_ADVSTOP: + //WRITELOG("DdeClientTransaction:Stopping advise trans") + pTrans->nType = XTYP_ADVSTOP; + break; + + case XTYP_ADVSTART: + //WRITELOG("DdeClientTransaction:Adj. Advise-Params") + pTrans->nType = XTYP_ADVREQ; + if( bNoData ) + pTrans->nType |= XTYPF_NODATA; + if( bAckReq ) + pTrans->nType |= XTYPF_ACKREQ; + if( pResult ) + *pResult = nTransId; + return (HDDEDATA)TRUE; + + case XTYP_REQUEST: + // WRITELOG("DdeClientTransaction:Using adv trans for req") + // nConvst wird unten auf XST_WAITING_REQDATA gesetzt + bReqOnAdvLoop = TRUE; + break; + + default: + WRITELOG("DdeClientTransaction:Invalid parameter") + ImpDdeMgr::nLastErrInstance = DMLERR_INVALIDPARAMETER; + if( bIsDdeHandle && !bAppOwnsHandle ) + DdeFreeDataHandle( (HDDEDATA)pDdeData ); + return (HDDEDATA)FALSE; + } + } + } + else + { + // WRITELOG("DdeClientTransaction:Creating transaction") + nTransId = CreateTransaction(pData, hConv, hszItem, nFormat, nType); + } + + pTrans = GetTransTable( pData ); + pTrans += (USHORT)nTransId; + pTrans->nConvst = XST_WAITING_ACK; + if( nType == XTYP_REQUEST ) + pTrans->nConvst = XST_WAITING_REQDATA; + + HWND hWndServer = pConv->hWndPartner; + HWND hWndClient = pConv->hWndThis; + + HDDEDATA pOutDDEData; + if( bIsDdeHandle ) + { + if( bAppOwnsHandle ) + { + // wir muessen leider leider duplizieren, da uns OS/2 + // keine Chance laesst, diesen Status im Datenobjekt + // zu versenken. + ////WRITELOG("DdeClientTransaction:Copying handle") + HDDEDATA pNew; + HDDEDATA pData = (HDDEDATA)pDdeData; + if( !(MyDosAllocSharedMem((PPVOID)&pNew, NULL, pData->cbData, + PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE | OBJ_ANY, + "MakeDDEObject"))) + { + memcpy( pNew, pData, pData->cbData ); + pOutDDEData = pNew; + } + else + { + WRITELOG("DdeClientTransaction:No Memory") + ImpDdeMgr::nLastErrInstance = DMLERR_LOW_MEMORY; + return (HDDEDATA)0; + } + } + else + pOutDDEData = (HDDEDATA)pDdeData; + } + else + pOutDDEData=MakeDDEObject(hWndServer,hszItem,0,nFormat,pDdeData,cbData); + + pOutDDEData->fsStatus |= nTypeFlags; + + HDDEDATA pDDEInData = 0; + if( bSync ) + { + if( nType != XTYP_REQUEST ) + pOutDDEData->fsStatus |= DDE_FACKREQ; + + // WRITELOG("DdeClientTransaction:Starting sync. trans.") + pThis->hSyncResponseData = (HDDEDATA)0; + pThis->nSyncResponseMsg = 0; + pThis->bInSyncTrans = TRUE; + pThis->nSyncTransId = nTransId; + pThis->bSyncAbandonTrans = FALSE; + + if ( !MyWinDdePostMsg( hWndServer, hWndClient, nMsg, pOutDDEData, + DDEPM_RETRY) ) + { + WRITELOG("DdeClientTransaction:PostMsg failed") + nLastErrInstance = DMLERR_POSTMSG_FAILED; + if( !bReqOnAdvLoop ) + FreeTransaction( pData, nTransId ); + else + { + DBG_ASSERT(pTrans->nType==XTYP_ADVREQ,"DDE:Error!") + pTrans->nConvst = 0; + } + return FALSE; + } + HAB hAB = WinQueryAnchorBlock( hWndClient ); + ULONG nDummyTimer = WinStartTimer( hAB, 0, 0, 50 ); + ULONG nTimeoutId = TID_USERMAX - nTransId; + WinStartTimer( hAB, hWndClient, nTimeoutId, nTimeout ); + QMSG aQueueMsg; + BOOL bLoop = TRUE; + while( bLoop ) + { + if( pThis->nSyncResponseMsg ) + bLoop = FALSE; + else + { + if( WinGetMsg(hAB,&aQueueMsg,0,0,0 )) + { + WinDispatchMsg( hAB, &aQueueMsg ); + } + else + bLoop = FALSE; + } + } + + WinStopTimer( hAB, hWndClient, nTimeoutId ); + WinStopTimer( hAB, 0, nDummyTimer ); + + // + // Der Speicherblock pOutDDEData muss vom Server geloescht worden sein! + // Ueberlegen: Nochmal loeschen, falls Server buggy ist, ansonsten + // platzt uns bald der Adressraum! + // + if( !pThis->nSyncResponseMsg ) + { + // unsere App wurde beendet + ////WRITELOG("DdeClientTransaction:App terminated") + return 0; + } + pDDEInData = pThis->hSyncResponseData; + nMsg = pThis->nSyncResponseMsg; + pThis->hSyncResponseData= 0; + pThis->nSyncResponseMsg = 0; + pThis->bInSyncTrans = FALSE; + pThis->nSyncTransId = 0; + if( !pDDEInData && nMsg != WM_TIMER ) + { + DBG_ASSERT(0,"Dde:No data!"); + WRITELOG("DdeClientTransaction: No Data!") + return (HDDEDATA)0; + } + switch( nMsg ) + { + case WM_TIMER: + WRITELOG("DdeClientTransaction:Timeout!") + nLastErrInstance = nTimeoutErr; + if( bReqOnAdvLoop ) + // auf normalen Loop-Betrieb zurueckschalten + pTrans->nConvst = XST_WAITING_ADVDATA; + break; + + case WM_DDE_ACK: + { + // WRITELOG("DdeClientTransaction:Ack received") + BOOL bPositive = (BOOL)(pDDEInData->fsStatus & DDE_FACK); + MyDosFreeMem( pDDEInData,"DdeClientTransaction" ); + pDDEInData = (HDDEDATA)bPositive; + if( nType == XTYP_ADVSTART && pDDEInData ) + { + +#if 0 && defined(OV_DEBUG) + char aBuf[ 128 ]; + ImpDdeMgr::DdeQueryString( pTrans->hszItem,aBuf,128,850); + String aXXStr("Hotlink "); +#endif + + if( bPositive ) + { + pTrans->nType = XTYP_ADVREQ; + // Hot/Warmlink, Ack + pTrans->nType |= nTypeFlags; + // XST_WAITING_ACK ==> XST_WAITING_ADVDATA + pTrans->nConvst = XST_WAITING_ADVDATA; + +#if 0 && defined(OV_DEBUG) + aXXStr += "established "; + aXXStr += aBuf; +#endif + + } + +#if 0 && defined(OV_DEBUG) + else + { + aXXStr += "failed "; + aXXStr += aBuf; + } + WRITELOG((char*)aXXStr.GetStr()); +#endif + + } + } + break; + + case WM_DDE_DATA: + // WRITELOG("DdeClientTransaction:Data received") + // WRITEDATA(pDDEInData) + if( bReqOnAdvLoop ) + { + DBG_ASSERT(pTrans->nConvst==XST_WAITING_REQDATA,"DDE:Bad state"); + DBG_ASSERT(pTrans->nType==XTYP_ADVREQ,"DDE:Bad state"); + // auf Loop-Betrieb umschalten + pTrans->nConvst = XST_WAITING_ADVDATA; + } + break; + + default: + WRITELOG("DdeClientTransaction:Unexpected msg") + MyDosFreeMem( pDDEInData,"DdeClientTransaction" ); + pDDEInData = 0; + } + pThis->bSyncAbandonTrans = FALSE; + pThis->bInSyncTrans = FALSE; + if( pThis->bSyncAbandonTrans && bReqOnAdvLoop ) + pThis->DdeAbandonTransaction( hConv, nTransId ); + } + else + { + // WRITELOG("DdeClientTransaction:Starting async. trans.") + pDDEInData = (HDDEDATA)MyWinDdePostMsg( hWndServer, hWndClient, nMsg, + pOutDDEData, DDEPM_RETRY); + if( !pDDEInData ) + { + WRITELOG("DdeClientTransaction:PostMsg failed") + nLastErrInstance = DMLERR_POSTMSG_FAILED; + if( !bReqOnAdvLoop ) + FreeTransaction( pData, nTransId ); + else + { + DBG_ASSERT(pTrans->nType==XTYP_ADVREQ,"DDE:Error!") + pTrans->nConvst = 0; + } + } + else + { + // WRITELOG("DdeClientTransaction:Async trans. success") + if( pResult ) + *pResult = nTransId; + } + } +#if 0 && defined( OV_DEBUG ) + if( nType == XTYP_REQUEST ) + { + WRITELOG("End XTYP_REQUEST"); + WinMessageBox(HWND_DESKTOP,HWND_DESKTOP, + "End XTYP_REQUEST","DdeClientTransaction", + HWND_DESKTOP,MB_OK); + } +#endif + //WRITELOG("DdeClientTransaction:End") + //WRITESTATUS("DdeClientTransaction:End") + return pDDEInData; +} + +MRESULT ImpDdeMgr::DdeRegister( ImpWndProcParams* pParams ) +{ + MRESULT nRet = (MRESULT)0; + if ( !(nTransactFilter & CBF_SKIP_REGISTRATIONS) ) + { + HSZ hSBaseName = (HSZ)pParams->nPar1; + HSZ hIBaseName = (HSZ)pParams->nPar2; + nRet=(MRESULT)Callback(XTYP_REGISTER,0,0,hSBaseName,hIBaseName,0,0,0); + } + return nRet; +} + +MRESULT ImpDdeMgr::DdeUnregister( ImpWndProcParams* pParams ) +{ + MRESULT nRet = (MRESULT)0; + if ( !(nTransactFilter & CBF_SKIP_UNREGISTRATIONS) ) + { + HSZ hSBaseName = (HSZ)pParams->nPar1; + HSZ hIBaseName = (HSZ)pParams->nPar2; + nRet=(MRESULT)Callback(XTYP_UNREGISTER,0,0,hSBaseName,hIBaseName,0,0,0); + } + return nRet; +} + +MRESULT ImpDdeMgr::DdeTimeout( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdeTimeout:Received") + if( nSyncResponseMsg ) + { + ////WRITELOG("DdeTimeout:Trans already processed->ignoring timeout") + return (MRESULT)1; + } + ULONG nTimerId = (ULONG)pParams->nPar1; + ULONG nTransId = TID_USERMAX - nTimerId; + Transaction* pTrans = pTransTable; + pTrans += (USHORT)nTransId; + if( nTransId < 1 || nTransId >= pData->nMaxTransCount || + pTrans->hConvOwner == 0 ) + { + DBG_ASSERT(0,"DdeTimeout:Invalid TransactionId"); + return (MRESULT)1; + } + if( bInSyncTrans && nTransId == nSyncTransId ) + { + USHORT nTempType = pTrans->nType; + nTempType &= (~XTYPF_MASK); + // advise-loops koennen nur innerhalb synchroner + // requests timeouts bekommen. die transaktion wird + // in diesem fall nicht geloescht. + if( nTempType != (XTYP_ADVREQ & (~XTYPF_NOBLOCK) )) + { + ////WRITELOG("DdeTimeout:Freeing transaction") + FreeTransaction( pData, nTransId ); + } + nSyncResponseMsg = WM_TIMER; +#if 0 && defined( OV_DEBUG ) + String aMsg("DdeTimeout:Transaction="); + aMsg += nTransId; + WRITELOG((char*)(const char*)aMsg) +#endif + } + else + { + ////WRITELOG("DdeTimeout:Async transaction timed out") + pTrans->nConvst = XST_TIMEOUT; + } + return (MRESULT)1; +} + + + +MRESULT ImpDdeMgr::DdeTerminate( ImpWndProcParams* pParams ) +{ + WRITELOG("DdeTerminate:Received") + HWND hWndThis = pParams->hWndReceiver; + HWND hWndPartner = (HWND)(pParams->nPar1); + + HCONV hConv = GetConvHandle( pData, hWndThis, hWndPartner ); +#if 0 && defined( OV_DEBUG ) + String strDebug("DdeTerminate:ConvHandle="); + strDebug += (USHORT)hConv; + WRITELOG((char*)(const char*)strDebug) +#endif + ImpHCONV* pConv = pConvTable + (USHORT)hConv; + if( hConv ) + { + // warten wir auf ein DDE_TERMINATE Acknowledge ? + if( pConv->nStatus & ST_TERMINATED ) + { + ////WRITELOG("DdeTerminate:TERMINATE-Ack received") + pConv->nStatus |= ST_TERMACKREC; + return (MRESULT)0; // DdeDisconnect raeumt jetzt auf + } + + // sind wir Server?, wenn ja: die App benachrichtigen, + // dass die Advise loops gestoppt wurden und die + // Transaktionen loeschen + + // OV 26.07.96: Die das TERMINATE empfangende App muss + // die Transaction-Tabelle abraeumen, egal ob Server oder Client!! + // Es muessen alle Trans geloescht werden, die als Owner den + // Client oder den Server haben! + // if( !(pConv->nStatus & ST_CLIENT ) ) + SendUnadvises( hConv, 0, FALSE ); // alle Formate & nicht loeschen + SendUnadvises( pConv->hConvPartner, 0, FALSE ); + + // wir werden von draussen gekillt + if ( !(nTransactFilter & CBF_SKIP_DISCONNECTS) ) + { + Callback( XTYP_DISCONNECT, 0, hConv, 0, 0, 0, + 0, (ULONG)IsSameInstance(hWndPartner)); + } + + // kann unsere Partner-App DDEML ? + if( !(pConv->hConvPartner) ) + { + // nein, deshalb Transaktionstabelle selbst loeschen + ////WRITELOG("DdeTerminate:Freeing transactions") + FreeTransactions( pData, hConv ); + } + } + else + nLastErrInstance = DMLERR_NO_CONV_ESTABLISHED; + +#if 0 && defined(OV_DEBUG) + if( !WinIsWindow(0,hWndPartner)) + { + WRITELOG("DdeTerminate:hWndPartner not valid") + } + if(!WinIsWindow(0,hWndThis)) + { + WRITELOG("DdeTerminate:hWndThis not valid") + } +#endif + + if( hConv ) + { + // hWndThis nicht loeschen, da wir den Handle noch fuer + // das Acknowledge brauchen + ////WRITELOG("DdeTerminate:Freeing conversation") + FreeConvHandle( pData, hConv, FALSE ); + } + + ////WRITELOG("DdeTerminate:Acknowledging DDE_TERMINATE") + +#ifdef OV_DEBUG + DBG_ASSERT(WinIsWindow( 0, hWndThis ),"hWndThis not valid"); +#endif + + if( !WinDdePostMsg( hWndPartner, hWndThis, WM_DDE_TERMINATE, 0, DDEPM_RETRY )) + { + ////WRITELOG("DdeTerminate:Acknowledging DDE_TERMINATE failed") + } + // jetzt hWndThis loeschen + DestroyConversationWnd( hWndThis ); + + return (MRESULT)0; +} + + +/* + Zuordnung des Conversationhandles: + + Verbindungsaufbau: + Client: DdeInitiate( HWNDClient ) + Server: Post( WM_DDE_INITIATEACK( HWNDServer )) + Client: CreateConvHandle( HWNDClient, HWNDServer ) + + Datenaustausch: + Server: Post(WM_DDE_ACK( HWNDSender )) + Client: GetConvHandle( HWNDClient, HWNDSender ) +*/ + +MRESULT ImpDdeMgr::ConvWndProc( HWND hWnd,ULONG nMsg,MPARAM nPar1,MPARAM nPar2 ) +{ + ImpWndProcParams aParams; + + MRESULT nRet = (MRESULT)0; + aParams.hWndReceiver= hWnd; + aParams.nPar1 = nPar1; + aParams.nPar2 = nPar2; + + switch( nMsg ) + { + +#ifdef DBG_UTIL + case WM_DDE_INITIATE : + DBG_ASSERT(0,"dde:unexpected msg"); + nRet = (MRESULT)TRUE; + break; +#endif + + case WM_DDE_INITIATEACK : nRet = DdeInitiateAck(&aParams); break; + case WM_DDE_ACK : nRet = DdeAck( &aParams ); break; + case WM_DDE_ADVISE : nRet = DdeAdvise( &aParams ); break; + case WM_DDE_DATA : nRet = DdeData( &aParams ); break; + case WM_DDE_EXECUTE : nRet = DdeExecute( &aParams ); break; + case WM_DDE_POKE : nRet = DdePoke( &aParams ); break; + case WM_DDE_REQUEST : nRet = DdeRequest( &aParams ); break; + case WM_DDE_TERMINATE : nRet = DdeTerminate( &aParams ); break; + case WM_DDE_UNADVISE : nRet = DdeUnadvise( &aParams ); break; + case WM_TIMER : nRet = DdeTimeout( &aParams ); break; + } + return nRet; +} + +MRESULT ImpDdeMgr::SrvWndProc( HWND hWnd,ULONG nMsg,MPARAM nPar1,MPARAM nPar2 ) +{ + MRESULT nRet = (MRESULT)0; + + ImpWndProcParams aParams; + aParams.hWndReceiver= hWnd; + aParams.nPar1 = nPar1; + aParams.nPar2 = nPar2; + + switch( nMsg ) + { +#ifdef DBG_UTIL + case WM_DDE_ACK : + case WM_DDE_ADVISE : + case WM_DDE_EXECUTE : + case WM_DDE_POKE : + case WM_DDE_REQUEST : + case WM_DDE_UNADVISE : + case WM_DDE_DATA : + case WM_DDE_INITIATEACK : + DBG_ASSERT(0,"dde:unexpected msg"); + nRet = (MRESULT)TRUE; + break; +#endif + + case WM_DDE_TERMINATE : + break; // DDE_INITIATE wurde im DDE_INITIATEACK terminiert + + // ein Client will was von uns + case WM_DDE_INITIATE : + nRet = DdeInitiate( &aParams ); + break; + + // eine ddeml-faehige App. hat einen Service (typ. AppName) [de]reg. + case WM_DDEML_REGISTER : + nRet = DdeRegister( &aParams ); + break; + + case WM_DDEML_UNREGISTER : + nRet = DdeUnregister( &aParams ); + break; + }; + return nRet; +} + + +MRESULT ImpDdeMgr::DdeAck( ImpWndProcParams* pParams ) +{ + //WRITELOG("DdeAck:Start") + HSZ hszItem; + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); + if( pInDDEData ) + { + BOOL bPositive = (BOOL)(pInDDEData->fsStatus & DDE_FACK ) != 0; + BOOL bBusy = bPositive ? FALSE : (BOOL)(pInDDEData->fsStatus & DDE_FBUSY ) != 0; + BOOL bNotProcessed = (BOOL)(pInDDEData->fsStatus & DDE_NOTPROCESSED ) != 0; +#if 0 && defined( OV_DEBUG ) + String aDebStr("DdeAck:Received "); + if( bPositive ) + aDebStr += "(positive)"; + else + aDebStr += "(negative)"; + if( bBusy ) + aDebStr += "(busy)"; + if( bNotProcessed ) + aDebStr += "(not processed)"; + WRITELOG((char*)(const char*)aDebStr) +#endif + // ein DDE_ACK niemals bestaetigen (um endlosschleifen zu vermeiden) + pInDDEData->fsStatus &= (~DDE_FACKREQ); + } + else + { + //WRITELOG("DdeAck:Received (no data!)") + return (MRESULT)0; + } + + HCONV hConv = CheckIncoming(pParams, 0, hszItem); +#ifdef OV_DEBUG + if( !hConv ) + { + WRITELOG("DdeAck:HCONV not found") + } +#endif + ULONG nTransId=GetTransaction(pData,hConv,hszItem,pInDDEData->usFormat); + if( !nTransId ) + { + WRITELOG("DdeAck:Transaction not found") + MyDosFreeMem( pInDDEData,"DdeAck" ); + return (MRESULT)0; + } + + BOOL bThisIsSync = (BOOL)( bInSyncTrans && nTransId == nSyncTransId ); +#if 0 && defined( OV_DEBUG ) + if( bThisIsSync) + WRITELOG("DdeAck: sync transaction") + else + WRITELOG("DdeAck: async transaction") +#endif + // pruefen, ob die Transaktion abgeschlossen ist. + Transaction* pTrans = pTransTable; + pTrans += (USHORT)nTransId; + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + + if( pTrans->nConvst == XST_UNADVSENT ) + { + //WRITELOG("DdeAck:Unadvise-Ack received") + pTrans->nConvst = XST_UNADVACKRCVD; + MyDosFreeMem( pInDDEData,"DdeAck" ); + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; + } + if( pTrans->nConvst == XST_ADVDATASENT ) + { + //WRITELOG("DdeAck:AdvData-Ack received") + pTrans->nConvst = XST_ADVDATAACKRCVD; + MyDosFreeMem( pInDDEData,"DdeAck" ); + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; + } + + USHORT nType = pTrans->nType; + nType &= (~XTYPF_MASK); + // beginn einer advise-loop oder request auf advise-loop ? + // wenn ja: transaktion nicht loeschen + BOOL bFinished = (BOOL)(nType != XTYP_ADVSTART && + nType != (XTYP_ADVREQ & (~XTYPF_NOBLOCK)) ); + if( bFinished ) + { + if( !bThisIsSync ) + { + ////WRITELOG("DdeAck:Transaction completed") + Callback( XTYP_XACT_COMPLETE, pInDDEData->usFormat, hConv, + pConv->hszTopic, hszItem, (HDDEDATA)0, nTransId, 0 ); + } + ////WRITELOG("DdeAck:Freeing transaction") + FreeTransaction( pData, nTransId ); + } + + if( bThisIsSync ) + { + hSyncResponseData = pInDDEData; + nSyncResponseMsg = WM_DDE_ACK; + } + else + { + MyDosFreeMem( pInDDEData,"DdeAck" ); + } + + DdeFreeStringHandle( hszItem ); + + return (MRESULT)0; +} + + +USHORT ImpDdeMgr::SendUnadvises(HCONV hConvServer,USHORT nFormat,BOOL bFree) +{ + USHORT nTransFound = 0; + BOOL bCallApp = (BOOL)(!(nTransactFilter & CBF_FAIL_ADVISES)); +#if 0 && defined( OV_DEBUG ) + String aStr("Unadvising transactions for HCONV="); + aStr += (ULONG)hConvServer; + aStr += " CallApp:"; aStr += (USHORT)bCallApp; + WRITELOG((char*)aStr.GetStr()) +#endif + + + // wenn wir weder loeschen noch die App benachrichtigen sollen, + // koennen wir gleich wieder returnen + if( !hConvServer || ( !bFree && !bCallApp ) ) + return 0; + + ImpHCONV* pConvSrv = pConvTable; + pConvSrv += (USHORT)hConvServer; + HSZ hszTopic = pConvSrv->hszTopic; + + Transaction* pTrans = pTransTable; + pTrans++; + USHORT nCurTransId = 1; + USHORT nCurTransactions = pData->nCurTransCount; + while( nCurTransactions && nCurTransId < pData->nMaxTransCount ) + { + if( pTrans->hConvOwner ) + nCurTransactions--; + if( pTrans->hConvOwner == hConvServer && + (pTrans->nType & XTYP_ADVREQ) ) + { + if( !nFormat || (nFormat == pTrans->nFormat) ) + { + nTransFound++; + if( bCallApp ) + { + //WRITELOG("SendUnadvises:Notifying App") + Callback( XTYP_ADVSTOP, pTrans->nFormat, hConvServer, + hszTopic, pTrans->hszItem, 0,0,0 ); + } + if( bFree ) + FreeTransaction( pData, (ULONG)nCurTransId ); + } + } + nCurTransId++; + pTrans++; + } + return nTransFound; +} + + + +HCONV ImpDdeMgr::CheckIncoming( ImpWndProcParams* pParams, ULONG nTransMask, + HSZ& rhszItem ) +{ +// ////WRITELOG("CheckIncoming") + rhszItem = 0; + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); + if( !pInDDEData ) + { + // ////WRITELOG("CheckIncoming:PDDESTRUCT==0") + return (HCONV)0; + } + + HWND hWndThis = pParams->hWndReceiver; + HWND hWndClient = (HWND)pParams->nPar1; + + BOOL bReject = (BOOL)(nTransactFilter & nTransMask); + HCONV hConv; + if( !bReject ) + hConv = GetConvHandle( pData, hWndThis, hWndClient ); + if ( bReject || !hConv ) + return (HCONV)0; + + rhszItem = DdeCreateStringHandle( + ((char*)(pInDDEData)+pInDDEData->offszItemName), 850 ); + + // ////WRITELOG("CheckIncoming:OK"); + return hConv; +} + + +MRESULT ImpDdeMgr::DdeAdvise( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdeAdvise:Received") + HSZ hszItem; + HCONV hConv = CheckIncoming(pParams, CBF_FAIL_ADVISES, hszItem); + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); + HWND hWndThis = pParams->hWndReceiver; + HWND hWndClient = (HWND)pParams->nPar1; + if( !hConv ) + { + ////WRITELOG("DdeAdvise:Conversation not found") + pInDDEData->fsStatus &= (~DDE_FACK); + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; + } + + Transaction* pTrans = pTransTable; + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + + // existiert schon ein Link auf Topic/Item/Format-Vektor ? + + ULONG nTransId=GetTransaction(pData,hConv,hszItem,pInDDEData->usFormat); + if( nTransId ) + { + ////WRITELOG("DdeAdvise:Transaction already exists") + pTrans += (USHORT)nTransId; + // ist es eine AdviseLoop ? + USHORT nTempType = pTrans->nType; + nTempType &= (~XTYPF_MASK); + if( nTempType == XTYP_ADVREQ ) + { + // Flags der laufenden Advise-Loop aktualisieren + ////WRITELOG("DdeAdvise:Adjusting Advise-Params") + pTrans->nType = XTYP_ADVREQ; + if( pInDDEData->fsStatus & DDE_FNODATA ) + pTrans->nType |= XTYPF_NODATA; + if( pInDDEData->fsStatus & DDE_FACKREQ ) + pTrans->nType |= XTYPF_ACKREQ; + pInDDEData->fsStatus |= DDE_FACK; + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; + } + else if( nTempType != XTYP_ADVSTART ) + { + ////WRITELOG("DdeAdvise:Not a advise transaction") + pInDDEData->fsStatus &= (~DDE_FACK); + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; + } + } + + if( !nTransId ) + { + ////WRITELOG("DdeAdvise:Creating Transaction") + ////WRITESTATUS("DdeAdvise:Creating Transaction") + nTransId = CreateTransaction( pData, hConv, hszItem, + pInDDEData->usFormat, XTYP_ADVREQ ); + ////WRITESTATUS("DdeAdvise:Created Transaction") + } + if( nTransId ) + { + pTrans = pTransTable; + pTrans += (USHORT)nTransId; + if( pInDDEData->fsStatus & DDE_FNODATA ) + pTrans->nType |= XTYPF_NODATA; + if( pInDDEData->fsStatus & DDE_FACKREQ ) + pTrans->nType |= XTYPF_ACKREQ; + } + else + { + ////WRITELOG("DdeAdvise:Cannot create Transaction") + pInDDEData->fsStatus &= (~DDE_FACK); + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; + } + + ////WRITELOG("DdeAdvise:Calling Server") + + if ( Callback( XTYP_ADVSTART, pInDDEData->usFormat, + hConv, pConv->hszTopic, hszItem, (HDDEDATA)0, 0, 0 ) ) + { + // + // ServerApp erlaubt AdviseLoop + // + ////WRITELOG("DdeAdvise:Advise loop established") + pInDDEData->fsStatus |= DDE_FACK; + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + } + else + { + ////WRITELOG("DdeAdvise:Advise loop not established") + FreeTransaction( pData, nTransId ); + pInDDEData->fsStatus &= (~DDE_FACK); // DDE_FNOTPROCESSED; + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + } + ////WRITESTATUS("DdeAdvise:End") + ////WRITELOG("DdeAdvise:End") + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; +} + +MRESULT ImpDdeMgr::DdeData( ImpWndProcParams* pParams ) +{ + WRITELOG("DdeData:Received") + HSZ hszItem; + HCONV hConv = CheckIncoming(pParams, 0, hszItem); + HWND hWndThis = pParams->hWndReceiver; + HWND hWndClient = (HWND)pParams->nPar1; + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); +#if 0 && defined( OV_DEBUG ) + { + String aStr("DdeData Address:"); + aStr += (ULONG)pInDDEData; + WRITELOG((char*)aStr.GetStr()) + } +#endif + + BOOL bSendAck; + if( pInDDEData && (pInDDEData->fsStatus & DDE_FACKREQ )) + { + WRITELOG("DdeData: Ackn requested") + bSendAck = TRUE; + } + else + { + WRITELOG("DdeData: Ackn not requested") + bSendAck = FALSE; + } + + ULONG nTransId = GetTransaction(pData,hConv,hszItem,pInDDEData->usFormat); + if( !nTransId ) + { + WRITELOG("DdeData:Transaction not found") + WRITEDATA(pInDDEData) + if( bSendAck ) + { + WRITELOG("DdeData: Posting Ackn") + pInDDEData->fsStatus &= (~DDE_FACK); // NOTPROCESSED; + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + } + else + { + MyDosFreeMem( pInDDEData,"DdeData" ); + } + return (MRESULT)0; + } + +#if 0 && defined( OV_DEBUG ) + if( pInDDEData ) + { + WRITEDATA(pInDDEData) + } +#endif + + BOOL bThisIsSync = (BOOL)( bInSyncTrans && nTransId == nSyncTransId ); + + // pruefen, ob die Transaktion abgeschlossen ist. + Transaction* pTrans = pTransTable; + pTrans += (USHORT)nTransId; + + if( pTrans->nConvst == XST_WAITING_ACK ) + { + // dieser Fall kann eintreten, wenn ein Server innerhalb + // einer WM_DDE_ADVISE-Msg. oder bevor beim Client das + // Ack eintrifft, Advise-Daten sendet. + WRITELOG("DdeData:Ignoring unexpected data") + if( bSendAck ) + { + WRITELOG("DdeData: Posting Ackn") + pInDDEData->fsStatus &= (~DDE_FACK); // NOTPROCESSED; + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + } + else + { + MyDosFreeMem( pInDDEData,"DdeData" ); + } + return (MRESULT)0; + } + + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + + USHORT nType = pTrans->nType; + nType &= (~XTYPF_MASK); + BOOL bNotAdviseLoop = (BOOL)(nType != (XTYP_ADVREQ & (~XTYPF_NOBLOCK))); + if( !bThisIsSync ) + { + // WRITELOG("DdeData:Is async transaction") + if( bNotAdviseLoop ) + { + // WRITELOG("DdeData:Transaction completed -> calling client") + Callback( XTYP_XACT_COMPLETE, pInDDEData->usFormat, hConv, + pConv->hszTopic, hszItem, pInDDEData, nTransId, 0 ); + // WRITELOG("DdeData:Freeing transaction") + FreeTransaction( pData, nTransId ); + } + else + { + WRITELOG("DdeData:Advise-Loop -> calling client") + HDDEDATA pToSend = pInDDEData; + if( pTrans->nType & XTYPF_NODATA ) + { + pToSend = 0; + // WRITELOG("DdeData:Is warm link") + } + Callback( XTYP_ADVDATA, pInDDEData->usFormat, hConv, + pConv->hszTopic, hszItem, pToSend, nTransId, 0 ); + } + if( bSendAck ) + { + WRITELOG("DdeData: Posting Ackn") + pInDDEData->fsStatus = DDE_FACK; + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + } + else + MyDosFreeMem( pInDDEData,"DdeData" ); + } + else // synchrone Transaktion (Datenhandle nicht freigeben!) + { + // WRITELOG("DdeData:Is sync transaction") + hSyncResponseData = pInDDEData; + nSyncResponseMsg = WM_DDE_DATA; + if( bSendAck ) + { + pInDDEData->fsStatus |= DDE_FACK; + WRITELOG("DdeData: Posting Ackn") + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData, + DDEPM_RETRY | DDEPM_NOFREE ); + } + } + + DdeFreeStringHandle( hszItem ); + // WRITELOG("DdeData:End") + return (MRESULT)0; +} + +MRESULT ImpDdeMgr::DdeExecute( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdeExecute:Received") + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); + HSZ hszItem; + HCONV hConv = CheckIncoming(pParams, 0, hszItem); + BOOL bSuccess = FALSE; + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + if ( hConv && !(nTransactFilter & CBF_FAIL_EXECUTES) && pInDDEData ) + { + if ( Callback( XTYP_EXECUTE, pInDDEData->usFormat, hConv, + pConv->hszTopic, hszItem, pInDDEData, 0, 0 ) + == (DDESTRUCT*)DDE_FACK ) + bSuccess = TRUE; + } + else + { + ////WRITELOG("DdeExecute:Not processed") + } + if( pInDDEData ) + { + if( bSuccess ) + pInDDEData->fsStatus |= DDE_FACK; + else + pInDDEData->fsStatus &= (~DDE_FACK); + MyWinDdePostMsg( pConv->hWndPartner, pConv->hWndThis, WM_DDE_ACK, + pInDDEData, DDEPM_RETRY ); + } + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; +} + +HCONV ImpDdeMgr::ConnectWithClient( HWND hWndClient, + HSZ hszPartner, HSZ hszService, HSZ hszTopic, BOOL bSameInst, + DDEINIT* pDDEData, CONVCONTEXT* pCC ) +{ + ////WRITELOG("ConnectWithClient:Start") + HWND hWndSrv = CreateConversationWnd(); + IncConversationWndRefCount( hWndSrv ); + HCONV hConv = CreateConvHandle( pData, pidThis, hWndSrv, hWndClient, + hszPartner, hszService, hszTopic ); + if(!hConv ) + return 0; + BOOL bFreeDdeData = FALSE; + if( !pDDEData ) + { + bFreeDdeData = TRUE; + pDDEData = CreateDDEInitData( hWndClient,hszService,hszTopic, pCC ); + PID pid; TID tid; + WinQueryWindowProcess( hWndClient, &pid, &tid ); + DosGiveSharedMem( pDDEData, pid, PAG_READ | PAG_WRITE); + } + HAB hAB = WinQueryAnchorBlock( hWndSrv ); + WinGetLastError( hAB ); // fehlercode zuruecksetzen + WinSendMsg(hWndClient,WM_DDE_INITIATEACK,(MPARAM)hWndSrv,(MPARAM)pDDEData); + if( WinGetLastError( hAB ) ) + { + // ////WRITELOG("DdeConnectWithClient:Client died") + if( bFreeDdeData ) + { + MyDosFreeMem( pDDEData,"ConnectWithClient" ); + } + FreeConvHandle( pData, hConv ); + return (HCONV)0; + } + + if( !(nTransactFilter & CBF_SKIP_CONNECT_CONFIRMS) ) + { + Callback( XTYP_CONNECT_CONFIRM, 0, hConv, hszTopic, hszService, + 0, 0, (ULONG)bSameInst ); + } + + if( bFreeDdeData ) + { + MyDosFreeMem( pDDEData,"ConnectWithClient" ); + } + // HCONV der PartnerApp suchen & bei uns eintragen + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + pConv->hConvPartner = GetConvHandle( pData, hWndClient, hWndSrv ); +#if 0 && defined(OV_DEBUG) + if( !pConv->hConvPartner ) + { + WRITELOG("DdeConnectWithClient:Partner not found") + } +#endif + pConv->nStatus = ST_CONNECTED; + //WRITESTATUS("Server:Connected with client") + //WRITELOG("ConnectWithClient:End") + return hConv; +} + +MRESULT ImpDdeMgr::DdeInitiate( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdeInitiate:Received") + HWND hWndClient = (HWND)(pParams->nPar1); +// BOOL bSameInst = IsSameInstance( hWndClient ); + BOOL bSameInst = (BOOL)(hWndClient==hWndServer); + DDEINIT* pDDEData = (DDEINIT*)pParams->nPar2; + + if ( ( nTransactFilter & (CBF_FAIL_CONNECTIONS | APPCMD_CLIENTONLY)) || + (( nTransactFilter & CBF_FAIL_SELFCONNECTIONS) && bSameInst ) + ) + { + MyDosFreeMem( pDDEData,"DdeInitiate" ); + return (MRESULT)FALSE; // narda + } + + HSZ hszService = (HSZ)0; + if( *(pDDEData->pszAppName) != '\0' ) + { + hszService = DdeCreateStringHandle( pDDEData->pszAppName, 850 ); + ////WRITELOG(pDDEData->pszAppName); + } + HSZ hszTopic = (HSZ)0; + if( *(pDDEData->pszTopic) != '\0' ) + { + hszTopic = DdeCreateStringHandle( pDDEData->pszTopic, 850 ); + ////WRITELOG(pDDEData->pszTopic); + } + HSZ hszPartner = GetAppName( hWndClient ); + + // nur weitermachen, wenn Service registriert oder + // Service-Name-Filtering ausgeschaltet. + if( !bServFilterOn || GetService(hszService) ) + { + // XTYP_CONNECT-Transaktionen erfolgen nur mit + // Services & Topics ungleich 0! + if( hszService && hszTopic ) + { + if( IsConvHandleAvailable(pData) && Callback( XTYP_CONNECT, + 0, 0, hszTopic,hszService, 0, 0, (ULONG)bSameInst)) + { + // App erlaubt Verbindung mit Client + ConnectWithClient( hWndClient, hszPartner, + hszService, hszTopic, bSameInst, pDDEData ); + } + } + else + { + // ** Wildcard-Connect ** + ////WRITELOG("DdeInitiate:Wildconnect") + // vom Server eine Liste aller Service/Topic-Paare anfordern + CONVCONTEXT* pCC=(CONVCONTEXT*)(pDDEData+pDDEData->offConvContext); + DDESTRUCT* hList = Callback( XTYP_WILDCONNECT, 0, (HCONV)0, + hszTopic,hszService, (HDDEDATA)0, (ULONG)pCC, (ULONG)bSameInst ); + if( hList ) + { + HSZPAIR* pPairs = (HSZPAIR*)((char*)hList+hList->offabData); + while( pPairs->hszSvc ) + { + ////WRITELOG("DdeInitiate:Wildconnect.Connecting") + ConnectWithClient( hWndClient, hszPartner, + pPairs->hszSvc, pPairs->hszTopic, bSameInst, 0, pCC); + // Stringhandles gehoeren der App! (nicht free-en) + pPairs++; + } + DdeFreeDataHandle( hList ); + } + } + } +#if 0 && defined(OV_DEBUG) + else + { + WRITELOG("DdeInitiate:Service filtered") + } +#endif + DdeFreeStringHandle( hszTopic ); + DdeFreeStringHandle( hszService ); + DdeFreeStringHandle( hszPartner ); + MyDosFreeMem( pDDEData,"DdeInitiate" ); + ////WRITELOG("DdeInitiate:End") + return (MRESULT)TRUE; +} + +MRESULT ImpDdeMgr::DdeInitiateAck( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdeInitiateAck:Received") + DDEINIT* pDDEData = (DDEINIT*)(pParams->nPar2); + + if( !bListConnect && hCurConv ) + { + ////WRITELOG("DdeInitiateAck:Already connected") + MyDosFreeMem( pDDEData,"DdeInitiateAck" ); + WinPostMsg( hWndServer, WM_DDE_TERMINATE, (MPARAM)hWndServer, 0 ); + return (MRESULT)FALSE; + } + + HWND hWndThis = pParams->hWndReceiver; + // Referenz-Count unseres Client-Windows inkrementieren + IncConversationWndRefCount( hWndThis ); + + HWND hWndSrv = (HWND)(pParams->nPar1); + HSZ hszService = DdeCreateStringHandle( pDDEData->pszAppName, 850 ); + HSZ hszTopic = DdeCreateStringHandle( pDDEData->pszTopic, 850 ); + HSZ hszPartnerApp = GetAppName( hWndSrv ); + + hCurConv = CreateConvHandle( pData, pidThis, hWndThis, hWndSrv, + hszPartnerApp, hszService, hszTopic, 0 ); + + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hCurConv; + + // HCONV der PartnerApp suchen & bei uns eintragen + pConv->hConvPartner = GetConvHandle( pData, hWndSrv, hWndThis ); + // nicht asserten, da ja non-ddeml-Partner moeglich + // DBG_ASSERT(pConv->hConvPartner,"DDE:Partner not found"); + pConv->nStatus = ST_CONNECTED | ST_CLIENT; + + if( bListConnect ) + { + ////WRITELOG("DdeInitiateAck:ListConnect/Connecting hConvs") + // Status setzen & verketten + pConv->hConvList = hCurListId; + pConv->nPrevHCONV = nPrevConv; + pConv->nStatus |= ST_INLIST; + if( nPrevConv ) + { + pConv = pConvTable; + pConv += nPrevConv; + pConv->nNextHCONV = (USHORT)hCurConv; + } + nPrevConv = (USHORT)hCurConv; + } + + DdeFreeStringHandle( hszService ); + DdeFreeStringHandle( hszTopic ); + DdeFreeStringHandle( hszPartnerApp ); + MyDosFreeMem( pDDEData,"DdeInitiateAck" ); + ////WRITESTATUS("After DdeInitiateAck") + ////WRITELOG("DdeInitiateAck:End") + return (MRESULT)TRUE; +} + +MRESULT ImpDdeMgr::DdePoke( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdePoke:Received") + HSZ hszItem = 0; + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); + HCONV hConv = CheckIncoming( pParams, CBF_FAIL_REQUESTS, hszItem ); + BOOL bSuccess =FALSE; + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + if ( hConv && !(nTransactFilter & CBF_FAIL_POKES) && pInDDEData ) + { + if( Callback( XTYP_POKE, pInDDEData->usFormat, hConv, + pConv->hszTopic, hszItem, pInDDEData, 0, 0 ) + == (DDESTRUCT*)DDE_FACK ) + bSuccess = TRUE; + } +#if 0 && defined( OV_DEBUG ) + else + { + WRITELOG("DdePoke:Not processed") + } +#endif + if( pInDDEData ) + { + if( bSuccess ) + pInDDEData->fsStatus |= DDE_FACK; + else + pInDDEData->fsStatus &= (~DDE_FACK); + + MyWinDdePostMsg( pConv->hWndPartner, pConv->hWndThis, WM_DDE_ACK, + pInDDEData, DDEPM_RETRY ); + } + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; +} + +MRESULT ImpDdeMgr::DdeRequest( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdeRequest:Received") + HSZ hszItem = 0; + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); + if( pInDDEData ) + // ist fuer Requests nicht definiert + pInDDEData->fsStatus = 0; + HCONV hConv = CheckIncoming( pParams, CBF_FAIL_REQUESTS, hszItem ); + HWND hWndThis = pParams->hWndReceiver; + HWND hWndClient = (HWND)pParams->nPar1; + if( hConv ) + { + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + + DDESTRUCT* pOutDDEData = Callback( XTYP_REQUEST, pInDDEData->usFormat, + hConv, pConv->hszTopic, hszItem, (HDDEDATA)0, 0, 0 ); + + if ( !pOutDDEData ) + { + ////WRITELOG("DdeRequest:Not processed") + pInDDEData->fsStatus &= (~DDE_FACK); + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + } + else + { + ////WRITELOG("DdeRequest:Success") + MyDosFreeMem( pInDDEData,"DdeRequest" ); + pOutDDEData->fsStatus |= DDE_FRESPONSE; + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_DATA,pOutDDEData,DDEPM_RETRY); + } + } + else + { + pInDDEData->fsStatus &= (~DDE_FACK); + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + } + + DdeFreeStringHandle( hszItem ); + ////WRITELOG("DdeRequest:End") + return (MRESULT)0; +} + + +MRESULT ImpDdeMgr::DdeUnadvise( ImpWndProcParams* pParams ) +{ + ////WRITELOG("DdeUnadvise:Received") + + HSZ hszItem; + HCONV hConv = CheckIncoming( pParams, 0, hszItem ); + DDESTRUCT* pInDDEData = (DDESTRUCT*)(pParams->nPar2); + HWND hWndThis = pParams->hWndReceiver; + HWND hWndClient = (HWND)pParams->nPar1; + USHORT nClosedTransactions = 0; + if( hConv ) + { + USHORT nFormat = pInDDEData->usFormat; + // alle Transaktionen des HCONVs loeschen ? + if( !hszItem ) + { + // App benachrichtigen & Transaktionen loeschen + nClosedTransactions = SendUnadvises( hConv, nFormat, TRUE ); + } + else + { + ULONG nTransId = GetTransaction(pData, hConv, hszItem, nFormat); + if( nTransId ) + { + ////WRITELOG("DdeUnadvise:Transaction found") + Transaction* pTrans = pTransTable; + pTrans += (USHORT)nTransId; + ImpHCONV* pConv = pConvTable; + pConv += (USHORT)hConv; + nClosedTransactions = 1; + if( !(nTransactFilter & CBF_FAIL_ADVISES) ) + Callback( XTYP_ADVSTOP, nFormat, hConv, + pConv->hszTopic, hszItem, 0, 0, 0 ); + if( !pConv->hConvPartner ) + FreeTransaction( pData, nTransId ); + } +#if defined(OV_DEBUG) + else + { + WRITELOG("DdeUnadvise:Transaction not found") + } +#endif + } + } +#if defined(OV_DEBUG) + else + { + WRITELOG("DdeUnadvise:Conversation not found") + } +#endif + + if( !nClosedTransactions ) + pInDDEData->fsStatus &= (~DDE_FACK); + else + pInDDEData->fsStatus |= DDE_FACK; + + MyWinDdePostMsg(hWndClient,hWndThis,WM_DDE_ACK,pInDDEData,DDEPM_RETRY); + DdeFreeStringHandle( hszItem ); + return (MRESULT)0; +} + +BOOL ImpDdeMgr::WaitTransState( Transaction* pTrans, ULONG nTransId, + USHORT nNewState, ULONG nTimeout ) +{ + ////WRITELOG("WaitTransState:Start") + ImpHCONV* pConv = pConvTable; + pConv += pTrans->hConvOwner; + HAB hAB = WinQueryAnchorBlock( pConv->hWndThis ); + ULONG nTimerId = WinStartTimer( hAB, 0, 0, 50 ); + QMSG aQueueMsg; + +// while( WinGetMsg( hAB, &aQueueMsg, 0, 0, 0 ) && +// WinIsWindow( hAB, pConv->hWndPartner) && +// pTrans->nConvst != nNewState ) +// { +// WinDispatchMsg( hAB, &aQueueMsg ); +// } + + BOOL bContinue = TRUE; + while( bContinue ) + { + if( WinGetMsg( hAB, &aQueueMsg, 0, 0, 0 )) + { + WinDispatchMsg( hAB, &aQueueMsg ); + if( (!WinIsWindow( hAB, pConv->hWndPartner)) || + (pTrans->nConvst == nNewState) ) + { + bContinue = FALSE; + } + } + else + bContinue = FALSE; + } + + WinStopTimer( hAB, 0, nTimerId ); + ////WRITELOG("WaitTransState:End") + return TRUE; +} + + + + |