1/**************************************************************
| 1/**************************************************************
|
2 *
| 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
| 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 *
| 10 *
|
11 * http://www.apache.org/licenses/LICENSE-2.0
| 11 * http://www.apache.org/licenses/LICENSE-2.0
|
12 *
| 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.
| 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 *
| 19 *
|
20 *************************************************************/ 21 22
| 20 *************************************************************/ 21 22
|
23
| 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 40class RegistryKeyGuard 41{
| 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 40class RegistryKeyGuard 41{
|
42public:
| 42public:
|
43 RegistryKeyGuard(HKEY hkey = 0) : 44 hkey_(hkey) 45 { 46 }
| 43 RegistryKeyGuard(HKEY hkey = 0) : 44 hkey_(hkey) 45 { 46 }
|
47
| 47
|
48 ~RegistryKeyGuard() 49 { 50 if (hkey_) 51 RegCloseKey(hkey_);
| 48 ~RegistryKeyGuard() 49 { 50 if (hkey_) 51 RegCloseKey(hkey_);
|
52 }
| 52 }
|
53private: 54 HKEY hkey_; 55 56private: 57 RegistryKeyGuard(const RegistryKeyGuard&);
| 53private: 54 HKEY hkey_; 55 56private: 57 RegistryKeyGuard(const RegistryKeyGuard&);
|
58 RegistryKeyGuard& operator=(const RegistryKeyGuard&);
| 58 RegistryKeyGuard& operator=(const RegistryKeyGuard&);
|
59}; 60 61typedef std::vector<TCHAR> CharacterBuffer_t; 62 63/* throws std::runtime_error when the value "Path" could
| 59}; 60 61typedef 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
| 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. */
| 66 properly installed product. */
|
67std::string FindProductInstallationPath(HKEY hkey) 68{
| 67std::string FindProductInstallationPath(HKEY hkey) 68{
|
69 DWORD nSubKeys; 70 DWORD lLongestSubKey;
| 69 DWORD nSubKeys; 70 DWORD lLongestSubKey;
|
71 72 if (RegQueryInfoKey(hkey, NULL, NULL, NULL, &nSubKeys, &lLongestSubKey, NULL, NULL, NULL, NULL, NULL, NULL) !=
| 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");
| 73 ERROR_SUCCESS) 74 throw std::runtime_error("Cannot query info for registery key");
|
75
| 75
|
76 CharacterBuffer_t buff(lLongestSubKey + 1);
| 76 CharacterBuffer_t buff(lLongestSubKey + 1);
|
77
| 77
|
78 for (DWORD i = 0; i < nSubKeys; i++) 79 { 80 buff[0] = 0; 81 LONG ret = RegEnumKey(hkey, i, &buff[0], buff.size());
| 78 for (DWORD i = 0; i < nSubKeys; i++) 79 { 80 buff[0] = 0; 81 LONG ret = RegEnumKey(hkey, i, &buff[0], buff.size());
|
82
| 82
|
83 if ((ret != ERROR_SUCCESS) && (ret != ERROR_MORE_DATA)) 84 throw std::runtime_error("Error enumerating registry key");
| 83 if ((ret != ERROR_SUCCESS) && (ret != ERROR_MORE_DATA)) 84 throw std::runtime_error("Error enumerating registry key");
|
85
| 85
|
86 HKEY hSubKey;
| 86 HKEY hSubKey;
|
87 if (RegOpenKey(hkey, &buff[0], &hSubKey) != ERROR_SUCCESS) 88 continue; 89
| 87 if (RegOpenKey(hkey, &buff[0], &hSubKey) != ERROR_SUCCESS) 88 continue; 89
|
90 RegistryKeyGuard guard(hSubKey);
| 90 RegistryKeyGuard guard(hSubKey);
|
91
| 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) ||
| 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))
| 97 (type != REG_SZ))
|
98 continue;
| 98 continue;
|
99 100 std::string path(pbuff);
| 99 100 std::string path(pbuff);
|
101 std::string::size_type idx = path.rfind("program\\soffice.exe");
| 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");
| 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 109UINT GetInstallProperty(MSIHANDLE handle, LPCTSTR name, CharacterBuffer_t* buffer)
| 107} 108 109UINT GetInstallProperty(MSIHANDLE handle, LPCTSTR name, CharacterBuffer_t* buffer)
|
110{
| 110{
|
111 DWORD size = buffer->size(); 112 UINT ret = MsiGetProperty(handle, name, &(*buffer)[0], &size);
| 111 DWORD size = buffer->size(); 112 UINT ret = MsiGetProperty(handle, name, &(*buffer)[0], &size);
|
113
| 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);
| 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 }
| 119 }
|
120 return ret; 121} 122
| 120 return ret; 121} 122
|
123/*
| 123/*
|
124 Try to find the installation path to an already installed product. 125 The installation path will be written in the Windows registry
| 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
| 126 during the installation. There may exist different products in
|
127 parallel e.g. StarOffice, StarSuite, OpenOffice.org, Apache OpenOffice.
| 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
| 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*/ 132extern "C" UINT __stdcall SetProductInstallationPath(MSIHANDLE handle) 133{ 134 //MessageBox(NULL, TEXT("SetProductInstallationPath"), TEXT("Language Pack Installation Helper"), MB_OK | MB_ICONINFORMATION);
| 129 will be found the path to the product will be set in the property 130 "INSTALLLOCATION" else nothing will be done. 131*/ 132extern "C" UINT __stdcall SetProductInstallationPath(MSIHANDLE handle) 133{ 134 //MessageBox(NULL, TEXT("SetProductInstallationPath"), TEXT("Language Pack Installation Helper"), MB_OK | MB_ICONINFORMATION);
|
135
| 135
|
136 try
| 136 try
|
137 { 138 CharacterBuffer_t regKeyProdPath(MAX_PATH); 139
| 137 { 138 CharacterBuffer_t regKeyProdPath(MAX_PATH); 139
|
140 GetInstallProperty(handle, TEXT("REGKEYPRODPATH"), ®KeyProdPath);
| 140 GetInstallProperty(handle, TEXT("REGKEYPRODPATH"), ®KeyProdPath);
|
141
| 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))
| 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 {
| 145 {
|
146 RegistryKeyGuard guard(hKey);
| 146 RegistryKeyGuard guard(hKey);
|
147 std::string path = FindProductInstallationPath(hKey); 148 MsiSetProperty(handle, TEXT("INSTALLLOCATION"), path.c_str()); 149 }
| 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
| 150 } 151 catch(std::runtime_error& ex) 152 { 153 ex = ex; // no warnings
|
154 } 155 return ERROR_SUCCESS;
| 154 } 155 return ERROR_SUCCESS;
|
156} 157 158void MakeCfgimportCommandLine(CharacterBuffer_t* productPath)
| 156} 157 158void MakeCfgimportCommandLine(CharacterBuffer_t* productPath)
|
159{
| 159{
|
160 char* p = &(*productPath)[0] + lstrlen(&(*productPath)[0]) - 1; 161
| 160 char* p = &(*productPath)[0] + lstrlen(&(*productPath)[0]) - 1; 161
|
162 if (*p != '\\') 163 lstrcat(&(*productPath)[0], "\\program\\configimport.exe --spool");
| 162 if (*p != '\\') 163 lstrcat(&(*productPath)[0], "\\program\\configimport.exe --spool");
|
164 else
| 164 else
|
165 lstrcat(&(*productPath)[0], "program\\configimport.exe --spool");
| 165 lstrcat(&(*productPath)[0], "program\\configimport.exe --spool");
|
166} 167 168/* 169 Calls configimport.exe --spool 170*/ 171extern "C" UINT __stdcall RegisterLanguagePack(MSIHANDLE handle) 172{ 173 //MessageBox(NULL, TEXT("RegisterLanguagePack"), TEXT("Language Pack Installation Helper"), MB_OK | MB_ICONINFORMATION);
| 166} 167 168/* 169 Calls configimport.exe --spool 170*/ 171extern "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;
| 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);
| 180 ZeroMemory(&si, sizeof(si)); 181 si.cb = sizeof(si);
|
182
| 182
|
183 PROCESS_INFORMATION pi; 184 ZeroMemory(&pi, sizeof(pi));
| 183 PROCESS_INFORMATION pi; 184 ZeroMemory(&pi, sizeof(pi));
|
185
| 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
| 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.
| 194 // Close process and thread handles.
|
195 CloseHandle(pi.hProcess);
| 195 CloseHandle(pi.hProcess);
|
196 CloseHandle(pi.hThread); 197 } 198 return ERROR_SUCCESS;
| 196 CloseHandle(pi.hThread); 197 } 198 return ERROR_SUCCESS;
|
199} 200
| 199} 200
|