I'd like to create a button that automatically opens a hyperlink from Powerpoint.
It's easy enough to create a hyperlink in Powerpoint (Insert -> Hyperlink) and then click on that hyperlink.
I want to skip this whole process and just be able to have a button that opens a hyperlink rather than having a hyperlink in my presentation that needs to be clicked.
The XML for the button would be something like:
<button id="myButton" label="Open Hyperlink"
imageMso="HyperlinkInsert"
size="large"
onAction="openHyperlink"
/>
Of course you will need to modify the file's Ribbon XML; the above is not a complete ribbon, just the node for the desired button. I have some other Q&A about modifying the ribbon here otherwise there are some great examples if you google for them. Most are for Word or Excel, but the same principles apply. If you need references, let me know and I can provide a few.
And the callback would be like:
Sub openHyperlink(control As IRibbonControl)
'your code that opens the hyperlink goes in here, something like:
Dim ie as Object
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.Navigate "http://google.com"
End Sub
To open a PDF instead of a browser, change that procedure:
Sub openHyperlink(control As IRibbonControl)
Dim acroPath As String
Dim filePath As String
acroPath = "C:\Program Files (x86)\Adobe\Reader 10.0\Reader\AcroRd32.exe" 'Modify as needed
filePath = "c:\users\me\file.pdf" 'Modify as needed
Shell acroPath & " " & filePath, vbNormalFocus
End Sub
You can use the ShellExecute API to open any document in the default app for that document's extension. Here's a simplified hack to start with:
Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpszOp As String, _
ByVal lpszFile As String, ByVal lpszParams As String, _
ByVal LpszDir As String, ByVal FsShowCmd As Long) _
As Long
Function ShellEx(sFile As String) As Long
ShellEx = ShellExecute(&O0, "Open", sFile, "", "C:\", 1)
End Function
Sub Test()
Debug.Print ShellEx("path to file goes here")
End Sub
More detailed version with all the options here:
http://support.microsoft.com/kb/170918
Related
I am trying to download file using InternetExplorer.Application, but it always opens a window asking to save or open the file. Is there a way to circumvent this and have it run and save in the background? Here is a block of code I have tried.
Set ie = CreateObject("InternetExplorer.Application")
ie.Navigate "https://pastebin.com/raw/terAweb"
State = 0
Do Until State = 4
DoEvents
State = ie.readyState
Loop
Dim file: file= ie.Document.Body.innerHTML
Using the URL Monikers API instead of trying to communicate with the InternetExplorer Application might be simpler.
Was that specifically done for Pastebin? Because it doesn’t really work with it, as far as I know. But I guess you can use another one 😉
Option Explicit
Private Declare PtrSafe Function URLDownloadToFileA Lib "URLMON" _
(ByVal pcaller As Long, _
ByVal szurl As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long) As LongPtr
Sub Example()
Dim Download$
On Error GoTo ErrorHandler
Download = URLDownloadToFileA(0, "myURL", "C:\Users\Name\Downloads\test.txt", 0, 0)
Exit Sub
ErrorHandler:
MsgBox Err.Number & " " & Err.Description
End Sub
Please refer to the following sample code, after using the getElementbyId method to find the download button, it will display the download prompt, we could using the Application.SendKeys "%{s}" command to click the Save button.
Sub downloadfile()
Dim IE As Object, Data As Object
Dim ticket As String
Set IE = CreateObject("InternetExplorer.Application")
With IE
.Visible = True
.navigate ("https://dillion132.github.io/default.html")
While IE.ReadyState <> 4
DoEvents
Wend
'Trigger the download button to download the file
IE.Document.getElementbyId("btnDowloadReport").Click
'wait the download prompt appear
Application.Wait (Now + TimeValue("00:00:03"))
'
Application.SendKeys "%{s}"
'Waiting for the site to load.
'loadingSite
End With
Set IE = Nothing
End Sub
The web page content:
<a id="btnDowloadReport" href="https://research.google.com/pubs/archive/44678.pdf" download>Download</a>
after a lot of research I couldn't find anyone with the same problem as me. So can any of the gurus please help me with my Excel Macro?
My macro does the following:
Open another excel workbook
Copy over the first sheet from this workbook to my current workbook
Create a button in the copied sheet
Write some code in this new created button
And here is the problem, when my macro writes the code in the button, it opens the VBA Code Editor and closes afterwards. My macro does it many times, so the VBA Code Editor keeps flashing during the macro run.
"Application.ScreenUpdating = False" didn't resolve the issue.
Please see below my code to do this Step 4 and let me know if you know a solution for that.
wb is my Workbook and ws my Worksheet
Set oOleObj = ws.OLEObjects.Add(ClassType:="Forms.CommandButton.1", Link:=False, DisplayAsIcon:=False, Left:=5.4, Top:=4.8, Width:=97.2, Height:=35.4)
Set VBP = wb.VBProject
Set VBC = VBP.VBComponents(VBP.VBComponents.Count)
Set CM = VBC.CodeModule
With wb.VBProject.VBComponents(wb.Worksheets(ws.Name).CodeName).CodeModule
LineNum = .CreateEventProc("click", oOleObj.Name)
LineNum = LineNum + 1
.InsertLines LineNum, "UploadToAlmButton_OnClick"
End With
I could simple protect the project from viewing with a password. That should resolve the issue, but creates another one: If it's protected, I cannot write code on it by macro as I am doing in the Step 4. :(
Thanks!
To hide VBE window
Application.VBE.MainWindow.Visible = False
Application.VBE.MainWindow.Visible = True
If VBE window is still flickering then you need to use LockWindowUpdate Windows API function.
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal ClassName As String, ByVal WindowName As String) As Long
Private Declare Function LockWindowUpdate Lib "user32" _
(ByVal hWndLock As Long) As Long
Sub EliminateScreenFlicker()
Dim VBEHwnd As Long
On Error GoTo ErrH:
Application.VBE.MainWindow.Visible = False
VBEHwnd = FindWindow("wndclass_desked_gsk", _
Application.VBE.MainWindow.Caption)
If VBEHwnd Then
LockWindowUpdate VBEHwnd
End If
'''''''''''''''''''''''''
' your code here
'''''''''''''''''''''''''
Application.VBE.MainWindow.Visible = False
ErrH:
LockWindowUpdate 0&
End Sub
References:
Cpearson - Eliminating Screen Flicker During VBProject Code
MSDN- VBE flashes while programming in the VBE
I have a master macro in an Excel file, 'file A' that opens another Excel file, 'file B'. On open, an add-in imports data into 'file B'. I would like to close 'file B' once the add-in is finished importing, and I'm looking for the best way to do that.
I've written the code to open 'file B' (which triggers the add-in automatically) and to close the file, but when the add-in is finished, it opens a MsgBox to notify the user. I'm trying to completely automate an internal process, so dismissing the MsgBox programmatically would be ideal.
Is it possible to dismiss a MsgBox through VBA? I'm aware that I can create timed MsgBoxes in VBA but I'm not creating this MsgBox (the add-in is); I just want to dismiss it. I'm open to creating a Word file and calling a macro from that if required, but would prefer not to use SendKeys.
Since the "add-in" and Excel/VBA run in the same context, we cannot launch it and monitor its message-box within the same VBA application, because each VBA application is a single-threaded process. Fortunately however, there is a solution that can exploit the fact that different VBA applications run in different contexts, so they can run in parallel.
My suggested solution is to create a MS-Word document that is dedicated to monitoring and closing that message box. We need this in Word (or any other office application) in order to make the monitoring code and the addin's code run in parallel, in different contexts.
1- create a Word macro-enable document, named mboxKiller.docm and place it in some folder; i.e. C:\SO in my example. place this code in ThisDocument and save:
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Sub WaitAndKillWindow()
On Error Resume Next
Dim h As Long: h = FindWindow(vbNullString, "Microsoft Excel")
If h <> 0 Then SendMessage h, 16, 0, 0 ' <-- WM_Close
Application.OnTime Now + TimeSerial(0, 0, 1), "WaitAndKillWindow"
End Sub
Private Sub Document_Open()
WaitAndKillWindow
End Sub
2- In the Excel workbook's VBA, create a class module, named mboxKiller with this code:
Private killerDoc As Object
Private Sub Class_Initialize()
On Error Resume Next
Set killerDoc = CreateObject("Word.Application").Documents.Open(Filename:="C:\SO\mboxKiller.docm", ReadOnly:=True)
If Err.Number <> 0 Then
If Not killerDoc Is Nothing Then killerDoc.Close False
Set killerDoc = Nothing
MsgBox "could not lauch The mboxKiller killer. The message-box shall be closed manuallt by the user."
End If
End Sub
Private Sub Class_Terminate()
On Error Resume Next
If Not killerDoc Is Nothing Then killerDoc.Application.Quit False
End Sub
3- Testing and Usage. In a normal class Module, place the following code and test the procedure
Sub Test() ' <-- run this for testing after finishing the setup
Dim killer: Set killer = New mboxKiller
simulateAddin
simulateAddin
simulateAddin
End Sub
' Procedure supposed to do some calculation then display a message box
Private Sub simulateAddin()
Dim i As Long
For i = 0 To 1000: DoEvents: Next ' simulates some calculations
MsgBox "This is a message box to simulate the message box of the addin." & VbCrLf & _
"It will be automatically closed by the Word app mboxKiller"
End Sub
VBA also has the ability to temporarily dismiss alerts.
Application.DisplayAlerts = False
'while you run your code here, no alerts will be displayed
Application.DisplayAlerts = True
I have some workbooks, which starts with automatic macros and data refreshing (and, pre-empting some suggestions, these workbooks need to work like that, because I'm starting them automatically from Windows scheduler and I need them to perform tasks without any action on the user's part).
When I need to check/update some formulas, SQL query or layout, I just open a workbook holding [Shift] key and it prevents triggering macros in Workbook_Open / Auto_Open events etc., which is great.
The problem is that there are still some external data sources which are automatically refreshed during the opening. In some of these workbooks queries take a long while to accomplish and I need to wait a minute or two before I can edit a workbook.
Is there any way I could open a workbook with both macros and data refreshing disabled? Or, perhaps, any simple way to cancel executing a query?
Go Into the Excel Options
navigate to Trust Center then Trust Center Settings and go to
External Content.
You'll see the Security Settings for Data Connections and Workbook Links. Disable both.
Restart Excel and you're done.
In Office 2010, go to the same External Content menu, and select Disable all Data Connections as well as Disable automatic update of workbook links.
After inserting the code into the proper modules run CreateAltStartVBS. CreateAltStartVBS will create a VBScript file (AltStart.vbs) in the workbooks folder. When you run AltStart.vbs it will start your workbook bypassing your opening macros and disabling the Connections from refreshing.
Workbook Module
Private Sub Workbook_BeforeClose(Cancel As Boolean)
EnableRefresh True
End Sub
Private Sub Workbook_Open()
If getSwitch = "/z" Then
EnableRefresh False
Exit Sub
End Sub
'Normal code goes here
End Sub
Sub EnableRefresh(Enable As Boolean)
Dim conn As Object
For Each conn In ActiveWorkbook.Connections
conn.ODBCConnection.EnableRefresh = Enable
Next
End Sub
Standard Module
Option Base 0
Option Explicit
Declare Function GetCommandLine Lib "kernel32" Alias "GetCommandLineW" () As Long
Declare Function lstrlenW Lib "kernel32" (ByVal lpString As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (MyDest As Any, MySource As Any, ByVal MySize As Long)
Function CmdToSTr(Cmd As Long) As String
Dim Buffer() As Byte
Dim StrLen As Long
If Cmd Then
StrLen = lstrlenW(Cmd) * 2
If StrLen Then
ReDim Buffer(0 To (StrLen - 1)) As Byte
CopyMemory Buffer(0), ByVal Cmd, StrLen
CmdToSTr = Buffer
End If
End If
End Function
Function getSwitch()
Dim CmdRaw As Long
Dim CmdLine As String
CmdRaw = GetCommandLine
CmdLine = CmdToSTr(CmdRaw)
getSwitch = Split(CmdLine, Chr(34))(2)
End Function
Sub EnableConnections(Enable As Boolean)
Dim conn As Object
For Each conn In ActiveWorkbook.Connections
conn.ODBCConnection.EnableRefresh = Enable
Next
End Sub
Sub CreateAltStartVBS()
Dim myFile As String
myFile = ThisWorkbook.Path & "\AltStart.vbs"
Open myFile For Output As #1
Print #1, "Dim objShell"
Print #1, "Set objShell = CreateObject (""WScript.Shell"")"
Print #1, "objShell.Run ""excel.exe /z """ & Chr(34) & ThisWorkbook.FullName & Chr(34)
Print #1, "Set objShell = Nothing"
Close #1
End Sub
How can I set a text in a Ribbon Editbox? I can't find it on internet :/
I just can find examples of click event but nothing about set a text from a Sub.
So for example, I want something like this:
Sub settingText()
editboxname = "my text"
end sub
The solution I found on this link: http://www.shulerent.com/2011/08/16/changing-the-value-of-an-editbox-office-ribbon-control-at-runtime/
Here is an example that I tested and it worked well:
'Global Variables:
Public MyRibbonUI As IRibbonUI
Public GBLtxtCurrentDate As String
Private Sub OnRibbonLoad(ribbonUI As IRibbonUI)
Set MyRibbonUI = ribbonUI
GBLtxtCurrentDate = ""
End Sub
Private Sub ocCurrentDate(control As IRibbonControl, ByRef text)
GBLtxtCurrentDate = text
MyRibbonUI.InvalidateControl (control.id)
End Sub
Private Sub onGetEbCurrentDate(control As IRibbonControl, ByRef text)
text = GBLtxtCurrentDate
End Sub
Public Sub MyTest()
'Here is an example which you are setting a text to the editbox
'When you call InvalidateControl it is going to refresh the editbox, when it happen the onGetEbCurrentDate (which is the Gettext) will be called and the text will be atributed.
GBLtxtCurrentDate = "09/09/2013"
MyRibbonUI.InvalidateControl ("ebCurrentDate")
End Sub
<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="OnRibbonLoad">
<ribbon>
<tabs>
<tab id="Objects" label="Objects">
<group id="grp" label="My Group">
<editBox id="ebCurrentDate" label="Date" onChange="ocCurrentDate" getText="onGetEbCurrentDate"/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
It's a little while since this answer was posted, and there looks to be a recent-ish change to the behaviour of the ribbon, which means the original answer posted may not be a solution any more. For the record, I'm using Excel 2013 with some updates that are dated after Braulio's answer.
The heart of the difference is that Invalidate and InvalidateControl on the ribbon don't behave the same way as previously. This means that InvalidateControl does not call the getText callback on the editBox. I replaced the InvalidateControl calls with Invalidate (so forces a re-draw on the entire ribbon), and that does trigger the callback as expected.
So here's the code of my solution for a filename/browse button (note I've included extra code for caching the ribbon UI reference on a very hidden sheet so that resets during development don't make the ribbon inaccessible).
Private sobjRibbon As IRibbonUI
Private strFilename As String
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (destination As Any, source As Any, ByVal length As Long)
Private Function GetRibbon() As IRibbonUI
If sobjRibbon Is Nothing Then
Dim objRibbon As Object
CopyMemory objRibbon, ThisWorkbook.Worksheets("Ribbon_HACK").Range("A1").Value, 4
Set sobjRibbon = objRibbon
End If
Set GetRibbon = sobjRibbon
End Function
'Callback for customUI.onLoad
Sub Ribbon_Load(ribbon As IRibbonUI)
Set sobjRibbon = ribbon
Dim lngRibPtr As Long
lngRibPtr = ObjPtr(ribbon)
' Write pointer to worksheet for safe keeping
ThisWorkbook.Worksheets("Ribbon_HACK").Range("A1").Value = lngRibPtr
strFilename = ""
End Sub
'Callback for FileName onChange
Sub OnChangeFilename(control As IRibbonControl, text As String)
strFilename = text
End Sub
'Callback for FileName getText
Sub GetFileNameText(control As IRibbonControl, ByRef returnedVal)
returnedVal = strFilename
End Sub
'Callback for FilenameBrowse onAction (I'm looking for XML files here)
Sub OnClickFilenameBrowse(control As IRibbonControl)
Dim objFileDialog As Office.FileDialog
Set objFileDialog = Application.FileDialog(msoFileDialogFilePicker)
With objFileDialog
.AllowMultiSelect = False
.Title = "Please select the file."
.Filters.Clear
.Filters.Add "XML", "*.xml"
If .Show = True Then
strFilename = .SelectedItems(1)
GetRibbon().Invalidate ' Note the change here, invalidating the entire ribbon not just the individual control
End If
End With
End Sub
For the record, here's the XML for the two objects I'm dealing with here:
<editBox id="FileName" onChange="OnChangeFilename" screentip="Filename of the XML file to upload" label="XML file name" showImage="false" getText="GetFileNameText" />
<button id="FilenameBrowse" imageMso="ImportExcel" onAction="OnClickFilenameBrowse" screentip="Find the file to upload" label="Browse" />