Community
Inventor Programming - iLogic, Macros, AddIns & Apprentice
Inventor iLogic, Macros, AddIns & Apprentice Forum. Share your knowledge, ask questions, and explore popular Inventor topics related to programming, creating add-ins, macros, working with the API or creating iLogic tools.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Write to Excel File that Is already Open

12 REPLIES 12
SOLVED
Reply
Message 1 of 13
C_Haines_ENG
1324 Views, 12 Replies

Write to Excel File that Is already Open

Id like to be able to write to an excel file that's open, I'm not entirely sure if that's possible with the way I've set this up but having the program close every time is counter productive and id like for the excel file to remain open and writeable. 

 

However, every time I run my rule it wants to open a new instance of inventor which I assume is due to the highlighted code below:

 

'define Excel Application object
excelApp = CreateObject("Excel.Application")

'workbook exists, open it
excelWorkbook = excelApp.Workbooks.Open(xlsPath)

 

However modifying this code, even removing the "Open" command still makes it create a new instance of Excel

 

the full code is below:

'define the file to create/open
xlsPath = "C:\BOM Calculator\Test.xlsx"

'define Excel Application object
excelApp = CreateObject("Excel.Application")
'set Excel to run visibly, change to false if you want to run it invisibly
excelApp.Visible = True
'suppress prompts (such as the compatibility checker)
excelApp.DisplayAlerts = False



'check for existing file 
If Dir(xlsPath) <> "" Then
'workbook exists, open it
excelWorkbook = excelApp.Workbooks.Open(xlsPath)
ExcelSheet = excelWorkbook.Worksheets(1)
Else
'workbook does NOT exist, so create a new one
excelWorkbook = excelApp.Workbooks.Add
End If

']


'Insert data into Excel.
With excelApp
	
	If .Range("A1").Value < 2
		
		RowNum = 2
	   .Range("A1").Value = 2

	Else 
		
		RowNUM = .Range("A1").Value
		
	End If
	
			.Range("B" & RowNum) = iProperties.Value(modelName,"Project", "Part Number")
			.Range("C" & RowNum) = iProperties.Value(modelName, "Project", "Description")
		
End With   

'set all of the columns to autofit
excelApp.Columns.AutoFit   
'save the file
excelWorkbook.SaveAs(xlsPath)

''close the workbook and the Excel Application
''uncomment if you want to close the xls file at the end
excelWorkbook.Close
excelApp.Quit
excelApp = Nothing     
12 REPLIES 12
Message 2 of 13
A.Acheson
in reply to: C_Haines_ENG

Try getting the object rather than creating a new version.

Dim oExcel As Object ' or Excel.Application
Set oExcel = GetObject("Workbook_Name.xlsx").Application

Here is the link discussing that.  

If this solved a problem, please click (accept) as solution.‌‌‌‌
Or if this helped you, please, click (like)‌‌
Regards
Alan
Message 3 of 13
C_Haines_ENG
in reply to: A.Acheson

How can i detect if its already open? I will have to create a new session for the first run through of the program. 

Message 4 of 13
WCrihfield
in reply to: C_Haines_ENG

Hi @C_Haines_ENG.  Below is a fairly simple little custom Function I often use for getting the Excel application in some of my solutions which access the Excel API directly.  It will first 'try' to get the already running instance of the application, and if that fails, it will then try to create a new instance of the application, and return that.  The process is pretty old, but still effective.

 

Function GetExcel(Optional oVisible As Boolean = False) As Excel.Application
	Dim oXL As Excel.Application
	Try
		'try to find an already running instance of the Excel Application
		oXL = GetObject(, "Excel.Application")
	Catch
		'it wasn't found open, so create an instance of it (start the application)
		oXL = CreateObject("Excel.Application")
	Catch
		Return Nothing
	End Try
	oXL.Visible = oVisible
	Return oXL
End Function

 

PS.  Using this may require that you have included a reference to the Excel API within the Header of your rule.

