I have a code that opens excel application with win32com and similar code with xlwings - win32com

The code looks like this:
wbtest = xw.Book('test1.xlsx')
ws1 = wbtest.sheets['Sheet1']
ws1.range("A1").value ="100"
wbtest.save()
wbtest.save(r'C:\Users\afoto001.000\Desktop\All projects\DC projects\codes\test1.xlsx')
wb.kill()
The code basically starts an excel document and writes 100 to Sheet1. After that, I'd like Excel to close on its own, without the need for user intervention. Any suggestions or ideas would be much appreciated.

I'm not sure how you are closing Excel without user intervention? If this whole thing was called from a script or a cron like scheduler then the whole thing could be run without user intervention.
import xlwings as xw
app = xw.App()
wbtest = app.books.open(r'path\to\test1.xlsx')
ws1 = wbtest.sheets['Sheet1']
ws1.range("A1").value ="100"
wbtest.save()
wbtest.save(r'C:\Users\afoto001.000\Desktop\All projects\DC projects\codes\test1.xlsx') # Are you saving to two places?
app.quit()
app.kill() # The instance will still be there without this.
# wb.kill() You did not have an instance of wb in your code.

I used this at the end of my code and now my Excel processes close automatically:
quit()
sys.exit()
def quit(self):
self.xlBook.Close(SaveChanges=0)
self.xlApp.Quit()
del self.xlApp

Related

How to prevent loss of 'link' for embedded chartdata

I'm currently receiving a 'Linked File Not Available' error when trying to manually open datasets for embedded charts in Word after successfully updating these datasets via a VBA script. I am trying to build a project which will allow users to automatically update a series of embedded charts based on a user defined worksheet which is produced monthly.
In order to support this project, I've been trying to find a way in which I can update chart data in Word using VBA while avoiding the ChartData.Activate method (eventually crashes the program due to the burden of successive open / close actions [context: I have around 300 charts in the largest of these reports]).
I've attempted to update the data using a direct call to the ChartData.Workbook and ChartData.ActivateChartDataWindow both of which allow me to successfully update the data. Following the successful update however, I get the below error when trying to access the dataset manually and can no longer access it via the Macro:
Linked File Not Available
I know I am probably missing something simple, or perhaps am approaching this in the wrong way by going through Word but wanted to throw it out there to see if anyone has a solution which could resolve / explain what's causing the loss of these 'links' to embedded datasets?
Chart Screenshot (Front)
Chart Screenshot (Data)
To try and streamline testing; I've created a stripped down version of the overall code which I've been using to try and troubleshoot:
Dim x As Integer 'Counter used to breakout of routine once 1 chart updated.
Dim strChartTitle As String
Dim objChart As InlineShape
Dim objTargetWorkbook As Workbook
Dim objTargetWorksheet As Worksheet
x = 0
For Each objChart In ActiveDocument.InlineShapes
strChartTitle = objChart.Chart.ChartTitle.Text
If x = 1 Then
Exit Sub
ElseIf strChartTitle Like "EHR Transactions Summary (By Endpoint)*" Then
'objChart.Chart.ChartData.Activate
objChart.Chart.ChartData.ActivateChartDataWindow
Set objTargetWorkbook = objChart.Chart.ChartData.Workbook
Set objTargetWorksheet = objTargetWorkbook.ActiveSheet
objTargetWorksheet.Range("C1:D11").Copy objTargetWorksheet.Range("B1")
objTargetWorksheet.Range("D1").Value = DateAdd("m", 1, objTargetWorksheet.Range("C1").Value)
x = 1
objTargetWorkbook.close
End If
Next objChart
Problem:
Couldn't find a way to update data on a large number of charts using vba without utilising the Chart.ChartData.Activate or Chart.ChartData.ActivateChartDataWindow commands which either caused crash due to CPU load on successive load / unload (former method) or broke links between the embedded charts and their datasheets (latter method).
Solution:
Solution was provided in part by #Slightly Snarky in comment to original question / problem post. Despite Microsoft's documentation, it is possible to update data within Chart workbooks without the need to call an activate command by referencing the workbook and worksheet directly.
Re-wrote script to utilise the new method and confirmed not only did this allow me to edit data; it was able to do so while avoiding the performance hit inherent in the repeated open / close events caused by the two above methods.
On testing; one problem did come up in that MS-Word would spin up a new Excel sub-process each time the code referenced a different chart without killing the previous sub-process. Given these reports have up to 300 charts, this inevitably caused the routine to crash once enough sub-processes had built up against the CPU.
To resolve this issue, I tweaked the code to include a ChartData.Workbook.Close command after each chart update completes which has helped keep CPU burden to a minimum and prevented crashes due to overloading with Excel sub-processes.
Dim strChartTitle As String
Dim objChart As InlineShape
For Each objChart In ActiveDocument.InlineShapes
strChartTitle = objChart.Chart.ChartTitle.Text
If strChartTitle Like "EHR Transactions Summary (By Endpoint)*" Then
With objChart.Chart.ChartData.Workbook.Worksheets(1)
.Range("C1:D11").Copy objChart.Chart.ChartData.Workbook.Worksheets(1).Range("B1")
.Range("D1").Value = objChart.Chart.ChartData.Workbook.Worksheets(1).Range("D1").Value = DateAdd("m", 1, objChart.Chart.ChartData.Workbook.Worksheets(1).Range("C1").Value)
End With
objChart.Chart.ChartData.Workbook.close
End If
Next objChart

