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