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