Open an Excel file in VBA without loading add ins?

I have some code that opens a file, copy/pastes some cells into a merged sheet, closes the file; then loops for all the files in a folder. Something like this:
Set SourceFile = Workbooks.Open(FilePath & FileName)
Set Ltab = SourceFile.Worksheets("Sheet1")
Ltab.Cells.Copy
NewTab.Cells.PasteSpecial xlPasteValuess
SourceFile.Close
Is there a line I can add that will stop Excel from loading add ins every time a file is opened? There are a lot of files and loading the add ins adds a good 5-10 seconds every time.
This didn't really answer my question, as I need a way to do it in VBA.
Thanks
So if you dont wana to disable all addins without naming them, and Installed = false is correct aproach try to iterate them with for each
Sub runWithoutAddins()
Dim var As AddIn
For Each var In AddIns
var.Installed = False
Next var
End Sub
I dont need to know their name, but this will loop every object in AddIn collection and set their atribute Installed to false. (which if im understanding it well, will disable them)

Is there a way to save all hyperlinked documents in excel?

I know this question has been answered before, but the problem I'm facing is a bit different, and this is why I'm asking for your help :)
So, I'm working with multiple excel files that contain multiple hyperlinks that lead to documents such as Excel files, PDFs, DOCs and sometimes even images. The problem with these hyperlinks is that they are not leading to a "normal" website, but to a special internal software, that in its turn links to a local address on my computer that contatins the desired file. That means that there is no direct link that could be grabbed with a simple VBA code.
Let's have an example, assuming the internal software name is "John":
I see in the Excel documents this link: John://3434545345/345345345
When I click on it, it opens the file, which is located, for example, in: C:/local/Cutekitten.pdf
After this long intro, my question is: Is there a way to automate the process of saving each document, instead of manually opening it and saving it? Could it be solved with a VBA code? Or does is require a different approach? I was actually thinking to bypass this problem by finding a way to open all hyperlinks at once with VBA, and then maybe find some code (not VBA?) that saves all open documents.
P.S Please keep in mind that I can't download EXE files or any other "suspicious" files due to workplace restrictions.
Any help will be much appreciated,
Thanks! :)
You may try this
'''
Input: test.xlsx
name link
1 location/file1.jpg
2 location/file2.xlsx
3 location/file3.pdf
4 location/file4.mp4
'''
from openpyxl import load_workbook
wb = load_workbook('test.xlsx')
print wb.get_sheet_names()
# ['Sheet 1', 'Sheet 2', 'Sheet 3']
ws1 = wb['Sheet 1']
## alternate -> worksheet2 = wb2.get_sheet_by_name('Sheet2')
import urllib
import os
## Result directory
directory = 'result'
if not os.path.exists(directory):
os.makedirs(directory)
for row in ws1:
if '.exe' in row[1].value:
continue
print row[0].value, '\t', row[1].value
urllib.urlretrieve (row[1].value, directory+'/'+row[1].value)
'''
Output:
Table 1 None
None None
name link
1 location/file1.jpg
2 location/file2.xlsx
3 location/file3.pdf
4 location/file4.mp4
'''
Sub PathsText()
Dim List(), Path As String
Dim i, x As Integer
Dim s As InlineShape
Dim fso As FileSystemObject, ts As TextStream
Set fso = New FileSystemObject
Set ts = fso.OpenTextFile("C:\MyFolder\List.txt", 8, True)
With ts
.WriteLine (ActiveDocument.InlineShapes.Count)
End With
For Each s In ActiveDocument.InlineShapes
Path = s.LinkFormat.SourcePath & "\" _
& s.LinkFormat.SourceName
With ts
.WriteLine (Path)
End With
Next s
End Sub
I guess the important part is if "Path = s.LinkFormat.SourcePath" works.
If so, if you have a ton of excel files to do it for, I'd put those (the ones with the links) in one folder. I'd make a new empty workbook with one button on a single sheet to call code. The button would "For Each workbook in directory, For Each sheet in workbook, For Each link on sheet" add source path to a text file.
Once you had a list of paths the next step would be obvious. I wish I had demo code, but I migrated to c# years ago. My monstrously slow cell-by-cell search, modify and graph inventions threatened to bury me.

