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