1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include "ddeimp.hxx"
21 #include <algorithm>
22 #include <memory>
23 #include <comphelper/string.hxx>
24 #include <rtl/ustring.hxx>
25 #include <svl/svdde.hxx>
26 #include <osl/thread.h>
27 #include <o3tl/sorted_vector.hxx>
28 #include <o3tl/char16_t2wchar_t.hxx>
29 
30 enum DdeItemType
31 {
32     DDEITEM,
33     DDEGETPUTITEM
34 };
35 
36 struct DdeItemImpData
37 {
38     HCONV nHCnv;
39     sal_uInt16 nCnt;
40 
DdeItemImpDataDdeItemImpData41     explicit DdeItemImpData( HCONV nH ) : nHCnv( nH ), nCnt( 1 ) {}
42 };
43 
SvrCallback(UINT nCode,UINT nCbType,HCONV hConv,HSZ hText1,HSZ hText2,HDDEDATA hData,ULONG_PTR,ULONG_PTR)44 HDDEDATA CALLBACK DdeInternal::SvrCallback(
45             UINT nCode, UINT nCbType, HCONV hConv, HSZ hText1, HSZ hText2,
46             HDDEDATA hData, ULONG_PTR, ULONG_PTR )
47 {
48     DdeServices&    rAll = DdeService::GetServices();
49     DdeService*     pService;
50     DdeTopic*       pTopic;
51     DdeItem*        pItem;
52     DdeData*        pData;
53     Conversation*   pC;
54 
55     DdeInstData* pInst = ImpGetInstData();
56     assert(pInst);
57 
58     switch( nCode )
59     {
60         case XTYP_WILDCONNECT:
61         {
62             int nTopics = 0;
63 
64             WCHAR chTopicBuf[250];
65             if( hText1 )
66                 DdeQueryStringW( pInst->hDdeInstSvr, hText1, chTopicBuf,
67                                 SAL_N_ELEMENTS(chTopicBuf), CP_WINUNICODE );
68 
69             for (auto& rpService : rAll)
70             {
71                 pService = rpService;
72                 if ( !hText2 || ( *pService->pName == hText2 ) )
73                 {
74                     OUString sTopics( pService->Topics() );
75                     if (!sTopics.isEmpty())
76                     {
77                         if( hText1 )
78                         {
79                             sal_Int32 n = 0;
80                             while( -1 != n )
81                             {
82                                 OUString s( sTopics.getToken( 0, '\t', n ));
83                                 if( s == o3tl::toU(chTopicBuf) )
84                                     ++nTopics;
85                             }
86                         }
87                         else
88                             nTopics += comphelper::string::getTokenCount(sTopics, '\t');
89                     }
90                 }
91             }
92 
93             if( !nTopics )
94                 return nullptr;
95 
96             auto pPairs = std::make_unique<HSZPAIR[]>(nTopics + 1);
97 
98             HSZPAIR* q = pPairs.get();
99             for (auto& rpService : rAll)
100             {
101                 pService = rpService;
102                 if ( !hText2 || (*pService->pName == hText2 ) )
103                 {
104                     OUString sTopics( pService->Topics() );
105                     sal_Int32 n = 0;
106                     while( -1 != n )
107                     {
108                         OUString s( sTopics.getToken( 0, '\t', n ));
109                         s = s.replaceAll("\n", "").replaceAll("\r", "");
110                         if( !hText1 || s == o3tl::toU(chTopicBuf) )
111                         {
112                             DdeString aDStr( pInst->hDdeInstSvr, s );
113                             pTopic = FindTopic( *pService, aDStr.getHSZ() );
114                             if( pTopic )
115                             {
116                                 q->hszSvc   = pService->pName->getHSZ();
117                                 q->hszTopic = pTopic->pName->getHSZ();
118                                 q++;
119                             }
120                         }
121                     }
122                 }
123             }
124 
125             q->hszSvc   = nullptr;
126             q->hszTopic = nullptr;
127             HDDEDATA h = DdeCreateDataHandle(
128                             pInst->hDdeInstSvr,
129                             reinterpret_cast<LPBYTE>(pPairs.get()),
130                             sizeof(HSZPAIR) * (nTopics+1),
131                             0, nullptr, nCbType, 0);
132             return h;
133         }
134 
135         case XTYP_CONNECT:
136             pService = FindService( hText2 );
137             if ( pService)
138                 pTopic = FindTopic( *pService, hText1 );
139             else
140                 pTopic = nullptr;
141             if ( pTopic )
142                 return reinterpret_cast<HDDEDATA>(DDE_FACK);
143             else
144                 return nullptr;
145 
146         case XTYP_CONNECT_CONFIRM:
147             pService = FindService( hText2 );
148             if ( pService )
149             {
150                 pTopic = FindTopic( *pService, hText1 );
151                 if ( pTopic )
152                 {
153                     pC = new Conversation;
154                     pC->hConv = hConv;
155                     pC->pTopic = pTopic;
156                     pService->m_vConv.emplace_back( pC );
157                 }
158             }
159             return nullptr;
160     }
161 
162     for (auto& rpService : rAll)
163     {
164         pService = rpService;
165         for ( size_t i = 0, n = pService->m_vConv.size(); i < n; ++i )
166         {
167             pC = pService->m_vConv[ i ].get();
168             if ( pC->hConv == hConv )
169                 goto found;
170         }
171     }
172 
173     return reinterpret_cast<HDDEDATA>(DDE_FNOTPROCESSED);
174 
175 found:
176     if ( nCode == XTYP_DISCONNECT)
177     {
178         DisconnectTopic(*pC->pTopic, hConv);
179         auto it = std::find_if(pService->m_vConv.begin(), pService->m_vConv.end(),
180             [&pC](const std::unique_ptr<Conversation>& rxConv) { return rxConv.get() == pC; });
181         if (it != pService->m_vConv.end())
182             pService->m_vConv.erase( it );
183         return nullptr;
184     }
185 
186     bool bExec = nCode == XTYP_EXECUTE;
187     pTopic = pC->pTopic;
188     if ( pTopic && !bExec )
189         pItem = FindItem( *pTopic, hText2 );
190     else
191         pItem = nullptr;
192 
193     if ( !bExec && !pService->HasCbFormat( nCbType ) )
194         pItem = nullptr;
195     if ( !pItem && !bExec )
196         return static_cast<HDDEDATA>(DDE_FNOTPROCESSED);
197     if ( pItem )
198         pTopic->aItem = pItem->GetName();
199     else
200         pTopic->aItem.clear();
201 
202     bool bRes = false;
203     switch( nCode )
204     {
205     case XTYP_REQUEST:
206     case XTYP_ADVREQ:
207         {
208             OUString aRes; // Must be free not until the end!
209             if ( pTopic->IsSystemTopic() )
210             {
211                 if ( pTopic->aItem == SZDDESYS_ITEM_TOPICS )
212                     aRes = pService->Topics();
213                 else if ( pTopic->aItem == SZDDESYS_ITEM_SYSITEMS )
214                     aRes = pService->SysItems();
215                 else if ( pTopic->aItem == SZDDESYS_ITEM_STATUS )
216                     aRes = pService->Status();
217                 else if ( pTopic->aItem == SZDDESYS_ITEM_FORMATS )
218                     aRes = pService->Formats();
219                 else if ( pTopic->aItem == SZDDESYS_ITEM_HELP )
220                     aRes = OUString();
221                 else
222                     aRes = OUString();
223 
224                 if ( !aRes.isEmpty() )
225                     pData = new DdeData( aRes );
226                 else
227                     pData = nullptr;
228             }
229             else if( DDEGETPUTITEM == pItem->nType )
230             {
231                 pData = static_cast<DdeGetPutItem*>(pItem)->Get( DdeData::GetInternalFormat( nCbType ) );
232             }
233             else
234             {
235                 pData = pTopic->Get( DdeData::GetInternalFormat( nCbType ));
236             }
237 
238             if ( pData )
239             {
240                 return DdeCreateDataHandle( pInst->hDdeInstSvr,
241                                             static_cast<LPBYTE>(const_cast<void *>(pData->xImp->pData)),
242                                             pData->xImp->nData,
243                                             0, hText2,
244                                             DdeData::GetExternalFormat(
245                                                 pData->xImp->nFmt ),
246                                             0 );
247             }
248         }
249         break;
250 
251     case XTYP_POKE:
252         if ( !pTopic->IsSystemTopic() )
253         {
254             DdeData d;
255             d.xImp->hData = hData;
256             d.xImp->nFmt  = DdeData::GetInternalFormat( nCbType );
257             d.Lock();
258             if( DDEGETPUTITEM == pItem->nType )
259                 bRes = static_cast<DdeGetPutItem*>(pItem)->Put( &d );
260             else
261                 bRes = pTopic->Put( &d );
262         }
263         if ( bRes )
264             return reinterpret_cast<HDDEDATA>(DDE_FACK);
265         else
266             return reinterpret_cast<HDDEDATA>(DDE_FNOTPROCESSED);
267 
268     case XTYP_ADVSTART:
269         {
270             // Is the Item turning into a HotLink for the first time?
271             if( !pItem->pImpData && pTopic->StartAdviseLoop() )
272             {
273                 // Then the Item has been exchanged
274                 std::vector<DdeItem*>::iterator it(std::find(pTopic->aItems.begin(),
275                                                              pTopic->aItems.end(),
276                                                              pItem));
277                 if (it != pTopic->aItems.end())
278                     pTopic->aItems.erase(it);
279 
280                 std::vector<DdeItem*>::iterator iter;
281                 iter = std::find_if(pTopic->aItems.begin(), pTopic->aItems.end(),
282                     [&hText2](const DdeItem* pDdeItem) { return *pDdeItem->pName == hText2; });
283                 if (iter != pTopic->aItems.end())
284                 {
285                     // It was exchanged indeed
286                     delete pItem;
287                     pItem = nullptr;
288                 }
289 
290                 if( pItem )
291                     // It was not exchange, so back in
292                     pTopic->aItems.push_back(pItem);
293                 else
294                     pItem = iter != pTopic->aItems.end() ? *iter : nullptr;
295             }
296 
297             if (pItem)
298             {
299                 IncMonitor(pItem, hConv);
300             }
301         }
302         return reinterpret_cast<HDDEDATA>(TRUE);
303 
304     case XTYP_ADVSTOP:
305         DecMonitor(pItem, hConv);
306         return reinterpret_cast<HDDEDATA>(TRUE);
307 
308     case XTYP_EXECUTE:
309         {
310             DdeData aExec;
311             aExec.xImp->hData = hData;
312             aExec.xImp->nFmt  = DdeData::GetInternalFormat( nCbType );
313             aExec.Lock();
314             OUString aName;
315 
316             aName = static_cast<const sal_Unicode *>(aExec.xImp->pData);
317 
318             if( pTopic->IsSystemTopic() )
319                 bRes = false;
320             else
321                 bRes = pTopic->Execute( &aName );
322         }
323         if ( bRes )
324             return reinterpret_cast<HDDEDATA>(DDE_FACK);
325         else
326             return reinterpret_cast<HDDEDATA>(DDE_FNOTPROCESSED);
327     }
328 
329     return nullptr;
330 }
331 
FindService(HSZ hService)332 DdeService* DdeInternal::FindService( HSZ hService )
333 {
334     DdeServices& rSvc = DdeService::GetServices();
335     auto aI = std::find_if(rSvc.begin(), rSvc.end(),
336         [&hService](const DdeService* s) { return *s->pName == hService; });
337     if (aI != rSvc.end())
338         return *aI;
339 
340     return nullptr;
341 }
342 
FindTopic(DdeService & rService,HSZ hTopic)343 DdeTopic* DdeInternal::FindTopic( DdeService& rService, HSZ hTopic )
344 {
345     std::vector<DdeTopic*> &rTopics = rService.aTopics;
346     DdeInstData* pInst = ImpGetInstData();
347     assert(pInst);
348 
349     auto iter = std::find_if(rTopics.begin(), rTopics.end(),
350         [&hTopic](const DdeTopic* pTopic) { return *pTopic->pName == hTopic; });
351     if (iter != rTopics.end())
352         return *iter;
353 
354     return nullptr;
355 }
356 
FindItem(DdeTopic & rTopic,HSZ hItem)357 DdeItem* DdeInternal::FindItem( DdeTopic& rTopic, HSZ hItem )
358 {
359     std::vector<DdeItem*>::iterator iter;
360     std::vector<DdeItem*> &rItems = rTopic.aItems;
361     DdeInstData* pInst = ImpGetInstData();
362     assert(pInst);
363     bool bContinue = false;
364 
365     do
366     {   // middle check loop
367         iter = std::find_if(rItems.begin(), rItems.end(),
368             [&hItem](const DdeItem* pItem) { return *pItem->pName == hItem; });
369         if (iter != rItems.end())
370             return *iter;
371         bContinue = !bContinue;
372         if( !bContinue )
373             break;
374 
375         // Let's query our subclass
376         WCHAR chBuf[250];
377         DdeQueryStringW(pInst->hDdeInstSvr,hItem,chBuf,SAL_N_ELEMENTS(chBuf),CP_WINUNICODE );
378         bContinue = rTopic.MakeItem( o3tl::toU(chBuf) );
379         // We need to search again
380     }
381     while( bContinue );
382 
383     return nullptr;
384 }
385 
DdeService(const OUString & rService)386 DdeService::DdeService( const OUString& rService )
387 {
388     DdeInstData* pInst = ImpGetInstData();
389     if( !pInst )
390         pInst = ImpInitInstData();
391     pInst->nRefCount++;
392     pInst->nInstanceSvr++;
393 
394     if ( !pInst->hDdeInstSvr )
395     {
396         nStatus = sal::static_int_cast< short >(
397             DdeInitializeW( &pInst->hDdeInstSvr,
398                             DdeInternal::SvrCallback,
399                             APPCLASS_STANDARD |
400                             CBF_SKIP_REGISTRATIONS |
401                             CBF_SKIP_UNREGISTRATIONS, 0L ) );
402         pInst->pServicesSvr = new DdeServices;
403     }
404     else
405         nStatus = DMLERR_NO_ERROR;
406 
407     if ( pInst->pServicesSvr )
408         pInst->pServicesSvr->push_back( this );
409 
410     pName = new DdeString( pInst->hDdeInstSvr, rService );
411     if ( nStatus == DMLERR_NO_ERROR )
412     {
413         if ( !DdeNameService( pInst->hDdeInstSvr, pName->getHSZ(), nullptr,
414                               DNS_REGISTER | DNS_FILTEROFF ) )
415         {
416             nStatus = DMLERR_SYS_ERROR;
417         }
418     }
419     AddFormat( SotClipboardFormatId::STRING );
420     pSysTopic = new DdeTopic( SZDDESYS_TOPIC );
421     pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_TOPICS ) );
422     pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_SYSITEMS ) );
423     pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_STATUS ) );
424     pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_FORMATS ) );
425     pSysTopic->AddItem( DdeItem( SZDDESYS_ITEM_HELP ) );
426     AddTopic( *pSysTopic );
427 }
428 
~DdeService()429 DdeService::~DdeService()
430 {
431     DdeInstData* pInst = ImpGetInstData();
432     assert(pInst);
433     if ( pInst->pServicesSvr )
434         pInst->pServicesSvr->erase(std::remove(pInst->pServicesSvr->begin(), pInst->pServicesSvr->end(), this), pInst->pServicesSvr->end());
435 
436     delete pSysTopic;
437     delete pName;
438 
439     pInst->nInstanceSvr--;
440     pInst->nRefCount--;
441     if ( !pInst->nInstanceSvr && pInst->hDdeInstSvr )
442     {
443         if( DdeUninitialize( pInst->hDdeInstSvr ) )
444         {
445             pInst->hDdeInstSvr = 0;
446             delete pInst->pServicesSvr;
447             pInst->pServicesSvr = nullptr;
448             if( pInst->nRefCount == 0)
449                 ImpDeinitInstData();
450         }
451     }
452 }
453 
GetName() const454 OUString DdeService::GetName() const
455 {
456     return pName->toOUString();
457 }
458 
GetServices()459 DdeServices& DdeService::GetServices()
460 {
461     DdeInstData* pInst = ImpGetInstData();
462     assert(pInst);
463     return *(pInst->pServicesSvr);
464 }
465 
AddTopic(const DdeTopic & rTopic)466 void DdeService::AddTopic( const DdeTopic& rTopic )
467 {
468     RemoveTopic( rTopic );
469     aTopics.push_back(const_cast<DdeTopic *>(&rTopic));
470 }
471 
RemoveTopic(const DdeTopic & rTopic)472 void DdeService::RemoveTopic( const DdeTopic& rTopic )
473 {
474     auto iter = std::find_if(aTopics.begin(), aTopics.end(),
475         [&rTopic](const DdeTopic* pTopic) { return DdeCmpStringHandles(pTopic->pName->getHSZ(), rTopic.pName->getHSZ()) == 0; });
476     if (iter != aTopics.end())
477     {
478         aTopics.erase(iter);
479         // Delete all conversions!
480         // Or else we work on deleted topics!
481         for( size_t n = m_vConv.size(); n; )
482         {
483             auto const& pC = m_vConv[ --n ];
484             if( pC->pTopic == &rTopic )
485                 m_vConv.erase( m_vConv.begin() + n );
486         }
487     }
488 }
489 
HasCbFormat(sal_uInt16 nFmt)490 bool DdeService::HasCbFormat( sal_uInt16 nFmt )
491 {
492     return std::any_of(aFormats.begin(), aFormats.end(),
493         [nFmt](const long nFormat) { return nFormat == nFmt; });
494 }
495 
HasFormat(SotClipboardFormatId nFmt)496 bool DdeService::HasFormat(SotClipboardFormatId nFmt)
497 {
498     return HasCbFormat( static_cast<sal_uInt16>(DdeData::GetExternalFormat( nFmt )));
499 }
500 
AddFormat(SotClipboardFormatId nFmt)501 void DdeService::AddFormat(SotClipboardFormatId nFmt)
502 {
503     sal_uLong nExternalFmt = DdeData::GetExternalFormat( nFmt );
504     if (std::any_of(aFormats.begin(), aFormats.end(),
505             [nExternalFmt](const long nFormat) { return static_cast<sal_uLong>(nFormat) == nExternalFmt; }))
506         return;
507     aFormats.push_back( nExternalFmt );
508 }
509 
RemoveFormat(SotClipboardFormatId nFmt)510 void DdeService::RemoveFormat(SotClipboardFormatId nFmt)
511 {
512     sal_uLong nExternalFmt = DdeData::GetExternalFormat( nFmt );
513     auto it = std::find_if(aFormats.begin(), aFormats.end(),
514         [nExternalFmt](const long nFormat) { return static_cast<sal_uLong>(nFormat) == nExternalFmt; });
515     if (it != aFormats.end())
516         aFormats.erase( it );
517 }
518 
DdeTopic(const OUString & rName)519 DdeTopic::DdeTopic( const OUString& rName )
520 {
521     DdeInstData* pInst = ImpGetInstData();
522     assert(pInst);
523     pName = new DdeString( pInst->hDdeInstSvr, rName );
524 }
525 
~DdeTopic()526 DdeTopic::~DdeTopic()
527 {
528     for (auto& rpItem : aItems)
529     {
530         rpItem->pMyTopic = nullptr;
531         delete rpItem;
532     }
533 
534     delete pName;
535 }
536 
GetName() const537 OUString DdeTopic::GetName() const
538 {
539     return pName->toOUString();
540 }
541 
IsSystemTopic()542 bool DdeTopic::IsSystemTopic()
543 {
544     return GetName() == SZDDESYS_TOPIC;
545 }
546 
AddItem(const DdeItem & r)547 DdeItem* DdeTopic::AddItem( const DdeItem& r )
548 {
549     DdeItem* s;
550     if( DDEGETPUTITEM == r.nType )
551         s = new DdeGetPutItem( r );
552     else
553         s = new DdeItem( r );
554 
555     aItems.push_back( s );
556     s->pMyTopic = this;
557     return s;
558 }
559 
InsertItem(DdeItem * pNew)560 void DdeTopic::InsertItem( DdeItem* pNew )
561 {
562     if( pNew )
563     {
564         aItems.push_back( pNew );
565         pNew->pMyTopic = this;
566     }
567 }
568 
RemoveItem(const DdeItem & r)569 void DdeTopic::RemoveItem( const DdeItem& r )
570 {
571     auto iter = std::find_if(aItems.begin(), aItems.end(),
572         [&r](const DdeItem* pItem) { return DdeCmpStringHandles(pItem->pName->getHSZ(), r.pName->getHSZ()) == 0; });
573 
574     if ( iter != aItems.end() )
575     {
576         (*iter)->pMyTopic = nullptr;
577         delete *iter;
578         aItems.erase(iter);
579     }
580 }
581 
NotifyClient(const OUString & rItem)582 void DdeTopic::NotifyClient( const OUString& rItem )
583 {
584     DdeInstData* pInst = ImpGetInstData();
585     assert(pInst);
586     auto iter = std::find_if(aItems.begin(), aItems.end(),
587         [&rItem](const DdeItem* pItem) { return pItem->GetName().equals(rItem) && pItem->pImpData; });
588     if (iter != aItems.end())
589         DdePostAdvise( pInst->hDdeInstSvr, pName->getHSZ(), (*iter)->pName->getHSZ() );
590 }
591 
DisconnectTopic(DdeTopic & rTopic,HCONV nId)592 void DdeInternal::DisconnectTopic(DdeTopic & rTopic, HCONV nId)
593 {
594     for (const auto& rpItem : rTopic.aItems)
595     {
596         DecMonitor(rpItem, nId);
597     }
598 }
599 
Get(SotClipboardFormatId)600 DdeData* DdeTopic::Get(SotClipboardFormatId /*nFmt*/)
601 {
602     return nullptr;
603 }
604 
Put(const DdeData *)605 bool DdeTopic::Put( const DdeData* )
606 {
607     return false;
608 }
609 
Execute(const OUString *)610 bool DdeTopic::Execute( const OUString* )
611 {
612     return false;
613 }
614 
StartAdviseLoop()615 bool DdeTopic::StartAdviseLoop()
616 {
617     return false;
618 }
619 
DdeItem(const sal_Unicode * p)620 DdeItem::DdeItem( const sal_Unicode* p )
621 {
622     DdeInstData* pInst = ImpGetInstData();
623     assert(pInst);
624     pName = new DdeString( pInst->hDdeInstSvr, p );
625     nType = DDEITEM;
626     pMyTopic = nullptr;
627     pImpData = nullptr;
628 }
629 
DdeItem(const OUString & r)630 DdeItem::DdeItem( const OUString& r)
631 {
632     DdeInstData* pInst = ImpGetInstData();
633     assert(pInst);
634     pName = new DdeString( pInst->hDdeInstSvr, r );
635     nType = DDEITEM;
636     pMyTopic = nullptr;
637     pImpData = nullptr;
638 }
639 
DdeItem(const DdeItem & r)640 DdeItem::DdeItem( const DdeItem& r)
641 {
642     DdeInstData* pInst = ImpGetInstData();
643     assert(pInst);
644     pName = new DdeString( pInst->hDdeInstSvr, r.pName->toOUString() );
645     nType = DDEITEM;
646     pMyTopic = nullptr;
647     pImpData = nullptr;
648 }
649 
~DdeItem()650 DdeItem::~DdeItem()
651 {
652     if( pMyTopic )
653         pMyTopic->aItems.erase(std::remove(pMyTopic->aItems.begin(),
654                                            pMyTopic->aItems.end(),this));
655     delete pName;
656     delete pImpData;
657 }
658 
GetName() const659 OUString DdeItem::GetName() const
660 {
661     return pName->toOUString();
662 }
663 
NotifyClient()664 void DdeItem::NotifyClient()
665 {
666     if( pMyTopic && pImpData )
667     {
668         DdeInstData* pInst = ImpGetInstData();
669         assert(pInst);
670         DdePostAdvise( pInst->hDdeInstSvr, pMyTopic->pName->getHSZ(), pName->getHSZ() );
671     }
672 }
673 
IncMonitor(DdeItem * const pItem,HCONV nHCnv)674 void DdeInternal::IncMonitor(DdeItem *const pItem, HCONV nHCnv)
675 {
676     if (!pItem->pImpData)
677     {
678         pItem->pImpData = new std::vector<DdeItemImpData>;
679         if (DDEGETPUTITEM == pItem->nType)
680         {
681             static_cast<DdeGetPutItem*>(pItem)->AdviseLoop( true );
682         }
683     }
684     else
685     {
686         for (size_t n = pItem->pImpData->size(); n; )
687         {
688             if ((*pItem->pImpData)[ --n ].nHCnv == nHCnv)
689             {
690                 ++(*pItem->pImpData)[ n ].nHCnv;
691                 return ;
692             }
693         }
694     }
695 
696     pItem->pImpData->push_back( DdeItemImpData( nHCnv ) );
697 }
698 
DecMonitor(DdeItem * const pItem,HCONV nHCnv)699 void DdeInternal::DecMonitor(DdeItem *const pItem, HCONV nHCnv)
700 {
701     if (pItem->pImpData)
702     {
703         for( size_t n = 0; n < pItem->pImpData->size(); ++n )
704         {
705             DdeItemImpData* pData = &(*pItem->pImpData)[n];
706             if( pData->nHCnv == nHCnv )
707             {
708                 if( !pData->nCnt || !--pData->nCnt )
709                 {
710                     if (1 < pItem->pImpData->size())
711                     {
712                         pItem->pImpData->erase(pItem->pImpData->begin() + n);
713                     }
714                     else
715                     {
716                         delete pItem->pImpData;
717                         pItem->pImpData = nullptr;
718                         if (DDEGETPUTITEM == pItem->nType)
719                         {
720                             static_cast<DdeGetPutItem*>(pItem)->AdviseLoop(false);
721                         }
722                     }
723                 }
724                 return ;
725             }
726         }
727     }
728 }
729 
GetLinks()730 short DdeItem::GetLinks()
731 {
732     short nCnt = 0;
733     if( pImpData )
734     {
735         for (const auto& rData : *pImpData)
736         {
737             nCnt += rData.nCnt;
738         }
739     }
740     return nCnt;
741 }
742 
DdeGetPutItem(const sal_Unicode * p)743 DdeGetPutItem::DdeGetPutItem( const sal_Unicode* p )
744     : DdeItem( p )
745 {
746     nType = DDEGETPUTITEM;
747 }
748 
DdeGetPutItem(const OUString & rStr)749 DdeGetPutItem::DdeGetPutItem( const OUString& rStr )
750     : DdeItem( rStr )
751 {
752     nType = DDEGETPUTITEM;
753 }
754 
DdeGetPutItem(const DdeItem & rItem)755 DdeGetPutItem::DdeGetPutItem( const DdeItem& rItem )
756     : DdeItem( rItem )
757 {
758     nType = DDEGETPUTITEM;
759 }
760 
Get(SotClipboardFormatId)761 DdeData* DdeGetPutItem::Get(SotClipboardFormatId)
762 {
763     return nullptr;
764 }
765 
Put(const DdeData *)766 bool DdeGetPutItem::Put( const DdeData* )
767 {
768     return false;
769 }
770 
AdviseLoop(bool)771 void DdeGetPutItem::AdviseLoop( bool )
772 {
773 }
774 
SysItems()775 OUString DdeService::SysItems()
776 {
777     OUString s;
778     for ( const auto& rpTopic : aTopics )
779     {
780         if ( rpTopic->GetName() == SZDDESYS_TOPIC )
781         {
782             short n = 0;
783             for ( const auto& rpItem : rpTopic->aItems )
784             {
785                 if ( n )
786                     s += "\t";
787                 s += rpItem->GetName();
788                 n++;
789             }
790             s += "\r\n";
791         }
792     }
793 
794     return s;
795 }
796 
Topics()797 OUString DdeService::Topics()
798 {
799     OUString    s;
800     short       n = 0;
801 
802     for ( const auto& rpTopic : aTopics )
803     {
804         if ( n )
805             s += "\t";
806         s += rpTopic->GetName();
807         n++;
808     }
809     s += "\r\n";
810 
811     return s;
812 }
813 
Formats()814 OUString DdeService::Formats()
815 {
816     OUString    s;
817     short       n = 0;
818 
819     for (size_t i = 0; i < aFormats.size(); ++i, ++n)
820     {
821         long f = aFormats[ i ];
822         if ( n )
823             s += "\t";
824 
825         switch( static_cast<sal_uInt16>(f) )
826         {
827         case CF_TEXT:
828             s += "TEXT";
829             break;
830         case CF_BITMAP:
831             s += "BITMAP";
832             break;
833         default:
834             {
835                 WCHAR buf[128];
836                 GetClipboardFormatNameW( static_cast<UINT>(f), buf, SAL_N_ELEMENTS(buf) );
837                 s += o3tl::toU(buf);
838             }
839             break;
840         }
841 
842     }
843     s += "\r\n";
844 
845     return s;
846 }
847 
Status()848 OUString DdeService::Status()
849 {
850     return "Ready\r\n";
851 }
852 
MakeItem(const OUString &)853 bool DdeTopic::MakeItem( const OUString& )
854 {
855     return false;
856 }
857 
858 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
859