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 #ifdef _MSC_VER
29 #pragma warning(push, 1) /* disable warnings within system headers */
30 #endif
31 #define WIN32_LEAN_AND_MEAN
32 #include <windows.h>
33 #include <msiquery.h>
34 #ifdef _MSC_VER
35 #pragma warning(pop)
36 #endif
37 
38 #include <malloc.h>
39 #include <tchar.h>
40 #include <string>
41 #include <stdexcept>
42 #include <vector>
43 
44 class RegistryKeyGuard
45 {
46 public:
47     RegistryKeyGuard(HKEY hkey = 0) :
48         hkey_(hkey)
49     {
50     }
51 
52     ~RegistryKeyGuard()
53     {
54         if (hkey_)
55             RegCloseKey(hkey_);
56     }
57 private:
58     HKEY hkey_;
59 
60 private:
61     RegistryKeyGuard(const RegistryKeyGuard&);
62     RegistryKeyGuard& operator=(const RegistryKeyGuard&);
63 };
64 
65 typedef std::vector<TCHAR> CharacterBuffer_t;
66 
67 /* throws std::runtime_error when the value "Path" could
68    not be found or contains an empty string or is not of
69    type REG_SZ. All such conditions are invalid for a
70    properly installed product. */
71 std::string FindProductInstallationPath(HKEY hkey)
72 {
73     DWORD nSubKeys;
74     DWORD lLongestSubKey;
75 
76     if (RegQueryInfoKey(hkey, NULL, NULL, NULL, &nSubKeys, &lLongestSubKey, NULL, NULL, NULL, NULL, NULL, NULL) !=
77         ERROR_SUCCESS)
78         throw std::runtime_error("Cannot query info for registery key");
79 
80     CharacterBuffer_t buff(lLongestSubKey + 1);
81 
82     for (DWORD i = 0; i < nSubKeys; i++)
83     {
84         buff[0] = 0;
85         LONG ret = RegEnumKey(hkey, i, &buff[0], buff.size());
86 
87         if ((ret != ERROR_SUCCESS) && (ret != ERROR_MORE_DATA))
88             throw std::runtime_error("Error enumerating registry key");
89 
90         HKEY hSubKey;
91         if (RegOpenKey(hkey, &buff[0], &hSubKey) != ERROR_SUCCESS)
92             continue;
93 
94         RegistryKeyGuard guard(hSubKey);
95 
96         DWORD type;
97         TCHAR pbuff[MAX_PATH];
98         DWORD size = sizeof(pbuff);
99         if ((RegQueryValueEx(
100                 hSubKey, TEXT("Path"), NULL, &type, reinterpret_cast<LPBYTE>(pbuff), &size) != ERROR_SUCCESS) ||
101                 (type != REG_SZ))
102             continue;
103 
104         std::string path(pbuff);
105         std::string::size_type idx = path.rfind("program\\soffice.exe");
106         if (idx != std::string::npos)
107             return path.substr(0, idx);
108     } // for
109 
110     throw std::runtime_error("No valid product path found");
111 }
112 
113 UINT GetInstallProperty(MSIHANDLE handle, LPCTSTR name, CharacterBuffer_t* buffer)
114 {
115     DWORD size = buffer->size();
116     UINT ret = MsiGetProperty(handle, name, &(*buffer)[0], &size);
117 
118     if (ret == ERROR_MORE_DATA)
119     {
120         buffer->resize(size + 1);
121         size = buffer->size();
122         ret = MsiGetProperty(handle, name, &(*buffer)[0], &size);
123     }
124     return ret;
125 }
126 
127 /*
128     Try to find the installation path to an already installed product.
129     The installation path will be written in the Windows registry
130     during the installation. There may exist different products in
131     parallel e.g. StarOffice, StarSuite, OpenOffice.org. It will be
132     searched in this order for an installed product. If a product
133     will be found the path to the product will be set in the property
134     "INSTALLLOCATION" else nothing will be done.
135 */
136 extern "C" UINT __stdcall SetProductInstallationPath(MSIHANDLE handle)
137 {
138     //MessageBox(NULL, TEXT("SetProductInstallationPath"), TEXT("Language Pack Installation Helper"), MB_OK | MB_ICONINFORMATION);
139 
140     try
141     {
142         CharacterBuffer_t regKeyProdPath(MAX_PATH);
143 
144         GetInstallProperty(handle, TEXT("REGKEYPRODPATH"), &regKeyProdPath);
145 
146         HKEY hKey;
147         if ((RegOpenKey(HKEY_CURRENT_USER, &regKeyProdPath[0], &hKey) == ERROR_SUCCESS) ||
148             (RegOpenKey(HKEY_LOCAL_MACHINE, &regKeyProdPath[0], &hKey) == ERROR_SUCCESS))
149         {
150             RegistryKeyGuard guard(hKey);
151             std::string path = FindProductInstallationPath(hKey);
152             MsiSetProperty(handle, TEXT("INSTALLLOCATION"), path.c_str());
153         }
154     }
155     catch(std::runtime_error& ex)
156     {
157         ex = ex; // no warnings
158     }
159     return ERROR_SUCCESS;
160 }
161 
162 void MakeCfgimportCommandLine(CharacterBuffer_t* productPath)
163 {
164     char* p = &(*productPath)[0] + lstrlen(&(*productPath)[0]) - 1;
165 
166     if (*p != '\\')
167         lstrcat(&(*productPath)[0], "\\program\\configimport.exe --spool");
168     else
169         lstrcat(&(*productPath)[0], "program\\configimport.exe --spool");
170 }
171 
172 /*
173     Calls configimport.exe --spool
174 */
175 extern "C" UINT __stdcall RegisterLanguagePack(MSIHANDLE handle)
176 {
177     //MessageBox(NULL, TEXT("RegisterLanguagePack"), TEXT("Language Pack Installation Helper"), MB_OK | MB_ICONINFORMATION);
178 
179     CharacterBuffer_t productPath(MAX_PATH);
180     GetInstallProperty(handle, TEXT("INSTALLLOCATION"), &productPath);
181     MakeCfgimportCommandLine(&productPath);
182 
183     STARTUPINFO si;
184     ZeroMemory(&si, sizeof(si));
185     si.cb = sizeof(si);
186 
187     PROCESS_INFORMATION pi;
188     ZeroMemory(&pi, sizeof(pi));
189 
190     if (CreateProcess(
191             NULL, &productPath[0], NULL, NULL,
192             FALSE, CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, NULL,
193             NULL, &si, &pi))
194     {
195         // Wait until child process exits.
196         WaitForSingleObject(pi.hProcess, INFINITE);
197 
198         // Close process and thread handles.
199         CloseHandle(pi.hProcess);
200         CloseHandle(pi.hThread);
201     }
202     return ERROR_SUCCESS;
203 }
204 
205