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