AddReference "Microsoft.Office.Interop.Excel.dll"
Imports Microsoft.Office.Interop
Imports Microsoft.Office.Interop.Excel

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 5 of 13
C_Haines_ENG
in reply to: WCrihfield

Inserting that into my code now gives me errors of

 

Ive tried to reorient the code like so:

 

xlsPath = "C:\BOM Calculator\Test.xlsx"


If Dir(xlsPath) <> "" Then

'define Excel Application object
Try
	'try to find an already running instance of the Excel Application
	excelApp = GetObject("Test.xlsx").Application
	MessageBox.Show("Found!", "Title")

	Catch
	'it wasn't found open, so create an instance of it (start the application)
	excelApp = CreateObject("Test.xlsx").Application
	excelWorkbook = excelApp.Workbooks.Open(xlsPath)	
	MessageBox.Show("Not Found :(", "Title")
End Try

Else
excelWorkbook = excelApp.Workbooks.Add	
excelWorkbook = excelApp.Workbooks.Open(xlsPath)
	
End If

 But I keep getting an AcitveX error.

 

Could you show me how I can impliment this? Using a function seems to screw everything up. 

Message 6 of 13
WCrihfield
in reply to: C_Haines_ENG

Sure.  I have attached the code in a text file, since it's fairly long.

One think I should mention though...once you include those 'AddReference' and 'Imports' lines, it will start to understand and recognize those API objects that are unique to Excel's API, so you will start to see the 'intellisense' pop-up hints for all that stuff that was not available before, but that can also complicate things for some folks, when they are not used to it.  It works great for some folks, and some processes, while seemingly making it more difficult or impossible for other folks/processes.  So, if you need to, you could just change my use of the 'Excel.Application' object Type, and use Object in its place, in those two locations of my custom function.  Or you could simply move my Try...Catch block of code out and put it directly into your code, then get rid of my function altogether.  If you do that, you may have to change the variable 'oXL' to your variable.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 7 of 13
C_Haines_ENG
in reply to: C_Haines_ENG

I am getting more errors with this section

 

	'define the file to create/open
	xlsPath = "C:\BOM Calculator\Test.xlsx"
	'define Excel Application object, and set it's Visibility to True
	excelApp = GetExcel(True)
	'suppress prompts (such as the compatibility checker)
	excelApp.DisplayAlerts = False
	excelWorkbook = excelApp.Workbooks.Open(xlsPath)
	ExcelSheet = excelWorkbook.Worksheets(1)

The problem being that  Workbook.Open is forcing it to always open the document instead of just selecting the opened excel file.

 

Aswell, doesnt the "Try" just select any excel application thats open at that moment?

Message 8 of 13
WCrihfield
in reply to: C_Haines_ENG

Hi @C_Haines_ENG.  If there are multiple instances of the Excel application running, this custom function (or that Try...Catch block) process, will simply get a random (or most likely the last initiated) instance of it.  That is different from having multiple Excel documents open.  You can have multiple Excel documents open within one instance of Excel, or you can have one or more documents open within multiple instances of the Excel application.  It can get pretty complicated when multiple instance of the main application may be involved.

If the document you want is already open within the instance of Excel you get, you can use something like the following to try to get that document:

 

excelWorkbook = excelApp.Workbooks.Item(xlsPath)

 

...then if it is not found that way, you can try opening it, if needed.  Those two attempts could be in a Try...Catch block too, in that order, but I would probably have a second Catch, for when it doesn't find either one (specified file can't be found).

PS.  I have actually developed my own custom functions for each step of that process (getting or creating an instance of the application, getting or creating the document, & getting or creating the sheet), but they are all set up for when the Excel API is being referenced, and are seemingly rather long.  I only use them for the most dynamic of situations, otherwise it is more efficient to do without them.

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 9 of 13
C_Haines_ENG
in reply to: WCrihfield

Error

 

