/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.components.excel.common.internal;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.activeX.ActiveXDispatchEvents;
import com.jacob.activeX.ActiveXInvocationProxy;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import de.rcenvironment.components.excel.common.ExcelComponentConstants;
import de.rcenvironment.components.excel.common.ExcelException;
import de.rcenvironment.components.excel.common.ExcelServiceGUIEvents;
import de.rcenvironment.core.datamodel.api.TypedDatumFactory;
/**
* Excel file representation with access to its data. Methods which ends with OLE are using OLE-interface. These methods may only used
* within MS Windows and MS Office installation.
*
* Note: These methods are unstable at the moment. This is because Eclipse 3.6 SWT-OLE interface in combination with Windows 7 64bit and MS
* Office 2010 is unstable.
*
* @author Markus Kunde
*/
public class ExcelServiceOLE extends ExcelServicePOI implements ExcelServiceGUIEvents {
/*
* OLE Keys.
*/
private static final String OLE_DISPLAY_ALERTS = "DisplayAlerts";
private static final String OLE_ACTIVE_WORKBOOK = "ActiveWorkbook";
private static final String OLE_ACTIVE_SHEET = "ActiveSheet";
private static final String OLE_OPEN = "Open";
private static final String OLE_WORKBOOKS = "Workbooks";
private static final String OLE_VISIBLE = "Visible";
private static final String EXCELAPPLICATION_PROGRAMID = "Excel.Application";
private static final String EXCELAPPLICATION_EXE = "\\EXCEL.EXE";
private String typeLibLocation = "C:\\Program Files (x86)\\Microsoft Office\\OFFICE14" + EXCELAPPLICATION_EXE; // Only default
/**
* Default constructor.
*
*/
public ExcelServiceOLE() {}
/**
* Constructor to get typedDatumFactory not from RCE-service into ExcelService class.
*
* @param typedDatumFactory the typed datum factory
*/
public ExcelServiceOLE(TypedDatumFactory typedDatumFactory) {
super(typedDatumFactory);
}
@Override
public String[] getMacros(File xlFile) throws ExcelException {
Set<String> macros = new HashSet<String>();
ComThread.InitSTA();
ActiveXComponent objExcel = null;
try {
objExcel = new ActiveXComponent(EXCELAPPLICATION_PROGRAMID);
objExcel.setProperty(OLE_VISIBLE, new Variant(false));
// Open Excel file, get the workbooks object required for access:
Dispatch workbooks = objExcel.getProperty(OLE_WORKBOOKS).toDispatch();
workbooks = Dispatch.call(workbooks, OLE_OPEN, xlFile.getAbsolutePath()).toDispatch();
Dispatch activeWorkbook = objExcel.getProperty(OLE_ACTIVE_WORKBOOK).toDispatch();
// VB specific
Variant varVbproject = Dispatch.get(activeWorkbook, "VBProject");
if (varVbproject != null) { // security rights are set properly
Dispatch vbproject = varVbproject.toDispatch();
Dispatch vbcomponents = Dispatch.get(vbproject, "VBComponents").toDispatch();
Variant varCount = Dispatch.get(vbcomponents, "Count");
for (int i = 1; i <= varCount.getInt(); i++) {
Dispatch vbComponent = Dispatch.call(vbcomponents, "Item", new Variant(i)).toDispatch();
String name = Dispatch.get(vbComponent, "Name").getString();
Dispatch codeModule =
Dispatch.get(vbComponent, "CodeModule").getDispatch();
int noOfLines =
Dispatch.get(codeModule, "CountOfLines").getInt();
for (int j = 1; j <= noOfLines; j++) {
String line = Dispatch.invoke(codeModule, "ProcOfLine", Dispatch.Get, new Object[] { j, 0 }, new int[1]).toString();
macros.add(name + "." + line);
}
}
}
} catch (RuntimeException e) {
String[] noMacroFoundArray = new String[1];
noMacroFoundArray[0] = "Failed to access macros - see log for details.";
LOGGER.warn("Failed to load macros. "
+ "Possibly your security setting prevent you from accessing macros with your Excel installation. "
+ "Excel response: " + e.getMessage());
return noMacroFoundArray;
} finally {
quitExcel(objExcel, false);
ComThread.Release();
}
return macros.toArray(new String[0]);
}
@Override
public void runMacro(File xlFile, String macroname) throws ExcelException {
if (macroname != null && !macroname.isEmpty()) {
ComThread.InitSTA();
ActiveXComponent objExcel = null;
try {
objExcel = new ActiveXComponent(EXCELAPPLICATION_PROGRAMID);
objExcel.setProperty(OLE_VISIBLE, new Variant(false));
// Open Excel file, get the workbooks object required for access:
Dispatch workbooks = objExcel.getProperty(OLE_WORKBOOKS).toDispatch();
workbooks = Dispatch.call(workbooks, OLE_OPEN, xlFile.getAbsolutePath()).toDispatch();
Dispatch activeWorkbook = objExcel.getProperty(OLE_ACTIVE_WORKBOOK).toDispatch();
// run macro specific
Dispatch.call(objExcel, "run", macroname);
for (int i = 0; i < BLOCKING_ITERATIONMAX; i++) {
try {
objExcel.setProperty(OLE_DISPLAY_ALERTS, false);
objExcel.setProperty("CalculateBeforeSave", false);
Dispatch.call(activeWorkbook, "Save");
break;
} catch (RuntimeException e) {
if (i == (BLOCKING_ITERATIONMAX - 1)) {
// Last iteration was not successful
LOGGER.error("Cannot save file with result data after running macro: " + macroname + ".");
throw e;
}
}
try {
Thread.sleep(BLOCKING_SLEEP);
} catch (InterruptedException e) {
LOGGER.error(e);
}
}
} catch (RuntimeException e) {
throw new ExcelException("Cannot run macro with OLE interface.", e);
} finally {
quitExcel(objExcel, false);
ComThread.Release();
}
}
}
@Override
public void recalculateFormulas(File xlFile) throws ExcelException {
ComThread.InitSTA();
ActiveXComponent objExcel = null;
try {
objExcel = new ActiveXComponent(EXCELAPPLICATION_PROGRAMID);
objExcel.setProperty(OLE_VISIBLE, new Variant(false));
// Open Excel file, get the workbooks object required for access:
Dispatch workbooks = objExcel.getProperty(OLE_WORKBOOKS).toDispatch();
workbooks = Dispatch.call(workbooks, OLE_OPEN, xlFile.getAbsolutePath()).toDispatch();
Dispatch activeWorkbook = objExcel.getProperty(OLE_ACTIVE_WORKBOOK).toDispatch();
// recalculate formulas specific
Dispatch.call(objExcel, "CalculateFullRebuild");
objExcel.setProperty(OLE_DISPLAY_ALERTS, false);
objExcel.setProperty("CalculateBeforeSave", false);
Dispatch.call(activeWorkbook, "Save");
} catch (RuntimeException e) {
throw new ExcelException("Cannot recalculate formulas with OLE interface.", e);
} finally {
quitExcel(objExcel, false);
ComThread.Release();
}
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.components.excel.common.ExcelServiceGUIEvents #openExcelApplicationRegisterListener(java.io.File,
* com.jacob.activeX.ActiveXInvocationProxy)
*/
@Override
public ActiveXComponent openExcelApplicationRegisterListener(final File xlFile,
final String address, final ActiveXInvocationProxy listener) {
ActiveXComponent objExcel = null;
try {
objExcel = new ActiveXComponent(EXCELAPPLICATION_PROGRAMID);
typeLibLocation = objExcel.getProperty("Path").getString() + "\\EXCEL.EXE";
objExcel.setProperty(OLE_VISIBLE, new Variant(true));
// Open Excel file, get the workbooks object required for access:
Dispatch workbooks = objExcel.getProperty(OLE_WORKBOOKS).toDispatch();
Dispatch.call(workbooks, OLE_OPEN, xlFile.getAbsolutePath()).toDispatch();
if (address != null && !address.isEmpty() && address.split(ExcelComponentConstants.DIVIDER_TABLECELLADDRESS).length == 2) {
// Preselect Excel Address range if possible
String[] rawAddress = address.split(ExcelComponentConstants.DIVIDER_TABLECELLADDRESS);
Dispatch sheet = Dispatch.call(objExcel, "Sheets", new Variant(rawAddress[0])).toDispatch();
Dispatch.call(sheet, "Activate");
Dispatch range = Dispatch.call(sheet, "Range", new Variant(rawAddress[1])).toDispatch();
Dispatch.call(range, "Select");
} else {
Dispatch sheet = objExcel.getProperty(OLE_ACTIVE_SHEET).toDispatch();
Dispatch range = Dispatch.call(sheet, "Range",
new Variant(ExcelComponentConstants.DEFAULTCOLUMNBEGIN + ExcelComponentConstants.DEFAULTROWBEGIN)).toDispatch();
Dispatch.call(range, "Select");
}
// Register listener
if (listener != null) {
new ActiveXDispatchEvents(objExcel, listener, EXCELAPPLICATION_PROGRAMID, typeLibLocation);
}
return objExcel;
} catch (RuntimeException e) {
quitExcel(objExcel, false);
throw new ExcelException("Cannot open Excel Application with GUI and event listener with OLE interface.", e);
}
}
/**
* {@inheritDoc}
*
* @see de.rcenvironment.components.excel.common.ExcelServiceGUIEvents#quitExcel(com.jacob.activeX.ActiveXComponent)
*/
@Override
public void quitExcel(final ActiveXComponent axc, boolean displayAlerts) {
if (axc != null) {
axc.setProperty(OLE_DISPLAY_ALERTS, displayAlerts);
axc.invoke("Quit", new Variant[] {});
}
}
}