1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
26 #pragma warning(push, 1)
33 #include "cppuhelper/findsofficepath.h"
34 #include "sal/types.h"
36 #define MY_LENGTH(s) (sizeof (s) / sizeof *(s) - 1)
38 char const* getPath();
39 char* createCommandLine( char* lpCmdLine
);
40 FILE* getErrorFile( int create
);
41 void writeError( const char* errstr
);
42 void closeErrorFile();
45 * The main function implements a loader for applications which use UNO.
47 * <p>This code runs on the Windows platform only.</p>
49 * <p>The main function detects a UNO installation on the system and adds the
50 * program directory of the UNO installation to the PATH environment variable.
51 * After that, the application process is loaded and started, whereby the
52 * new process inherits the environment of the calling process, including
53 * the modified PATH environment variable. The application's executable name
54 * must be the same as the name of this executable, prefixed by '_'.</p>
56 * <p>A UNO installation can be specified by the user by setting the UNO_PATH
57 * environment variable to the program directory of the UNO installation.
58 * If no installation is specified by the user, the default installation on
59 * the system will be taken. The default installation is read from the
60 * default value of the key "Software\LibreOffice\UNO\InstallPath" from the
61 * root key HKEY_CURRENT_USER in the Windows Registry. If this key is missing,
62 * the key is read from the root key HKEY_LOCAL_MACHINE.</p>
64 int WINAPI
WinMain( HINSTANCE hInstance
, HINSTANCE hPrevInstance
,
65 LPSTR lpCmdLine
, int nCmdShow
)
67 const char* ENVVARNAME
= "PATH";
68 const char* PATHSEPARATOR
= ";";
70 char const* path
= NULL
;
76 STARTUPINFO startup_info
;
77 PROCESS_INFORMATION process_info
;
80 (void) hInstance
; /* unused */
81 (void) hPrevInstance
; /* unused */
82 (void) nCmdShow
; /* unused */
84 /* get the path of the UNO installation */
90 MY_LENGTH(L
"\"") + MAX_PATH
+
91 MY_LENGTH(L
"\\unoinfo.exe\" c++")];
92 /* hopefully does not overflow */
94 SECURITY_ATTRIBUTES sec
;
98 STARTUPINFOW startinfo
;
99 PROCESS_INFORMATION procinfo
;
102 pathsize
= MultiByteToWideChar(CP_ACP
, 0, path
, -1, cmd
+ 1, MAX_PATH
);
104 writeError("Error: MultiByteToWideChar failed!\n");
108 if (wcschr(cmd
+ 1, L
'"') != NULL
) {
109 writeError("Error: bad characters in UNO installation path!\n");
115 (L
"\\unoinfo.exe\" c++" +
116 (pathsize
== 1 || cmd
[pathsize
- 1] != L
'\\' ? 0 : 1)));
117 sec
.nLength
= sizeof (SECURITY_ATTRIBUTES
);
118 sec
.lpSecurityDescriptor
= NULL
;
119 sec
.bInheritHandle
= TRUE
;
120 if (CreatePipe(&temp
, &stdoutWrite
, &sec
, 0) == 0 ||
122 GetCurrentProcess(), temp
, GetCurrentProcess(), &stdoutRead
, 0,
123 FALSE
, DUPLICATE_CLOSE_SOURCE
| DUPLICATE_SAME_ACCESS
) == 0)
125 writeError("Error: CreatePipe/DuplicateHandle failed!\n");
129 memset(&startinfo
, 0, sizeof (STARTUPINFOW
));
130 startinfo
.cb
= sizeof (STARTUPINFOW
);
131 startinfo
.lpDesktop
= L
"";
132 startinfo
.dwFlags
= STARTF_USESTDHANDLES
;
133 startinfo
.hStdOutput
= stdoutWrite
;
134 ret
= CreateProcessW(
135 NULL
, cmd
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
, &startinfo
, &procinfo
);
142 CloseHandle(stdoutWrite
);
143 CloseHandle(procinfo
.hThread
);
146 buf
= realloc(buf
, n
);
149 "Error: out of memory reading unoinfo output!\n");
153 if (!ReadFile(stdoutRead
, buf
+ k
, n
- k
, &m
, NULL
))
155 DWORD err
= GetLastError();
156 if (err
== ERROR_HANDLE_EOF
|| err
== ERROR_BROKEN_PIPE
) {
159 writeError("Error: cannot read unoinfo output!\n");
168 if (n
>= SAL_MAX_SIZE
/ 2) {
170 "Error: out of memory reading unoinfo output!\n");
178 writeError("Error: bad unoinfo output!\n");
182 CloseHandle(stdoutRead
);
183 if (!GetExitCodeProcess(procinfo
.hProcess
, &exitcode
) ||
186 writeError("Error: executing unoinfo failed!\n");
193 path2size
= WideCharToMultiByte(
194 CP_ACP
, 0, (wchar_t *) buf
, k
/ 2, path2
, MAX_PATH
- 1,
196 if (path2size
== 0) {
197 writeError("Error: converting unoinfo output failed!\n");
202 path2
[path2size
] = '\0';
205 if (GetLastError() != ERROR_FILE_NOT_FOUND
) {
206 writeError("Error: calling unoinfo failed!\n");
210 CloseHandle(stdoutRead
);
211 CloseHandle(stdoutWrite
);
214 /* get the value of the PATH environment variable */
215 value
= getenv( ENVVARNAME
);
218 * add the UNO installation path to the PATH environment variable;
219 * note that this only affects the environment variable of the current
220 * process, the command processor's environment is not changed
222 size
= strlen( ENVVARNAME
) + strlen( "=" ) + strlen( path
) + 1;
224 size
+= strlen( PATHSEPARATOR
) + strlen( value
);
225 envstr
= (char*) malloc( size
);
226 strcpy( envstr
, ENVVARNAME
);
227 strcat( envstr
, "=" );
228 strcat( envstr
, path
);
231 strcat( envstr
, PATHSEPARATOR
);
232 strcat( envstr
, value
);
239 writeError( "Warning: no UNO installation found!\n" );
242 /* create the command line for the application process */
243 cmdline
= createCommandLine( lpCmdLine
);
244 if ( cmdline
== NULL
)
246 writeError( "Error: cannot create command line!\n" );
251 /* create the application process */
252 memset( &startup_info
, 0, sizeof( STARTUPINFO
) );
253 startup_info
.cb
= sizeof( STARTUPINFO
);
254 bCreate
= CreateProcess( NULL
, cmdline
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
,
255 &startup_info
, &process_info
);
259 writeError( "Error: cannot create process!\n" );
264 /* close the error file */
271 * Gets the path of a UNO installation.
273 * @return the installation path or NULL, if no installation was specified or
274 * found, or if an error occurred
276 char const* getPath()
278 char const* path
= cppuhelper_detail_findSofficePath();
281 writeError( "Warning: getting path from Windows Registry failed!\n" );
287 * Creates the command line for the application process including the absolute
288 * path of the executable.
290 * <p>The application's executable file name is the name of this executable
291 * prefixed by '_'.</p>
293 * @param appendix specifies the command line for the application excluding
294 * the executable name
296 * @return the command line for the application process or NULL, if an error
299 char* createCommandLine( char* appendix
)
301 const char* CMDPREFIX
= "_";
302 const char* DQUOTE
= "\"";
303 const char* SPACE
= " ";
305 char* cmdline
= NULL
;
307 char cmdname
[ _MAX_PATH
];
308 char drive
[ _MAX_DRIVE
];
309 char dir
[ _MAX_PATH
];
310 char base
[ _MAX_FNAME
];
311 char newbase
[ _MAX_FNAME
];
312 char ext
[ _MAX_EXT
];
314 /* get the absolute path of the executable file */
315 if ( GetModuleFileName( NULL
, cmdname
, sizeof( cmdname
) ) )
317 /* prefix the executable file name by '_' */
318 _splitpath( cmdname
, drive
, dir
, base
, ext
);
319 strcpy( newbase
, CMDPREFIX
);
320 strcat( newbase
, base
);
321 _makepath( cmdname
, drive
, dir
, newbase
, ext
);
323 /* create the command line */
324 cmdline
= (char*) malloc( strlen( DQUOTE
) + strlen( cmdname
) +
325 strlen ( DQUOTE
) + strlen( SPACE
) + strlen( appendix
) + 1 );
326 strcpy( cmdline
, DQUOTE
);
327 strcat( cmdline
, cmdname
);
328 strcat( cmdline
, DQUOTE
);
329 strcat( cmdline
, SPACE
);
330 strcat( cmdline
, appendix
);
337 * Gets the pointer to the error file.
339 * <p>The error file will only be created, if create != 0.</p>
341 * <p>The error file has the name <executable file name>-error.log and is
342 * created in the same directory as the executable file. If this fails,
343 * the error file is created in the directory designated for temporary files.
346 * @param create specifies, if the error file should be created (create != 0)
348 * @return the pointer to the open error file or NULL, if no error file is
349 * open or can be created
351 FILE* getErrorFile( int create
)
353 const char* MODE
= "w";
354 const char* BASEPOSTFIX
= "-error";
355 const char* EXTENSION
= ".log";
357 static FILE* ferr
= NULL
;
359 char fname
[ _MAX_PATH
];
360 char drive
[ _MAX_DRIVE
];
361 char dir
[ _MAX_PATH
];
362 char base
[ _MAX_FNAME
];
363 char newbase
[ _MAX_FNAME
];
364 char ext
[ _MAX_EXT
];
366 if ( ferr
== NULL
&& create
)
368 /* get the absolute path of the executable file */
369 if ( GetModuleFileName( NULL
, fname
, sizeof( fname
) ) )
371 /* create error file in the directory of the executable file */
372 _splitpath( fname
, drive
, dir
, base
, ext
);
373 strcpy( newbase
, base
);
374 strcat( newbase
, BASEPOSTFIX
);
375 _makepath( fname
, drive
, dir
, newbase
, EXTENSION
);
376 ferr
= fopen( fname
, MODE
);
380 /* create error file in the temp directory */
381 GetTempPath( sizeof( fname
), fname
);
382 strcat( fname
, newbase
);
383 strcat( fname
, EXTENSION
);
384 ferr
= fopen( fname
, MODE
);
393 * Writes an error message to the error file.
395 * @param errstr specifies the error message
397 void writeError( const char* errstr
)
399 FILE* ferr
= getErrorFile( 1 );
402 fprintf( ferr
, errstr
);
408 * Closes the error file.
410 void closeErrorFile()
412 FILE* ferr
= getErrorFile( 0 );
417 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */