1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // Use UNICODE Windows and C API.
29 #define _UNICODE
30 #define UNICODE
31 
32 #ifdef _MSC_VER
33 #pragma warning(push, 1)
34 #endif
35 #include <windows.h>
36 #include "uno/environment.hxx"
37 #ifdef _MSC_VER
38 #pragma warning(pop)
39 #endif
40 
41 #include <tchar.h>
42 
43 #include "native_share.h"
44 
45 #include "rtl/bootstrap.hxx"
46 #include "com/sun/star/uno/XComponentContext.hpp"
47 #include "cppuhelper/bootstrap.hxx"
48 #include <delayimp.h>
49 #include <stdio.h>
50 
51 using namespace ::rtl;
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::uno;
54 
55 namespace cli_ure {
56     WCHAR * resolveLink(WCHAR * path);
57 }
58 
59 #define INSTALL_PATH L"Software\\OpenOffice.org\\UNO\\InstallPath"
60 #define BASIS_LINK L"\\basis-link"
61 #define URE_LINK L"\\ure-link"
62 #define URE_BIN L"\\bin"
63 #define UNO_PATH L"UNO_PATH"
64 
65 namespace
66 {
67 
68  /*
69  * Gets the installation path from the Windows Registry for the specified
70  * registry key.
71  *
72  * @param hroot       open handle to predefined root registry key
73  * @param subKeyName  name of the subkey to open
74  *
75  * @return the installation path or NULL, if no installation was found or
76  *         if an error occured
77  */
78 WCHAR* getPathFromRegistryKey( HKEY hroot, LPCWSTR subKeyName )
79 {
80     HKEY hkey;
81     DWORD type;
82     TCHAR* data = NULL;
83     DWORD size;
84 
85     /* open the specified registry key */
86     if ( RegOpenKeyEx( hroot, subKeyName, 0, KEY_READ, &hkey ) != ERROR_SUCCESS )
87     {
88         return NULL;
89     }
90 
91     /* find the type and size of the default value */
92     if ( RegQueryValueEx( hkey, NULL, NULL, &type, NULL, &size) != ERROR_SUCCESS )
93     {
94         RegCloseKey( hkey );
95         return NULL;
96     }
97 
98     /* get memory to hold the default value */
99     data = new WCHAR[size];
100 
101     /* read the default value */
102     if ( RegQueryValueEx( hkey, NULL, NULL, &type, (LPBYTE) data, &size ) != ERROR_SUCCESS )
103     {
104         RegCloseKey( hkey );
105         return NULL;
106     }
107 
108     /* release registry key handle */
109     RegCloseKey( hkey );
110 
111     return data;
112 }
113 
114 /* If the path does not end with '\' the las segment will be removed.
115     path: C:\a\b
116     ->    C:\a
117     @param io_path
118         in/out parameter. The string is not reallocated. Simply a '\0'
119         will be inserted to shorten the string.
120 */
121 void oneDirUp(LPTSTR io_path)
122 {
123     WCHAR * pEnd = io_path + lstrlen(io_path) - 1;
124     while (pEnd > io_path //prevent crashing if provided string does not contain a backslash
125         && *pEnd != L'\\')
126         pEnd --;
127     *pEnd = L'\0';
128 }
129 
130 
131 /* Returns the path to the program folder of the brand layer,
132     for example c:/openoffice.org 3/program
133    This path is either obtained from the environment variable UNO_PATH
134    or the registry item
135    "Software\\OpenOffice.org\\UNO\\InstallPath"
136    either in HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE
137    The return value must be freed with delete[]
138 */
139 WCHAR * getInstallPath()
140 {
141     WCHAR * szInstallPath = NULL;
142 
143     DWORD  cChars = GetEnvironmentVariable(UNO_PATH, NULL, 0);
144     if (cChars > 0)
145     {
146         szInstallPath = new WCHAR[cChars];
147         cChars = GetEnvironmentVariable(UNO_PATH, szInstallPath, cChars);
148 		//If PATH is not set then it is no error
149 		if (cChars == 0)
150 		{
151 			delete[] szInstallPath;
152 			return NULL;
153 		}
154     }
155 
156     if (! szInstallPath)
157     {
158         szInstallPath = getPathFromRegistryKey( HKEY_CURRENT_USER, INSTALL_PATH );
159         if ( szInstallPath == NULL )
160         {
161             /* read the key's default value from HKEY_LOCAL_MACHINE */
162             szInstallPath = getPathFromRegistryKey( HKEY_LOCAL_MACHINE, INSTALL_PATH );
163         }
164     }
165     return szInstallPath;
166 }
167 
168 /* Returns the path to the URE/bin path, where cppuhelper lib resides.
169     The returned string must be freed with delete[]
170 */
171 WCHAR* getUnoPath()
172 {
173     WCHAR * szLinkPath = NULL;
174     WCHAR * szUrePath = NULL;
175     WCHAR * szUreBin = NULL; //the return value
176 
177     WCHAR * szInstallPath = getInstallPath();
178     if (szInstallPath)
179     {
180         //build the path tho the basis-link file
181         oneDirUp(szInstallPath);
182         int sizeLinkPath = lstrlen(szInstallPath) + lstrlen(INSTALL_PATH) + 1;
183         if (sizeLinkPath < MAX_PATH)
184             sizeLinkPath = MAX_PATH;
185         szLinkPath = new WCHAR[sizeLinkPath];
186         szLinkPath[0] = L'\0';
187         lstrcat(szLinkPath, szInstallPath);
188         lstrcat(szLinkPath, BASIS_LINK);
189 
190         //get the path to the actual Basis folder
191         if (cli_ure::resolveLink(szLinkPath))
192         {
193             //build the path to the ure-link file
194             int sizeUrePath = lstrlen(szLinkPath) + lstrlen(URE_LINK) + 1;
195             if (sizeUrePath < MAX_PATH)
196                 sizeUrePath = MAX_PATH;
197             szUrePath = new WCHAR[sizeUrePath];
198             szUrePath[0] = L'\0';
199             lstrcat(szUrePath, szLinkPath);
200             lstrcat(szUrePath, URE_LINK);
201 
202             //get the path to the actual Ure folder
203             if (cli_ure::resolveLink(szUrePath))
204             {
205                 //build the path to the URE/bin directory
206         	    szUreBin = new WCHAR[lstrlen(szUrePath) + lstrlen(URE_BIN) + 1];
207  	            szUreBin[0] = L'\0';
208                 lstrcat(szUreBin, szUrePath);
209  	            lstrcat(szUreBin, URE_BIN);
210             }
211         }
212     }
213 #if OSL_DEBUG_LEVEL >=2
214     if (szUreBin)
215     {
216         fwprintf(stdout,L"[cli_cppuhelper]: Path to URE libraries:\n %s \n", szUreBin);
217     }
218     else
219     {
220         fwprintf(stdout,L"[cli_cppuhelper]: Failed to determine location of URE.\n");
221     }
222 #endif
223     delete[] szInstallPath;
224     delete[] szLinkPath;
225     delete[] szUrePath;
226     return szUreBin;
227 }
228 
229 
230 /*We extend the path to contain the Ure/bin folder,
231   so that components can use osl_loadModule with arguments, such as
232   "reg3.dll". That is, the arguments are only the library names.
233 */
234 void extendPath(LPCWSTR szUreBinPath)
235 {
236 	if (!szUreBinPath)
237 		return;
238 
239     WCHAR * sEnvPath = NULL;
240     DWORD  cChars = GetEnvironmentVariable(L"PATH", sEnvPath, 0);
241     if (cChars > 0)
242     {
243         sEnvPath = new WCHAR[cChars];
244         cChars = GetEnvironmentVariable(L"PATH", sEnvPath, cChars);
245 		//If PATH is not set then it is no error
246 		if (cChars == 0 && GetLastError() != ERROR_ENVVAR_NOT_FOUND)
247 		{
248 			delete[] sEnvPath;
249 			return;
250 		}
251     }
252     //prepare the new PATH. Add the Ure/bin directory at the front.
253     //note also adding ';'
254     WCHAR * sNewPath = new WCHAR[lstrlen(sEnvPath) + lstrlen(szUreBinPath) + 2];
255     sNewPath[0] = L'\0';
256 	lstrcat(sNewPath, szUreBinPath);
257 	if (lstrlen(sEnvPath))
258 	{
259 		lstrcat(sNewPath, L";");
260 		lstrcat(sNewPath, sEnvPath);
261 	}
262     BOOL bSet = SetEnvironmentVariable(L"PATH", sNewPath);
263 
264     delete[] sEnvPath;
265     delete[] sNewPath;
266 }
267 
268 
269 HMODULE loadFromPath(LPCWSTR sLibName)
270 {
271 	if (sLibName == NULL)
272 		return NULL;
273 
274 	WCHAR * szUreBinPath =  getUnoPath();
275 	if (!szUreBinPath)
276 		return NULL;
277 
278     extendPath(szUreBinPath);
279 
280     WCHAR*  szFullPath = new WCHAR[lstrlen(sLibName) + lstrlen(szUreBinPath) + 2];
281     szFullPath[0] = L'\0';
282     lstrcat(szFullPath, szUreBinPath);
283     lstrcat(szFullPath, L"\\");
284     lstrcat(szFullPath, sLibName);
285     HMODULE handle = LoadLibraryEx(szFullPath, NULL,
286 		LOAD_WITH_ALTERED_SEARCH_PATH);
287 
288     delete[] szFullPath;
289     delete[] szUreBinPath;
290 	return handle;
291 }
292 
293 /*Hook for delayed loading of libraries which this library is linked with.
294     This is a failure hook. That is, it is only called when the loading of
295     a library failed. It will be called when loading of cppuhelper failed.
296     Because we extend the PATH to the URE/bin folder while this function is
297     executed (see extendPath), all other libraries are found.
298 */
299 extern "C" FARPROC WINAPI delayLoadHook(
300     unsigned        dliNotify,
301     PDelayLoadInfo  pdli
302     )
303 {
304     if (dliNotify == dliFailLoadLib)
305     {
306         LPWSTR szLibName = NULL;
307      	//Convert the ansi file name to wchar_t*
308 		int size = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pdli->szDll, -1, NULL, 0);
309 		if (size > 0)
310 		{
311 			szLibName = new WCHAR[size];
312 			if (! MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pdli->szDll, -1, szLibName, size))
313 			{
314                 return 0;
315 			}
316 		}
317         HANDLE h = loadFromPath(szLibName);
318         delete[] szLibName;
319 		return (FARPROC) h;
320     }
321     return 0;
322 }
323 }
324 
325 ExternC
326 PfnDliHook   __pfnDliFailureHook2 = delayLoadHook;
327 
328 namespace uno
329 {
330 namespace util
331 {
332 
333 /** Bootstrapping native UNO.
334 
335     Bootstrapping requires the existence of many libraries which are contained
336     in an URE installation. To find and load these libraries the Windows
337     registry keys HKEY_CURRENT_USER\Software\OpenOffice.org\Layer\URE\1
338     and HKEY_LOCAL_MACHINE\Software\OpenOffice.org\Layer\URE\1 are examined.
339     These contain a named value UREINSTALLLOCATION which holds a path to the URE
340 	installation folder.
341 */
342 public __sealed __gc class Bootstrap
343 {
344     inline Bootstrap() {}
345 
346 public:
347 
348     /** Bootstraps the initial component context from a native UNO installation.
349 
350         @see cppuhelper/bootstrap.hxx:defaultBootstrap_InitialComponentContext()
351     */
352     static ::unoidl::com::sun::star::uno::XComponentContext *
353         defaultBootstrap_InitialComponentContext();
354 
355     /** Bootstraps the initial component context from a native UNO installation.
356 
357         @param ini_file
358                a file URL of an ini file, e.g. uno.ini/unorc. (The ini file must
359                reside next to the cppuhelper library)
360         @param bootstrap_parameters
361                bootstrap parameters (maybe null)
362 
363         @see cppuhelper/bootstrap.hxx:defaultBootstrap_InitialComponentContext()
364     */
365     static ::unoidl::com::sun::star::uno::XComponentContext *
366         defaultBootstrap_InitialComponentContext(
367             ::System::String * ini_file,
368             ::System::Collections::IDictionaryEnumerator *
369               bootstrap_parameters );
370 
371     /** Bootstraps the initial component context from a native UNO installation.
372 
373     @see cppuhelper/bootstrap.hxx:bootstrap()
374      */
375     static ::unoidl::com::sun::star::uno::XComponentContext *
376     bootstrap();
377 };
378 
379 //______________________________________________________________________________
380 ::unoidl::com::sun::star::uno::XComponentContext *
381 Bootstrap::defaultBootstrap_InitialComponentContext(
382     ::System::String * ini_file,
383     ::System::Collections::IDictionaryEnumerator * bootstrap_parameters )
384 {
385     if (0 != bootstrap_parameters)
386     {
387         bootstrap_parameters->Reset();
388         while (bootstrap_parameters->MoveNext())
389         {
390             OUString key(
391                 String_to_ustring( __try_cast< ::System::String * >(
392                                        bootstrap_parameters->get_Key() ) ) );
393             OUString value(
394                 String_to_ustring( __try_cast< ::System::String * >(
395                                        bootstrap_parameters->get_Value() ) ) );
396 
397             ::rtl::Bootstrap::set( key, value );
398         }
399     }
400 
401     // bootstrap native uno
402     Reference< XComponentContext > xContext;
403     if (0 == ini_file)
404     {
405         xContext = ::cppu::defaultBootstrap_InitialComponentContext();
406     }
407     else
408     {
409         xContext = ::cppu::defaultBootstrap_InitialComponentContext(
410             String_to_ustring( __try_cast< ::System::String * >( ini_file ) ) );
411     }
412 
413     return __try_cast< ::unoidl::com::sun::star::uno::XComponentContext * >(
414         to_cli( xContext ) );
415 }
416 
417 //______________________________________________________________________________
418 ::unoidl::com::sun::star::uno::XComponentContext *
419 Bootstrap::defaultBootstrap_InitialComponentContext()
420 {
421     return defaultBootstrap_InitialComponentContext( 0, 0 );
422 }
423 
424 ::unoidl::com::sun::star::uno::XComponentContext * Bootstrap::bootstrap()
425 {
426     Reference<XComponentContext> xContext = ::cppu::bootstrap();
427     return __try_cast< ::unoidl::com::sun::star::uno::XComponentContext * >(
428         to_cli( xContext ) );
429 
430 }
431 
432 }
433 }
434