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"), ®KeyProdPath);
139
140 HKEY hKey;
141 if ((RegOpenKey(HKEY_CURRENT_USER, ®KeyProdPath[0], &hKey) == ERROR_SUCCESS) ||
142 (RegOpenKey(HKEY_LOCAL_MACHINE, ®KeyProdPath[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