Line data Source code
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 <vcl/wrkwin.hxx>
21 : #include <svl/rectitem.hxx>
22 : #include <svl/eitem.hxx>
23 : #include <svl/intitem.hxx>
24 : #include <basic/sbstar.hxx>
25 : #include <svl/stritem.hxx>
26 : #include <svl/svdde.hxx>
27 : #include <sfx2/lnkbase.hxx>
28 : #include <sfx2/linkmgr.hxx>
29 :
30 : #include <tools/urlobj.hxx>
31 : #include <tools/diagnose_ex.h>
32 : #include <unotools/pathoptions.hxx>
33 :
34 : #include <sfx2/app.hxx>
35 : #include "appdata.hxx"
36 : #include <sfx2/objsh.hxx>
37 : #include <sfx2/viewfrm.hxx>
38 : #include <sfx2/dispatch.hxx>
39 : #include "sfxtypes.hxx"
40 : #include <sfx2/sfxsids.hrc>
41 : #include "helper.hxx"
42 : #include <sfx2/docfile.hxx>
43 : #include <comphelper/processfactory.hxx>
44 : #include <comphelper/string.hxx>
45 : #include <com/sun/star/ucb/IllegalIdentifierException.hpp>
46 :
47 : #if defined WNT
48 :
49 : OUString SfxDdeServiceName_Impl( const OUString& sIn )
50 : {
51 : OUStringBuffer sReturn(sIn.getLength());
52 :
53 : for ( sal_uInt16 n = sIn.getLength(); n; --n )
54 : {
55 : sal_Unicode cChar = sIn[n-1];
56 : if (comphelper::string::isalnumAscii(cChar))
57 : sReturn.append(cChar);
58 : }
59 :
60 : return sReturn.makeStringAndClear();
61 : }
62 :
63 : class ImplDdeService : public DdeService
64 : {
65 : public:
66 : ImplDdeService( const OUString& rNm )
67 : : DdeService( rNm )
68 : {}
69 : virtual bool MakeTopic( const OUString& );
70 :
71 : virtual OUString Topics();
72 :
73 : virtual bool SysTopicExecute( const OUString* pStr );
74 : };
75 :
76 :
77 : namespace
78 : {
79 : sal_Bool lcl_IsDocument( const OUString& rContent )
80 : {
81 : using namespace com::sun::star;
82 :
83 : sal_Bool bRet = sal_False;
84 : INetURLObject aObj( rContent );
85 : DBG_ASSERT( aObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" );
86 :
87 : try
88 : {
89 : ::ucbhelper::Content aCnt( aObj.GetMainURL( INetURLObject::NO_DECODE ), uno::Reference< ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext() );
90 : bRet = aCnt.isDocument();
91 : }
92 : catch( const ucb::CommandAbortedException& )
93 : {
94 : DBG_WARNING( "CommandAbortedException" );
95 : }
96 : catch( const ucb::IllegalIdentifierException& )
97 : {
98 : DBG_WARNING( "IllegalIdentifierException" );
99 : }
100 : catch( const ucb::ContentCreationException& )
101 : {
102 : DBG_WARNING( "IllegalIdentifierException" );
103 : }
104 : catch( const uno::Exception& )
105 : {
106 : SAL_WARN( "sfx.appl", "Any other exception" );
107 : }
108 :
109 : return bRet;
110 : }
111 : }
112 :
113 : bool ImplDdeService::MakeTopic( const OUString& rNm )
114 : {
115 : // Workaround for Event after Main() under OS/2
116 : // happens when exiting starts the App again
117 : if ( !Application::IsInExecute() )
118 : return false;
119 :
120 : // The Topic rNm is sought, do we have it?
121 : // First only loop over the ObjectShells to find those
122 : // with the specific name:
123 : sal_Bool bRet = sal_False;
124 : OUString sNm( rNm.toAsciiLowerCase() );
125 : TypeId aType( TYPE(SfxObjectShell) );
126 : SfxObjectShell* pShell = SfxObjectShell::GetFirst( &aType );
127 : while( pShell )
128 : {
129 : OUString sTmp( pShell->GetTitle(SFX_TITLE_FULLNAME) );
130 : if( sNm == sTmp.toAsciiLowerCase() )
131 : {
132 : SfxGetpApp()->AddDdeTopic( pShell );
133 : bRet = true;
134 : break;
135 : }
136 : pShell = SfxObjectShell::GetNext( *pShell, &aType );
137 : }
138 :
139 : if( !bRet )
140 : {
141 : INetURLObject aWorkPath( SvtPathOptions().GetWorkPath() );
142 : INetURLObject aFile;
143 : if ( aWorkPath.GetNewAbsURL( rNm, &aFile ) &&
144 : lcl_IsDocument( aFile.GetMainURL( INetURLObject::NO_DECODE ) ) )
145 : {
146 : // File exists? then try to load it:
147 : SfxStringItem aName( SID_FILE_NAME, aFile.GetMainURL( INetURLObject::NO_DECODE ) );
148 : SfxBoolItem aNewView(SID_OPEN_NEW_VIEW, sal_True);
149 :
150 : SfxBoolItem aSilent(SID_SILENT, sal_True);
151 : SfxDispatcher* pDispatcher = SfxGetpApp()->GetDispatcher_Impl();
152 : const SfxPoolItem* pRet = pDispatcher->Execute( SID_OPENDOC,
153 : SfxCallMode::SYNCHRON,
154 : &aName, &aNewView,
155 : &aSilent, 0L );
156 :
157 : if( pRet && pRet->ISA( SfxViewFrameItem ) &&
158 : ((SfxViewFrameItem*)pRet)->GetFrame() &&
159 : 0 != ( pShell = ((SfxViewFrameItem*)pRet)
160 : ->GetFrame()->GetObjectShell() ) )
161 : {
162 : SfxGetpApp()->AddDdeTopic( pShell );
163 : bRet = true;
164 : }
165 : }
166 : }
167 : return bRet;
168 : }
169 :
170 : OUString ImplDdeService::Topics()
171 : {
172 : OUString sRet;
173 : if( GetSysTopic() )
174 : sRet += GetSysTopic()->GetName();
175 :
176 : TypeId aType( TYPE(SfxObjectShell) );
177 : SfxObjectShell* pShell = SfxObjectShell::GetFirst( &aType );
178 : while( pShell )
179 : {
180 : if( SfxViewFrame::GetFirst( pShell ) )
181 : {
182 : if( !sRet.isEmpty() )
183 : sRet += "\t";
184 : sRet += pShell->GetTitle(SFX_TITLE_FULLNAME);
185 : }
186 : pShell = SfxObjectShell::GetNext( *pShell, &aType );
187 : }
188 : if( !sRet.isEmpty() )
189 : sRet += "\r\n";
190 : return sRet;
191 : }
192 :
193 : bool ImplDdeService::SysTopicExecute( const OUString* pStr )
194 : {
195 : return SfxGetpApp()->DdeExecute( *pStr );
196 : }
197 : #endif
198 :
199 : class SfxDdeTriggerTopic_Impl : public DdeTopic
200 : {
201 : #if defined WNT
202 : public:
203 : SfxDdeTriggerTopic_Impl()
204 : : DdeTopic( "TRIGGER" )
205 : {}
206 :
207 : virtual bool Execute( const OUString* ) SAL_OVERRIDE { return true; }
208 : #endif
209 : };
210 :
211 : class SfxDdeDocTopic_Impl : public DdeTopic
212 : {
213 : #if defined WNT
214 : public:
215 : SfxObjectShell* pSh;
216 : DdeData aData;
217 : ::com::sun::star::uno::Sequence< sal_Int8 > aSeq;
218 :
219 : SfxDdeDocTopic_Impl( SfxObjectShell* pShell )
220 : : DdeTopic( pShell->GetTitle(SFX_TITLE_FULLNAME) ), pSh( pShell )
221 : {}
222 :
223 : virtual DdeData* Get( sal_uIntPtr ) SAL_OVERRIDE;
224 : virtual bool Put( const DdeData* ) SAL_OVERRIDE;
225 : virtual bool Execute( const OUString* ) SAL_OVERRIDE;
226 : virtual bool StartAdviseLoop() SAL_OVERRIDE;
227 : virtual bool MakeItem( const OUString& rItem ) SAL_OVERRIDE;
228 : #endif
229 : };
230 :
231 :
232 : #if defined( WNT )
233 :
234 : namespace {
235 :
236 : /* [Description]
237 :
238 : Checks if 'rCmd' of the event 'rEvent' is (without '(') and then assemble
239 : this data into a <ApplicationEvent>, which is then excecuted through
240 : <Application::AppEvent()>. If 'rCmd' is the given event 'rEvent', then
241 : TRUE is returned, otherwise FALSE.
242 :
243 : [Example]
244 :
245 : rCmd = "Open(\"d:\doc\doc.sdw\")"
246 : rEvent = "Open"
247 : */
248 : sal_Bool SfxAppEvent_Impl( const OUString& rCmd, const OUString& rEvent,
249 : ApplicationEvent::Type eType )
250 : {
251 : OUString sEvent(rEvent + "(");
252 : if (rCmd.startsWithIgnoreAsciiCase(sEvent))
253 : {
254 : sal_Int32 start = sEvent.getLength();
255 : if ( rCmd.getLength() - start >= 2 )
256 : {
257 : // Transform into the ApplicationEvent Format
258 : //TODO: I /assume/ that rCmd should match the syntax of
259 : // <http://msdn.microsoft.com/en-us/library/ms648995.aspx>
260 : // "WM_DDE_EXECUTE message" but does not (handle commands enclosed
261 : // in [...]; handle commas separating multiple arguments; handle
262 : // double "", ((, )), [[, ]] in quoted arguments); see also the mail
263 : // thread starting at <http://lists.freedesktop.org/archives/
264 : // libreoffice/2013-July/054779.html> "DDE on Windows."
265 : std::vector<OUString> aData;
266 : for ( sal_Int32 n = start; n < rCmd.getLength() - 1; )
267 : {
268 : // Resiliently read arguments either starting with " and
269 : // spanning to the next " (if any; TODO: do we need to undo any
270 : // escaping within the string?) or with neither " nor SPC and
271 : // spanning to the next SPC (if any; TODO: is this from not
272 : // wrapped in "..." relevant? it would have been parsed by the
273 : // original code even if that was only by accident, so I left it
274 : // in), with runs of SPCs treated like single ones:
275 : switch ( rCmd[n] )
276 : {
277 : case '"':
278 : {
279 : sal_Int32 i = rCmd.indexOf('"', ++n);
280 : if (i < 0 || i > rCmd.getLength() - 1) {
281 : i = rCmd.getLength() - 1;
282 : }
283 : aData.push_back(rCmd.copy(n, i - n));
284 : n = i + 1;
285 : break;
286 : }
287 : case ' ':
288 : ++n;
289 : break;
290 : default:
291 : {
292 : sal_Int32 i = rCmd.indexOf(' ', n);
293 : if (i < 0 || i > rCmd.getLength() - 1) {
294 : i = rCmd.getLength() - 1;
295 : }
296 : aData.push_back(rCmd.copy(n, i - n));
297 : n = i + 1;
298 : break;
299 : }
300 : }
301 : }
302 :
303 : GetpApp()->AppEvent( ApplicationEvent(eType, aData) );
304 : return sal_True;
305 : }
306 : }
307 :
308 : return sal_False;
309 : }
310 :
311 : }
312 :
313 : /* Description]
314 :
315 : This method can be overloaded by application developers, to receive
316 : DDE-commands directed to their SfxApplication subclass.
317 :
318 : The base implementation understands the API functionality of the
319 : relevant SfxApplication subclass in BASIC syntax. Return values can
320 : not be transferred, unfortunately.
321 : */
322 : long SfxApplication::DdeExecute( const OUString& rCmd ) // Expressed in our BASIC-Syntax
323 : {
324 : // Print or Open-Event?
325 : if ( !( SfxAppEvent_Impl( rCmd, "Print", ApplicationEvent::TYPE_PRINT ) ||
326 : SfxAppEvent_Impl( rCmd, "Open", ApplicationEvent::TYPE_OPEN ) ) )
327 : {
328 : // all others are BASIC
329 : StarBASIC* pBasic = GetBasic();
330 : DBG_ASSERT( pBasic, "Where is the Basic???" );
331 : SbxVariable* pRet = pBasic->Execute( rCmd );
332 : if( !pRet )
333 : {
334 : SbxBase::ResetError();
335 : return 0;
336 : }
337 : }
338 : return 1;
339 : }
340 :
341 : #endif
342 :
343 : /* [Description]
344 :
345 : This method can be overloaded by application developers, to receive
346 : DDE-commands directed to the their SfxApplication subclass.
347 :
348 : The base implementation does nothing and returns 0.
349 : */
350 0 : long SfxObjectShell::DdeExecute( const OUString& rCmd ) // Expressed in our BASIC-Syntax
351 : {
352 : #if !HAVE_FEATURE_SCRIPTING
353 : (void) rCmd;
354 : #else
355 0 : StarBASIC* pBasic = GetBasic();
356 : DBG_ASSERT( pBasic, "Where is the Basic???" ) ;
357 0 : SbxVariable* pRet = pBasic->Execute( rCmd );
358 0 : if( !pRet )
359 : {
360 0 : SbxBase::ResetError();
361 0 : return 0;
362 : }
363 : #endif
364 0 : return 1;
365 : }
366 :
367 :
368 :
369 : /* [Description]
370 :
371 : This method can be overloaded by application developers, to receive
372 : DDE-data-requests directed to their SfxApplication subclass.
373 :
374 : The base implementation provides no data and returns false.
375 : */
376 0 : bool SfxObjectShell::DdeGetData( const OUString&, // the Item to be addressed
377 : const OUString&, // in: Format
378 : ::com::sun::star::uno::Any& )// out: requested data
379 : {
380 0 : return false;
381 : }
382 :
383 :
384 :
385 : /* [Description]
386 :
387 : This method can be overloaded by application developers, to receive
388 : DDE-data directed to their SfxApplication subclass.
389 :
390 : The base implementation is not receiving any data and returns false.
391 : */
392 0 : bool SfxObjectShell::DdeSetData( const OUString&, // the Item to be addressed
393 : const OUString&, // in: Format
394 : const ::com::sun::star::uno::Any& )// out: requested data
395 : {
396 0 : return false;
397 : }
398 :
399 : /* [Description]
400 :
401 : This method can be overloaded by application developers, to establish
402 : a DDE-hotlink to their SfxApplication subclass.
403 :
404 : The base implementation is not generate a link and returns 0.
405 : */
406 0 : ::sfx2::SvLinkSource* SfxObjectShell::DdeCreateLinkSource( const OUString& ) // the Item to be addressed
407 : {
408 0 : return 0;
409 : }
410 :
411 722 : void SfxObjectShell::ReconnectDdeLink(SfxObjectShell& /*rServer*/)
412 : {
413 722 : }
414 :
415 4728 : void SfxObjectShell::ReconnectDdeLinks(SfxObjectShell& rServer)
416 : {
417 4728 : TypeId aType = TYPE(SfxObjectShell);
418 4728 : SfxObjectShell* p = GetFirst(&aType, false);
419 15602 : while (p)
420 : {
421 6146 : if (&rServer != p)
422 1418 : p->ReconnectDdeLink(rServer);
423 :
424 6146 : p = GetNext(*p, &aType, false);
425 : }
426 4728 : }
427 :
428 : /* [Description]
429 :
430 : This method can be overloaded by application developers, to receive
431 : DDE-commands directed to the their SfxApplication subclass.
432 :
433 : The base implementation understands the API functionality of the
434 : relevant SfxViewFrame, which is shown and the relevant SfxViewShell
435 : and the relevant SfxApplication subclass in BASIC syntax. Return
436 : values can not be transferred, unfortunately.
437 : */
438 0 : long SfxViewFrame::DdeExecute( const OUString& rCmd ) // Expressed in our BASIC-Syntax
439 : {
440 0 : if ( GetObjectShell() )
441 0 : return GetObjectShell()->DdeExecute( rCmd );
442 :
443 0 : return 0;
444 : }
445 :
446 : /* [Description]
447 :
448 : This method can be overloaded by application developers, to receive
449 : DDE-data-requests directed to their SfxApplication subclass.
450 :
451 : The base implementation provides no data and returns false.
452 : */
453 0 : bool SfxViewFrame::DdeGetData( const OUString&, // the Item to be addressed
454 : const OUString&, // in: Format
455 : ::com::sun::star::uno::Any& )// out: requested data
456 : {
457 0 : return false;
458 : }
459 :
460 : /* [Description]
461 :
462 : This method can be overloaded by application developers, to receive
463 : DDE-data directed to their SfxApplication subclass.
464 :
465 : The base implementation is not receiving any data and returns false.
466 : */
467 0 : bool SfxViewFrame::DdeSetData( const OUString&, // the Item to be addressed
468 : const OUString&, // in: Format
469 : const ::com::sun::star::uno::Any& )// out: requested data
470 : {
471 0 : return false;
472 : }
473 :
474 : /* [Description]
475 :
476 : This method can be overloaded by application developers, to establish
477 : a DDE-hotlink to their SfxApplication subclass.
478 :
479 : The base implementation is not generate a link and returns 0.
480 : */
481 0 : ::sfx2::SvLinkSource* SfxViewFrame::DdeCreateLinkSource( const OUString& )// the Item to be addressed
482 : {
483 0 : return 0;
484 : }
485 :
486 303 : bool SfxApplication::InitializeDde()
487 : {
488 303 : int nError = 0;
489 : #if defined( WNT )
490 : DBG_ASSERT( !pAppData_Impl->pDdeService,
491 : "Dde can not be initialized multiple times" );
492 :
493 : pAppData_Impl->pDdeService = new ImplDdeService( Application::GetAppName() );
494 : nError = pAppData_Impl->pDdeService->GetError();
495 : if( !nError )
496 : {
497 : pAppData_Impl->pDocTopics = new SfxDdeDocTopics_Impl;
498 :
499 : // we certainly want to support RTF!
500 : pAppData_Impl->pDdeService->AddFormat( FORMAT_RTF );
501 :
502 : // Config path as a topic becauseof multiple starts
503 : INetURLObject aOfficeLockFile( SvtPathOptions().GetUserConfigPath() );
504 : aOfficeLockFile.insertName( "soffice.lck" );
505 : OUString aService( SfxDdeServiceName_Impl(
506 : aOfficeLockFile.GetMainURL(INetURLObject::DECODE_TO_IURI) ) );
507 : aService = aService.toAsciiUpperCase();
508 : pAppData_Impl->pDdeService2 = new ImplDdeService( aService );
509 : pAppData_Impl->pTriggerTopic = new SfxDdeTriggerTopic_Impl;
510 : pAppData_Impl->pDdeService2->AddTopic( *pAppData_Impl->pTriggerTopic );
511 : }
512 : #endif
513 303 : return !nError;
514 : }
515 :
516 168 : void SfxAppData_Impl::DeInitDDE()
517 : {
518 168 : DELETEZ( pTriggerTopic );
519 168 : DELETEZ( pDdeService2 );
520 168 : DELETEZ( pDocTopics );
521 168 : DELETEZ( pDdeService );
522 168 : }
523 :
524 : #if defined( WNT )
525 : void SfxApplication::AddDdeTopic( SfxObjectShell* pSh )
526 : {
527 : DBG_ASSERT( pAppData_Impl->pDocTopics, "There is no Dde-Service" );
528 : //OV: DDE is disconnected in server mode!
529 : if( !pAppData_Impl->pDocTopics )
530 : return;
531 :
532 : // prevent double submit
533 : OUString sShellNm;
534 : sal_Bool bFnd = sal_False;
535 : for (size_t n = pAppData_Impl->pDocTopics->size(); n;)
536 : {
537 : if( (*pAppData_Impl->pDocTopics)[ --n ]->pSh == pSh )
538 : {
539 : // If the document is untitled, is still a new Topic is created!
540 : if( !bFnd )
541 : {
542 : bFnd = sal_True;
543 : sShellNm = pSh->GetTitle(SFX_TITLE_FULLNAME).toAsciiLowerCase();
544 : }
545 : OUString sNm( (*pAppData_Impl->pDocTopics)[ n ]->GetName() );
546 : if( sShellNm == sNm.toAsciiLowerCase() )
547 : return ;
548 : }
549 : }
550 :
551 : SfxDdeDocTopic_Impl *const pTopic = new SfxDdeDocTopic_Impl(pSh);
552 : pAppData_Impl->pDocTopics->push_back(pTopic);
553 : pAppData_Impl->pDdeService->AddTopic( *pTopic );
554 : }
555 : #endif
556 :
557 0 : void SfxApplication::RemoveDdeTopic( SfxObjectShell* pSh )
558 : {
559 : #if defined WNT
560 : DBG_ASSERT( pAppData_Impl->pDocTopics, "There is no Dde-Service" );
561 : //OV: DDE is disconnected in server mode!
562 : if( !pAppData_Impl->pDocTopics )
563 : return;
564 :
565 : for (size_t n = pAppData_Impl->pDocTopics->size(); n; )
566 : {
567 : SfxDdeDocTopic_Impl *const pTopic = (*pAppData_Impl->pDocTopics)[ --n ];
568 : if (pTopic->pSh == pSh)
569 : {
570 : pAppData_Impl->pDdeService->RemoveTopic( *pTopic );
571 : delete pTopic;
572 : pAppData_Impl->pDocTopics->erase( pAppData_Impl->pDocTopics->begin() + n );
573 : }
574 : }
575 : #else
576 : (void) pSh;
577 : #endif
578 0 : }
579 :
580 0 : const DdeService* SfxApplication::GetDdeService() const
581 : {
582 0 : return pAppData_Impl->pDdeService;
583 : }
584 :
585 10525 : DdeService* SfxApplication::GetDdeService()
586 : {
587 10525 : return pAppData_Impl->pDdeService;
588 951 : }
589 :
590 : #if defined WNT
591 :
592 : DdeData* SfxDdeDocTopic_Impl::Get( sal_uIntPtr nFormat )
593 : {
594 : OUString sMimeType( SotExchange::GetFormatMimeType( nFormat ));
595 : ::com::sun::star::uno::Any aValue;
596 : bool nRet = pSh->DdeGetData( GetCurItem(), sMimeType, aValue );
597 : if( nRet && aValue.hasValue() && ( aValue >>= aSeq ) )
598 : {
599 : aData = DdeData( aSeq.getConstArray(), aSeq.getLength(), nFormat );
600 : return &aData;
601 : }
602 : aSeq.realloc( 0 );
603 : return 0;
604 : }
605 :
606 : bool SfxDdeDocTopic_Impl::Put( const DdeData* pData )
607 : {
608 : aSeq = ::com::sun::star::uno::Sequence< sal_Int8 >(
609 : (sal_Int8*)(const void*)*pData, (long)*pData );
610 : bool bRet;
611 : if( aSeq.getLength() )
612 : {
613 : ::com::sun::star::uno::Any aValue;
614 : aValue <<= aSeq;
615 : OUString sMimeType( SotExchange::GetFormatMimeType( pData->GetFormat() ));
616 : bRet = pSh->DdeSetData( GetCurItem(), sMimeType, aValue );
617 : }
618 : else
619 : bRet = false;
620 : return bRet;
621 : }
622 :
623 : bool SfxDdeDocTopic_Impl::Execute( const OUString* pStr )
624 : {
625 : long nRet = pStr ? pSh->DdeExecute( *pStr ) : 0;
626 : return 0 != nRet;
627 : }
628 :
629 : bool SfxDdeDocTopic_Impl::MakeItem( const OUString& rItem )
630 : {
631 : AddItem( DdeItem( rItem ) );
632 : return true;
633 : }
634 :
635 : bool SfxDdeDocTopic_Impl::StartAdviseLoop()
636 : {
637 : bool bRet = false;
638 : ::sfx2::SvLinkSource* pNewObj = pSh->DdeCreateLinkSource( GetCurItem() );
639 : if( pNewObj )
640 : {
641 : // then we also establish a corresponding SvBaseLink
642 : OUString sNm, sTmp( Application::GetAppName() );
643 : ::sfx2::MakeLnkName( sNm, &sTmp, pSh->GetTitle(SFX_TITLE_FULLNAME), GetCurItem() );
644 : new ::sfx2::SvBaseLink( sNm, OBJECT_DDE_EXTERN, pNewObj );
645 : bRet = true;
646 : }
647 : return bRet;
648 : }
649 :
650 : #endif
651 :
652 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|