1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: officeipcthread.cxx,v $
10 * $Revision: 1.62.44.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_desktop.hxx"
35 #include "officeipcthread.hxx"
36 #include "cmdlineargs.hxx"
37 #include "dispatchwatcher.hxx"
40 #include <vos/process.hxx>
41 #include <unotools/bootstrap.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/help.hxx>
44 #include <unotools/configmgr.hxx>
45 #include <osl/thread.hxx>
46 #include <rtl/digest.h>
47 #include <rtl/ustrbuf.hxx>
48 #include <rtl/instance.hxx>
49 #include <osl/conditn.hxx>
50 #include <svtools/moduleoptions.hxx>
51 #include <rtl/bootstrap.hxx>
52 #include <rtl/strbuf.hxx>
53 #include <comphelper/processfactory.hxx>
54 #include "osl/file.hxx"
55 #include "rtl/process.h"
56 #include "tools/getprocessworkingdir.hxx"
60 using namespace desktop
;
61 using namespace ::com::sun::star::uno
;
62 using namespace ::com::sun::star::lang
;
63 using namespace ::com::sun::star::frame
;
65 const char *OfficeIPCThread::sc_aTerminationSequence
= "InternalIPC::TerminateThread";
66 const int OfficeIPCThread::sc_nTSeqLength
= 28;
67 const char *OfficeIPCThread::sc_aShowSequence
= "-tofront";
68 const int OfficeIPCThread::sc_nShSeqLength
= 5;
69 const char *OfficeIPCThread::sc_aConfirmationSequence
= "InternalIPC::ProcessingDone";
70 const int OfficeIPCThread::sc_nCSeqLength
= 27;
72 namespace { static char const ARGUMENT_PREFIX
[] = "InternalIPC::Arguments"; }
74 // Type of pipe we use
87 class Parser
: public CommandLineArgs::Supplier
{
89 explicit Parser(rtl::OString
const & input
): m_input(input
) {
90 if (!m_input
.match(ARGUMENT_PREFIX
) ||
91 m_input
.getLength() == RTL_CONSTASCII_LENGTH(ARGUMENT_PREFIX
))
93 throw CommandLineArgs::Supplier::Exception();
95 m_index
= RTL_CONSTASCII_LENGTH(ARGUMENT_PREFIX
);
96 switch (m_input
[m_index
++]) {
102 if (!next(&url
, false)) {
103 throw CommandLineArgs::Supplier::Exception();
111 if (!next(&path
, false)) {
112 throw CommandLineArgs::Supplier::Exception();
115 if (osl::FileBase::getFileURLFromSystemPath(path
, url
) ==
116 osl::FileBase::E_None
)
123 throw CommandLineArgs::Supplier::Exception();
129 virtual boost::optional
< rtl::OUString
> getCwdUrl() { return m_cwdUrl
; }
131 virtual bool next(rtl::OUString
* argument
) { return next(argument
, true); }
134 virtual bool next(rtl::OUString
* argument
, bool prefix
) {
135 OSL_ASSERT(argument
!= NULL
);
136 if (m_index
< m_input
.getLength()) {
138 if (m_input
[m_index
] != ',') {
139 throw CommandLineArgs::Supplier::Exception();
143 rtl::OStringBuffer b
;
144 while (m_index
< m_input
.getLength()) {
145 char c
= m_input
[m_index
];
151 if (m_index
< m_input
.getLength()) {
152 c
= m_input
[m_index
++];
161 throw CommandLineArgs::Supplier::Exception();
164 throw CommandLineArgs::Supplier::Exception();
169 rtl::OString
b2(b
.makeStringAndClear());
170 if (!rtl_convertStringToUString(
171 &argument
->pData
, b2
.getStr(), b2
.getLength(),
172 RTL_TEXTENCODING_UTF8
,
173 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
174 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
175 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
177 throw CommandLineArgs::Supplier::Exception();
185 boost::optional
< rtl::OUString
> m_cwdUrl
;
186 rtl::OString m_input
;
191 ByteString
* arguments
, char prefix
, rtl::OUString
const & argument
)
194 if (!argument
.convertToString(
195 &utf8
, RTL_TEXTENCODING_UTF8
,
196 (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
|
197 RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR
)))
201 *arguments
+= prefix
;
202 for (sal_Int32 i
= 0; i
< utf8
.getLength(); ++i
) {
212 *arguments
+= "\\\\";
224 OfficeIPCThread
* OfficeIPCThread::pGlobalOfficeIPCThread
= 0;
225 namespace { struct Security
: public rtl::Static
<OSecurity
, Security
> {}; }
226 ::osl::Mutex
* OfficeIPCThread::pOfficeIPCThreadMutex
= 0;
229 String
CreateMD5FromString( const OUString
& aMsg
)
232 // BACK: Str "ababab....0f" Hexcode String
234 rtlDigest handle
= rtl_digest_create( rtl_Digest_AlgorithmMD5
);
237 const sal_uInt8
* pData
= (const sal_uInt8
*)aMsg
.getStr();
238 sal_uInt32 nSize
= ( aMsg
.getLength() * sizeof( sal_Unicode
));
239 sal_uInt32 nMD5KeyLen
= rtl_digest_queryLength( handle
);
240 sal_uInt8
* pMD5KeyBuffer
= new sal_uInt8
[ nMD5KeyLen
];
242 rtl_digest_init( handle
, pData
, nSize
);
243 rtl_digest_update( handle
, pData
, nSize
);
244 rtl_digest_get( handle
, pMD5KeyBuffer
, nMD5KeyLen
);
245 rtl_digest_destroy( handle
);
247 // Create hex-value string from the MD5 value to keep the string size minimal
248 OUStringBuffer
aBuffer( nMD5KeyLen
* 2 + 1 );
249 for ( sal_uInt32 i
= 0; i
< nMD5KeyLen
; i
++ )
250 aBuffer
.append( (sal_Int32
)pMD5KeyBuffer
[i
], 16 );
252 delete [] pMD5KeyBuffer
;
253 return aBuffer
.makeStringAndClear();
259 class ProcessEventsClass_Impl
262 DECL_STATIC_LINK( ProcessEventsClass_Impl
, CallEvent
, void* pEvent
);
263 DECL_STATIC_LINK( ProcessEventsClass_Impl
, ProcessDocumentsEvent
, void* pEvent
);
266 IMPL_STATIC_LINK_NOINSTANCE( ProcessEventsClass_Impl
, CallEvent
, void*, pEvent
)
268 // Application events are processed by the Desktop::HandleAppEvent implementation.
269 Desktop::HandleAppEvent( *((ApplicationEvent
*)pEvent
) );
270 delete (ApplicationEvent
*)pEvent
;
274 IMPL_STATIC_LINK_NOINSTANCE( ProcessEventsClass_Impl
, ProcessDocumentsEvent
, void*, pEvent
)
276 // Documents requests are processed by the OfficeIPCThread implementation
277 ProcessDocumentsRequest
* pDocsRequest
= (ProcessDocumentsRequest
*)pEvent
;
281 OfficeIPCThread::ExecuteCmdLineRequests( *pDocsRequest
);
287 void ImplPostForeignAppEvent( ApplicationEvent
* pEvent
)
289 Application::PostUserEvent( STATIC_LINK( NULL
, ProcessEventsClass_Impl
, CallEvent
), pEvent
);
292 void ImplPostProcessDocumentsEvent( ProcessDocumentsRequest
* pEvent
)
294 Application::PostUserEvent( STATIC_LINK( NULL
, ProcessEventsClass_Impl
, ProcessDocumentsEvent
), pEvent
);
297 OSignalHandler::TSignalAction SAL_CALL
SalMainPipeExchangeSignalHandler::signal(TSignalInfo
*pInfo
)
299 if( pInfo
->Signal
== osl_Signal_Terminate
)
300 OfficeIPCThread::DisableOfficeIPCThread();
301 return (TAction_CallNextHandler
);
304 // ----------------------------------------------------------------------------
306 // The OfficeIPCThreadController implementation is a bookkeeper for all pending requests
307 // that were created by the OfficeIPCThread. The requests are waiting to be processed by
308 // our framework loadComponentFromURL function (e.g. open/print request).
309 // During shutdown the framework is asking OfficeIPCThreadController about pending requests.
310 // If there are pending requests framework has to stop the shutdown process. It is waiting
311 // for these requests because framework is not able to handle shutdown and open a document
316 OUString SAL_CALL
OfficeIPCThreadController::getImplementationName()
317 throw ( RuntimeException
)
319 return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.OfficeIPCThreadController" ));
322 sal_Bool SAL_CALL
OfficeIPCThreadController::supportsService( const OUString
& )
323 throw ( RuntimeException
)
328 Sequence
< OUString
> SAL_CALL
OfficeIPCThreadController::getSupportedServiceNames()
329 throw ( RuntimeException
)
331 Sequence
< OUString
> aSeq( 0 );
336 void SAL_CALL
OfficeIPCThreadController::disposing( const EventObject
& )
337 throw( RuntimeException
)
341 // XTerminateListener
342 void SAL_CALL
OfficeIPCThreadController::queryTermination( const EventObject
& )
343 throw( TerminationVetoException
, RuntimeException
)
345 // Desktop ask about pending request through our office ipc pipe. We have to
346 // be sure that no pending request is waiting because framework is not able to
347 // handle shutdown and open a document concurrently.
349 if ( OfficeIPCThread::AreRequestsPending() )
350 throw TerminationVetoException();
352 OfficeIPCThread::SetDowning();
355 void SAL_CALL
OfficeIPCThreadController::notifyTermination( const EventObject
& )
356 throw( RuntimeException
)
360 // ----------------------------------------------------------------------------
362 ::osl::Mutex
& OfficeIPCThread::GetMutex()
364 // Get or create our mutex for thread-saftey
365 if ( !pOfficeIPCThreadMutex
)
367 ::osl::MutexGuard
aGuard( osl::Mutex::getGlobalMutex() );
368 if ( !pOfficeIPCThreadMutex
)
369 pOfficeIPCThreadMutex
= new osl::Mutex
;
372 return *pOfficeIPCThreadMutex
;
375 void OfficeIPCThread::SetDowning()
377 // We have the order to block all incoming requests. Framework
378 // wants to shutdown and we have to make sure that no loading/printing
379 // requests are executed anymore.
380 ::osl::MutexGuard
aGuard( GetMutex() );
382 if ( pGlobalOfficeIPCThread
)
383 pGlobalOfficeIPCThread
->mbDowning
= true;
386 static bool s_bInEnableRequests
= false;
388 void OfficeIPCThread::EnableRequests( bool i_bEnable
)
390 // switch between just queueing the requests and executing them
391 ::osl::MutexGuard
aGuard( GetMutex() );
393 if ( pGlobalOfficeIPCThread
)
395 s_bInEnableRequests
= true;
396 pGlobalOfficeIPCThread
->mbRequestsEnabled
= i_bEnable
;
399 // hit the compiler over the head
400 ProcessDocumentsRequest aEmptyReq
= ProcessDocumentsRequest( boost::optional
< rtl::OUString
>() );
401 // trigger already queued requests
402 OfficeIPCThread::ExecuteCmdLineRequests( aEmptyReq
);
404 s_bInEnableRequests
= false;
408 sal_Bool
OfficeIPCThread::AreRequestsPending()
410 // Give info about pending requests
411 ::osl::MutexGuard
aGuard( GetMutex() );
412 if ( pGlobalOfficeIPCThread
)
413 return ( pGlobalOfficeIPCThread
->mnPendingRequests
> 0 );
418 void OfficeIPCThread::RequestsCompleted( int nCount
)
420 // Remove nCount pending requests from our internal counter
421 ::osl::MutexGuard
aGuard( GetMutex() );
422 if ( pGlobalOfficeIPCThread
)
424 if ( pGlobalOfficeIPCThread
->mnPendingRequests
> 0 )
425 pGlobalOfficeIPCThread
->mnPendingRequests
-= nCount
;
429 OfficeIPCThread::Status
OfficeIPCThread::EnableOfficeIPCThread()
431 ::osl::MutexGuard
aGuard( GetMutex() );
433 if( pGlobalOfficeIPCThread
)
434 return IPC_STATUS_OK
;
436 ::rtl::OUString aUserInstallPath
;
437 ::rtl::OUString aDummy
;
439 ::vos::OStartupInfo aInfo
;
440 OfficeIPCThread
* pThread
= new OfficeIPCThread
;
442 pThread
->maPipeIdent
= OUString( RTL_CONSTASCII_USTRINGPARAM( "SingleOfficeIPC_" ) );
444 // The name of the named pipe is created with the hashcode of the user installation directory (without /user). We have to retrieve
445 // this information from a unotools implementation.
446 ::utl::Bootstrap::PathStatus aLocateResult
= ::utl::Bootstrap::locateUserInstallation( aUserInstallPath
);
447 if ( aLocateResult
== ::utl::Bootstrap::PATH_EXISTS
|| aLocateResult
== ::utl::Bootstrap::PATH_VALID
)
448 aDummy
= aUserInstallPath
;
452 return IPC_STATUS_BOOTSTRAP_ERROR
;
455 // Try to determine if we are the first office or not! This should prevent multiple
456 // access to the user directory !
457 // First we try to create our pipe if this fails we try to connect. We have to do this
458 // in a loop because the the other office can crash or shutdown between createPipe
463 aInfo
.getExecutableFile( aIniName
);
464 sal_uInt32 lastIndex
= aIniName
.lastIndexOf('/');
467 aIniName
= aIniName
.copy( 0, lastIndex
+1 );
468 aIniName
+= OUString( RTL_CONSTASCII_USTRINGPARAM( "perftune" ));
469 #if defined(WNT) || defined(OS2)
470 aIniName
+= OUString( RTL_CONSTASCII_USTRINGPARAM( ".ini" ));
472 aIniName
+= OUString( RTL_CONSTASCII_USTRINGPARAM( "rc" ));
476 ::rtl::Bootstrap
aPerfTuneIniFile( aIniName
);
478 OUString
aDefault( RTL_CONSTASCII_USTRINGPARAM( "0" ));
479 OUString aPreloadData
;
481 aPerfTuneIniFile
.getFrom( OUString( RTL_CONSTASCII_USTRINGPARAM( "FastPipeCommunication" )), aPreloadData
, aDefault
);
484 OUString aUserInstallPathHashCode
;
486 if ( aPreloadData
.equalsAscii( "1" ))
488 sal_Char szBuffer
[32];
489 sprintf( szBuffer
, "%d", SUPD
);
490 aUserInstallPathHashCode
= OUString( szBuffer
, strlen(szBuffer
), osl_getThreadTextEncoding() );
493 aUserInstallPathHashCode
= CreateMD5FromString( aDummy
);
496 // Check result to create a hash code from the user install path
497 if ( aUserInstallPathHashCode
.getLength() == 0 )
498 return IPC_STATUS_BOOTSTRAP_ERROR
; // Something completely broken, we cannot create a valid hash code!
500 pThread
->maPipeIdent
= pThread
->maPipeIdent
+ aUserInstallPathHashCode
;
502 PipeMode nPipeMode
= PIPEMODE_DONTKNOW
;
505 OSecurity
&rSecurity
= Security::get();
506 // Try to create pipe
507 if ( pThread
->maPipe
.create( pThread
->maPipeIdent
.getStr(), OPipe::TOption_Create
, rSecurity
))
510 nPipeMode
= PIPEMODE_CREATED
;
512 else if( pThread
->maPipe
.create( pThread
->maPipeIdent
.getStr(), OPipe::TOption_Open
, rSecurity
)) // Creation not successfull, now we try to connect
514 // Pipe connected to first office
515 nPipeMode
= PIPEMODE_CONNECTED
;
519 OPipe::TPipeError eReason
= pThread
->maPipe
.getError();
520 if ((eReason
== OPipe::E_ConnectionRefused
) || (eReason
== OPipe::E_invalidError
))
521 return IPC_STATUS_BOOTSTRAP_ERROR
;
523 // Wait for second office to be ready
524 TimeValue aTimeValue
;
525 aTimeValue
.Seconds
= 0;
526 aTimeValue
.Nanosec
= 10000000; // 10ms
527 osl::Thread::wait( aTimeValue
);
530 } while ( nPipeMode
== PIPEMODE_DONTKNOW
);
532 if ( nPipeMode
== PIPEMODE_CREATED
)
534 // Seems we are the one and only, so start listening thread
535 pGlobalOfficeIPCThread
= pThread
;
536 pThread
->create(); // starts thread
540 // Seems another office is running. Pipe arguments to it and self terminate
541 pThread
->maStreamPipe
= pThread
->maPipe
;
543 sal_Bool bWaitBeforeClose
= sal_False
;
544 ByteString
aArguments(RTL_CONSTASCII_STRINGPARAM(ARGUMENT_PREFIX
));
545 rtl::OUString cwdUrl
;
546 if (!(tools::getProcessWorkingDir(&cwdUrl
) &&
547 addArgument(&aArguments
, '1', cwdUrl
)))
551 sal_uInt32 nCount
= rtl_getAppCommandArgCount();
552 for( sal_uInt32 i
=0; i
< nCount
; i
++ )
554 rtl_getAppCommandArg( i
, &aDummy
.pData
);
555 if( aDummy
.indexOf('-',0) != 0 )
557 bWaitBeforeClose
= sal_True
;
559 if (!addArgument(&aArguments
, ',', aDummy
)) {
560 return IPC_STATUS_BOOTSTRAP_ERROR
;
563 // finaly, write the string onto the pipe
564 pThread
->maStreamPipe
.write( aArguments
.GetBuffer(), aArguments
.Len() );
565 pThread
->maStreamPipe
.write( "\0", 1 );
567 // wait for confirmation #95361# #95425#
568 ByteString
aToken(sc_aConfirmationSequence
);
569 char *aReceiveBuffer
= new char[aToken
.Len()+1];
570 int n
= pThread
->maStreamPipe
.read( aReceiveBuffer
, aToken
.Len() );
571 aReceiveBuffer
[n
]='\0';
574 if (aToken
.CompareTo(aReceiveBuffer
)!= COMPARE_EQUAL
) {
575 // something went wrong
576 delete[] aReceiveBuffer
;
577 return IPC_STATUS_BOOTSTRAP_ERROR
;
579 delete[] aReceiveBuffer
;
580 return IPC_STATUS_2ND_OFFICE
;
584 return IPC_STATUS_OK
;
587 void OfficeIPCThread::DisableOfficeIPCThread()
589 osl::ClearableMutexGuard
aMutex( GetMutex() );
591 if( pGlobalOfficeIPCThread
)
593 OfficeIPCThread
*pOfficeIPCThread
= pGlobalOfficeIPCThread
;
594 pGlobalOfficeIPCThread
= 0;
596 // send thread a termination message
597 // this is done so the subsequent join will not hang
598 // because the thread hangs in accept of pipe
599 OPipe
Pipe( pOfficeIPCThread
->maPipeIdent
, OPipe::TOption_Open
, Security::get() );
600 //Pipe.send( TERMINATION_SEQUENCE, TERMINATION_LENGTH );
603 Pipe
.send( sc_aTerminationSequence
, sc_nTSeqLength
+1 ); // also send 0-byte
605 // close the pipe so that the streampipe on the other
610 // release mutex to avoid deadlocks
613 OfficeIPCThread::SetReady(pOfficeIPCThread
);
615 // exit gracefully and join
616 pOfficeIPCThread
->join();
617 delete pOfficeIPCThread
;
623 OfficeIPCThread::OfficeIPCThread() :
625 mbRequestsEnabled( false ),
626 mnPendingRequests( 0 ),
627 mpDispatchWatcher( 0 )
631 OfficeIPCThread::~OfficeIPCThread()
633 ::osl::ClearableMutexGuard
aGuard( GetMutex() );
635 if ( mpDispatchWatcher
)
636 mpDispatchWatcher
->release();
638 maStreamPipe
.close();
639 pGlobalOfficeIPCThread
= 0;
642 static void AddURLToStringList( const rtl::OUString
& aURL
, rtl::OUString
& aStringList
)
644 if ( aStringList
.getLength() )
645 aStringList
+= ::rtl::OUString::valueOf( (sal_Unicode
)APPEVENT_PARAM_DELIMITER
);
649 void OfficeIPCThread::SetReady(OfficeIPCThread
* pThread
)
651 if (pThread
== NULL
) pThread
= pGlobalOfficeIPCThread
;
654 pThread
->cReady
.set();
658 void SAL_CALL
OfficeIPCThread::run()
663 nError
= maPipe
.accept( maStreamPipe
);
666 if( nError
== OStreamPipe::E_None
)
669 // #111143# and others:
670 // if we receive a request while the office is displaying some dialog or error during
671 // bootstrap, that dialogs event loop might get events that are dispatched by this thread
672 // we have to wait for cReady to be set by the real main loop.
673 // only reqests that dont dispatch events may be processed before cReady is set.
676 // we might have decided to shutdown while we were sleeping
677 if (!pGlobalOfficeIPCThread
) return;
679 // only lock the mutex when processing starts, othewise we deadlock when the office goes
681 osl::ClearableMutexGuard
aGuard( GetMutex() );
683 ByteString aArguments
;
685 const int nBufSz
= 2048;
689 // read into pBuf until '\0' is read or read-error
690 while ((nResult
=maStreamPipe
.recv( pBuf
+nBytes
, nBufSz
-nBytes
))>0) {
692 if (pBuf
[nBytes
-1]=='\0') {
697 // don't close pipe ...
699 // #90717# Is this a lookup message from another application? if so, ignore
700 if ( aArguments
.Len() == 0 )
703 // is this a termination message ? if so, terminate
704 if(( aArguments
.CompareTo( sc_aTerminationSequence
, sc_nTSeqLength
) == COMPARE_EQUAL
) ||
707 std::auto_ptr
< CommandLineArgs
> aCmdLineArgs
;
710 Parser
p( aArguments
);
711 aCmdLineArgs
.reset( new CommandLineArgs( p
) );
713 catch ( CommandLineArgs::Supplier::Exception
& )
715 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
716 fprintf( stderr
, "Error in received command line arguments\n" );
720 CommandLineArgs
*pCurrentCmdLineArgs
= Desktop::GetCommandLineArgs();
722 if ( aCmdLineArgs
->IsQuickstart() )
724 // we have to use application event, because we have to start quickstart service in main thread!!
725 ApplicationEvent
* pAppEvent
=
726 new ApplicationEvent( aEmpty
, aEmpty
,
727 "QUICKSTART", aEmpty
);
728 ImplPostForeignAppEvent( pAppEvent
);
731 // handle request for acceptor
732 sal_Bool bAcceptorRequest
= sal_False
;
733 OUString aAcceptString
;
734 if ( aCmdLineArgs
->GetAcceptString(aAcceptString
) && Desktop::CheckOEM()) {
735 ApplicationEvent
* pAppEvent
=
736 new ApplicationEvent( aEmpty
, aEmpty
,
737 "ACCEPT", aAcceptString
);
738 ImplPostForeignAppEvent( pAppEvent
);
739 bAcceptorRequest
= sal_True
;
741 // handle acceptor removal
742 OUString aUnAcceptString
;
743 if ( aCmdLineArgs
->GetUnAcceptString(aUnAcceptString
) ) {
744 ApplicationEvent
* pAppEvent
=
745 new ApplicationEvent( aEmpty
, aEmpty
,
746 "UNACCEPT", aUnAcceptString
);
747 ImplPostForeignAppEvent( pAppEvent
);
748 bAcceptorRequest
= sal_True
;
752 // only in non-unix version, we need to handle a -help request
753 // in a running instance in order to display the command line help
754 if ( aCmdLineArgs
->IsHelp() ) {
755 ApplicationEvent
* pAppEvent
=
756 new ApplicationEvent( aEmpty
, aEmpty
, "HELP", aEmpty
);
757 ImplPostForeignAppEvent( pAppEvent
);
761 sal_Bool bDocRequestSent
= sal_False
;
762 ProcessDocumentsRequest
* pRequest
= new ProcessDocumentsRequest(
763 aCmdLineArgs
->getCwdUrl());
765 pRequest
->pcProcessed
= &cProcessed
;
767 // Print requests are not dependent on the -invisible cmdline argument as they are
768 // loaded with the "hidden" flag! So they are always checked.
769 bDocRequestSent
|= aCmdLineArgs
->GetPrintList( pRequest
->aPrintList
);
770 bDocRequestSent
|= ( aCmdLineArgs
->GetPrintToList( pRequest
->aPrintToList
) &&
771 aCmdLineArgs
->GetPrinterName( pRequest
->aPrinterName
) );
773 if ( !pCurrentCmdLineArgs
->IsInvisible() )
775 // Read cmdline args that can open/create documents. As they would open a window
776 // they are only allowed if the "-invisible" is currently not used!
777 bDocRequestSent
|= aCmdLineArgs
->GetOpenList( pRequest
->aOpenList
);
778 bDocRequestSent
|= aCmdLineArgs
->GetViewList( pRequest
->aViewList
);
779 bDocRequestSent
|= aCmdLineArgs
->GetStartList( pRequest
->aStartList
);
780 bDocRequestSent
|= aCmdLineArgs
->GetForceOpenList( pRequest
->aForceOpenList
);
781 bDocRequestSent
|= aCmdLineArgs
->GetForceNewList( pRequest
->aForceNewList
);
783 // Special command line args to create an empty document for a given module
786 // we only do this if no document was specified on the command line,
787 // since this would be inconsistent with the the behaviour of
788 // the first process, see OpenClients() (call to OpenDefault()) in app.cxx
789 if ( aCmdLineArgs
->HasModuleParam() && Desktop::CheckOEM() && (!bDocRequestSent
))
791 SvtModuleOptions aOpt
;
792 SvtModuleOptions::EFactory eFactory
= SvtModuleOptions::E_WRITER
;
793 if ( aCmdLineArgs
->IsWriter() )
794 eFactory
= SvtModuleOptions::E_WRITER
;
795 else if ( aCmdLineArgs
->IsCalc() )
796 eFactory
= SvtModuleOptions::E_CALC
;
797 else if ( aCmdLineArgs
->IsDraw() )
798 eFactory
= SvtModuleOptions::E_DRAW
;
799 else if ( aCmdLineArgs
->IsImpress() )
800 eFactory
= SvtModuleOptions::E_IMPRESS
;
801 else if ( aCmdLineArgs
->IsBase() )
802 eFactory
= SvtModuleOptions::E_DATABASE
;
803 else if ( aCmdLineArgs
->IsMath() )
804 eFactory
= SvtModuleOptions::E_MATH
;
805 else if ( aCmdLineArgs
->IsGlobal() )
806 eFactory
= SvtModuleOptions::E_WRITERGLOBAL
;
807 else if ( aCmdLineArgs
->IsWeb() )
808 eFactory
= SvtModuleOptions::E_WRITERWEB
;
810 if ( pRequest
->aOpenList
.getLength() )
811 pRequest
->aModule
= aOpt
.GetFactoryName( eFactory
);
813 AddURLToStringList( aOpt
.GetFactoryEmptyDocumentURL( eFactory
), pRequest
->aOpenList
);
814 bDocRequestSent
= sal_True
;
818 if (!aCmdLineArgs
->IsQuickstart() && Desktop::CheckOEM()) {
819 sal_Bool bShowHelp
= sal_False
;
820 rtl::OUStringBuffer aHelpURLBuffer
;
821 if (aCmdLineArgs
->IsHelpWriter()) {
822 bShowHelp
= sal_True
;
823 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://swriter/start");
824 } else if (aCmdLineArgs
->IsHelpCalc()) {
825 bShowHelp
= sal_True
;
826 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://scalc/start");
827 } else if (aCmdLineArgs
->IsHelpDraw()) {
828 bShowHelp
= sal_True
;
829 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://sdraw/start");
830 } else if (aCmdLineArgs
->IsHelpImpress()) {
831 bShowHelp
= sal_True
;
832 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://simpress/start");
833 } else if (aCmdLineArgs
->IsHelpBase()) {
834 bShowHelp
= sal_True
;
835 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://sdatabase/start");
836 } else if (aCmdLineArgs
->IsHelpBasic()) {
837 bShowHelp
= sal_True
;
838 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://sbasic/start");
839 } else if (aCmdLineArgs
->IsHelpMath()) {
840 bShowHelp
= sal_True
;
841 aHelpURLBuffer
.appendAscii("vnd.sun.star.help://smath/start");
844 Any aRet
= ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::LOCALE
);
847 aHelpURLBuffer
.appendAscii("?Language=");
848 aHelpURLBuffer
.append(aTmp
);
850 aHelpURLBuffer
.appendAscii("&System=UNX");
852 aHelpURLBuffer
.appendAscii("&System=WIN");
854 aHelpURLBuffer
.appendAscii("&System=MAC");
856 aHelpURLBuffer
.appendAscii("&System=OS2");
858 ApplicationEvent
* pAppEvent
=
859 new ApplicationEvent( aEmpty
, aEmpty
,
860 "OPENHELPURL", aHelpURLBuffer
.makeStringAndClear());
861 ImplPostForeignAppEvent( pAppEvent
);
865 if ( bDocRequestSent
&& Desktop::CheckOEM())
867 // Send requests to dispatch watcher if we have at least one. The receiver
868 // is responsible to delete the request after processing it.
869 if ( aCmdLineArgs
->HasModuleParam() )
871 SvtModuleOptions aOpt
;
873 // Support command line parameters to start a module (as preselection)
874 if ( aCmdLineArgs
->IsWriter() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SWRITER
) )
875 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_WRITER
);
876 else if ( aCmdLineArgs
->IsCalc() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SCALC
) )
877 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_CALC
);
878 else if ( aCmdLineArgs
->IsImpress() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SIMPRESS
) )
879 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_IMPRESS
);
880 else if ( aCmdLineArgs
->IsDraw() && aOpt
.IsModuleInstalled( SvtModuleOptions::E_SDRAW
) )
881 pRequest
->aModule
= aOpt
.GetFactoryName( SvtModuleOptions::E_DRAW
);
885 ImplPostProcessDocumentsEvent( pRequest
);
889 // delete not used request again
893 if (( aArguments
.CompareTo( sc_aShowSequence
, sc_nShSeqLength
) == COMPARE_EQUAL
) ||
894 aCmdLineArgs
->IsEmpty() )
896 // no document was sent, just bring Office to front
897 ApplicationEvent
* pAppEvent
=
898 new ApplicationEvent( aEmpty
, aEmpty
, "APPEAR", aEmpty
);
899 ImplPostForeignAppEvent( pAppEvent
);
902 // we don't need the mutex any longer...
904 // wait for processing to finish
907 // processing finished, inform the requesting end
910 (nResult
= maStreamPipe
.send(sc_aConfirmationSequence
+nBytes
, sc_nCSeqLength
-nBytes
))>0 &&
911 ((nBytes
+= nResult
) < sc_nCSeqLength
) ) ;
912 // now we can close, don't we?
913 // maStreamPipe.close();
918 #if (OSL_DEBUG_LEVEL > 1) || defined DBG_UTIL
919 fprintf( stderr
, "Error on accept: %d\n", (int)nError
);
926 } while( schedule() );
929 static void AddToDispatchList(
930 DispatchWatcher::DispatchList
& rDispatchList
,
931 boost::optional
< rtl::OUString
> const & cwdUrl
,
932 const OUString
& aRequestList
,
933 DispatchWatcher::RequestType nType
,
934 const OUString
& aParam
,
935 const OUString
& aFactory
)
937 if ( aRequestList
.getLength() > 0 )
939 sal_Int32 nIndex
= 0;
942 OUString aToken
= aRequestList
.getToken( 0, APPEVENT_PARAM_DELIMITER
, nIndex
);
943 if ( aToken
.getLength() > 0 )
944 rDispatchList
.push_back(
945 DispatchWatcher::DispatchRequest( nType
, aToken
, cwdUrl
, aParam
, aFactory
));
947 while ( nIndex
>= 0 );
951 sal_Bool
OfficeIPCThread::ExecuteCmdLineRequests( ProcessDocumentsRequest
& aRequest
)
953 // protect the dispatch list
954 osl::ClearableMutexGuard
aGuard( GetMutex() );
956 static DispatchWatcher::DispatchList aDispatchList
;
958 rtl::OUString aEmpty
;
959 // Create dispatch list for dispatch watcher
960 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aOpenList
, DispatchWatcher::REQUEST_OPEN
, aEmpty
, aRequest
.aModule
);
961 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aViewList
, DispatchWatcher::REQUEST_VIEW
, aEmpty
, aRequest
.aModule
);
962 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aStartList
, DispatchWatcher::REQUEST_START
, aEmpty
, aRequest
.aModule
);
963 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aPrintList
, DispatchWatcher::REQUEST_PRINT
, aEmpty
, aRequest
.aModule
);
964 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aPrintToList
, DispatchWatcher::REQUEST_PRINTTO
, aRequest
.aPrinterName
, aRequest
.aModule
);
965 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aForceOpenList
, DispatchWatcher::REQUEST_FORCEOPEN
, aEmpty
, aRequest
.aModule
);
966 AddToDispatchList( aDispatchList
, aRequest
.aCwdUrl
, aRequest
.aForceNewList
, DispatchWatcher::REQUEST_FORCENEW
, aEmpty
, aRequest
.aModule
);
968 sal_Bool
bShutdown( sal_False
);
970 if ( pGlobalOfficeIPCThread
)
972 if( ! pGlobalOfficeIPCThread
->AreRequestsEnabled() )
975 pGlobalOfficeIPCThread
->mnPendingRequests
+= aDispatchList
.size();
976 if ( !pGlobalOfficeIPCThread
->mpDispatchWatcher
)
978 pGlobalOfficeIPCThread
->mpDispatchWatcher
= DispatchWatcher::GetDispatchWatcher();
979 pGlobalOfficeIPCThread
->mpDispatchWatcher
->acquire();
983 DispatchWatcher::DispatchList
aTempList( aDispatchList
);
984 aDispatchList
.clear();
988 // Execute dispatch requests
989 bShutdown
= pGlobalOfficeIPCThread
->mpDispatchWatcher
->executeDispatchRequests( aTempList
, s_bInEnableRequests
);
991 // set processed flag
992 if (aRequest
.pcProcessed
!= NULL
)
993 aRequest
.pcProcessed
->set();