xref: /AOO41X/main/sfx2/source/appl/lnkbase2.cxx (revision eb494517ff9e4d147e78b6406401aa4afea48484)
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