1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sfx2.hxx"
26
27
28 #include <sfx2/lnkbase.hxx>
29 #include <sot/exchange.hxx>
30 #include <com/sun/star/uno/Any.hxx>
31 #include <com/sun/star/uno/Sequence.hxx>
32 #include <vcl/msgbox.hxx>
33 #include <sfx2/linkmgr.hxx>
34 #include <vcl/svapp.hxx>
35 #include "app.hrc"
36 #include "sfx2/sfxresid.hxx"
37 #include <sfx2/filedlghelper.hxx>
38 #include <tools/debug.hxx>
39 #include <svl/svdde.hxx>
40
41 using namespace ::com::sun::star::uno;
42
43 namespace sfx2
44 {
45
46 TYPEINIT0( SvBaseLink )
47
48 static DdeTopic* FindTopic( const String &, sal_uInt16* = 0 );
49
50 class ImplDdeItem;
51
52 struct BaseLink_Impl
53 {
54 Link m_aEndEditLink;
55 LinkManager* m_pLinkMgr;
56 Window* m_pParentWin;
57 FileDialogHelper* m_pFileDlg;
58 bool m_bIsConnect;
59
BaseLink_Implsfx2::BaseLink_Impl60 BaseLink_Impl() :
61 m_pLinkMgr( NULL )
62 , m_pParentWin( NULL )
63 , m_pFileDlg( NULL )
64 , m_bIsConnect( false )
65 {}
66
~BaseLink_Implsfx2::BaseLink_Impl67 ~BaseLink_Impl()
68 { delete m_pFileDlg; }
69 };
70
71 // nur fuer die interne Verwaltung
72 struct ImplBaseLinkData
73 {
74 struct tClientType
75 {
76 // gilt fuer alle Links
77 sal_uIntPtr nCntntType; // Update Format
78 // nicht Ole-Links
79 sal_Bool bIntrnlLnk; // ist es ein interner Link
80 sal_uInt16 nUpdateMode;// UpdateMode
81 };
82
83 struct tDDEType
84 {
85 ImplDdeItem* pItem;
86 };
87
88 union {
89 tClientType ClientType;
90 tDDEType DDEType;
91 };
ImplBaseLinkDatasfx2::ImplBaseLinkData92 ImplBaseLinkData()
93 {
94 ClientType.nCntntType = 0;
95 ClientType.bIntrnlLnk = sal_False;
96 ClientType.nUpdateMode = 0;
97 DDEType.pItem = NULL;
98 }
99 };
100
101
102 class ImplDdeItem : public DdeGetPutItem
103 {
104 SvBaseLink* pLink;
105 DdeData aData;
106 Sequence< sal_Int8 > aSeq; // Datacontainer for DdeData !!!
107 sal_Bool bIsValidData : 1;
108 sal_Bool bIsInDTOR : 1;
109 public:
ImplDdeItem(SvBaseLink & rLink,const String & rStr)110 ImplDdeItem( SvBaseLink& rLink, const String& rStr )
111 : DdeGetPutItem( rStr ), pLink( &rLink ), bIsValidData( sal_False ),
112 bIsInDTOR( sal_False )
113 {}
114 virtual ~ImplDdeItem();
115
116 virtual DdeData* Get( sal_uIntPtr );
117 virtual sal_Bool Put( const DdeData* );
118 virtual void AdviseLoop( sal_Bool );
119
Notify()120 void Notify()
121 {
122 bIsValidData = sal_False;
123 DdeGetPutItem::NotifyClient();
124 }
125
IsInDTOR() const126 sal_Bool IsInDTOR() const { return bIsInDTOR; }
127 };
128
129
130 /************************************************************************
131 |* SvBaseLink::SvBaseLink()
132 |*
133 |* Beschreibung
134 *************************************************************************/
135
SvBaseLink()136 SvBaseLink::SvBaseLink()
137 : SvRefBase(),
138 xObj(),
139 aLinkName(),
140 pImpl(new BaseLink_Impl()),
141 nObjType(OBJECT_CLIENT_SO),
142 bVisible(sal_True),
143 bSynchron(sal_True),
144 bUseCache(sal_True),
145 bWasLastEditOK(sal_False),
146 pImplData(new ImplBaseLinkData),
147 m_bIsReadOnly(false),
148 m_xInputStreamToLoadFrom()
149 {
150 }
151
152 /************************************************************************
153 |* SvBaseLink::SvBaseLink()
154 |*
155 |* Beschreibung
156 *************************************************************************/
157
SvBaseLink(sal_uInt16 nUpdateMode,sal_uIntPtr nContentType)158 SvBaseLink::SvBaseLink( sal_uInt16 nUpdateMode, sal_uIntPtr nContentType )
159 : SvRefBase(),
160 xObj(),
161 aLinkName(),
162 pImpl(new BaseLink_Impl()),
163 nObjType(OBJECT_CLIENT_SO),
164 bVisible(sal_True),
165 bSynchron(sal_True),
166 bUseCache(sal_True),
167 bWasLastEditOK(sal_False),
168 pImplData(new ImplBaseLinkData),
169 m_bIsReadOnly(false),
170 m_xInputStreamToLoadFrom()
171 {
172 // falls es ein Ole-Link wird,
173 pImplData->ClientType.nUpdateMode = nUpdateMode;
174 pImplData->ClientType.nCntntType = nContentType;
175 pImplData->ClientType.bIntrnlLnk = sal_False;
176 }
177
178 /************************************************************************
179 |* SvBaseLink::SvBaseLink()
180 |*
181 |* Beschreibung
182 *************************************************************************/
183
SvBaseLink(const String & rLinkName,sal_uInt16 nObjectType,SvLinkSource * pObj)184 SvBaseLink::SvBaseLink( const String& rLinkName, sal_uInt16 nObjectType, SvLinkSource* pObj )
185 : SvRefBase(),
186 xObj(),
187 aLinkName(rLinkName),
188 pImpl(0),
189 nObjType(nObjectType),
190 bVisible(sal_True),
191 bSynchron(sal_True),
192 bUseCache(sal_True),
193 bWasLastEditOK(sal_False),
194 pImplData(new ImplBaseLinkData),
195 m_bIsReadOnly(false),
196 m_xInputStreamToLoadFrom()
197 {
198 if( !pObj )
199 {
200 DBG_ASSERT( pObj, "Wo ist mein zu linkendes Object" );
201 return;
202 }
203
204 if( OBJECT_DDE_EXTERN == nObjType )
205 {
206 sal_uInt16 nItemStt = 0;
207 DdeTopic* pTopic = FindTopic( aLinkName, &nItemStt );
208 if( pTopic )
209 {
210 // dann haben wir alles zusammen
211 // MM hat gefummelt ???
212 // MM_TODO wie kriege ich den Namen
213 String aStr = aLinkName; // xLinkName->GetDisplayName();
214 aStr = aStr.Copy( nItemStt );
215 pImplData->DDEType.pItem = new ImplDdeItem( *this, aStr );
216 pTopic->InsertItem( pImplData->DDEType.pItem );
217
218 // dann koennen wir uns auch das Advise merken
219 xObj = pObj;
220 }
221 }
222 else if( pObj->Connect( this ) )
223 xObj = pObj;
224 }
225
226 /************************************************************************
227 |* SvBaseLink::~SvBaseLink()
228 |*
229 |* Beschreibung
230 *************************************************************************/
231
~SvBaseLink()232 SvBaseLink::~SvBaseLink()
233 {
234 Disconnect();
235
236 switch( nObjType )
237 {
238 case OBJECT_DDE_EXTERN:
239 if( !pImplData->DDEType.pItem->IsInDTOR() )
240 delete pImplData->DDEType.pItem;
241 break;
242 }
243
244 delete pImplData;
245
246 if(pImpl)
247 {
248 delete pImpl;
249 }
250 }
251
IMPL_LINK(SvBaseLink,EndEditHdl,String *,_pNewName)252 IMPL_LINK( SvBaseLink, EndEditHdl, String*, _pNewName )
253 {
254 if(pImpl)
255 {
256 String sNewName;
257 if ( _pNewName )
258 sNewName = *_pNewName;
259 if ( !ExecuteEdit( sNewName ) )
260 sNewName.Erase();
261 bWasLastEditOK = ( sNewName.Len() > 0 );
262 if ( pImpl->m_aEndEditLink.IsSet() )
263 pImpl->m_aEndEditLink.Call( this );
264 }
265 else
266 {
267 OSL_ENSURE(false, "No pImpl (!)");
268 }
269 return 0;
270 }
271
272 /************************************************************************
273 |* SvBaseLink::SetObjType()
274 |*
275 |* Beschreibung
276 *************************************************************************/
277
SetObjType(sal_uInt16 nObjTypeP)278 void SvBaseLink::SetObjType( sal_uInt16 nObjTypeP )
279 {
280 DBG_ASSERT( nObjType != OBJECT_CLIENT_DDE, "type already set" );
281 DBG_ASSERT( !xObj.Is(), "object exist" );
282
283 nObjType = nObjTypeP;
284 }
285
286 /************************************************************************
287 |* SvBaseLink::SetName()
288 |*
289 |* Beschreibung
290 *************************************************************************/
291
SetName(const String & rNm)292 void SvBaseLink::SetName( const String & rNm )
293 {
294 aLinkName = rNm;
295 }
296
297 /************************************************************************
298 |* SvBaseLink::GetName()
299 |*
300 |* Beschreibung
301 *************************************************************************/
302
GetName() const303 String SvBaseLink::GetName() const
304 {
305 return aLinkName;
306 }
307
308 /************************************************************************
309 |* SvBaseLink::SetObj()
310 |*
311 |* Beschreibung
312 *************************************************************************/
313
SetObj(SvLinkSource * pObj)314 void SvBaseLink::SetObj( SvLinkSource * pObj )
315 {
316 DBG_ASSERT( (nObjType & OBJECT_CLIENT_SO &&
317 pImplData->ClientType.bIntrnlLnk) ||
318 nObjType == OBJECT_CLIENT_GRF,
319 "no intern link" );
320 xObj = pObj;
321 }
322
323 /************************************************************************
324 |* SvBaseLink::SetLinkSourceName()
325 |*
326 |* Beschreibung
327 *************************************************************************/
328
SetLinkSourceName(const String & rLnkNm)329 void SvBaseLink::SetLinkSourceName( const String & rLnkNm )
330 {
331 if( aLinkName == rLnkNm )
332 return;
333
334 AddNextRef(); // sollte ueberfluessig sein
335 // Alte Verbindung weg
336 Disconnect();
337
338 aLinkName = rLnkNm;
339
340 // Neu verbinden
341 _GetRealObject();
342 ReleaseRef(); // sollte ueberfluessig sein
343 }
344
345 /************************************************************************
346 |* SvBaseLink::GetLinkSourceName()
347 |*
348 |* Beschreibung
349 *************************************************************************/
350
GetLinkSourceName() const351 String SvBaseLink::GetLinkSourceName() const
352 {
353 return aLinkName;
354 }
355
356
357 /************************************************************************
358 |* SvBaseLink::SetUpdateMode()
359 |*
360 |* Beschreibung
361 *************************************************************************/
362
SetUpdateMode(sal_uInt16 nMode)363 void SvBaseLink::SetUpdateMode( sal_uInt16 nMode )
364 {
365 if( ( OBJECT_CLIENT_SO & nObjType ) &&
366 pImplData->ClientType.nUpdateMode != nMode )
367 {
368 AddNextRef();
369 Disconnect();
370
371 pImplData->ClientType.nUpdateMode = nMode;
372 _GetRealObject();
373 ReleaseRef();
374 }
375 }
376
377 // --> OD 2008-06-19 #i88291#
clearStreamToLoadFrom()378 void SvBaseLink::clearStreamToLoadFrom()
379 {
380 m_xInputStreamToLoadFrom.clear();
381 if( xObj.Is() )
382 {
383 xObj->clearStreamToLoadFrom();
384 }
385 }
386 // <--
387
Update()388 sal_Bool SvBaseLink::Update()
389 {
390 if( OBJECT_CLIENT_SO & nObjType )
391 {
392 AddNextRef();
393 Disconnect();
394
395 _GetRealObject();
396 ReleaseRef();
397 if( xObj.Is() )
398 {
399 xObj->setStreamToLoadFrom(m_xInputStreamToLoadFrom,m_bIsReadOnly);
400 // m_xInputStreamToLoadFrom = 0;
401 String sMimeType( SotExchange::GetFormatMimeType(
402 pImplData->ClientType.nCntntType ));
403 Any aData;
404
405 if( xObj->GetData( aData, sMimeType ) )
406 {
407 DataChanged( sMimeType, aData );
408 //JP 13.07.00: Bug 76817 - for manual Updates there is no
409 // need to hold the ServerObject
410 if( OBJECT_CLIENT_DDE == nObjType &&
411 LINKUPDATE_ONCALL == GetUpdateMode() && xObj.Is() )
412 xObj->RemoveAllDataAdvise( this );
413 return sal_True;
414 }
415 if( xObj.Is() )
416 {
417 // sollten wir asynschron sein?
418 if( xObj->IsPending() )
419 return sal_True;
420
421 // dann brauchen wir das Object auch nicht mehr
422 AddNextRef();
423 Disconnect();
424 ReleaseRef();
425 }
426 }
427 }
428 return sal_False;
429 }
430
431
GetUpdateMode() const432 sal_uInt16 SvBaseLink::GetUpdateMode() const
433 {
434 return ( OBJECT_CLIENT_SO & nObjType )
435 ? pImplData->ClientType.nUpdateMode
436 : sal::static_int_cast< sal_uInt16 >( LINKUPDATE_ONCALL );
437 }
438
439
_GetRealObject(sal_Bool bConnect)440 void SvBaseLink::_GetRealObject( sal_Bool bConnect)
441 {
442 if(pImpl)
443 {
444 if( !pImpl->m_pLinkMgr )
445 return;
446
447 DBG_ASSERT( !xObj.Is(), "object already exist" );
448
449 if( OBJECT_CLIENT_DDE == nObjType )
450 {
451 String sServer;
452 if( pImpl->m_pLinkMgr->GetDisplayNames( this, &sServer ) &&
453 sServer == GetpApp()->GetAppName() ) // interner Link !!!
454 {
455 // damit der Internal - Link erzeugt werden kann !!!
456 nObjType = OBJECT_INTERN;
457 xObj = pImpl->m_pLinkMgr->CreateObj( this );
458
459 pImplData->ClientType.bIntrnlLnk = sal_True;
460 nObjType = OBJECT_CLIENT_DDE; // damit wir wissen was es mal war !!
461 }
462 else
463 {
464 pImplData->ClientType.bIntrnlLnk = sal_False;
465 xObj = pImpl->m_pLinkMgr->CreateObj( this );
466 }
467 }
468 else if( OBJECT_CLIENT_SO & nObjType )
469 xObj = pImpl->m_pLinkMgr->CreateObj( this );
470
471 if( bConnect && ( !xObj.Is() || !xObj->Connect( this ) ) )
472 Disconnect();
473 }
474 else
475 {
476 OSL_ENSURE(false, "No pImpl (!)");
477 }
478 }
479
GetContentType() const480 sal_uIntPtr SvBaseLink::GetContentType() const
481 {
482 if( OBJECT_CLIENT_SO & nObjType )
483 return pImplData->ClientType.nCntntType;
484
485 return 0; // alle Formate ?
486 }
487
488
SetContentType(sal_uIntPtr nType)489 sal_Bool SvBaseLink::SetContentType( sal_uIntPtr nType )
490 {
491 if( OBJECT_CLIENT_SO & nObjType )
492 {
493 pImplData->ClientType.nCntntType = nType;
494 return sal_True;
495 }
496 return sal_False;
497 }
498
GetLinkManager()499 LinkManager* SvBaseLink::GetLinkManager()
500 {
501 if(pImpl)
502 {
503 return pImpl->m_pLinkMgr;
504 }
505
506 return 0;
507 }
508
GetLinkManager() const509 const LinkManager* SvBaseLink::GetLinkManager() const
510 {
511 if(pImpl)
512 {
513 return pImpl->m_pLinkMgr;
514 }
515
516 return 0;
517 }
518
SetLinkManager(LinkManager * _pMgr)519 void SvBaseLink::SetLinkManager( LinkManager* _pMgr )
520 {
521 if(pImpl)
522 {
523 pImpl->m_pLinkMgr = _pMgr;
524 }
525 else
526 {
527 OSL_ENSURE(false, "No pImpl (!)");
528 }
529 }
530
Disconnect()531 void SvBaseLink::Disconnect()
532 {
533 if( xObj.Is() )
534 {
535 xObj->RemoveAllDataAdvise( this );
536 xObj->RemoveConnectAdvise( this );
537 xObj.Clear();
538 }
539 }
540
DataChanged(const String &,const::com::sun::star::uno::Any &)541 void SvBaseLink::DataChanged( const String &, const ::com::sun::star::uno::Any & )
542 {
543 switch( nObjType )
544 {
545 case OBJECT_DDE_EXTERN:
546 if( pImplData->DDEType.pItem )
547 pImplData->DDEType.pItem->Notify();
548 break;
549 }
550 }
551
Edit(Window * pParent,const Link & rEndEditHdl)552 void SvBaseLink::Edit( Window* pParent, const Link& rEndEditHdl )
553 {
554 if(pImpl)
555 {
556 pImpl->m_pParentWin = pParent;
557 pImpl->m_aEndEditLink = rEndEditHdl;
558 pImpl->m_bIsConnect = ( xObj.Is() != sal_False );
559 if( !pImpl->m_bIsConnect )
560 _GetRealObject( xObj.Is() );
561
562 bool bAsync = false;
563 Link aLink = LINK( this, SvBaseLink, EndEditHdl );
564
565 if( OBJECT_CLIENT_SO & nObjType && pImplData->ClientType.bIntrnlLnk )
566 {
567 if( pImpl->m_pLinkMgr )
568 {
569 SvLinkSourceRef ref = pImpl->m_pLinkMgr->CreateObj( this );
570 if( ref.Is() )
571 {
572 ref->Edit( pParent, this, aLink );
573 bAsync = true;
574 }
575 }
576 }
577 else
578 {
579 xObj->Edit( pParent, this, aLink );
580 bAsync = true;
581 }
582
583 if ( !bAsync )
584 {
585 ExecuteEdit( String() );
586 bWasLastEditOK = sal_False;
587 if ( pImpl->m_aEndEditLink.IsSet() )
588 pImpl->m_aEndEditLink.Call( this );
589 }
590 }
591 else
592 {
593 OSL_ENSURE(false, "No pImpl (!)");
594 }
595 }
596
ExecuteEdit(const String & _rNewName)597 bool SvBaseLink::ExecuteEdit( const String& _rNewName )
598 {
599 if(pImpl)
600 {
601 if( _rNewName.Len() != 0 )
602 {
603 SetLinkSourceName( _rNewName );
604 if( !Update() )
605 {
606 String sApp, sTopic, sItem, sError;
607 pImpl->m_pLinkMgr->GetDisplayNames( this, &sApp, &sTopic, &sItem );
608 if( nObjType == OBJECT_CLIENT_DDE )
609 {
610 sError = SfxResId( STR_DDE_ERROR );
611
612 sal_uInt16 nFndPos = sError.Search( '%' );
613 if( STRING_NOTFOUND != nFndPos )
614 {
615 sError.Erase( nFndPos, 1 ).Insert( sApp, nFndPos );
616 nFndPos = nFndPos + sApp.Len();
617 }
618 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
619 {
620 sError.Erase( nFndPos, 1 ).Insert( sTopic, nFndPos );
621 nFndPos = nFndPos + sTopic.Len();
622 }
623 if( STRING_NOTFOUND != ( nFndPos = sError.Search( '%', nFndPos )))
624 sError.Erase( nFndPos, 1 ).Insert( sItem, nFndPos );
625 }
626 else
627 return false;
628
629 ErrorBox( pImpl->m_pParentWin, WB_OK, sError ).Execute();
630 }
631 }
632 else if( !pImpl->m_bIsConnect )
633 Disconnect();
634 pImpl->m_bIsConnect = false;
635 return true;
636 }
637 else
638 {
639 OSL_ENSURE(false, "No pImpl (!)");
640 return false;
641 }
642 }
643
Closed()644 void SvBaseLink::Closed()
645 {
646 if( xObj.Is() )
647 // beim Advise Abmelden
648 xObj->RemoveAllDataAdvise( this );
649 }
650
GetFileDialog(sal_uInt32 nFlags,const String & rFactory) const651 FileDialogHelper* SvBaseLink::GetFileDialog( sal_uInt32 nFlags, const String& rFactory ) const
652 {
653 if(pImpl)
654 {
655 if ( pImpl->m_pFileDlg )
656 delete pImpl->m_pFileDlg;
657 pImpl->m_pFileDlg = new FileDialogHelper( nFlags, rFactory );
658 return pImpl->m_pFileDlg;
659 }
660 else
661 {
662 OSL_ENSURE(false, "No pImpl (!)");
663 return 0;
664 }
665 }
666
~ImplDdeItem()667 ImplDdeItem::~ImplDdeItem()
668 {
669 bIsInDTOR = sal_True;
670 // damit im Disconnect nicht jemand auf die Idee kommt, den Pointer zu
671 // loeschen!!
672 SvBaseLinkRef aRef( pLink );
673 aRef->Disconnect();
674 }
675
Get(sal_uIntPtr nFormat)676 DdeData* ImplDdeItem::Get( sal_uIntPtr nFormat )
677 {
678 if( pLink->GetObj() )
679 {
680 // ist das noch gueltig?
681 if( bIsValidData && nFormat == aData.GetFormat() )
682 return &aData;
683
684 Any aValue;
685 String sMimeType( SotExchange::GetFormatMimeType( nFormat ));
686 if( pLink->GetObj()->GetData( aValue, sMimeType ) )
687 {
688 if( aValue >>= aSeq )
689 {
690 aData = DdeData( (const char *)aSeq.getConstArray(), aSeq.getLength(), nFormat );
691
692 bIsValidData = sal_True;
693 return &aData;
694 }
695 }
696 }
697 aSeq.realloc( 0 );
698 bIsValidData = sal_False;
699 return 0;
700 }
701
702
Put(const DdeData *)703 sal_Bool ImplDdeItem::Put( const DdeData* )
704 {
705 DBG_ERROR( "ImplDdeItem::Put not implemented" );
706 return sal_False;
707 }
708
709
AdviseLoop(sal_Bool bOpen)710 void ImplDdeItem::AdviseLoop( sal_Bool bOpen )
711 {
712 // Verbindung wird geschlossen, also Link abmelden
713 if( pLink->GetObj() )
714 {
715 if( bOpen )
716 {
717 // es wird wieder eine Verbindung hergestellt
718 if( OBJECT_DDE_EXTERN == pLink->GetObjType() )
719 {
720 pLink->GetObj()->AddDataAdvise( pLink, String::CreateFromAscii( "text/plain;charset=utf-16" ), ADVISEMODE_NODATA );
721 pLink->GetObj()->AddConnectAdvise( pLink );
722 }
723 }
724 else
725 {
726 // damit im Disconnect nicht jemand auf die Idee kommt,
727 // den Pointer zu loeschen!!
728 SvBaseLinkRef aRef( pLink );
729 aRef->Disconnect();
730 }
731 }
732 }
733
734
FindTopic(const String & rLinkName,sal_uInt16 * pItemStt)735 static DdeTopic* FindTopic( const String & rLinkName, sal_uInt16* pItemStt )
736 {
737 if( 0 == rLinkName.Len() )
738 return 0;
739
740 String sNm( rLinkName );
741 sal_uInt16 nTokenPos = 0;
742 String sService( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
743
744 DdeServices& rSvc = DdeService::GetServices();
745 for( DdeService* pService = rSvc.First(); pService;
746 pService = rSvc.Next() )
747 if( pService->GetName() == sService )
748 {
749 // dann suchen wir uns das Topic
750 String sTopic( sNm.GetToken( 0, cTokenSeperator, nTokenPos ) );
751 if( pItemStt )
752 *pItemStt = nTokenPos;
753
754 DdeTopics& rTopics = pService->GetTopics();
755
756 for( int i = 0; i < 2; ++i )
757 {
758 for( DdeTopic* pTopic = rTopics.First(); pTopic;
759 pTopic = rTopics.Next() )
760 if( pTopic->GetName() == sTopic )
761 return pTopic;
762
763 // Topic nicht gefunden ?
764 // dann versuchen wir ihn mal anzulegen
765 if( i || !pService->MakeTopic( sTopic ) )
766 break; // hat nicht geklappt, also raus
767 }
768 break;
769 }
770 return 0;
771 }
772
773 }
774