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: unoapploader.c,v $
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 ************************************************************************/
37 #pragma warning(push, 1)
44 #include "cppuhelper/findsofficepath.h"
45 #include "sal/types.h"
47 #define MY_LENGTH(s) (sizeof (s) / sizeof *(s) - 1)
49 char const* getPath();
50 char* createCommandLine( char* lpCmdLine
);
51 FILE* getErrorFile( int create
);
52 void writeError( const char* errstr
);
53 void closeErrorFile();
56 * The main function implements a loader for applications which use UNO.
58 * <p>This code runs on the Windows platform only.</p>
60 * <p>The main function detects a UNO installation on the system and adds the
61 * program directory of the UNO installation to the PATH environment variable.
62 * After that, the application process is loaded and started, whereby the
63 * new process inherits the environment of the calling process, including
64 * the modified PATH environment variable. The application's executable name
65 * must be the same as the name of this executable, prefixed by '_'.</p>
67 * <p>A UNO installation can be specified by the user by setting the UNO_PATH
68 * environment variable to the program directory of the UNO installation.
69 * If no installation is specified by the user, the default installation on
70 * the system will be taken. The default installation is read from the
71 * default value of the key "Software\OpenOffice.org\UNO\InstallPath" from the
72 * root key HKEY_CURRENT_USER in the Windows Registry. If this key is missing,
73 * the key is read from the root key HKEY_LOCAL_MACHINE.</p>
75 int WINAPI
WinMain( HINSTANCE hInstance
, HINSTANCE hPrevInstance
,
76 LPSTR lpCmdLine
, int nCmdShow
)
78 const char* ENVVARNAME
= "PATH";
79 const char* PATHSEPARATOR
= ";";
81 char const* path
= NULL
;
87 STARTUPINFO startup_info
;
88 PROCESS_INFORMATION process_info
;
91 (void) hInstance
; /* unused */
92 (void) hPrevInstance
; /* unused */
93 (void) nCmdShow
; /* unused */
95 /* get the path of the UNO installation */
101 MY_LENGTH(L
"\"") + MAX_PATH
+
102 MY_LENGTH(L
"\\unoinfo.exe\" c++")];
103 /* hopefully does not overflow */
105 SECURITY_ATTRIBUTES sec
;
109 STARTUPINFOW startinfo
;
110 PROCESS_INFORMATION procinfo
;
113 pathsize
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, cmd
+ 1, MAX_PATH
);
115 writeError("Error: MultiByteToWideChar failed!\n");
119 if (wcschr(cmd
+ 1, L
'"') != NULL
) {
120 writeError("Error: bad characters in UNO installation path!\n");
126 (L
"\\unoinfo.exe\" c++" +
127 (pathsize
== 1 || cmd
[pathsize
- 1] != L
'\\' ? 0 : 1)));
128 sec
.nLength
= sizeof (SECURITY_ATTRIBUTES
);
129 sec
.lpSecurityDescriptor
= NULL
;
130 sec
.bInheritHandle
= TRUE
;
131 if (CreatePipe(&temp
, &stdoutWrite
, &sec
, 0) == 0 ||
133 GetCurrentProcess(), temp
, GetCurrentProcess(), &stdoutRead
, 0,
134 FALSE
, DUPLICATE_CLOSE_SOURCE
| DUPLICATE_SAME_ACCESS
) == 0)
136 writeError("Error: CreatePipe/DuplicateHandle failed!\n");
140 memset(&startinfo
, 0, sizeof (STARTUPINFOW
));
141 startinfo
.cb
= sizeof (STARTUPINFOW
);
142 startinfo
.lpDesktop
= L
"";
143 startinfo
.dwFlags
= STARTF_USESTDHANDLES
;
144 startinfo
.hStdOutput
= stdoutWrite
;
145 ret
= CreateProcessW(
146 NULL
, cmd
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startinfo
, &procinfo
);
153 CloseHandle(stdoutWrite
);
154 CloseHandle(procinfo
.hThread
);
157 buf
= realloc(buf
, n
);
160 "Error: out of memory reading unoinfo output!\n");
164 if (!ReadFile(stdoutRead
, buf
+ k
, n
- k
, &m
, NULL
))
166 DWORD err
= GetLastError();
167 if (err
== ERROR_HANDLE_EOF
|| err
== ERROR_BROKEN_PIPE
) {
170 writeError("Error: cannot read unoinfo output!\n");
179 if (n
>= SAL_MAX_SIZE
/ 2) {
181 "Error: out of memory reading unoinfo output!\n");
189 writeError("Error: bad unoinfo output!\n");
193 CloseHandle(stdoutRead
);
194 if (!GetExitCodeProcess(procinfo
.hProcess
, &exitcode
) ||
197 writeError("Error: executing unoinfo failed!\n");
204 path2size
= WideCharToMultiByte(
205 CP_ACP
, 0, (wchar_t *) buf
, k
/ 2, path2
, MAX_PATH
- 1,
207 if (path2size
== 0) {
208 writeError("Error: converting unoinfo output failed!\n");
213 path2
[path2size
] = '\0';
216 if (GetLastError() != ERROR_FILE_NOT_FOUND
) {
217 writeError("Error: calling unoinfo failed!\n");
221 CloseHandle(stdoutRead
);
222 CloseHandle(stdoutWrite
);
225 /* get the value of the PATH environment variable */
226 value
= getenv( ENVVARNAME
);
229 * add the UNO installation path to the PATH environment variable;
230 * note that this only affects the environment variable of the current
231 * process, the command processor's environment is not changed
233 size
= strlen( ENVVARNAME
) + strlen( "=" ) + strlen( path
) + 1;
235 size
+= strlen( PATHSEPARATOR
) + strlen( value
);
236 envstr
= (char*) malloc( size
);
237 strcpy( envstr
, ENVVARNAME
);
238 strcat( envstr
, "=" );
239 strcat( envstr
, path
);
242 strcat( envstr
, PATHSEPARATOR
);
243 strcat( envstr
, value
);
250 writeError( "Warning: no UNO installation found!\n" );
253 /* create the command line for the application process */
254 cmdline
= createCommandLine( lpCmdLine
);
255 if ( cmdline
== NULL
)
257 writeError( "Error: cannot create command line!\n" );
262 /* create the application process */
263 memset( &startup_info
, 0, sizeof( STARTUPINFO
) );
264 startup_info
.cb
= sizeof( STARTUPINFO
);
265 bCreate
= CreateProcess( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
,
266 &startup_info
, &process_info
);
270 writeError( "Error: cannot create process!\n" );
275 /* close the error file */
282 * Gets the path of a UNO installation.
284 * @return the installation path or NULL, if no installation was specified or
285 * found, or if an error occured
287 char const* getPath()
289 char const* path
= cppuhelper_detail_findSofficePath();
292 writeError( "Warning: getting path from Windows Registry failed!\n" );
298 * Creates the command line for the application process including the absolute
299 * path of the executable.
301 * <p>The application's executable file name is the name of this executable
302 * prefixed by '_'.</p>
304 * @param appendix specifies the command line for the application excluding
305 * the executable name
307 * @return the command line for the application process or NULL, if an error
310 char* createCommandLine( char* appendix
)
312 const char* CMDPREFIX
= "_";
313 const char* DQUOTE
= "\"";
314 const char* SPACE
= " ";
316 char* cmdline
= NULL
;
318 char cmdname
[ _MAX_PATH
];
319 char drive
[ _MAX_DRIVE
];
320 char dir
[ _MAX_PATH
];
321 char base
[ _MAX_FNAME
];
322 char newbase
[ _MAX_FNAME
];
323 char ext
[ _MAX_EXT
];
325 /* get the absolute path of the executable file */
326 if ( GetModuleFileName( NULL
, cmdname
, sizeof( cmdname
) ) )
328 /* prefix the executable file name by '_' */
329 _splitpath( cmdname
, drive
, dir
, base
, ext
);
330 strcpy( newbase
, CMDPREFIX
);
331 strcat( newbase
, base
);
332 _makepath( cmdname
, drive
, dir
, newbase
, ext
);
334 /* create the command line */
335 cmdline
= (char*) malloc( strlen( DQUOTE
) + strlen( cmdname
) +
336 strlen ( DQUOTE
) + strlen( SPACE
) + strlen( appendix
) + 1 );
337 strcpy( cmdline
, DQUOTE
);
338 strcat( cmdline
, cmdname
);
339 strcat( cmdline
, DQUOTE
);
340 strcat( cmdline
, SPACE
);
341 strcat( cmdline
, appendix
);
348 * Gets the pointer to the error file.
350 * <p>The error file will only be created, if create != 0.</p>
352 * <p>The error file has the name <executable file name>-error.log and is
353 * created in the same directory as the executable file. If this fails,
354 * the error file is created in the directory designated for temporary files.
357 * @param create specifies, if the error file should be created (create != 0)
359 * @return the pointer to the open error file or NULL, if no error file is
360 * open or can be created
362 FILE* getErrorFile( int create
)
364 const char* MODE
= "w";
365 const char* BASEPOSTFIX
= "-error";
366 const char* EXTENSION
= ".log";
368 static FILE* ferr
= NULL
;
370 char fname
[ _MAX_PATH
];
371 char drive
[ _MAX_DRIVE
];
372 char dir
[ _MAX_PATH
];
373 char base
[ _MAX_FNAME
];
374 char newbase
[ _MAX_FNAME
];
375 char ext
[ _MAX_EXT
];
377 if ( ferr
== NULL
&& create
)
379 /* get the absolute path of the executable file */
380 if ( GetModuleFileName( NULL
, fname
, sizeof( fname
) ) )
382 /* create error file in the directory of the executable file */
383 _splitpath( fname
, drive
, dir
, base
, ext
);
384 strcpy( newbase
, base
);
385 strcat( newbase
, BASEPOSTFIX
);
386 _makepath( fname
, drive
, dir
, newbase
, EXTENSION
);
387 ferr
= fopen( fname
, MODE
);
391 /* create error file in the temp directory */
392 GetTempPath( sizeof( fname
), fname
);
393 strcat( fname
, newbase
);
394 strcat( fname
, EXTENSION
);
395 ferr
= fopen( fname
, MODE
);
404 * Writes an error message to the error file.
406 * @param errstr specifies the error message
408 void writeError( const char* errstr
)
410 FILE* ferr
= getErrorFile( 1 );
413 fprintf( ferr
, errstr
);
419 * Closes the error file.
421 void closeErrorFile()
423 FILE* ferr
= getErrorFile( 0 );