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