Update ooo320-m1
[ooovba.git] / desktop / win32 / source / officeloader / officeloader.cxx
blob36ab5ad49b423697a7305b1acd0095b6c5008aaf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: officeloader.cxx,v $
10 * $Revision: 1.18 $
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"
33 #define UNICODE
34 #define _UNICODE
36 #include <cstddef>
38 #define WIN32_LEAN_AND_MEAN
39 #if defined _MSC_VER
40 #pragma warning(push, 1)
41 #endif
42 #include <windows.h>
43 #include <shellapi.h>
44 #if defined _MSC_VER
45 #pragma warning(pop)
46 #endif
48 #include <tchar.h>
50 #include <malloc.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <systools/win32/uwinapi.h>
55 #include "rtl/string.h"
57 #include "../../../source/inc/exithelper.hxx"
58 #include "../extendloaderenvironment.hxx"
60 #define PIPE_PREFIX TEXT("\\\\.\\pipe\\OSL_PIPE_")
61 #define PIPE_POSTFIX TEXT("_SingleOfficeIPC_")
62 #define PIPE_TERMINATION_SEQUENCE "InternalIPC::ProcessingDone"
64 BOOL WINAPI ConvertSidToStringSid( PSID pSid, LPTSTR* StringSid )
66 PSID_IDENTIFIER_AUTHORITY psia;
67 DWORD dwSubAuthorities;
68 DWORD dwSidRev=SID_REVISION;
69 DWORD dwCounter;
70 DWORD dwSidSize;
72 // Validate the binary SID.
74 if(!IsValidSid(pSid)) return FALSE;
76 // Get the identifier authority value from the SID.
78 psia = GetSidIdentifierAuthority(pSid);
80 // Get the number of subauthorities in the SID.
82 dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
84 // Compute the buffer length.
85 // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
87 dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
89 *StringSid = (LPTSTR)LocalAlloc( LMEM_FIXED, dwSidSize );
91 // Add 'S' prefix and revision number to the string.
93 dwSidSize=wsprintf(*StringSid, TEXT("S-%lu-"), dwSidRev );
95 // Add a SID identifier authority to the string.
97 if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
99 dwSidSize+=wsprintf(*StringSid + lstrlen(*StringSid),
100 TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
101 (USHORT)psia->Value[0],
102 (USHORT)psia->Value[1],
103 (USHORT)psia->Value[2],
104 (USHORT)psia->Value[3],
105 (USHORT)psia->Value[4],
106 (USHORT)psia->Value[5]);
108 else
110 dwSidSize+=wsprintf(*StringSid + lstrlen(*StringSid),
111 TEXT("%lu"),
112 (ULONG)(psia->Value[5] ) +
113 (ULONG)(psia->Value[4] << 8) +
114 (ULONG)(psia->Value[3] << 16) +
115 (ULONG)(psia->Value[2] << 24) );
118 // Add SID subauthorities to the string.
120 for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
122 dwSidSize+=wsprintf(*StringSid + dwSidSize, TEXT("-%lu"),
123 *GetSidSubAuthority(pSid, dwCounter) );
126 return TRUE;
130 //---------------------------------------------------------------------------
132 static LPTSTR *GetCommandArgs( int *pArgc )
134 #ifdef UNICODE
135 return CommandLineToArgvW( GetCommandLineW(), pArgc );
136 #else
137 *pArgc = __argc;
138 return __argv;
139 #endif
142 //---------------------------------------------------------------------------
144 namespace {
146 bool writeArgument(HANDLE pipe, char prefix, WCHAR const * argument) {
147 CHAR szBuffer[4096];
148 int n = WideCharToMultiByte(
149 CP_UTF8, 0, argument, -1, szBuffer, sizeof (szBuffer), NULL, NULL);
150 char b[1 + 2 * ((sizeof szBuffer) - 1)]; // hopefully does not overflow
151 b[0] = prefix;
152 char * p = b + 1;
153 for (int i = 0; i < n - 1; ++i) { // cannot underflow (n >= 0)
154 char c = szBuffer[i];
155 switch (c) {
156 case '\0':
157 *p++ = '\\';
158 *p++ = '0';
159 break;
160 case ',':
161 *p++ = '\\';
162 *p++ = ',';
163 break;
164 case '\\':
165 *p++ = '\\';
166 *p++ = '\\';
167 break;
168 default:
169 *p++ = c;
170 break;
173 DWORD w;
174 return WriteFile(pipe, b, p - b, &w, NULL);
179 #ifdef __MINGW32__
180 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int )
181 #else
182 int WINAPI _tWinMain( HINSTANCE, HINSTANCE, LPTSTR, int )
183 #endif
185 TCHAR szTargetFileName[MAX_PATH] = TEXT("");
186 TCHAR szIniDirectory[MAX_PATH];
187 TCHAR szPerfTuneIniFile[MAX_PATH] = TEXT("");
188 STARTUPINFO aStartupInfo;
190 desktop_win32::extendLoaderEnvironment(szTargetFileName, szIniDirectory);
192 ZeroMemory( &aStartupInfo, sizeof(aStartupInfo) );
193 aStartupInfo.cb = sizeof(aStartupInfo);
195 GetStartupInfo( &aStartupInfo );
196 // Get image path with same name but with .bin extension
198 TCHAR szModuleFileName[MAX_PATH];
200 GetModuleFileName( NULL, szModuleFileName, MAX_PATH );
201 _TCHAR *lpLastSlash = _tcsrchr( szModuleFileName, '\\' );
202 if ( lpLastSlash )
204 size_t len = lpLastSlash - szModuleFileName + 1;
205 _tcsncpy( szPerfTuneIniFile, szModuleFileName, len );
206 _tcsncpy( szPerfTuneIniFile + len, _T("perftune.ini"), sizeof(szPerfTuneIniFile)/sizeof(szPerfTuneIniFile[0]) - len );
209 // Create process with same command line, environment and stdio handles which
210 // are directed to the created pipes
212 DWORD dwExitCode = (DWORD)-1;
214 BOOL fSuccess = FALSE;
215 LPTSTR lpCommandLine = NULL;
216 int argc = 0;
217 LPTSTR * argv = NULL;
218 bool first = true;
219 WCHAR cwd[MAX_PATH];
220 DWORD cwdLen = GetCurrentDirectoryW(MAX_PATH, cwd);
221 if (cwdLen >= MAX_PATH) {
222 cwdLen = 0;
227 TCHAR szKey[32];
229 GetPrivateProfileString(
230 TEXT("PerformanceTuning"),
231 TEXT("FastPipeCommunication"),
232 TEXT("0"),
233 szKey,
234 elementsof(szKey),
235 szPerfTuneIniFile
238 if ( 0 == _tcscmp( szKey, TEXT("1") ) )
240 HANDLE hProcessToken;
242 if ( OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hProcessToken ) )
244 TCHAR szPipeName[4096];
247 DWORD dwTokenLength = 0;
250 fSuccess = GetTokenInformation( hProcessToken, TokenUser, NULL, dwTokenLength, &dwTokenLength );
252 PVOID pTokenInfo = _alloca(dwTokenLength);
253 fSuccess = GetTokenInformation( hProcessToken, TokenUser, pTokenInfo, dwTokenLength, &dwTokenLength );
254 CloseHandle( hProcessToken );
256 PSID pSid = ((PTOKEN_USER)pTokenInfo)->User.Sid;
257 LPTSTR szUserIdent = NULL;
258 TCHAR szSUPD[11] = TEXT("0");
260 fSuccess = ConvertSidToStringSid( pSid, &szUserIdent );
262 _tcsncpy( szPipeName, PIPE_PREFIX, elementsof(szPipeName) );
263 _tcsncat( szPipeName, szUserIdent, elementsof(szPipeName) - _tcslen(szPipeName) - 1 );
264 _tcsncat( szPipeName, PIPE_POSTFIX, elementsof(szPipeName) - _tcslen(szPipeName) - 1 );
265 _tcsncat( szPipeName, _ultot( SUPD, szSUPD, 10), elementsof(szPipeName) - _tcslen(szPipeName) - 1 );
267 LocalFree( szUserIdent );
269 HANDLE hPipe = CreateFile(
270 szPipeName,
271 GENERIC_READ|GENERIC_WRITE,
272 FILE_SHARE_READ | FILE_SHARE_WRITE,
273 NULL,
274 OPEN_EXISTING,
275 FILE_ATTRIBUTE_NORMAL,
276 NULL);
278 if ( INVALID_HANDLE_VALUE != hPipe )
280 DWORD dwBytesWritten;
281 int argc = 0;
282 LPWSTR *argv = CommandLineToArgvW( GetCommandLine(), &argc );
284 fSuccess = WriteFile( hPipe, RTL_CONSTASCII_STRINGPARAM("InternalIPC::Arguments"), &dwBytesWritten, NULL );
285 if (fSuccess) {
286 if (cwdLen > 0) {
287 fSuccess = writeArgument(hPipe, '2', cwd);
288 } else {
289 fSuccess = WriteFile(
290 hPipe, RTL_CONSTASCII_STRINGPARAM("0"),
291 &dwBytesWritten, NULL);
294 for ( int argn = 1; fSuccess && argn < argc; argn++ )
296 fSuccess = writeArgument(hPipe, ',', argv[argn]);
299 if ( fSuccess )
301 fSuccess = WriteFile( hPipe, "", 1, &dwBytesWritten, NULL );
302 if ( fSuccess )
304 DWORD dwBytesRead = 0;
305 char *pBuffer = (char *)_alloca( sizeof(PIPE_TERMINATION_SEQUENCE) );
306 fSuccess = ReadFile( hPipe, pBuffer, sizeof(PIPE_TERMINATION_SEQUENCE) - 1, &dwBytesRead, NULL );
307 if ( fSuccess )
309 pBuffer[dwBytesRead] = 0;
310 if ( 0 != strcmp( PIPE_TERMINATION_SEQUENCE, pBuffer ) )
311 fSuccess = FALSE;
316 CloseHandle( hPipe );
318 return fSuccess ? 0 : -1;
324 if (first) {
325 argv = GetCommandArgs(&argc);
326 std::size_t n = wcslen(argv[0]) + 2;
327 for (int i = 1; i < argc; ++i) {
328 n += wcslen(argv[i]) + 3;
330 n += MY_LENGTH(L" \"-env:OOO_CWD=2") + 4 * cwdLen +
331 MY_LENGTH(L"\"") + 1;
332 // 4 * cwdLen: each char preceded by backslash, each trailing
333 // backslash doubled
334 lpCommandLine = new WCHAR[n];
336 WCHAR * p = desktop_win32::commandLineAppend(
337 lpCommandLine, MY_STRING(L"\""));
338 p = desktop_win32::commandLineAppend(p, argv[0]);
339 for (int i = 1; i < argc; ++i) {
340 if (first || wcsncmp(argv[i], MY_STRING(L"-env:")) == 0) {
341 p = desktop_win32::commandLineAppend(p, MY_STRING(L"\" \""));
342 p = desktop_win32::commandLineAppend(p, argv[i]);
345 p = desktop_win32::commandLineAppend(
346 p, MY_STRING(L"\" \"-env:OOO_CWD="));
347 if (cwdLen == 0) {
348 p = desktop_win32::commandLineAppend(p, MY_STRING(L"0"));
349 } else {
350 p = desktop_win32::commandLineAppend(p, MY_STRING(L"2"));
351 p = desktop_win32::commandLineAppendEncoded(p, cwd);
353 desktop_win32::commandLineAppend(p, MY_STRING(L"\""));
354 first = false;
356 TCHAR szParentProcessId[64]; // This is more than large enough for a 128 bit decimal value
357 BOOL bHeadlessMode( FALSE );
360 // Check command line arguments for "-headless" parameter. We only
361 // set the environment variable "ATTACHED_PARENT_PROCESSID" for the headless
362 // mode as self-destruction of the soffice.bin process can lead to
363 // certain side-effects (log-off can result in data-loss, ".lock" is not deleted.
364 // See 138244 for more information.
365 int argc;
366 LPTSTR *argv = GetCommandArgs( &argc );
368 if ( argc > 1 )
370 int n;
372 for ( n = 1; n < argc; n++ )
374 if ( 0 == _tcsnicmp( argv[n], _T("-headless"), 9 ) )
375 bHeadlessMode = TRUE;
380 if ( _ltot( (long)GetCurrentProcessId(),szParentProcessId, 10 ) && bHeadlessMode )
381 SetEnvironmentVariable( TEXT("ATTACHED_PARENT_PROCESSID"), szParentProcessId );
383 PROCESS_INFORMATION aProcessInfo;
385 fSuccess = CreateProcess(
386 szTargetFileName,
387 lpCommandLine,
388 NULL,
389 NULL,
390 TRUE,
392 NULL,
393 szIniDirectory,
394 &aStartupInfo,
395 &aProcessInfo );
397 if ( fSuccess )
399 DWORD dwWaitResult;
403 // On Windows XP it seems as the desktop calls WaitForInputIdle after "OpenWidth" so we have to do so
404 // as if we where processing any messages
406 dwWaitResult = MsgWaitForMultipleObjects( 1, &aProcessInfo.hProcess, FALSE, INFINITE, QS_ALLEVENTS );
408 if ( WAIT_OBJECT_0 + 1 == dwWaitResult )
410 MSG msg;
412 PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
414 } while ( WAIT_OBJECT_0 + 1 == dwWaitResult );
416 dwExitCode = 0;
417 GetExitCodeProcess( aProcessInfo.hProcess, &dwExitCode );
419 CloseHandle( aProcessInfo.hProcess );
420 CloseHandle( aProcessInfo.hThread );
422 } while ( fSuccess && ::desktop::ExitHelper::E_CRASH_WITH_RESTART == dwExitCode );
423 delete[] lpCommandLine;
425 return fSuccess ? dwExitCode : -1;