summaryrefslogtreecommitdiffstats
path: root/svl/source/svdde/ddecli.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svl/source/svdde/ddecli.cxx')
-rw-r--r--svl/source/svdde/ddecli.cxx387
1 files changed, 387 insertions, 0 deletions
diff --git a/svl/source/svdde/ddecli.cxx b/svl/source/svdde/ddecli.cxx
new file mode 100644
index 000000000..852d7db9e
--- /dev/null
+++ b/svl/source/svdde/ddecli.cxx
@@ -0,0 +1,387 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <string.h>
+#include <algorithm>
+#include "ddeimp.hxx"
+#include <svl/svdde.hxx>
+#include <osl/thread.h>
+#include <comphelper/solarmutex.hxx>
+
+namespace {
+
+DdeInstData * theDdeInstData;
+
+}
+
+DdeInstData* ImpGetInstData()
+{
+ return theDdeInstData;
+}
+
+DdeInstData* ImpInitInstData()
+{
+ theDdeInstData = new DdeInstData;
+ return theDdeInstData;
+}
+
+void ImpDeinitInstData()
+{
+ delete theDdeInstData;
+ theDdeInstData = nullptr;
+}
+
+
+struct DdeImp
+{
+ HCONV hConv;
+ UINT nStatus;
+};
+
+HDDEDATA CALLBACK DdeInternal::CliCallback( UINT nCode, UINT nCbType,
+ HCONV hConv, HSZ, HSZ hText2,
+ HDDEDATA hData, ULONG_PTR nInfo1, ULONG_PTR )
+{
+ HDDEDATA nRet = DDE_FNOTPROCESSED;
+ const std::vector<DdeConnection*> &rAll = DdeConnection::GetConnections();
+ DdeConnection* self = nullptr;
+
+ DdeInstData* pInst = ImpGetInstData();
+ assert(pInst);
+
+ for ( size_t i = 0; i < rAll.size(); ++i)
+ {
+ self = rAll[i];
+
+ if ( self->pImp->hConv == hConv )
+ break;
+ }
+
+ if( self )
+ {
+ bool bFound = false;
+ std::vector<DdeTransaction*>::iterator iter;
+ for( iter = self->aTransactions.begin(); iter != self->aTransactions.end(); ++iter )
+ {
+ switch( nCode )
+ {
+ case XTYP_XACT_COMPLETE:
+ if( static_cast<DWORD>((*iter)->nId) == nInfo1 )
+ {
+ nCode = (*iter)->nType & (XCLASS_MASK | XTYP_MASK);
+ (*iter)->bBusy = false;
+ (*iter)->Done( nullptr != hData );
+ bFound = true;
+ }
+ break;
+
+ case XTYP_DISCONNECT:
+ self->pImp->hConv = DdeReconnect( hConv );
+ self->pImp->nStatus = self->pImp->hConv
+ ? DMLERR_NO_ERROR
+ : DdeGetLastError( pInst->hDdeInstCli );
+ iter = self->aTransactions.end();
+ nRet = nullptr;
+ bFound = true;
+ break;
+
+ case XTYP_ADVDATA:
+ bFound = *(*iter)->pName == hText2;
+ break;
+ }
+ if( bFound )
+ break;
+ }
+
+ if( iter != self->aTransactions.end() )
+ {
+ switch( nCode )
+ {
+ case XTYP_ADVDATA:
+ if( !hData )
+ {
+ static_cast<DdeLink*>(*iter)->Notify();
+ nRet = reinterpret_cast<HDDEDATA>(DDE_FACK);
+ break;
+ }
+ [[fallthrough]];
+
+ case XTYP_REQUEST:
+ DdeData d;
+ d.xImp->hData = hData;
+ d.xImp->nFmt = DdeData::GetInternalFormat( nCbType );
+ d.Lock();
+ (*iter)->Data( &d );
+ nRet = reinterpret_cast<HDDEDATA>(DDE_FACK);
+ break;
+ }
+ }
+ }
+ return nRet;
+}
+
+DdeConnection::DdeConnection( const OUString& rService, const OUString& rTopic ):
+ pImp(std::make_unique<DdeImp>())
+{
+ pImp->nStatus = DMLERR_NO_ERROR;
+ pImp->hConv = nullptr;
+
+ DdeInstData* pInst = ImpGetInstData();
+ if( !pInst )
+ pInst = ImpInitInstData();
+ pInst->nRefCount++;
+ pInst->nInstanceCli++;
+ if ( !pInst->hDdeInstCli )
+ {
+ pImp->nStatus = DdeInitializeW( &pInst->hDdeInstCli,
+ DdeInternal::CliCallback,
+ APPCLASS_STANDARD | APPCMD_CLIENTONLY |
+ CBF_FAIL_ALLSVRXACTIONS |
+ CBF_SKIP_REGISTRATIONS |
+ CBF_SKIP_UNREGISTRATIONS, 0L );
+ }
+
+ pService = new DdeString( pInst->hDdeInstCli, rService );
+ pTopic = new DdeString( pInst->hDdeInstCli, rTopic );
+
+ if ( pImp->nStatus == DMLERR_NO_ERROR )
+ {
+ pImp->hConv = DdeConnect( pInst->hDdeInstCli,pService->getHSZ(),pTopic->getHSZ(), nullptr);
+ if( !pImp->hConv )
+ pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
+ }
+
+ pInst->aConnections.push_back( this );
+}
+
+DdeConnection::~DdeConnection()
+{
+ if ( pImp->hConv )
+ DdeDisconnect( pImp->hConv );
+
+ delete pService;
+ delete pTopic;
+
+ DdeInstData* pInst = ImpGetInstData();
+ assert(pInst);
+
+ std::vector<DdeConnection*>::iterator it(std::find(pInst->aConnections.begin(),
+ pInst->aConnections.end(),
+ this));
+ if (it != pInst->aConnections.end())
+ pInst->aConnections.erase(it);
+
+ pInst->nInstanceCli--;
+ pInst->nRefCount--;
+ if ( !pInst->nInstanceCli && pInst->hDdeInstCli )
+ {
+ if( DdeUninitialize( pInst->hDdeInstCli ) )
+ {
+ pInst->hDdeInstCli = 0;
+ if( pInst->nRefCount == 0 )
+ ImpDeinitInstData();
+ }
+ }
+}
+
+bool DdeConnection::IsConnected()
+{
+ CONVINFO c;
+ c.cb = sizeof( c );
+ if ( DdeQueryConvInfo( pImp->hConv, QID_SYNC, &c ) )
+ return true;
+ else
+ {
+ DdeInstData* pInst = ImpGetInstData();
+ pImp->hConv = DdeReconnect( pImp->hConv );
+ pImp->nStatus = pImp->hConv ? DMLERR_NO_ERROR : DdeGetLastError( pInst->hDdeInstCli );
+ return pImp->nStatus == DMLERR_NO_ERROR;
+ }
+}
+
+OUString DdeConnection::GetServiceName() const
+{
+ return pService->toOUString();
+}
+
+ OUString DdeConnection::GetTopicName() const
+{
+ return pTopic->toOUString();
+}
+
+const std::vector<DdeConnection*>& DdeConnection::GetConnections()
+{
+ DdeInstData* pInst = ImpGetInstData();
+ assert(pInst);
+ return pInst->aConnections;
+}
+
+DdeTransaction::DdeTransaction( DdeConnection& d, const OUString& rItemName,
+ tools::Long n )
+ : rDde( d )
+{
+ DdeInstData* pInst = ImpGetInstData();
+ pName = new DdeString( pInst->hDdeInstCli, rItemName );
+ nTime = n;
+ nId = 0;
+ nType = 0;
+ bBusy = false;
+
+ rDde.aTransactions.push_back( this );
+}
+
+DdeTransaction::~DdeTransaction()
+{
+ if ( nId && rDde.pImp->hConv )
+ {
+ DdeInstData* pInst = ImpGetInstData();
+ DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId );
+ }
+
+ delete pName;
+ rDde.aTransactions.erase(std::remove(rDde.aTransactions.begin(),
+ rDde.aTransactions.end(),this));
+}
+
+void DdeTransaction::Execute()
+{
+ HSZ hItem = pName->getHSZ();
+ void const * pData = aDdeData.getData();
+ DWORD nData = static_cast<DWORD>(aDdeData.getSize());
+ SotClipboardFormatId nIntFmt = aDdeData.xImp->nFmt;
+ UINT nExtFmt = DdeData::GetExternalFormat( nIntFmt );
+ DdeInstData* pInst = ImpGetInstData();
+
+ if ( nType == XTYP_EXECUTE )
+ hItem = nullptr;
+ if ( nType != XTYP_EXECUTE && nType != XTYP_POKE )
+ {
+ pData = nullptr;
+ nData = 0;
+ }
+ if ( nTime )
+ {
+ HDDEDATA hData = DdeClientTransaction( static_cast<LPBYTE>(const_cast<void *>(pData)),
+ nData, rDde.pImp->hConv,
+ hItem, nExtFmt, static_cast<UINT>(nType),
+ static_cast<DWORD>(nTime), nullptr );
+
+ rDde.pImp->nStatus = DdeGetLastError( pInst->hDdeInstCli );
+ if( hData && nType == XTYP_REQUEST )
+ {
+ {
+ DdeData d;
+ d.xImp->hData = hData;
+ d.xImp->nFmt = nIntFmt;
+ d.Lock();
+ Data( &d );
+ }
+ DdeFreeDataHandle( hData );
+ }
+ }
+ else
+ {
+ if ( nId && rDde.pImp->hConv )
+ DdeAbandonTransaction( pInst->hDdeInstCli, rDde.pImp->hConv, nId);
+ nId = 0;
+ bBusy = true;
+ DWORD result;
+ HDDEDATA hRet = DdeClientTransaction( static_cast<LPBYTE>(const_cast<void *>(pData)), nData,
+ rDde.pImp->hConv, hItem, nExtFmt,
+ static_cast<UINT>(nType), TIMEOUT_ASYNC,
+ &result );
+ nId = result;
+ rDde.pImp->nStatus = hRet ? DMLERR_NO_ERROR
+ : DdeGetLastError( pInst->hDdeInstCli );
+ }
+}
+
+OUString DdeTransaction::GetName() const
+{
+ return pName->toOUString();
+}
+
+void DdeTransaction::Data( const DdeData* p )
+{
+ comphelper::SolarMutex *pSolarMutex = comphelper::SolarMutex::get();
+ if ( pSolarMutex )
+ {
+ pSolarMutex->acquire();
+ aData.Call( p );
+ pSolarMutex = comphelper::SolarMutex::get();
+ if ( pSolarMutex )
+ pSolarMutex->release();
+ }
+}
+
+void DdeTransaction::Done( bool bDataValid )
+{
+ aDone.Call( bDataValid );
+}
+
+DdeLink::DdeLink( DdeConnection& d, const OUString& aItemName, tools::Long n )
+ : DdeTransaction (d, aItemName, n)
+{
+}
+
+DdeLink::~DdeLink()
+{
+ nType = sal_uInt16(XTYP_ADVSTOP);
+ nTime = 0;
+}
+
+void DdeLink::Notify()
+{
+ aNotify.Call( nullptr );
+}
+
+DdeRequest::DdeRequest( DdeConnection& d, const OUString& i, tools::Long n )
+ : DdeTransaction( d, i, n )
+{
+ nType = XTYP_REQUEST;
+}
+
+DdeHotLink::DdeHotLink( DdeConnection& d, const OUString& i )
+ : DdeLink( d, i, 0 )
+{
+ nType = XTYP_ADVSTART;
+}
+
+DdePoke::DdePoke( DdeConnection& d, const OUString& i, const DdeData& rData,
+ tools::Long n )
+ : DdeTransaction( d, i, n )
+{
+ aDdeData = rData;
+ nType = XTYP_POKE;
+}
+
+DdeExecute::DdeExecute( DdeConnection& d, const OUString& rData, tools::Long n )
+ : DdeTransaction( d, OUString(), n )
+{
+ aDdeData = DdeData( rData.getStr(), sizeof(sal_Unicode) * (rData.getLength() + 1), SotClipboardFormatId::STRING );
+ nType = XTYP_EXECUTE;
+}
+
+tools::Long DdeConnection::GetError() const
+{
+ return pImp->nStatus;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */