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 // XMergeFilter.cpp: implementation of the CXMergeFilter class. 23 // 24 ////////////////////////////////////////////////////////////////////// 25 26 27 #include "stdafx.h" 28 29 #include "XMergeFilter.h" 30 31 #include <string> 32 33 34 #define ERR_NOJAVA 1 35 #define ERR_BADCLASSPATH 2 36 #define ERR_INITJAVA 3 37 38 39 const LPTSTR CXMergeFilter::m_pszPSWExportCLSID = _T("{BDD611C3-7BAB-460F-8711-5B9AC9EF6020}"); 40 const LPTSTR CXMergeFilter::m_pszPSWExportExt = _T("sxw"); 41 const LPTSTR CXMergeFilter::m_pszPSWExportDesc = _T("OpenOffice.org XML Writer Document"); 42 const LPTSTR CXMergeFilter::m_pszPSWExportShortDesc = _T("OpenOffice.org XML Writer"); 43 44 const LPTSTR CXMergeFilter::m_pszPSWImportCLSID = _T("{CB43F086-838D-4FA4-B5F6-3406B9A57439}"); 45 const LPTSTR CXMergeFilter::m_pszPSWImportExt = _T("psw"); 46 const LPTSTR CXMergeFilter::m_pszPSWImportDesc = _T("Pocket Word Document - Pocket PC"); 47 const LPTSTR CXMergeFilter::m_pszPSWImportShortDesc = _T("Pocket Word"); 48 49 const LPTSTR CXMergeFilter::m_pszPXLExportCLSID = _T("{C6AB3E74-9F4F-4370-8120-A8A6FABB7A7C}"); 50 const LPTSTR CXMergeFilter::m_pszPXLExportExt = _T("sxc"); 51 const LPTSTR CXMergeFilter::m_pszPXLExportDesc = _T("OpenOffice.org XML Calc Document"); 52 const LPTSTR CXMergeFilter::m_pszPXLExportShortDesc = _T("OpenOffice.org XML Calc"); 53 54 const LPTSTR CXMergeFilter::m_pszPXLImportCLSID = _T("{43887C67-4D5D-4127-BAAC-87A288494C7C}"); 55 const LPTSTR CXMergeFilter::m_pszPXLImportExt = _T("pxl"); 56 const LPTSTR CXMergeFilter::m_pszPXLImportDesc = _T("Pocket Excel Document - Pocket PC"); 57 const LPTSTR CXMergeFilter::m_pszPXLImportShortDesc = _T("Pocket Excel"); 58 59 60 ////////////////////////////////////////////////////////////////////// 61 // Construction/Destruction 62 ////////////////////////////////////////////////////////////////////// 63 64 CXMergeFilter::CXMergeFilter() : m_cRef(1) 65 { 66 m_bHaveExcel = FALSE; 67 m_bHaveWord = FALSE; 68 69 m_szClasspath = NULL; 70 m_szJavaBaseDir = NULL; 71 } 72 73 CXMergeFilter::~CXMergeFilter() 74 { 75 if (m_szClasspath != NULL) 76 { 77 delete m_szClasspath; 78 } 79 80 if (m_szJavaBaseDir != NULL) 81 { 82 delete m_szJavaBaseDir; 83 } 84 85 } 86 87 88 ////////////////////////////////////////////////////////////////////// 89 // IUnknown Methods 90 ////////////////////////////////////////////////////////////////////// 91 92 STDMETHODIMP CXMergeFilter::QueryInterface(REFIID riid, void **ppvObject) 93 { 94 if(ppvObject == NULL) 95 return E_INVALIDARG; 96 97 if (::IsEqualIID(riid, IID_IUnknown)) 98 { 99 *ppvObject = static_cast<IUnknown *>(this); 100 } 101 else if (::IsEqualIID(riid, IID_ICeFileFilter)) 102 { 103 *ppvObject = static_cast<ICeFileFilter *>(this); 104 } 105 else 106 { 107 *ppvObject = NULL; 108 return E_NOINTERFACE; 109 } 110 111 reinterpret_cast<IUnknown *>(*ppvObject)->AddRef(); 112 return S_OK; 113 } 114 115 116 STDMETHODIMP_(ULONG) CXMergeFilter::AddRef() 117 { 118 return ::InterlockedIncrement(&m_cRef); 119 } 120 121 122 STDMETHODIMP_(ULONG) CXMergeFilter::Release() 123 { 124 if(::InterlockedDecrement(&m_cRef) == 0) 125 { 126 delete this; 127 return 0; 128 } 129 return m_cRef; 130 } 131 132 133 ////////////////////////////////////////////////////////////////////// 134 // ICeFileFilter 135 ////////////////////////////////////////////////////////////////////// 136 137 STDMETHODIMP CXMergeFilter::FilterOptions(HWND hwndParent) 138 { 139 // We don't currently allow any options 140 return HRESULT_FROM_WIN32(NOERROR); 141 } 142 143 STDMETHODIMP CXMergeFilter::FormatMessage(DWORD dwFlags, DWORD dwMessageId, 144 DWORD dwLanguageId, LPTSTR lpBuffer, DWORD nSize, 145 va_list *Arguments, DWORD *pcb) 146 { 147 TCHAR errMsg[1024]; 148 149 HKEY hKey = NULL; 150 DWORD dwSize = 1024; 151 152 153 long lRet = 0; 154 155 // Attempt to find the messages in the registry 156 lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Sun Microsystems\\StarOffice\\XMergeSync\\Messages\\Error"), 157 0, KEY_READ, &hKey); 158 if (lRet != ERROR_SUCCESS) 159 { 160 // Try the user's portion of the registry 161 lRet = ::RegOpenKeyEx(HKEY_CURRENT_USER, _T("Software\\Sun Microsystems\\StarOffice\\XMergeSync\\Messages\\Error"), 162 0, KEY_READ, &hKey); 163 if (lRet != ERROR_SUCCESS) 164 { 165 hKey = NULL; 166 } 167 } 168 169 170 switch(dwMessageId) 171 { 172 case ERR_NOJAVA: 173 lRet = ::RegQueryValueEx(hKey, _T("Java"), 0, NULL, (LPBYTE)errMsg, &dwSize); 174 if (lRet != ERROR_SUCCESS) 175 { 176 lstrcpy(errMsg, "Unable to locate Java 1.4/1.5 installation."); 177 } 178 break; 179 180 case ERR_BADCLASSPATH: 181 lRet = ::RegQueryValueEx(hKey, _T("Classpath"), 0, NULL, (LPBYTE)errMsg, &dwSize); 182 if (lRet != ERROR_SUCCESS) 183 { 184 lstrcpy(errMsg, "Unable to locate XMerge Jar files."); 185 } 186 break; 187 188 case ERR_INITJAVA: 189 lRet = ::RegQueryValueEx(hKey, _T("JavaInit"), 0, NULL, (LPBYTE)errMsg, &dwSize); 190 if (lRet != ERROR_SUCCESS) 191 { 192 lstrcpy(errMsg, "Error initialising the Java Runtime Environment."); 193 } 194 break; 195 } 196 197 char* buf = (char*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (lstrlen(errMsg) + 1) * sizeof(TCHAR)); 198 lstrcpyn(buf, errMsg, lstrlen(errMsg)); 199 200 *(char**)lpBuffer = buf; 201 *pcb = strlen(errMsg); 202 203 return HRESULT_FROM_WIN32(NOERROR); 204 } 205 206 207 STDMETHODIMP CXMergeFilter::NextConvertFile(int nConversion, CFF_CONVERTINFO *pci, 208 CFF_SOURCEFILE *psf, CFF_DESTINATIONFILE *pdf, 209 volatile BOOL *pbCancel, CF_ERROR *perr) 210 { 211 std::string appArgs; 212 std::string appName; 213 214 STARTUPINFO si; 215 PROCESS_INFORMATION pi; 216 217 ZeroMemory( &si, sizeof(si) ); 218 ZeroMemory( &pi, sizeof(pi) ); 219 220 si.cb = sizeof(si); 221 222 223 /* 224 * First step: Locate Java and establish the classpath. If these can't 225 * be done succesfully, then avoid all further processing. 226 */ 227 228 // Locate Java Home if it hasn't already been done. 229 if (m_szJavaBaseDir == NULL) 230 { 231 m_szJavaBaseDir = GetJavaBaseDir(); 232 233 if (m_szJavaBaseDir == NULL) 234 { 235 *perr = ERR_NOJAVA; 236 return HRESULT_FROM_WIN32(E_FAIL); 237 } 238 } 239 240 // Get the Apache OpenOffice class directory 241 if (m_szClasspath == NULL) 242 { 243 m_szClasspath = GetXMergeClassPath(); 244 245 if (m_szClasspath == NULL) 246 { 247 *perr = ERR_BADCLASSPATH; 248 return HRESULT_FROM_WIN32(E_FAIL); 249 } 250 } 251 252 253 /* 254 * Second step: Check the files we're going to process. If we don't have 255 * an XMerge plugin for the file then we can't convert. 256 */ 257 if ((!lstrcmp(psf->szExtension, "sxw") || !lstrcmp(psf->szExtension, "psw")) 258 && !m_bHaveWord) 259 { 260 *perr = ERR_BADCLASSPATH; 261 return HRESULT_FROM_WIN32(E_FAIL); 262 } 263 else if ((!lstrcmp(psf->szExtension, "sxc") || !lstrcmp(psf->szExtension, "pxl")) 264 && !m_bHaveExcel) 265 { 266 *perr = ERR_BADCLASSPATH; 267 return HRESULT_FROM_WIN32(E_FAIL); 268 } 269 270 271 /* 272 * Third step: Locate the Java executable and build and execute the command 273 * line to carry out the conversion. 274 */ 275 276 // Find the Java executable and make sure it exists 277 appName += m_szJavaBaseDir; 278 appName += "\\bin\\javaw.exe"; 279 280 if (GetFileAttributes(appName.c_str()) == INVALID_FILE_SIZE) 281 { 282 *perr = ERR_NOJAVA; 283 return HRESULT_FROM_WIN32(E_FAIL); 284 } 285 286 // Wrap the executable path in quotes in case of spaces 287 appName.insert(0, "\""); 288 appName.append("\""); 289 290 291 292 // Need to build the entire command line for calling out to Java 293 appArgs = appName + " -Djava.class.path="; 294 appArgs += m_szClasspath; 295 appArgs += " org.openoffice.xmerge.util.ActiveSyncDriver "; 296 297 if (!lstrcmp(psf->szExtension, "sxw")) 298 { 299 appArgs += "staroffice/sxw "; 300 appArgs += "application/x-pocket-word "; 301 } 302 else if(!lstrcmp(psf->szExtension, "psw")) 303 { 304 appArgs += "application/x-pocket-word "; 305 appArgs += "staroffice/sxw "; 306 } 307 else if(!lstrcmp(psf->szExtension, "sxc")) 308 { 309 appArgs += "staroffice/sxc "; 310 appArgs += "application/x-pocket-excel "; 311 } 312 else if(!lstrcmp(psf->szExtension, "pxl")) 313 { 314 appArgs += "application/x-pocket-excel "; 315 appArgs += "staroffice/sxc "; 316 } 317 318 319 // ActiveSync sometimes gives out long file names, especially when automatically syncing 320 appArgs += "\""; 321 appArgs += psf->szFullpath; 322 appArgs += "\" \""; 323 appArgs += pdf->szFullpath; 324 appArgs += "\""; 325 326 if(!CreateProcess(NULL, 327 (char*)appArgs.c_str(), 328 NULL, // No Process Attributes 329 NULL, // No Thread Attributes 330 FALSE, // Don't want this process getting handles 331 CREATE_NO_WINDOW, // No console 332 NULL, // No special environment 333 NULL, // Current Working Directory is okay 334 &si, 335 &pi)) 336 { 337 *perr = ERR_INITJAVA; 338 return HRESULT_FROM_WIN32(E_FAIL); 339 } 340 341 // Wait for the new process to work 342 WaitForSingleObject(pi.hProcess, INFINITE); 343 344 CloseHandle(pi.hProcess); 345 CloseHandle(pi.hThread); 346 347 return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); 348 } 349 350 351 typedef HRESULT (WINAPI *SHGETFOLDERPATH)( HWND, int, HANDLE, DWORD, LPTSTR ); 352 353 354 TCHAR* CXMergeFilter::GetJavaBaseDir() 355 { 356 HRESULT lRet; 357 358 HKEY hKey = NULL; 359 HKEY hDataKey = NULL; 360 361 TCHAR szClassName[_MAX_PATH] = "\0"; 362 TCHAR szKeyName[_MAX_PATH] = "\0"; 363 TCHAR szCurrentJava[_MAX_PATH] = "\0"; 364 DWORD dwClassName = _MAX_PATH; 365 DWORD dwKeyName = _MAX_PATH; 366 367 /* 368 * Java leaves registry keys at HKLM\SOFTWARE\JavaSoft. 369 * 370 * Check for a JRE installation first 371 */ 372 lRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 0, KEY_READ, &hKey); 373 if (lRet != ERROR_SUCCESS) 374 return NULL; 375 376 // Locations shouldn't be greater than _MAX_PATH 377 TCHAR* szJavaHome = new TCHAR[_MAX_PATH + 1]; 378 DWORD dwSize = _MAX_PATH + 1; 379 380 /* use current version */ 381 lRet = ::RegQueryValueEx(hKey, _T("CurrentVersion"), 0, NULL, (LPBYTE)szCurrentJava, &dwSize); 382 383 /* 384 for (DWORD i = 0; lRet != ERROR_NO_MORE_ITEMS; i++) 385 { 386 lRet = ::RegEnumKeyEx(hKey, i, szKeyName, &dwKeyName, 0, szClassName, &dwClassName, NULL); 387 if(!strncmp(szKeyName, "1.4", 3)) 388 break; 389 dwKeyName = _MAX_PATH; 390 } 391 // Found a Java 1.4 installation. Can now read its home directory. 392 */ 393 394 395 lRet = ::RegOpenKeyEx(hKey, _T(szCurrentJava), 0, KEY_READ, &hDataKey); 396 if (lRet != ERROR_SUCCESS) 397 { 398 RegCloseKey(hKey); 399 delete [] szJavaHome; 400 return NULL; 401 } 402 403 404 // Now read the JavaHome value 405 dwSize = _MAX_PATH + 1; 406 lRet = ::RegQueryValueEx(hDataKey, _T("JavaHome"), 0, NULL, (LPBYTE)szJavaHome, &dwSize); 407 if (lRet != ERROR_SUCCESS) 408 { 409 RegCloseKey(hDataKey); 410 RegCloseKey(hKey); 411 delete [] szJavaHome; 412 return NULL; 413 } 414 415 RegCloseKey(hDataKey); 416 RegCloseKey(hKey); 417 418 419 // Check that the directory exists before returning it 420 DWORD dwAttrs = GetFileAttributes(szJavaHome); 421 422 if (((dwAttrs & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) || dwAttrs == INVALID_FILE_SIZE) 423 { 424 delete [] szJavaHome; 425 return NULL; 426 } 427 428 return szJavaHome; 429 } 430 431 432 433 TCHAR* CXMergeFilter::GetXMergeClassPath() 434 { 435 /* 436 * The DLL will be installed by setup in the program directory of 437 * the installation. The XMerge Jar files, if present, will be 438 * located in the classes directory below program. 439 */ 440 441 TCHAR szJarPath[MAX_PATH]; 442 TCHAR szTmpPath[MAX_PATH]; 443 444 ZeroMemory(szJarPath, MAX_PATH); 445 ZeroMemory(szTmpPath, MAX_PATH); 446 447 WIN32_FILE_ATTRIBUTE_DATA fInfo; 448 449 std::string clsPath; 450 451 452 // Get the location of the module. 453 GetModuleFileName(_Module.m_hInst, szTmpPath, MAX_PATH); 454 455 // Strip off the xmergesync.dll component 456 _strlwr(szTmpPath); 457 char* modName = strstr(szTmpPath, "xmergesync.dll"); 458 strncpy(szJarPath, szTmpPath, modName - szTmpPath); 459 460 // Append the classes directory 461 strncat(szJarPath, "classes\\", 8); 462 463 464 // The core xmerge.jar must be present 465 ZeroMemory(szTmpPath, MAX_PATH); 466 _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "xmerge.jar"); 467 468 if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo)) 469 { 470 return NULL; 471 } 472 else 473 { 474 clsPath += szTmpPath; 475 clsPath += ";"; 476 } 477 478 479 // Now check for Pocket Word 480 ZeroMemory(szTmpPath, MAX_PATH); 481 _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pocketword.jar"); 482 483 if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo)) 484 { 485 m_bHaveWord = FALSE; 486 } 487 else 488 { 489 m_bHaveWord = TRUE; 490 clsPath += szTmpPath; 491 clsPath += ";"; 492 } 493 494 // Now check for Pocket Excel 495 ZeroMemory(szTmpPath, MAX_PATH); 496 _snprintf(szTmpPath, MAX_PATH, "%s%s\0", szJarPath, "pexcel.jar"); 497 498 if (!GetFileAttributesEx(szTmpPath, GetFileExInfoStandard, &fInfo)) 499 { 500 m_bHaveExcel = FALSE; 501 } 502 else 503 { 504 m_bHaveExcel = TRUE; 505 clsPath += szTmpPath; 506 clsPath += ";"; 507 } 508 509 // Quotes may be need around the ClassPath 510 clsPath.insert(0, "\""); 511 clsPath += "\""; 512 513 514 // Return the data 515 return _strdup(clsPath.c_str()); 516 } 517