Exception from HRESULT: 0x8002000B (DISP_E_BADINDEX

 

Im astouded at how complicated this integration is. Riddled with bugs. 

 

Did I put it in correclty?

 

	'define the file to create/open
	xlsPath = "C:\BOM Calculator\Test.xlsx"
	'define Excel Application object, and set it's Visibility to True
	excelApp = GetExcel(True)
	'suppress prompts (such as the compatibility checker)
	excelApp.DisplayAlerts = False
	excelWorkbook = excelApp.Workbooks.Item(xlsPath)
	ExcelSheet = excelWorkbook.Worksheets(1)
Message 10 of 13
WCrihfield
in reply to: C_Haines_ENG

Hi @C_Haines_ENG.  Sorry for all the confusion.  Debugging someone else's code that is accessing Excel, when you don't have the files on hand to test with can be fairly challenging, especially when I've got several different things going on.  I have attempted once again to slightly rewrite your code, but this time I have also included my other two custom functions, just so you can see what all is going on within them, for some ideas.  As I mentioned before, you can do without them, once you've got a good handle on most of the related possibilities, and debugging methods.  I did notice two variables that were slightly different from each other...one named "RowNum", and the other "RowNUM".  Although the spelling is the same, capitalization is important in variable names.  Also, I found out why it was showing the message 'Range is ReadOnly'.  Your two lines of code that include calls to the iProperties.Value() method did not include the ".Value" after the Range specification, so it thought you were trying to overwrite the Range object itself, instead of the Range's Value.

I attached my updated code again as a text file, to keep the post short.  Hopefully this version will work better for you.  I'm about to leave for the day, so if more changes are needed, I can look at it again tomorrow, if I have time.  Or one of the others here on the forum can give it a try.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

Message 11 of 13

Hi I have tried your code and as in previous answers from others I got error on Getobject(,"Excel.Application"). Error

as follows : 

 


Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Interop.Excel.Application'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{000208D5-0000-0000-C000-000000000046}' failed due to the following error: Element not found. (Exception from HRESULT: 0x8002802B (TYPE_E_ELEMENTNOTFOUND)).


 

 

Message 12 of 13

It seems that if you just LOOK at the excel file without touching it, the command line will work. However if you EDIT it at all, the system will not register it as the same excel file and seems to store it in a temp file somewhere.

 

I gave up on solving this one eons ago, it just doesnt work. You can write a try command telling you to close the excel file before running it.

Message 13 of 13
C_Haines_ENG
in reply to: A.Acheson

This seems to be the best solution I could come up with, sometimes it fails but it will pretty consistently grab the right application, open or not, and display it to the user.

 

 

Imports Microsoft.Office.Interop 'To use excel
Imports Microsoft.Office.Interop.Excel 'To use excel
AddReference "Microsoft.Office.Interop.Excel" 'To use excel 

Sub Main

	ExcelPath = "PATH TO EXCEL FILE"
	
	'GET THE WORKBOOK, THIS WILL EITHER GET THE OPEN WORKBOOK OR OPEN
	'AS A BACKGROUND TASK??
	Dim WB As Excel.Workbook = GetObject(ExcelPath)
	
	'DEFINE THE WORKSHEET, BETTER TO DO IT THIS WAY THEN USE THE APPLICATION
	Dim WS As Excel.Worksheet = WB.Worksheets("Sheet1")
	
	'IF EXCEL OPENED AS A BACKGROUND TASK, MAKE ITS WINDOW VISIBLE
	If WB.Windows.Item(1).Visible = False Then WB.Windows.Item(1).Visible = True
	
	'BRING EXCEL TO FRONT
	WB.Windows.Item(1).WindowState = XlWindowState.xlNormal
	AppActivate(WB.Application.Caption)
	
	'WRITE A RANDOM NUMBER INTO THE CELL "A1"
	WS.Range("A1").Value = CInt(Math.Ceiling(Rnd() * 50)) + 1

End Sub  
  

 

 

  

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report