820 lines
22 KiB
C++
820 lines
22 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 "ddeimp.hxx"
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <comphelper/string.hxx>
|
|
#include <rtl/ustring.hxx>
|
|
#include <svl/svdde.hxx>
|
|
#include <osl/thread.h>
|
|
#include <o3tl/sorted_vector.hxx>
|
|
#include <o3tl/char16_t2wchar_t.hxx>
|
|
#include <officecfg/Office/Common.hxx>
|
|
|
|
namespace {
|
|
|
|
enum DdeItemType
|
|
{
|
|
DDEITEM,
|
|
DDEGETPUTITEM
|
|
};
|
|
|
|
}
|
|
|
|
struct DdeItemImpData
|
|
{
|
|
HCONV nHCnv;
|
|
sal_uInt16 nCnt;
|
|
|
|
explicit DdeItemImpData( HCONV nH ) : nHCnv( nH ), nCnt( 1 ) {}
|
|
};
|
|
|
|
HDDEDATA CALLBACK DdeInternal::SvrCallback(
|
|
UINT nCode, UINT nCbType, HCONV hConv, HSZ hText1, HSZ hText2,
|
|
HDDEDATA hData, ULONG_PTR, ULONG_PTR )
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
|
|
switch( nCode )
|
|
{
|
|
case XTYP_WILDCONNECT:
|
|
{
|
|
std::vector<HSZPAIR> aPairs;
|
|
|
|
WCHAR chTopicBuf[256];
|
|
if( hText1 )
|
|
DdeQueryStringW( pInst->hDdeInstSvr, hText1, chTopicBuf,
|
|
SAL_N_ELEMENTS(chTopicBuf), CP_WINUNICODE );
|
|
|
|
for (auto& pService : DdeService::GetServices())
|
|
{
|
|
if (hText2 && !(*pService->pName == hText2))
|
|
continue;
|
|
|
|
OUString sTopics(pService->Topics().replaceAll("\n", "").replaceAll("\r", ""));
|
|
if (sTopics.isEmpty())
|
|
continue;
|
|
|
|
for (sal_Int32 n = 0; -1 != n;)
|
|
{
|
|
OUString s(sTopics.getToken(0, '\t', n));
|
|
if (hText1 && s != o3tl::toU(chTopicBuf))
|
|
continue;
|
|
|
|
DdeString aDStr(pInst->hDdeInstSvr, s);
|
|
if (auto pTopic = FindTopic(*pService, aDStr.getHSZ()))
|
|
{
|
|
auto& pair = aPairs.emplace_back();
|
|
pair.hszSvc = pService->pName->getHSZ();
|
|
pair.hszTopic = pTopic->pName->getHSZ();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aPairs.empty())
|
|
return nullptr;
|
|
aPairs.emplace_back(); // trailing zero
|
|
|
|
HDDEDATA h = DdeCreateDataHandle(
|
|
pInst->hDdeInstSvr,
|
|
reinterpret_cast<LPBYTE>(aPairs.data()),
|
|
sizeof(HSZPAIR) * aPairs.size(),
|
|
0, nullptr, nCbType, 0);
|
|
return h;
|
|
}
|
|
|
|
case XTYP_CONNECT:
|
|
if (auto pService = FindService(hText2))
|
|
if (FindTopic(*pService, hText1))
|
|
return reinterpret_cast<HDDEDATA>(DDE_FACK);
|
|
return nullptr;
|
|
|
|
case XTYP_CONNECT_CONFIRM:
|
|
if (auto pService = FindService(hText2))
|
|
{
|
|
if (auto pTopic = FindTopic(*pService, hText1))
|
|
{
|
|
auto pC = new Conversation;
|
|
pC->hConv = hConv;
|
|
pC->pTopic = pTopic;
|
|
pService->m_vConv.emplace_back( pC );
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
DdeService* pService = nullptr;
|
|
Conversation* pC = nullptr;
|
|
for (auto& rpService : DdeService::GetServices())
|
|
{
|
|
for ( size_t i = 0, n = rpService->m_vConv.size(); i < n; ++i )
|
|
{
|
|
pC = rpService->m_vConv[ i ].get();
|
|
if ( pC->hConv == hConv )
|
|
pService = rpService;
|
|
}
|
|
}
|
|
|
|
if (!pService)
|
|
return reinterpret_cast<HDDEDATA>(DDE_FNOTPROCESSED);
|
|
assert(pC);
|
|
|
|
if ( nCode == XTYP_DISCONNECT)
|
|
{
|
|
DisconnectTopic(*pC->pTopic, hConv);
|
|
auto it = std::find_if(pService->m_vConv.begin(), pService->m_vConv.end(),
|
|
[&pC](const std::unique_ptr<Conversation>& rxConv) { return rxConv.get() == pC; });
|
|
if (it != pService->m_vConv.end())
|
|
pService->m_vConv.erase( it );
|
|
return nullptr;
|
|
}
|
|
|
|
bool bExec = nCode == XTYP_EXECUTE;
|
|
DdeTopic* pTopic = pC->pTopic;
|
|
DdeItem* pItem;
|
|
if (pTopic && !bExec && pService->HasCbFormat(nCbType))
|
|
pItem = FindItem( *pTopic, hText2 );
|
|
else
|
|
pItem = nullptr;
|
|
|
|
if ( !pItem && !bExec )
|
|
return static_cast<HDDEDATA>(DDE_FNOTPROCESSED);
|
|
if ( pItem )
|
|
pTopic->aItem = pItem->GetName();
|
|
else
|
|
pTopic->aItem.clear();
|
|
|
|
bool bRes = false;
|
|
switch( nCode )
|
|
{
|
|
case XTYP_REQUEST:
|
|
case XTYP_ADVREQ:
|
|
{
|
|
OUString aRes; // Must be free not until the end!
|
|
DdeData* pData;
|
|
if ( pTopic->IsSystemTopic() )
|
|
{
|
|
if ( pTopic->aItem == SZDDESYS_ITEM_TOPICS )
|
|
aRes = pService->Topics();
|
|
else if ( pTopic->aItem == SZDDESYS_ITEM_SYSITEMS )
|
|
aRes = pService->SysItems();
|
|
else if ( pTopic->aItem == SZDDESYS_ITEM_STATUS )
|
|
aRes = pService->Status();
|
|
else if ( pTopic->aItem == SZDDESYS_ITEM_FORMATS )
|
|
aRes = pService->Formats();
|
|
else if ( pTopic->aItem == SZDDESYS_ITEM_HELP )
|
|
aRes = OUString();
|
|
else
|
|
aRes = OUString();
|
|
|
|
if ( !aRes.isEmpty() )
|
|
pData = new DdeData( aRes );
|
|
else
|
|
pData = nullptr;
|
|
}
|
|
else if( DDEGETPUTITEM == pItem->nType )
|
|
{
|
|
pData = static_cast<DdeGetPutItem*>(pItem)->Get( DdeData::GetInternalFormat( nCbType ) );
|
|
}
|
|
else
|
|
{
|
|
pData = pTopic->Get( DdeData::GetInternalFormat( nCbType ));
|
|
}
|
|
|
|
if ( pData )
|
|
{
|
|
return DdeCreateDataHandle( pInst->hDdeInstSvr,
|
|
static_cast<LPBYTE>(const_cast<void *>(pData->xImp->pData)),
|
|
pData->xImp->nData,
|
|
0, hText2,
|
|
DdeData::GetExternalFormat(
|
|
pData->xImp->nFmt ),
|
|
0 );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case XTYP_POKE:
|
|
if ( !pTopic->IsSystemTopic() )
|
|
{
|
|
DdeData d;
|
|
d.xImp->hData = hData;
|
|
d.xImp->nFmt = DdeData::GetInternalFormat( nCbType );
|
|
d.Lock();
|
|
if( DDEGETPUTITEM == pItem->nType )
|
|
bRes = static_cast<DdeGetPutItem*>(pItem)->Put( &d );
|
|
else
|
|
bRes = pTopic->Put( &d );
|
|
}
|
|
if ( bRes )
|
|
return reinterpret_cast<HDDEDATA>(DDE_FACK);
|
|
else
|
|
return reinterpret_cast<HDDEDATA>(DDE_FNOTPROCESSED);
|
|
|
|
case XTYP_ADVSTART:
|
|
{
|
|
// Is the Item turning into a HotLink for the first time?
|
|
if( !pItem->pImpData && pTopic->StartAdviseLoop() )
|
|
{
|
|
// Then the Item has been exchanged
|
|
std::vector<DdeItem*>::iterator it(std::find(pTopic->aItems.begin(),
|
|
pTopic->aItems.end(),
|
|
pItem));
|
|
if (it != pTopic->aItems.end())
|
|
pTopic->aItems.erase(it);
|
|
|
|
std::vector<DdeItem*>::iterator iter;
|
|
iter = std::find_if(pTopic->aItems.begin(), pTopic->aItems.end(),
|
|
[&hText2](const DdeItem* pDdeItem) { return *pDdeItem->pName == hText2; });
|
|
if (iter != pTopic->aItems.end())
|
|
{
|
|
// It was exchanged indeed
|
|
delete pItem;
|
|
pItem = nullptr;
|
|
}
|
|
|
|
if( pItem )
|
|
// It was not exchange, so back in
|
|
pTopic->aItems.push_back(pItem);
|
|
else
|
|
pItem = iter != pTopic->aItems.end() ? *iter : nullptr;
|
|
}
|
|
|
|
if (pItem)
|
|
{
|
|
IncMonitor(pItem, hConv);
|
|
}
|
|
}
|
|
return reinterpret_cast<HDDEDATA>(TRUE);
|
|
|
|
case XTYP_ADVSTOP:
|
|
DecMonitor(pItem, hConv);
|
|
return reinterpret_cast<HDDEDATA>(TRUE);
|
|
|
|
case XTYP_EXECUTE:
|
|
{
|
|
DdeData aExec;
|
|
aExec.xImp->hData = hData;
|
|
aExec.xImp->nFmt = DdeData::GetInternalFormat( nCbType );
|
|
aExec.Lock();
|
|
OUString aName;
|
|
|
|
aName = static_cast<const sal_Unicode *>(aExec.xImp->pData);
|
|
|
|
if( pTopic->IsSystemTopic() )
|
|
bRes = false;
|
|
else
|
|
bRes = pTopic->Execute( &aName );
|
|
}
|
|
if ( bRes )
|
|
return reinterpret_cast<HDDEDATA>(DDE_FACK);
|
|
else
|
|
return reinterpret_cast<HDDEDATA>(DDE_FNOTPROCESSED);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
DdeService* DdeInternal::FindService( HSZ hService )
|
|
{
|
|
DdeServices& rSvc = DdeService::GetServices();
|
|
auto aI = std::find_if(rSvc.begin(), rSvc.end(),
|
|
[&hService](const DdeService* s) { return *s->pName == hService; });
|
|
if (aI != rSvc.end())
|
|
return *aI;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
DdeTopic* DdeInternal::FindTopic( DdeService& rService, HSZ hTopic )
|
|
{
|
|
std::vector<DdeTopic*> &rTopics = rService.aTopics;
|
|
|
|
auto iter = std::find_if(rTopics.begin(), rTopics.end(),
|
|
[&hTopic](const DdeTopic* pTopic) { return *pTopic->pName == hTopic; });
|
|
if (iter != rTopics.end())
|
|
return *iter;
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
DdeItem* DdeInternal::FindItem( DdeTopic& rTopic, HSZ hItem )
|
|
{
|
|
std::vector<DdeItem*>::iterator iter;
|
|
std::vector<DdeItem*> &rItems = rTopic.aItems;
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
bool bContinue = false;
|
|
|
|
do
|
|
{ // middle check loop
|
|
iter = std::find_if(rItems.begin(), rItems.end(),
|
|
[&hItem](const DdeItem* pItem) { return *pItem->pName == hItem; });
|
|
if (iter != rItems.end())
|
|
return *iter;
|
|
bContinue = !bContinue;
|
|
if( !bContinue )
|
|
break;
|
|
|
|
// Let's query our subclass
|
|
WCHAR chBuf[250];
|
|
DdeQueryStringW(pInst->hDdeInstSvr,hItem,chBuf,SAL_N_ELEMENTS(chBuf),CP_WINUNICODE );
|
|
bContinue = rTopic.MakeItem( OUString(o3tl::toU(chBuf)) );
|
|
// We need to search again
|
|
}
|
|
while( bContinue );
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
DdeService::DdeService( const OUString& rService )
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
if( !pInst )
|
|
pInst = ImpInitInstData();
|
|
pInst->nRefCount++;
|
|
pInst->nInstanceSvr++;
|
|
|
|
if ( !pInst->hDdeInstSvr )
|
|
{
|
|
nStatus = DMLERR_SYS_ERROR;
|
|
if ( !officecfg::Office::Common::Security::Scripting::DisableActiveContent::get() )
|
|
{
|
|
nStatus = sal::static_int_cast< short >(
|
|
DdeInitializeW( &pInst->hDdeInstSvr,
|
|
DdeInternal::SvrCallback,
|
|
APPCLASS_STANDARD |
|
|
CBF_SKIP_REGISTRATIONS |
|
|
CBF_SKIP_UNREGISTRATIONS, 0 ) );
|
|
}
|
|
pInst->pServicesSvr = new DdeServices;
|
|
}
|
|
else
|
|
nStatus = DMLERR_NO_ERROR;
|
|
|
|
if ( pInst->pServicesSvr )
|
|
pInst->pServicesSvr->push_back( this );
|
|
|
|
pName = new DdeString( pInst->hDdeInstSvr, rService );
|
|
if ( nStatus == DMLERR_NO_ERROR )
|
|
{
|
|
if ( !DdeNameService( pInst->hDdeInstSvr, pName->getHSZ(), nullptr,
|
|
DNS_REGISTER | DNS_FILTEROFF ) )
|
|
{
|
|
nStatus = DMLERR_SYS_ERROR;
|
|
}
|
|
}
|
|
AddFormat( SotClipboardFormatId::STRING );
|
|
pSysTopic = new DdeTopic( SZDDESYS_TOPIC );
|
|
pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_TOPICS ) );
|
|
pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_SYSITEMS ) );
|
|
pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_STATUS ) );
|
|
pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_FORMATS ) );
|
|
pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_HELP ) );
|
|
AddTopic( *pSysTopic );
|
|
}
|
|
|
|
DdeService::~DdeService()
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
if ( pInst->pServicesSvr )
|
|
std::erase(*pInst->pServicesSvr, this);
|
|
|
|
delete pSysTopic;
|
|
delete pName;
|
|
|
|
pInst->nInstanceSvr--;
|
|
pInst->nRefCount--;
|
|
if ( !pInst->nInstanceSvr && pInst->hDdeInstSvr )
|
|
{
|
|
if( DdeUninitialize( pInst->hDdeInstSvr ) )
|
|
{
|
|
pInst->hDdeInstSvr = 0;
|
|
delete pInst->pServicesSvr;
|
|
pInst->pServicesSvr = nullptr;
|
|
if( pInst->nRefCount == 0)
|
|
ImpDeinitInstData();
|
|
}
|
|
}
|
|
}
|
|
|
|
OUString DdeService::GetName() const
|
|
{
|
|
return pName->toOUString();
|
|
}
|
|
|
|
DdeServices& DdeService::GetServices()
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
return *(pInst->pServicesSvr);
|
|
}
|
|
|
|
void DdeService::AddTopic( const DdeTopic& rTopic )
|
|
{
|
|
RemoveTopic( rTopic );
|
|
aTopics.push_back(const_cast<DdeTopic *>(&rTopic));
|
|
}
|
|
|
|
void DdeService::RemoveTopic( const DdeTopic& rTopic )
|
|
{
|
|
auto iter = std::find_if(aTopics.begin(), aTopics.end(),
|
|
[&rTopic](const DdeTopic* pTopic) { return DdeCmpStringHandles(pTopic->pName->getHSZ(), rTopic.pName->getHSZ()) == 0; });
|
|
if (iter != aTopics.end())
|
|
{
|
|
aTopics.erase(iter);
|
|
// Delete all conversions!
|
|
// Or else we work on deleted topics!
|
|
for( size_t n = m_vConv.size(); n; )
|
|
{
|
|
auto const& pC = m_vConv[ --n ];
|
|
if( pC->pTopic == &rTopic )
|
|
m_vConv.erase( m_vConv.begin() + n );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool DdeService::HasCbFormat( sal_uInt32 nFmt )
|
|
{
|
|
return std::find(aFormats.begin(), aFormats.end(), nFmt) != aFormats.end();
|
|
}
|
|
|
|
bool DdeService::HasFormat(SotClipboardFormatId nFmt)
|
|
{
|
|
return HasCbFormat( DdeData::GetExternalFormat( nFmt ));
|
|
}
|
|
|
|
void DdeService::AddFormat(SotClipboardFormatId nFmt)
|
|
{
|
|
sal_uInt32 nExternalFmt = DdeData::GetExternalFormat( nFmt );
|
|
if (HasCbFormat(nExternalFmt))
|
|
return;
|
|
aFormats.push_back( nExternalFmt );
|
|
}
|
|
|
|
void DdeService::RemoveFormat(SotClipboardFormatId nFmt)
|
|
{
|
|
sal_uInt32 nExternalFmt = DdeData::GetExternalFormat( nFmt );
|
|
auto it = std::find(aFormats.begin(), aFormats.end(), nExternalFmt);
|
|
if (it != aFormats.end())
|
|
aFormats.erase( it );
|
|
}
|
|
|
|
DdeTopic::DdeTopic( const OUString& rName )
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
pName = new DdeString( pInst->hDdeInstSvr, rName );
|
|
}
|
|
|
|
DdeTopic::~DdeTopic()
|
|
{
|
|
for (auto& rpItem : aItems)
|
|
{
|
|
rpItem->pMyTopic = nullptr;
|
|
delete rpItem;
|
|
}
|
|
|
|
delete pName;
|
|
}
|
|
|
|
OUString DdeTopic::GetName() const
|
|
{
|
|
return pName->toOUString();
|
|
}
|
|
|
|
bool DdeTopic::IsSystemTopic()
|
|
{
|
|
return GetName() == SZDDESYS_TOPIC;
|
|
}
|
|
|
|
DdeItem* DdeTopic::AddItem( const DdeItem& r )
|
|
{
|
|
DdeItem* s;
|
|
if( DDEGETPUTITEM == r.nType )
|
|
s = new DdeGetPutItem( r );
|
|
else
|
|
s = new DdeItem( r );
|
|
|
|
aItems.push_back( s );
|
|
s->pMyTopic = this;
|
|
return s;
|
|
}
|
|
|
|
void DdeTopic::InsertItem( DdeItem* pNew )
|
|
{
|
|
if( pNew )
|
|
{
|
|
aItems.push_back( pNew );
|
|
pNew->pMyTopic = this;
|
|
}
|
|
}
|
|
|
|
void DdeTopic::RemoveItem( const DdeItem& r )
|
|
{
|
|
auto iter = std::find_if(aItems.begin(), aItems.end(),
|
|
[&r](const DdeItem* pItem) { return DdeCmpStringHandles(pItem->pName->getHSZ(), r.pName->getHSZ()) == 0; });
|
|
|
|
if ( iter != aItems.end() )
|
|
{
|
|
(*iter)->pMyTopic = nullptr;
|
|
delete *iter;
|
|
aItems.erase(iter);
|
|
}
|
|
}
|
|
|
|
void DdeTopic::NotifyClient( const OUString& rItem )
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
auto iter = std::find_if(aItems.begin(), aItems.end(),
|
|
[&rItem](const DdeItem* pItem) { return pItem->GetName().equals(rItem) && pItem->pImpData; });
|
|
if (iter != aItems.end())
|
|
DdePostAdvise( pInst->hDdeInstSvr, pName->getHSZ(), (*iter)->pName->getHSZ() );
|
|
}
|
|
|
|
void DdeInternal::DisconnectTopic(DdeTopic & rTopic, HCONV nId)
|
|
{
|
|
for (const auto& rpItem : rTopic.aItems)
|
|
{
|
|
DecMonitor(rpItem, nId);
|
|
}
|
|
}
|
|
|
|
DdeData* DdeTopic::Get(SotClipboardFormatId /*nFmt*/)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
bool DdeTopic::Put( const DdeData* )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool DdeTopic::Execute( const OUString* )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool DdeTopic::StartAdviseLoop()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DdeItem::DdeItem( const sal_Unicode* p )
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
pName = new DdeString( pInst->hDdeInstSvr, OUString(p) );
|
|
nType = DDEITEM;
|
|
pMyTopic = nullptr;
|
|
pImpData = nullptr;
|
|
}
|
|
|
|
DdeItem::DdeItem( const OUString& r)
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
pName = new DdeString( pInst->hDdeInstSvr, r );
|
|
nType = DDEITEM;
|
|
pMyTopic = nullptr;
|
|
pImpData = nullptr;
|
|
}
|
|
|
|
DdeItem::DdeItem( const DdeItem& r)
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
pName = new DdeString( pInst->hDdeInstSvr, r.pName->toOUString() );
|
|
nType = DDEITEM;
|
|
pMyTopic = nullptr;
|
|
pImpData = nullptr;
|
|
}
|
|
|
|
DdeItem::~DdeItem()
|
|
{
|
|
if( pMyTopic )
|
|
std::erase(pMyTopic->aItems, this);
|
|
delete pName;
|
|
delete pImpData;
|
|
}
|
|
|
|
OUString DdeItem::GetName() const
|
|
{
|
|
return pName->toOUString();
|
|
}
|
|
|
|
void DdeItem::NotifyClient()
|
|
{
|
|
if( pMyTopic && pImpData )
|
|
{
|
|
DdeInstData* pInst = ImpGetInstData();
|
|
assert(pInst);
|
|
DdePostAdvise( pInst->hDdeInstSvr, pMyTopic->pName->getHSZ(), pName->getHSZ() );
|
|
}
|
|
}
|
|
|
|
void DdeInternal::IncMonitor(DdeItem *const pItem, HCONV nHCnv)
|
|
{
|
|
if (!pItem->pImpData)
|
|
{
|
|
pItem->pImpData = new std::vector<DdeItemImpData>;
|
|
if (DDEGETPUTITEM == pItem->nType)
|
|
{
|
|
static_cast<DdeGetPutItem*>(pItem)->AdviseLoop( true );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (size_t n = pItem->pImpData->size(); n; )
|
|
{
|
|
if ((*pItem->pImpData)[ --n ].nHCnv == nHCnv)
|
|
{
|
|
++(*pItem->pImpData)[ n ].nHCnv;
|
|
return ;
|
|
}
|
|
}
|
|
}
|
|
|
|
pItem->pImpData->push_back( DdeItemImpData( nHCnv ) );
|
|
}
|
|
|
|
void DdeInternal::DecMonitor(DdeItem *const pItem, HCONV nHCnv)
|
|
{
|
|
if (pItem->pImpData)
|
|
{
|
|
for( size_t n = 0; n < pItem->pImpData->size(); ++n )
|
|
{
|
|
DdeItemImpData* pData = &(*pItem->pImpData)[n];
|
|
if( pData->nHCnv == nHCnv )
|
|
{
|
|
if( !pData->nCnt || !--pData->nCnt )
|
|
{
|
|
if (1 < pItem->pImpData->size())
|
|
{
|
|
pItem->pImpData->erase(pItem->pImpData->begin() + n);
|
|
}
|
|
else
|
|
{
|
|
delete pItem->pImpData;
|
|
pItem->pImpData = nullptr;
|
|
if (DDEGETPUTITEM == pItem->nType)
|
|
{
|
|
static_cast<DdeGetPutItem*>(pItem)->AdviseLoop(false);
|
|
}
|
|
}
|
|
}
|
|
return ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
short DdeItem::GetLinks()
|
|
{
|
|
short nCnt = 0;
|
|
if( pImpData )
|
|
{
|
|
for (const auto& rData : *pImpData)
|
|
{
|
|
nCnt += rData.nCnt;
|
|
}
|
|
}
|
|
return nCnt;
|
|
}
|
|
|
|
DdeGetPutItem::DdeGetPutItem( const sal_Unicode* p )
|
|
: DdeItem( p )
|
|
{
|
|
nType = DDEGETPUTITEM;
|
|
}
|
|
|
|
DdeGetPutItem::DdeGetPutItem( const OUString& rStr )
|
|
: DdeItem( rStr )
|
|
{
|
|
nType = DDEGETPUTITEM;
|
|
}
|
|
|
|
DdeGetPutItem::DdeGetPutItem( const DdeItem& rItem )
|
|
: DdeItem( rItem )
|
|
{
|
|
nType = DDEGETPUTITEM;
|
|
}
|
|
|
|
DdeData* DdeGetPutItem::Get(SotClipboardFormatId)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
bool DdeGetPutItem::Put( const DdeData* )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void DdeGetPutItem::AdviseLoop( bool )
|
|
{
|
|
}
|
|
|
|
OUString DdeService::SysItems()
|
|
{
|
|
OUString s;
|
|
for ( const auto& rpTopic : aTopics )
|
|
{
|
|
if ( rpTopic->GetName() == SZDDESYS_TOPIC )
|
|
{
|
|
short n = 0;
|
|
for ( const auto& rpItem : rpTopic->aItems )
|
|
{
|
|
if ( n )
|
|
s += "\t";
|
|
s += rpItem->GetName();
|
|
n++;
|
|
}
|
|
s += "\r\n";
|
|
}
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
OUString DdeService::Topics()
|
|
{
|
|
OUString s;
|
|
short n = 0;
|
|
|
|
for ( const auto& rpTopic : aTopics )
|
|
{
|
|
if ( n )
|
|
s += "\t";
|
|
s += rpTopic->GetName();
|
|
n++;
|
|
}
|
|
s += "\r\n";
|
|
|
|
return s;
|
|
}
|
|
|
|
OUString DdeService::Formats()
|
|
{
|
|
OUString s;
|
|
short n = 0;
|
|
|
|
for (size_t i = 0; i < aFormats.size(); ++i, ++n)
|
|
{
|
|
sal_uInt32 f = aFormats[ i ];
|
|
if ( n )
|
|
s += "\t";
|
|
|
|
switch( f )
|
|
{
|
|
case CF_TEXT:
|
|
s += "TEXT";
|
|
break;
|
|
case CF_BITMAP:
|
|
s += "BITMAP";
|
|
break;
|
|
default:
|
|
{
|
|
WCHAR buf[128];
|
|
GetClipboardFormatNameW( f, buf, SAL_N_ELEMENTS(buf) );
|
|
s += o3tl::toU(buf);
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
s += "\r\n";
|
|
|
|
return s;
|
|
}
|
|
|
|
OUString DdeService::Status()
|
|
{
|
|
return "Ready\r\n";
|
|
}
|
|
|
|
bool DdeTopic::MakeItem( const OUString& )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|