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: 43 RegistryKeyGuard(HKEY hkey = 0) : 44 hkey_(hkey) 45 { 46 } 47 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. */ 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 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 */ 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 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 */ 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