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 #define _WIN32_WINDOWS 0x0410 25 26 #ifdef _MSC_VER 27 #pragma warning(push, 1) /* disable warnings within system headers */ 28 #endif 29 #define WIN32_LEAN_AND_MEAN 30 #include <windows.h> 31 #include <msiquery.h> 32 #ifdef _MSC_VER 33 #pragma warning(pop) 34 #endif 35 36 #include <malloc.h> 37 #include <assert.h> 38 39 #ifdef UNICODE 40 #define _UNICODE 41 #define _tstring wstring 42 #else 43 #define _tstring string 44 #endif 45 #include <tchar.h> 46 #include <string> 47 #include <queue> 48 #include <stdio.h> 49 50 #include <systools/win32/uwinapi.h> 51 #include <../tools/seterror.hxx> 52 53 #define WININIT_FILENAME "wininit.ini" 54 #define RENAME_SECTION "rename" 55 56 #ifdef DEBUG 57 inline void OutputDebugStringFormat( LPCTSTR pFormat, ... ) 58 { 59 _TCHAR buffer[1024]; 60 va_list args; 61 62 va_start( args, pFormat ); 63 _vsntprintf( buffer, elementsof(buffer), pFormat, args ); 64 OutputDebugString( buffer ); 65 } 66 #else 67 static inline void OutputDebugStringFormat( LPCTSTR, ... ) 68 { 69 } 70 #endif 71 72 static std::_tstring GetMsiProperty( MSIHANDLE handle, const std::_tstring& sProperty ) 73 { 74 std::_tstring result; 75 TCHAR szDummy[1] = TEXT(""); 76 DWORD nChars = 0; 77 78 if ( MsiGetProperty( handle, sProperty.c_str(), szDummy, &nChars ) == ERROR_MORE_DATA ) 79 { 80 DWORD nBytes = ++nChars * sizeof(TCHAR); 81 LPTSTR buffer = reinterpret_cast<LPTSTR>(_alloca(nBytes)); 82 ZeroMemory( buffer, nBytes ); 83 MsiGetProperty(handle, sProperty.c_str(), buffer, &nChars); 84 result = buffer; 85 } 86 87 return result; 88 } 89 90 static inline bool IsSetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) 91 { 92 std::_tstring value = GetMsiProperty(handle, sProperty); 93 return (value.length() > 0); 94 } 95 96 static inline void UnsetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) 97 { 98 MsiSetProperty(handle, sProperty.c_str(), NULL); 99 } 100 101 static inline void SetMsiProperty(MSIHANDLE handle, const std::_tstring& sProperty) 102 { 103 MsiSetProperty(handle, sProperty.c_str(), TEXT("1")); 104 } 105 106 static BOOL MoveFileEx9x( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags ) 107 { 108 BOOL fSuccess = FALSE; // assume failure 109 110 // Windows 9x has a special mechanism to move files after reboot 111 112 if ( dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT ) 113 { 114 CHAR szExistingFileNameA[MAX_PATH]; 115 CHAR szNewFileNameA[MAX_PATH] = "NUL"; 116 117 // Path names in WININIT.INI must be in short path name form 118 119 if ( 120 GetShortPathNameA( lpExistingFileNameA, szExistingFileNameA, MAX_PATH ) && 121 (!lpNewFileNameA || GetShortPathNameA( lpNewFileNameA, szNewFileNameA, MAX_PATH )) 122 ) 123 { 124 CHAR szBuffer[32767]; // The buffer size must not exceed 32K 125 DWORD dwBufLen = GetPrivateProfileSectionA( RENAME_SECTION, szBuffer, elementsof(szBuffer), WININIT_FILENAME ); 126 127 CHAR szRename[MAX_PATH]; // This is enough for at most to times 67 chracters 128 strcpy( szRename, szNewFileNameA ); 129 strcat( szRename, "=" ); 130 strcat( szRename, szExistingFileNameA ); 131 size_t lnRename = strlen(szRename); 132 133 if ( dwBufLen + lnRename + 2 <= elementsof(szBuffer) ) 134 { 135 CopyMemory( &szBuffer[dwBufLen], szRename, lnRename ); 136 szBuffer[dwBufLen + lnRename ] = 0; 137 szBuffer[dwBufLen + lnRename + 1 ] = 0; 138 139 fSuccess = WritePrivateProfileSectionA( RENAME_SECTION, szBuffer, WININIT_FILENAME ); 140 } 141 else 142 SetLastError( ERROR_BUFFER_OVERFLOW ); 143 } 144 } 145 else 146 { 147 148 fSuccess = MoveFileA( lpExistingFileNameA, lpNewFileNameA ); 149 150 if ( !fSuccess && GetLastError() != ERROR_ACCESS_DENIED && 151 0 != (dwFlags & (MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING)) ) 152 { 153 BOOL bFailIfExist = 0 == (dwFlags & MOVEFILE_REPLACE_EXISTING); 154 155 fSuccess = CopyFileA( lpExistingFileNameA, lpNewFileNameA, bFailIfExist ); 156 157 if ( fSuccess ) 158 fSuccess = DeleteFileA( lpExistingFileNameA ); 159 } 160 161 } 162 163 return fSuccess; 164 } 165 166 static BOOL MoveFileExImpl( LPCSTR lpExistingFileNameA, LPCSTR lpNewFileNameA, DWORD dwFlags ) 167 { 168 if ( 0 > ((LONG)GetVersion())) // High order bit indicates Win 9x 169 return MoveFileEx9x( lpExistingFileNameA, lpNewFileNameA, dwFlags ); 170 else 171 return MoveFileExA( lpExistingFileNameA, lpNewFileNameA, dwFlags ); 172 } 173 174 extern "C" UINT __stdcall IsOfficeRunning( MSIHANDLE handle ) 175 { 176 OSVERSIONINFO osverinfo; 177 osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 178 GetVersionEx( &osverinfo ); 179 180 // renaming the vcl resource doesn't work reliable with OS >= Windows Vista 181 if (osverinfo.dwMajorVersion < 6 ) 182 { 183 std::_tstring sInstDir = GetMsiProperty( handle, TEXT("INSTALLLOCATION") ); 184 // Property empty -> no office installed 185 if ( sInstDir.length() == 0 ) 186 return ERROR_SUCCESS; 187 188 std::_tstring sResourceDir = sInstDir + TEXT("Basis\\program\\resource\\"); 189 std::_tstring sPattern = sResourceDir + TEXT("vcl*.res"); 190 191 // std::_tstring mystr; 192 // mystr = "IsOfficeRunning start. Checking file in dir: " + sResourceDir; 193 // MessageBox( NULL, mystr.c_str(), "IsOfficeRunning", MB_OK ); 194 195 WIN32_FIND_DATA aFindFileData; 196 HANDLE hFind = FindFirstFile( sPattern.c_str(), &aFindFileData ); 197 198 if ( IsValidHandle(hFind) ) 199 { 200 BOOL fSuccess = false; 201 bool fRenameSucceeded; 202 203 do 204 { 205 std::_tstring sResourceFile = sResourceDir + aFindFileData.cFileName; 206 std::_tstring sIntermediate = sResourceFile + TEXT(".tmp"); 207 208 fRenameSucceeded = MoveFileExImpl( sResourceFile.c_str(), sIntermediate.c_str(), MOVEFILE_REPLACE_EXISTING ); 209 if ( fRenameSucceeded ) 210 { 211 MoveFileExImpl( sIntermediate.c_str(), sResourceFile.c_str(), 0 ); 212 fSuccess = FindNextFile( hFind, &aFindFileData ); 213 } 214 } while ( fSuccess && fRenameSucceeded ); 215 216 if ( !fRenameSucceeded ) 217 { 218 MsiSetProperty(handle, TEXT("OFFICERUNS"), TEXT("1")); 219 SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING ); 220 221 // mystr = "Office is running"; 222 // MessageBox( NULL, mystr.c_str(), "IsOfficeRunning", MB_OK ); 223 } 224 225 FindClose( hFind ); 226 } 227 // mystr = "IsOfficeRunning end"; 228 // MessageBox( NULL, mystr.c_str(), "IsOfficeRunning", MB_OK ); 229 } 230 else 231 { 232 std::_tstring sOfficeInstallPath = GetMsiProperty(handle, TEXT("INSTALLLOCATION")); 233 // Property empty -> no office installed 234 if ( sOfficeInstallPath.length() == 0 ) 235 return ERROR_SUCCESS; 236 237 std::_tstring sRenameSrc = sOfficeInstallPath + TEXT("program"); 238 std::_tstring sRenameDst = sOfficeInstallPath + TEXT("program_test"); 239 240 bool bSuccess = MoveFile( sRenameSrc.c_str(), sRenameDst.c_str() ); 241 242 if ( bSuccess ) 243 { 244 MoveFile( sRenameDst.c_str(), sRenameSrc.c_str() ); 245 } 246 else 247 { 248 DWORD dwError = GetLastError(); 249 LPVOID lpMsgBuf; 250 // When there is no program folder, there could be no running office 251 if ( dwError == ERROR_FILE_NOT_FOUND ) 252 return ERROR_SUCCESS; 253 if ( dwError == ERROR_PATH_NOT_FOUND ) 254 return ERROR_SUCCESS; 255 256 // The destination folder should never exist, don't know what to do here 257 if ( dwError == ERROR_ALREADY_EXISTS ) 258 return ERROR_SUCCESS; 259 260 if ( FormatMessage( 261 FORMAT_MESSAGE_ALLOCATE_BUFFER | 262 FORMAT_MESSAGE_FROM_SYSTEM | 263 FORMAT_MESSAGE_IGNORE_INSERTS, 264 NULL, 265 GetLastError(), 266 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language 267 (LPTSTR) &lpMsgBuf, 268 0, 269 NULL )) 270 { 271 OutputDebugStringFormat( TEXT("Error Code %d: %s"), dwError, lpMsgBuf ); 272 LocalFree( lpMsgBuf ); 273 } 274 else 275 OutputDebugStringFormat( TEXT("Error Code %d: Unknown"), dwError ); 276 277 MsiSetProperty( handle, TEXT("OFFICERUNS"), TEXT("1") ); 278 SetMsiErrorCode( MSI_ERROR_OFFICE_IS_RUNNING ); 279 } 280 } 281 282 return ERROR_SUCCESS; 283 } 284 285 286 287