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