Community
Participate
Working Groups
I am trying to use swt automation to open an existing excel file. I picked up code from Snippet199.java to get it going http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet199.java?rev=HEAD&content-type=text/vnd.viewcvs-markup The code works, as in it opens up the excel file for me. However my CPU usage goes up to 100% when excel is launched! I tried to debug a little further and found that the following line of code in org.eclipse.swt.ole.win32.OleClientSite causes the CPU usage to go to 100% /********************************************************/ protected void addObjectReferences() { ... ... // Notify the control object that it is embedded in an OLE container COM.OleSetContainedObject(objIUnknown.getAddress(), true); ... ... } /********************************************************/ I commented out the call to OleSetContainedObject and recompiled swt.jar. The application seems to run fine now and the CPU load is perfectly normal. But probably I have added a few memory leaks now. Please find the relevant code to reproduce the problem below. Environment details: Win XP / Office 2003 / Eclipse3.2M4 / jdk1.4.2_08 /********************************************************/ public static void main (String [] args) { Display display = new Display (); Shell shell = new Shell (display); shell.setLayout(new FillLayout()); OleControlSite controlSite; OleAutomation application; OleAutomation workbook ; try { OleFrame frame = new OleFrame(shell, SWT.NONE); controlSite = new OleControlSite(frame, SWT.None, "Excel.Application"); } catch (SWTError e) { System.out.println("Unable to open activeX control"); return; } application = new OleAutomation(controlSite); int[] dispIDs = application.getIDsOfNames(new String[] {"Workbooks"}); Variant pVarResult = application.getProperty(dispIDs[0]); OleAutomation workbooks = pVarResult.getAutomation(); pVarResult.dispose(); final int[] dispMIDs = workbooks.getIDsOfNames(new String[] {"Open"}); Variant[] arguments = new Variant[]{new Variant("C:\\excel test\\Book1.xls")}; if ((dispMIDs != null) && (dispMIDs.length > 0)) { workbook= workbooks.invoke(dispMIDs[0],arguments).getAutomation(); } workbooks.dispose(); dispIDs = application.getIDsOfNames(new String[] {"Visible"}); pVarResult = application.getProperty(dispIDs[0]); application.setProperty(dispIDs[0], new Variant(true)); pVarResult.dispose(); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } application.dispose(); display.dispose (); } /********************************************************/
Aditya, did this ever get resolved on the newsgroup?
This issue never got resolved in the newsgroup. A quite popular workaround however was mentioned which is to use "Excel.Sheet" as the progId. This does not lead to the high CPU usage problem. The workaround is however not very usable since it has its own share of problems. see- http://www.eclipse.org/newsportal/article.php?id=27096&group=eclipse.platform.swt#27096
I believe the "hijack" problem is no longer an issue.
Duong, please get to the bottom of it. Is the bug still happening or not? Is the news group work around necessary?
The 100% CPU usage occurs after invoking this line in the OleClientSite: // Notify the control object that it is embedded in an OLE container COM.OleSetContainedObject(objIUnknown.getAddress(), true); MSDN doc states that calling this method "ensures that reference counting is done correctly for containers that support links to embedded objects." I'm not sure if why this caused the CPU usage to spike to 100%. Even when the SWT app is terminated, the CPU usage remains at 100%. You must terminate EXCEL.EXE to restore things back to normal. In fact, you don't need to open up any SWT shell. Just causing the Excel application to run by creating the OleControlSite was sufficient to cause the CPU usage to go up to 100%. Another interesting observation I found is that if you click on any menus in the Excel app, the CPU will drop back down to 0%. It would appear that the application is mis-behaving. I found a few bugs on MSDN related to CPU usage spikes to 100% when using Excel. They have a couple of patches for this problem. I applied them to my machine but it doesn't seem to fix the problem. Since there's a reasonable work around using Excel.Sheet and it appears to be an Windows issue. I'm marking this defect as WONTFIX.
I know this bug was marked as a WONTFIX, but I am curious why would this still work then from a Visual Basic 6 application? It seems like if this was a windows issue this should be occurring no matter what technology I go through. Currently, we have this working in an old visual basic application and are in the process of re-writing it in Java. As for the workaround, the Excel.sheets is not a viable option because (as I understand it), Excel will be treated as an ActiveX control and will therefore be controlled by the Java application instantiating it. Meaning, it can't close unless the entire Java application closes or we programmatically dispose of it ourselves. The problem is that we want to be able to open Excel and allow the user to have it open as long as they want. So we won't ever know when we can dispose of it. We want it to be treated as a completely separate process. Thanks
Shawn, it seems the best bet is "Excel.Sheet". Duong, we need to understand why this is no good. Please help this guy.
I'm not sure I understand what you mean when you said: > Meaning, it can't close unless the entire Java application > closes or we programmatically dispose of it ourselves. You can open Excel hosted inside of Eclipse (in-place editor) and close the (Excel) editor when you're done. You don't have to close the entire Java application.
(In reply to comment #8) > I'm not sure I understand what you mean when you said: > > > Meaning, it can't close unless the entire Java application > > closes or we programmatically dispose of it ourselves. > > You can open Excel hosted inside of Eclipse (in-place editor) and close the > (Excel) editor when you're done. You don't have to close the entire Java > application. > What I mean is, Excel closes, but the process does not terminate. The workflow we are trying to implement is from an RCP application, open excel and populate a worksheet with some data and then allow Excel to run by itself completely separate from our RCP app (which is why running Excel.application is the option we prefer as opposed to Excel.Sheet). For instance they may leave Excel open long after the RCP app or close it before the RCP app closes. Does that help?
Thanks for the clarification. In that case, wouldn't it be easier to launch Excel as a separate application instead of using OLE? Something like this: Display display = new Display (); Program program = Program.findProgram("xls"); program.execute("e:/temp/ole/test.xls"); display.dispose ();
Actually, I agree. I would prefer to do something like that, however we need to be able to generate the data on a worksheet in memory. I cannot leave the files on the file system. If I write the document out using an API like Apache POI and then open the workbook I will have to have some other process later on clean up the files that we write out when it is not currently open, because I won't know when they closed Excel.