1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <process.h>
28 
29 #if defined _MSC_VER
30 #pragma warning(push, 1)
31 #endif
32 #include <windows.h>
33 #if defined _MSC_VER
34 #pragma warning(pop)
35 #endif
36 
37 #include "cppuhelper/findsofficepath.h"
38 #include "sal/types.h"
39 
40 #define MY_LENGTH(s) (sizeof (s) / sizeof *(s) - 1)
41 
42 char const* getPath();
43 char* createCommandLine( char* lpCmdLine );
44 FILE* getErrorFile( int create );
45 void writeError( const char* errstr );
46 void closeErrorFile();
47 
48 /*
49  * The main function implements a loader for applications which use UNO.
50  *
51  * <p>This code runs on the Windows platform only.</p>
52  *
53  * <p>The main function detects a UNO installation on the system and adds the
54  * program directory of the UNO installation to the PATH environment variable.
55  * After that, the application process is loaded and started, whereby the
56  * new process inherits the environment of the calling process, including
57  * the modified PATH environment variable. The application's executable name
58  * must be the same as the name of this executable, prefixed by '_'.</p>
59  *
60  * <p>A UNO installation can be specified by the user by setting the UNO_PATH
61  * environment variable to the program directory of the UNO installation.
62  * If no installation is specified by the user, the default installation on
63  * the system will be taken. The default installation is read from the
64  * default value of the key "Software\OpenOffice\UNO\InstallPath" from the
65  * root key HKEY_CURRENT_USER in the Windows Registry. If this key is missing,
66  * the key is read from the root key HKEY_LOCAL_MACHINE.</p>
67  */
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)68 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
69                     LPSTR lpCmdLine, int nCmdShow )
70 {
71     const char* ENVVARNAME = "PATH";
72     const char* PATHSEPARATOR = ";";
73 
74     char const* path = NULL;
75     char* value = NULL;
76     char* envstr = NULL;
77     char* cmdline = NULL;
78     int size;
79     STARTUPINFO startup_info;
80     PROCESS_INFORMATION process_info;
81     BOOL bCreate;
82 
83     (void) hInstance; /* unused */
84     (void) hPrevInstance; /* unused */
85     (void) nCmdShow; /* unused */
86 
87     /* get the path of the UNO installation */
88     path = getPath();
89 
90     if ( path != NULL )
91     {
92         /* The former code to call unoinfo first is removed because we can use the office path
93            from the registry or from the UNO_PATH variable directly.
94            Further cleanup can remove unoinfo from the installation when all places where it is
95            used are checked.
96           */
97 
98         /* get the value of the PATH environment variable */
99         value = getenv( ENVVARNAME );
100 
101         /*
102          * add the UNO installation path to the PATH environment variable;
103          * note that this only affects the environment variable of the current
104          * process, the command processor's environment is not changed
105          */
106         size = strlen( ENVVARNAME ) + strlen( "=" ) + strlen( path ) + 1;
107 		if ( value != NULL )
108             size += strlen( PATHSEPARATOR ) + strlen( value );
109 		envstr = (char*) malloc( size );
110         strcpy( envstr, ENVVARNAME );
111         strcat( envstr, "=" );
112         strcat( envstr, path );
113 		if ( value != NULL )
114 		{
115             strcat( envstr, PATHSEPARATOR );
116             strcat( envstr, value );
117 		}
118         _putenv( envstr );
119         free( envstr );
120     }
121     else
122     {
123         writeError( "Warning: no UNO installation found!\n" );
124     }
125 
126     /* create the command line for the application process */
127     cmdline = createCommandLine( lpCmdLine );
128     if ( cmdline == NULL )
129     {
130         writeError( "Error: cannot create command line!\n" );
131         closeErrorFile();
132         return 1;
133     }
134 
135     /* create the application process */
136 	memset( &startup_info, 0, sizeof( STARTUPINFO ) );
137 	startup_info.cb = sizeof( STARTUPINFO );
138     bCreate = CreateProcess( NULL, cmdline, NULL,  NULL, FALSE, 0, NULL, NULL,
139                              &startup_info, &process_info );
140     free( cmdline );
141     if ( !bCreate )
142     {
143         writeError( "Error: cannot create process!\n" );
144         closeErrorFile();
145         return 1;
146     }
147 
148     /* close the error file */
149     closeErrorFile();
150 
151     return 0;
152 }
153 
154 /*
155  * Gets the path of a UNO installation.
156  *
157  * @return the installation path or NULL, if no installation was specified or
158  *         found, or if an error occurred
159  */
getPath()160 char const* getPath()
161 {
162     char const* path = cppuhelper_detail_findSofficePath();
163 
164     if ( path == NULL )
165         writeError( "Warning: getting path from Windows Registry failed!\n" );
166 
167     return path;
168 }
169 
170 /*
171  * Creates the command line for the application process including the absolute
172  * path of the executable.
173  *
174  * <p>The application's executable file name is the name of this executable
175  * prefixed by '_'.</p>
176  *
177  * @param appendix specifies the command line for the application excluding
178  *                 the executable name
179  *
180  * @return the command line for the application process or NULL, if an error
181  *         occurred
182  */
createCommandLine(char * appendix)183 char* createCommandLine( char* appendix )
184 {
185     const char* CMDPREFIX = "_";
186     const char* DQUOTE = "\"";
187     const char* SPACE = " ";
188 
189     char* cmdline = NULL;
190 
191     char cmdname[ _MAX_PATH ];
192     char drive[ _MAX_DRIVE ];
193     char dir[ _MAX_PATH ];
194     char base[ _MAX_FNAME ];
195     char newbase[ _MAX_FNAME ];
196     char ext[ _MAX_EXT ];
197 
198     /* get the absolute path of the executable file */
199     if ( GetModuleFileName( NULL, cmdname, sizeof( cmdname ) ) )
200     {
201         /* prefix the executable file name by '_' */
202         _splitpath( cmdname, drive, dir, base, ext );
203         strcpy( newbase, CMDPREFIX );
204         strcat( newbase, base );
205         _makepath( cmdname, drive, dir, newbase, ext );
206 
207         /* create the command line */
208         cmdline = (char*) malloc( strlen( DQUOTE ) + strlen( cmdname ) +
209             strlen ( DQUOTE ) + strlen( SPACE ) + strlen( appendix ) + 1 );
210         strcpy( cmdline, DQUOTE );
211         strcat( cmdline, cmdname );
212         strcat( cmdline, DQUOTE );
213         strcat( cmdline, SPACE );
214         strcat( cmdline, appendix );
215     }
216 
217     return cmdline;
218 }
219 
220 /*
221  * Gets the pointer to the error file.
222  *
223  * <p>The error file will only be created, if create != 0.</p>
224  *
225  * <p>The error file has the name <executable file name>-error.log and is
226  * created in the same directory as the executable file. If this fails,
227  * the error file is created in the directory designated for temporary files.
228  * </p>
229 
230  * @param create specifies, if the error file should be created (create != 0)
231  *
232  * @return the pointer to the open error file or NULL, if no error file is
233  *         open or can be created
234  */
getErrorFile(int create)235 FILE* getErrorFile( int create )
236 {
237     const char* MODE = "w";
238     const char* BASEPOSTFIX = "-error";
239     const char* EXTENSION = ".log";
240 
241     static FILE* ferr = NULL;
242 
243     char fname[ _MAX_PATH ];
244     char drive[ _MAX_DRIVE ];
245     char dir[ _MAX_PATH ];
246     char base[ _MAX_FNAME ];
247     char newbase[ _MAX_FNAME ];
248     char ext[ _MAX_EXT ];
249 
250     if ( ferr == NULL && create )
251     {
252         /* get the absolute path of the executable file */
253         if ( GetModuleFileName( NULL, fname, sizeof( fname ) ) )
254         {
255             /* create error file in the directory of the executable file */
256             _splitpath( fname, drive, dir, base, ext );
257             strcpy( newbase, base );
258             strcat( newbase, BASEPOSTFIX );
259             _makepath( fname, drive, dir, newbase, EXTENSION );
260             ferr = fopen( fname, MODE );
261 
262             if ( ferr == NULL )
263             {
264                 /* create error file in the temp directory */
265                 GetTempPath( sizeof( fname ), fname );
266                 strcat( fname, newbase );
267                 strcat( fname, EXTENSION );
268                 ferr = fopen( fname, MODE );
269             }
270         }
271     }
272 
273     return ferr;
274 }
275 
276 /*
277  * Writes an error message to the error file.
278  *
279  * @param errstr specifies the error message
280  */
writeError(const char * errstr)281 void writeError( const char* errstr )
282 {
283     FILE* ferr = getErrorFile( 1 );
284     if ( ferr != NULL )
285     {
286         fprintf( ferr, errstr );
287         fflush( ferr );
288     }
289 }
290 
291 /*
292  * Closes the error file.
293  */
closeErrorFile()294 void closeErrorFile()
295 {
296     FILE* ferr = getErrorFile( 0 );
297     if ( ferr != NULL )
298         fclose( ferr );
299 }
300