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