1
0
Fork 0
libreoffice/svl/source/svdde/ddecli.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

391 lines
11 KiB
C++

/* -*- 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 <officecfg/Office/Common.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 = DMLERR_SYS_ERROR;
if ( !officecfg::Office::Common::Security::Scripting::DisableActiveContent::get() )
{
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;
std::erase(rDde.aTransactions,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: */