PowerPoint 2013 macro keeps file locked open after close command

I have a PowerPoint VBA function that opens presentations, copies slides into the active presentation, then closes the source presentation. It worked fine in 2010, but fails in 2013 (all on Windows 7) if it tries to open the same presentation more than once. It appears to me that after the presentation.close command is issued, the window is closed, but the file remains locked open until the VBA code exits. So if the code attempts to open that file again it returns the error:
"Method 'Open' of object 'Presentations' failed"
Here's a simplified form of the function I'm running that behaves the same way. I've had a colleague test this again in PowerPoint 2010 and it runs fine. I've also had a colleague test it under his 2013 to make sure it's not something with my particular installation.
Sub testopen()
Dim ppFile As Presentation
Dim i As Integer
Const fpath = "C:\test.pptx"
For i = 1 To 2
Set ppFile = Application.Presentations.Open(fpath)
ppFile.Close
Set ppFile = Nothing
Next i
End Sub
The file test.pptx is just a blank presentation. In debug mode I can see the file opens and closes on the first loop, then on the second loop the open command fails and I can see in Windows explorer that the hidden temporary file still exists, indicating the file is still open, until I exit the VBA code. I also verified that the file is held open by adding in a function to check the file open status.
I've spent probably an hour googling this and cannot find any other descriptions of this problem. I'm sure I can implement a workaround but it's driving me crazy that I can't find any other reports of seemingly such a simple issue. Any suggestions are greatly appreciated! Thanks.
The Best way that I have achieved this is to simply create a VBS file and in the VBS file I call out the desired VBA code. It's little more hassle than to write the VBA code, but it's the solution that worked for me.
For example in the VBS file:
Dim args, objPP
Set args = WScript.Arguments
Set objPP = CreateObject("Powerpoint.Application")
objPP.Open "C:\path\to\file.ppx"
objPP.Visible = True
objPP.Run "The_Macro"
objPP.Save
objPP.Close(0)
objPP.Quit
Or better yet, have the entire code within the VBS file and have it copy the desired slides.
Hope this helps you achieve your result.
Setting the file as Read Only resolved the issue. The open command is now:
Set ppFile = Application.Presentations.Open(fpath, msoTrue)
Also, saving the file before closing it resolved the issue. For that, add:
ppFile.Save
Interestingly, I had already tried setting the Saved property to True (ppFile.Saved = msoTrue), which does NOT work. Thanks to Michael for his suggestion on the VBS script. That does work and I had never run an external VBS script so I learned something new. In this case, I'd prefer to stick with a VBA solution.

vbScript opens up excel but doesn't load macro/modules?

I m in a very weird situation. I created a vbs script that would open my excel file. I had defined vba code in WorkBook_open method. I thought creating a vbs script to open up my excel would invoke my workBook_open method and execute the vba code inside it. But I was wrong. Below is my vbs code.
filePath = "E:\data_extracts\mydata.xlsm"
Set oExcel = CreateObject("Excel.Application")
oExcel.Workbooks.Open(filepath)
oExcel.Visible = True
oExcel.Run "RefreshDataFromIQY"
oExcel.ActiveWorkbook.Save
oExcel.ActiveWorkbook.Close
oExcel.Quit
Set oExcel = Nothing
On debugging, it fails at oExcel.Run "RefreshDataFromIQY" saying either macros are not available or disabled. Hence it is the code just opnes up excel application successfully and that's all it does. I have macro codes in module1, module2. How/where do I write to execute my macros in vbs script below. My macros/modules have to be executed in sequence and some of my macros are recorded macros. Any help is much appreciated. Thanks.
Thanks for your input Scott. Here's what I made changes to my code
Dim oExcelApp
Dim oExcelWkb
set oExcelApp = createobject("Excel.Application")
set oExcelWkb = oExcelApp.Workbooks.Open("\\myserver\data_extracts\TestTOPTMay307.xlsm")
oExcelWkb.Close True
oExcelApp.Quit
However on running it from command line, its giving me runtime error Object required: 'Close'. Any idea why? Why is it failing to Close? What am i doing wrong? Thanks.
I just tested your code against a dummy file I made. It worked when I placed the code inside a module and left it as public. However, when I put into a private module -> like worksheet level module, I got the error you got.
However, when I referenced the private object, the code ran through. So my answer to you is to replace
oExcel.Run "RefreshDataFromIQY"
With
oExcel.Run "[yourClassName].RefreshDataFromIQY"
Also, I placed a workbook_event in my file as well. The event triggered successfully on open, so if there is trouble with yours, it's most likely in the code inside the event.