I'm using Jacob to call a VB function that resides in a Macro in an Excel file.
Here is my code : [I pass the file and the vb function name as paramaters to the below java method]
private static void callExcelMacro(File file, String macroName) {
ComThread.InitSTA();
final ActiveXComponent excel = new ActiveXComponent("Excel.Application");
try {
// This will open the excel if the property is set to true
excel.setProperty("Visible", new Variant(false));
final Dispatch workbooks = excel.getProperty("Workbooks").getDispatch();
//String eventSink = null ;
int id = Dispatch.get(workbooks, "Count").getInt();
System.out.println("le nbre" + id);
Dispatch.call(workbooks, "Add");
Dispatch workBook = Dispatch.call(workbooks, "Open", file.getAbsolutePath()).toDispatch();
//new DispatchEvents(sourceOfEvent, eventSink, progId)
//new DispatchEvents(workBook, w , "Excel.Application");
//System.out.println("le résultat"+eventSink);
//d.safeRelease();
Variant V1 = new Variant( file.getName() + macroName);
// Calls the macro
final Variant result = Dispatch.call(excel, "Run", V1);
// Saves and closes
//Dispatch.call(workBook, "Save");
com.jacob.com.Variant f = new com.jacob.com.Variant(true);
// Dispatch.call(workBook, "Close", f);
} catch (Exception e) {
e.printStackTrace();
} finally {
excel.invoke("Quit", new Variant[0]);
ComThread.Release();
}
}
The code runs fine, but my problem is that I don't want to call the instrcution
Dispatch workBook = Dispatch.call(workbooks, "Open", file.getAbsolutePath()).toDispatch();
which displays me what the default macro executes (an Interface with input fields).
Is there a way to "Run" the VB function without "Opening" the Excel file ?
Thanks.
there is no way to execute a VBA function in an Excel workbook without opening the file...
Of course, you can prevent the AUto_open macro running by disabling events on the Excel Application object.
In Excel VBA we do this like so:
Application.enableevents=false
(frequently in conjunction with other settings like ScreenUpdating and DisplayAlerts)
in Java maybe you use:
excel.setProperty("EnableEvents", new Variant(false));
I hope that pointers you in the right direction (lol, boom boom !)
Philip
Related
I have used JNA library and this small API (JnaFileChooser)
https://github.com/steos/jnafilechooser
JnaFileChooser fc = new JnaFileChooser();
fc.addFilter("All Files", "*");
fc.addFilter("Pictures", "jpg", "jpeg", "png", "gif", "bmp");
if (fc.showDialog(parent)) {
File f = fc.getSelectedFile();
// do something with f
}
But how do I use JNA to access this dialg "select folder"
The entire dialogue is controlled on the native side. The package you are are using is already accessing that dialog and that button.
Tracing through the source code of the JnaFileChooser class, this dialogue is part of the WindowsFolderBrowser class. The dialog appears using the SHBrowseForFolder() function combined with SHGetPathFromIDList, and returns the path when the Select Folder button is pressed.
final Pointer pidl = Shell32.SHBrowseForFolder(params);
if (pidl != null)
// MAX_PATH is 260 on Windows XP x32 so 4kB should
// be more than big enough
final Pointer path = new Memory(1024 * 4);
Shell32.SHGetPathFromIDListW(pidl, path);
final String filePath = path.getWideString(0);
final File file = new File(filePath);
Ole32.CoTaskMemFree(pidl);
return file;
}
The params variable passed to this function is of native type BROWSEINFO which controls the dialog box. You can see in the code how a few things have been assigned to it (abbreviated version of code):
final Shell32.BrowseInfo params = new Shell32.BrowseInfo();
params.hwndOwner = Native.getWindowPointer(parent);
params.ulFlags = Shell32.BIF_RETURNONLYFSDIRS | Shell32.BIF_USENEWUI;
params.lpszTitle = title;
If you want to change anything else about the dialog, you need to use a callback. One of the elements in BROWSEINFO is BFFCALLBACK lpfn; where you would define that function, e.g., params.lpfn = the defined callback function.
Documentation for BFFCALLBACK indicates you'll use the option to use SendMessage to change the OK button text with BFFM_SETOKTEXT.
I am using POI to read,edit and write excel files.
My process flow is like write an excel, read it and again write it.
Then if I try to edit the file using normal desktop excel application while my Java app is still running, the excel cannot be saved, it says some process is holding the excel,
I am properly closing all file handles.
Please help and tell me how to fix this issue.
SXSSFWorkbook wb = new SXSSFWorkbook(WINDOW_SIZE);
Sheet sheet = getCurrentSheet();//stores the current sheet in a instance variable
for (int rowNum = 0; rowNum < data.size(); rowNum++) {
if (rowNum > RECORDS_PER_SHEET) {
if (rowNum % (RECORDS_PER_SHEET * numberOfSheets) == 1) {
numberOfSheets++;
setCurrentSheet(wb.getXSSFWorkbook().createSheet());
sheet = getCurrentSheet();
}
}
final Row row = sheet.createRow(effectiveRowCnt);
for (int columnCount = 0; columnCount < data.get(rowNum).size(); columnCount++) {
final Object value = data.get(rowNum).get(columnCount);
final Cell cell = row.createCell(columnCount);
//This method creates the row and cell at the given loc and adds value
createContent(value, cell, effectiveRowCnt, columnCount, false, false);
}
}
public void closeFile(boolean toOpen) {
FileOutputStream out = null;
try {
out = new FileOutputStream(getFileName());
wb.write(out);
}
finally {
try {
if (out != null) {
out.close();
out = null;
if(toOpen){
// Open the file for user with default program
final Desktop dt = Desktop.getDesktop();
dt.open(new File(getFileName()));
}
}
}
}
}
The code looks correct. After out.close();, there shouldn't be any locks left.
Things that could still happen:
You have another Java process (for example hanging in a debugger). Your new process tries to write the file, fails (because of process 1) and in the finally, it tries to open Excel which sees the same problem. Make sure you log all exceptions that happen in wb.write(out);
Note: The code above looks correct in this respect, since it only starts Excel when out != null and that should only be the case when Java could open the file.
Maybe the file wasn't written completely (i.e. there was an exception during write()). Excel tries to open the corrupt file and gives you the wrong error message.
Use a tool like Process Explorer to find out which process keeps a lock on a file.
I tried all the options. After looking thoroughly, it seems the problem is the Event User model.
I am using the below code for reading the data:
final OPCPackage pkg = OPCPackage.open(getFileName());
final XSSFReader r = new XSSFReader(pkg);
final SharedStringsTable sst = r.getSharedStringsTable();
final XMLReader parser = fetchSheetParser(sst);
final Iterator<InputStream> sheets = r.getSheetsData();
while (sheets.hasNext()) {
final InputStream sheet = sheets.next();
final InputSource sheetSource = new InputSource(sheet);
parser.parse(sheetSource);
sheet.close();
}
I assume the excel is for some reason held by this process for some time. If I remove this code and use the below code:
final File file = new File(getFileName());
final FileInputStream fis = new FileInputStream(file);
final XSSFWorkbook xWb = new XSSFWorkbook(fis);
The process works fine an the excel does not remain locked.
I figured it out actually.
A very simple line was required but some some reason it was not explained in the New Halloween Document (http://poi.apache.org/spreadsheet/how-to.html#sxssf)
I checked the Busy Developer's Guide and got the solution.
I needed to add
pkg.close(); //To close the OPCPackage
This added my code works fine with any number of reads and writes on the same excel file.
I'm using rundll32 url.dll,FileProtocolHandler my_file.dotx to open files under Windows.
It works fine with .docx documents, but when I try it with .dotx documents (template documents), it creates a new .docx based on the template.
Just as the normal behavior in the windows explorer : when you double-click on a .dotx template file, it creates a new .docx file based on it. If you want to open the real .dotx file, you have to right-click on it and select "open" instead of "new".
Question is: how to do the same with rundll32? Is there an option in the command to force the opening of the underlying template instead of creating a new document?
Edit: I need a way to do it without C functions, just plain text, in the command line (I'm using Java to do it).
Maybe you can wrap a simple C program around ShellExecute, passing the verb OPEN.
ShellExecute(NULL, TEXT("open"),
TEXT("rundll32.exe"), TEXT("url.dll,FileProtocolHandler pathToGadget"),
NULL, SW_SHOWNORMAL);
I found this example here.
edit:
Since you're doing this in Java - you could try a JNI wrapping of the ShellExceute function like this (from the example I found on The Wannabe Java Rockstar and butchered)
public static boolean execute(String file, String parameters) {
Function shellExecute =
Shell32.getInstance().getFunction(SHELL_EXECUTE.toString());
Int32 ret = new Int32();
shellExecute.invoke(ret, // return value
new Parameter[] {
new Handle(), // hWnd
new Str("open"), // lpOperation
new Str(file), // lpFile
new Str(parameters), // lpParameters
new Str(), // lpDirectory
new Int32(1) // nShowCmd
});
if(ret.getValue() <= 32) {
System.err.println("could not execute ShellExecute: " +
file + ". Return: " + ret.getValue());
}
return (ret.getValue() > 32);
}
public static void main(String[] args) {
ShellExecute.execute("rundll32.exe","url.dll,FileProtocolHandler pathToGadget" );
}
i am a barely new to the java (was always on c# before) and need to create a swing application where i need to read a data from xls file. So i use jXL.
I have a class, which returns name of a first sheet from excel file, choosen in jFileChooser. Here is the code:
import java.io.File;
import jxl.Sheet;
import jxl.Workbook;
public class ExcelObject
{
private String filename = null;
private Workbook wb = null;
private Sheet sheet = null;
public ExcelObject(String f)
{
filename = f;
}
public String getSheetName()
{
String sheet_name = null;
try
{
wb = Workbook.getWorkbook(new File(filename));
sheet = wb.getSheet(0);
sheet_name = sheet.getName();
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
wb.close();
}
return sheet_name;
}
}
in the program call looks like :
ExcelObject ex = new ExcelObject(filename);
String s = ex.getSheetName();
lblReport.setText(s);
So the issue is : when ran in the eclipse (3.4.2) i am getting a correct value, when jar is compiled, NO VALUE IS RETURNED! I mean lblReport is empty, with no exceptions and warnings.
Keep in mind : all other external jars work fine.
I tried a lot of things but none is working.
Also, if i do something like
ExcelObject ex = new ExcelObject(filename);
String s = ex.getSheetName();
// lblReportRun.setText(s);
lblReportRun.setText("Test");
lblAnyOtherLabel.setText("Test");
no text is displayed in the labels either, in compiled jar, and fine in eclipse.
This is probably because if some exception occurs when opening the workbook, you catch it, print the stack trace, and then close the workbook in the finally block. But since an exception occurred when calling Workbook.getWorkbook, the wb variable is still null, and you're trying to invoke close on it. So a NullPointerException happens while in the finally block.
Watch your console, you must have some exception popping up.
Also, note that fileName should be the only instance variable of your class, that Java variable normally don't contain underscores and use camelCase, and thet the fileName variable should be of type File, rather than String : you get a File from the file chooser, transform it into a string, and then transform it back to a File.
Another possibility, since it works in Eclipse and not when run externally, is that you forgot to put the jXL jar in the classpath, which causes some ClassNotFoundException when trying to use the ExcelObject class.
I am trying to communicate with Excel from a Java/SWT application. I have been able to open a worksheet, open a file and save it but that's about it.
Can anyone point me to some documentation/examples for this? I especially need to know which commands are available. I did try to record macros to inspect. This was useful but did not give me everything I wanted.
This is a sample of what I have been trying so far:
private static OleAutomation openFile(
OleAutomation automation, String fileName) {
Variant workbooks = automation.getProperty(0x0000023c);// get User
// Defined
// Workbooks
Variant[] arguments = new Variant[1];
arguments[0] = new Variant(fileName);
System.out.println("workbooks::\t" + workbooks);
IDispatch p1 = workbooks.getDispatch();
int[] rgdispid = workbooks.getAutomation().getIDsOfNames(new String[] { "Open" });
int dispIdMember = rgdispid[0];
Variant workbook = workbooks.getAutomation().invoke(dispIdMember, arguments);
System.out.println("Opened the Work Book");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
int id = workbook.getAutomation().getIDsOfNames(new String[] { "ActiveSheet" })[0];
System.out.println(id);
Variant sheet = workbook.getAutomation().getProperty(id);
OleAutomation sheetAutomation = sheet.getAutomation();
return (sheetAutomation);
}
Use VBA help MSOffice. Also you can use Object Browser in Office's VB editor.
Not a documentation, but since you asked about the available commands via automation: have you tried the OLE/COM Object viewer that comes with the Windows 2000 resource kit? Download here.