How do I copy MsgBox text to the clipboard using VBA?
myValue = InputBox("Please enter user text")
MsgBox("This is my text " & myValue & ", my second text & Now & ".")
I don't want to use ctrl + c, I want to copy this automatically after the MsgBox appears.
Copy the message where?
If you want it to be pasted in a cell use something like this:
myValue = InputBox("Please enter user text")
MsgBox("This is my text " & myValue & "," & my second text & Now & ".")
myMsgBox = "This is my text " & myValue & "," & my second text & Now & "."
ThisWorkbook.Sheets("Sheet_to_be_pasted_in").Range("A2").Value = myMsgBox
If u want to use it in any other way, the value is stored in the variable myMsgBox.
Copy it to clipboard so it's available on next paste command:
Dim objMsgBox As New DataObject
myValue = InputBox("Please enter user text")
MsgBox("This is my text " & myValue & "," & my second text & Now & ".")
myMsgBox = "This is my text " & myValue & "," & my second text & Now & "."
objMsgBox.SetText myMsgBox
objMsgBox.PutInClipboard
There is a straightforward approach to how to copy all "MsgBox" text!
The easiest way to do so (even if you personally don't want to do it that way :-) definitely IS to use the Ctrl+C "Copy-Handler that's builtin in every MsgBox.
The only thing you have to do is to send the ctrl+c keystroke back to VBA itself before executing the MsgBox(...) command.
Don't get mislead by other folks who want to make you believe that using the Application.SendKeys() command is not reliable. That's not true! The only truth is, that the Application.SendKeys() command will stuff your keystrokes into the keyboard buffer of your application regardless of what's already in there. Exactly that is the reason many other VBA guys believe that the Application.SendKeys() command isn't reliable.
The only step you have to take before issuing your Ctrl+C SendKeys command is, you have to clear your host's keyboard buffer! That is a piece of cake: Just write "DoEvents" one line before you call the "Application.SendKeys()" method and you're done!
Now, to make the whole approach really bullet-proof, you only have to make sure that your MsgBox really is the current window receiving Windows' messages. Only the top-most (active) window receives messages that are sent without a special receiver address (including your own "Ctrl+c" message). To achieve that, simply flag your MsgBox "vbSystemModal + vbMsgBoxSetForeground", and you're good to go.
That said, it's a walk in the park to solve your "problem". Here is some code to play with.
Public Sub Test(Optional ByVal myValue As String = vbNullString, _
Optional ByVal ShowMsgBox As Boolean = False, _
Optional ByVal EchoOut As Boolean = True)
' Param: myValue => Text that gets decorated
' Param: ShowMsgBox => If true then messageBox gets displayed
' Param: EchoOut => If true echos Clipboard to immediate window
If Len(myValue) = 0 Then
' Get something from the user
myValue = InputBox("Please enter something")
End If
' Clear keyboard buffer
DoEvents
' Send "Ctrl+c" "Copy2Clip" to MSO Host
Application.SendKeys "^c"
' If you like, let's also press the OK button of the message box
If Not ShowMsgBox Then
Application.SendKeys "{ENTER}"
End If
' Display Msgbox
MsgBox "This is my text '" & myValue & _
"' my second text [" & Now & "].", _
vbSystemModal + vbMsgBoxSetForeground
If EchoOut Then
' This will clear VBA's Console.
DoEvents
Application.SendKeys "^g ^a {DEL}"
' Copy what's in the Clipboard into VBA's "Immediate" window
DoEvents
Application.SendKeys "^g ^v"
End If
' Do not call DoEvents here! This only works when debugging in
' single-step mode(!) At runtime, VBA's immediate window cannot
' get the focus (Ctrl+g) to receive the "Ctrl+v" windows message
' here(!) Thus, DoEvents would eat up your
' Application.SendKeys "^g ^v"
'
' DoEvents ' no, No, NO!
'
End Sub
Add the test routine to one of your public code modules. Then go to your immediate window and type Test "This is my text" then hit enter. Have fun!
PS: There is not only the Application.SendKeys() method (see here: https://learn.microsoft.com/de-de/office/vba/api/Excel.Application.SendKeys), but also the VBA "SendKeys()" statement (see here: https://learn.microsoft.com/de-de/office/vba/Language/Reference/User-Interface-Help/sendkeys-statement). The latter even lets you send keystrokes to a different application (like some external text editor). The only thing you have to do from inside your VBA code is, you have to open the other application and bring its main window to the front, before sending "Ctrl+v" to that window. Well, starting other Windows executables, waiting for them being ready, sending keystrokes (using VBA's SendKeys statement) definitely can be a little bit tricky and also error-prone. Thus, that approach should be your last resort. You can find examples of how to do that here on StackOverflow. If you have Microsoft Word installed, I strongly recommend using Word-Automation instead of playing Tic-Tac-Toe with NotePad.exe :-)
Related
Is there a way in VBA-Excel to find how is named the Immediate window in a localized version of Microsoft Office Excel, not English ?
For example, I use an Italian version of Excel, and here Immediate window is called "Immediata", other, for example Dutch here, called it "Direct"
and so on...
I'm trying to modify a function finded in the page linked above, but I wish to release a version able to work in any localized version of MsO Excel.
Thanks in advance for the answer.
The name of the Immediate Window is available in the Window object with the type vbext_wt_Immediate. This type is only available with the correct imports, but all it says is vbext_wt_Immediate = 5. Instead of creating a reference to this, it can be declared and used like this:
Const VBEXT_WT_IMMEDIATE = 5
Function ImmediateLabel() As String
Dim win As Object
For Each win In Application.VBE.Windows
If win.Type = VBEXT_WT_IMMEDIATE Then
ImmediateLabel = win.Caption
End If
Next
End Function
Sub Test()
Debug.Print ImmediateLabel
End Sub
'++++++++++++++++++++++++++++++++++++++++++++++
'+ Function to find the name of the localized +
'+ version of the Immediate windows. +
'++++++++++++++++++++++++++++++++++++++++++++++
Public Function LocalizedImmediateWin() As String
' String pass to the MsgBox.
Dim strMsg As String
' This Integer'll contain the total number of the VBE Windows.
Dim intNumWin As Integer
' This Integer is used as counter in the For...Next loop.
Dim intLoop As Integer
' Count the number of all the windows (show or hidden) in the VBE.
intNumWin = Application.VBE.Windows.Count
' Loop for all the windows find, starting from 1.
For intLoop = 1 To intNumWin
' If the Type of the Windows we're examine is an Immediate Windows then
If Application.VBE.Windows.Item(intLoop).Type = vbext_wt_Immediate Then
' Build the MsgBox.
strMsg = MsgBox("In this localized version of " & Chr(13) & Chr(10) & "Microsoft Office Excel, " & Chr(13) & Chr(10) & "Immediate windows is called:" & Chr(13) & Chr(10) & Chr(13) & Chr(10) & Application.VBE.Windows.Item(intLoop).Caption & "", vbCritical, "Localized Immediate")
' Pass the value as result of the Function.
LocalizedImmediateWin = Application.VBE.Windows.Item(intLoop).Caption
Exit For
End If
' Next windows to examine.
Next intLoop
' End of the function.
End Function
' Simple way to try.
Sub Try()
MsgBox LocalizedImmediateWin
End Sub
I have this simple VBA code below, and I don't know why is not working.
Sub Run()
test = "MsgBox" & """" & "Job Done!" & """"
Application.Run test
End Sub
What I want to do is to put the VBA Command into a variable as text and run it as a command. In this case, I want to run like MsgBox "Job Done!" and print just:
Job Done!
You may be tempted by adding your own string "Executer":
Sub StringExecute(s As String)
Dim vbComp As Object
Set vbComp = ThisWorkbook.VBProject.VBComponents.Add(1)
vbComp.CodeModule.AddFromString "Sub foo()" & vbCrLf & s & vbCrLf & "End Sub"
Application.Run vbComp.name & ".foo"
ThisWorkbook.VBProject.VBComponents.Remove vbComp
End Sub
Sub Testing()
StringExecute "MsgBox" & """" & "Job Done!" & """"
End Sub
Short answer is, you cannot do that (You should not do that) but ... read the following to find out why and see a work around!
As you know you are writing your code in a compiler. What you want to do is running human-legible line of text as a command which is not possible. While you run the program all of it is compiled to machine language. When you pass that line of text to it, it cannot recognize it as a command and you will end up getting an error. What you can do is passing arguments to it:
Sub Run()
test = "Job Done"
MsgBox(test)
End Sub
You can also run an executable which can be written as a text file within a macro and then runs within the same Sub (extension needs to be taken care of).
If you cannot change the variable (i.e. test) then you need to take another approach towards it. I would suggest something like extracting the argument which can be passed to the function and use that. Something like below;
Sub Run()
test = "MsgBox" & """" & "Job Done!" & """"
extest = Right(test, Len(test) - 7)
MsgBox (extest)
End Sub
I believe there was a same question on SO but I couldn't find it. I will included it as a reference if found it.
P.S. These two posts may help to find an answer:
Access VBA - Evaluate function with string arguments
Excel VBA - How to run a string as a line of code
ANOTHER SOLUTION
This needs to trust the VB project. Quoting from ExcelForum and referencing to Programmatic Access To Visual Basic Project Is Not Trusted - Excel
Quote:
Place your Macro-Enabled Workbook in a folder which you can designate
as macro friendly.
Then open the workbook.
Click on the Office Button -> Excel Options ->
Trust Center -> Trust Center Setting -> Trusted Locations.
Then you add your folder (where you have your Excel Macro-Enabled Workbook) as
a trusted location.
Also you need to do this:
File -> Options -> Trust Center -> Trust Center Setting -> Macro Setting ->
Check the box beside "Trust access to the VBA project object model"
Close and re-open your workbook.
Those who use your macro should go through the same steps.
Unquote.
Then you can use this which I got from VBA - Execute string as command in Excel (This is not tested)
Sub test()
Set VBComp = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_StdModule)
VBComp.Name = "NewModule"
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("NewModule").CodeModule
Dim test As String
test = "MsgBox " & """" & "Job Done!" & """"
With VBCodeMod
LineNum = .CountOfLines + 1
.InsertLines LineNum, _
"Sub MyNewProcedure()" & Chr(13) & test & Chr(13) & "End Sub"
End With
'run the new module
Application.Run "MyNewProcedure"
UserForm1.Show
'Delete the created module
ThisWorkbook.VBProject.VBComponents.Remove VBComp
End Sub
#A.S.H answer does the thing that last solution intends to implement. I am including it here for the sake of completeness. You can refer to the original answer and up-vote it.
Public Sub StringExecute(s As String)
Dim vbComp As Object
Set vbComp = ThisWorkbook.VBProject.VBComponents.Add(1)
vbComp.CodeModule.AddFromString "Sub foo" & vbCrLf & s & vbCrLf & "End Sub"
Application.Run vbComp.name & ".foo"
ThisWorkbook.VBProject.VBComponents.Remove vbComp
End Sub
Sub Testing()
StringExecute "MsgBox" & """" & "Job Done!" & """"
End Sub
If you need a solution which doesn't require special permissions, and has significantly more power than hard coding code, I maintain a library, stdLambda from stdVBA, for this kind of thing:
'Ensure module name is "mainModule"
Public Sub Main()
Call stdLambda.bindGlobal("msgbox", stdCallback.CreateFromModule("mainModule","msgbox"))
x = stdLambda.Create("msgbox(""hello world"")").Run()
End Sub
Public Function msgbox(ByVal sMessage as string) as long
msgbox = VBA.msgbox(sMessage)
End Function
stdLambda syntax is vba-like but is a fully embedded programming language in its own right. See the documentation for more details.
I was up against a similar variation: the macro name was in a 'control specification' worksheet table. A custom ribbon was added with an 'onAction' parameter in the ribbon XML. The 'tag' Name was returned in the Ribbon call back macro that was then used to lookup the macro Name to run based on the XML tag name. Makes sense so far!!!! I already had the handling subs in an existing Code Module=[m0_RibbonCallBack]. In the [m0_RibbonCallBack] module I wanted to run the sub name=[mResetToCellA2] when I clicked the ribbon button with tagName=[Reset2CellA2]. In the 'control specification' worksheet table I did a vLookUp() on the tagname=[Reset2CellA2] and returned the string value from column 3 (onAction) ="mResetToCellA2". Now I need to run the macro string (macroName) name on the VBA side!!!
I wound up solving the challenge with this simple line:
Application.Run "m0_RibbonCallBack." & macroName
Cheers!
Ok so I have a hyperlink function in a spread sheet cell of the form:
=HYPERLINK(JJmp(I1030), I1030)
With the function JJmp():
Function JJmp(x) As String
dim iint as variant
iint = x
If IsNull(iint) Then GoTo out:
If Left(iint, 1) <> "_" Then GoTo out:
pat1 = """C:\Program Files (x86)\Adobe\Acrobat 10.0\Acrobat\Acrobat.exe"""
'pat1 = """C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe""" (this is the default, and I don't want to change the reg).
pat3 = "D:\__Numerical_Files_by_Page\" & iint & ".pdf"
pat3 = """" & pat3 & """"
Shell pat1 & " " & pat3, vbNormalFocus
JJmp = x
out:
End Function
For whatever reason the hyperlink based on this function has some very odd behavior. As stated in the title dragging the fill handle doesn't just fill the cells but also opens adobe for each one. Secondly, the hyperlink is super sensitive, I don't have to even click on it--just hovering over it will trigger acrobat 10 to open.
In essence its a very unstable hyperlink in that it is nearly self triggering. If I use the function directly I get an entry that requires some return key gymnastics to open acrobat.
I would just like this to respond like a normal hyperlink. TIA
This behaviour is because everytime you hover over the link or you drag it to a new field, excel tries to resolve the link before you click it meaning it executes your function. How else would it be possible for excel to keep your link up to date and provide it before you click it?
-> Your Function is not executed at the time to click at it as excel thinks, your function returns a link, which it then can follow.
You could try something like this:
herber hype2macro.
then don't use Shell in your UDF. What you want is more like this
Function JJmp(x) As String
If Not IsNull(x) And x Like "_*" Then _
JJmp = """C:\Program Files (x86)\Adobe\Acrobat 10.0\Acrobat\Acrobat.exe"" " & _
"""D:\__Numerical_Files_by_Page\" & x & ".pdf"""
End Function
Can someone help me alter this code so that when it finds the word it will also display the number of times the word appears? Thanks!
Sub findtext()
'
' findrobot Macro
' Will find the word robot
'
' Keyboard Shortcut: Ctrl+t
'
Dim found As Variant
Set found = Sheets("Email").Cells.find("robot", Sheets("Email").Cells(1, 1), xlValues, xlPart)
If (Not found Is Nothing) Then
'found
MsgBox "Words Found =" & found, vbOKOnly, "Found"
Else
'not found
MsgBox "Sorry the text was not found please try again. Macro stopping"
End If
End Sub
Just for fun (and not really stress tested, but seems to work), here is a non-looping version:
Sub test()
Dim Number As Long
Dim str As String
str = "robot"
Number = Evaluate("=SUMPRODUCT(--(NOT(ISERROR(FIND(""" & str & """,A1:AZ6,1)))))")
MsgBox str & " was found " & Number & " times!"
End Sub
Be sure to adjust the range in the Evaluate line (currently A1:AZ6) to suit your situation. Also, I'm pretty sure this will not return the correct results if the word you're looking for appears multiple times in a cell. I've got to run to a meeting, but if you think that will be the case, I can see if I can sort that out a bit later...
I found a VBA code online that opens up an internal (shared drive) PDF document page in IE (e.g. goes to page 8 of PDF file). I would like to display text in the cell for a user to click (e.g. "Click here to view").
Problem: The cell currently displays '0' and I have to go to the function bar and hit [Enter] to execute.
Excel Version: 2003
Function call:
=GoToPDFpage("S:\...x_2011.pdf",8)
VBA Code:
Function GoToPDFpage(Fname As String, pg As Integer)
Set IE = CreateObject("InternetExplorer.Application")
With IE
.Navigate Fname & "#page=" & pg
.Visible = True
End With
End Function
:EDIT:
I was able to display text, but it's still not a link like I wanted.
="Click to view" & GoToPDFpage("S:\...x_2011.pdf",8)
Thank you for your help.
If you dont have a high complex workbook/worksheet you could try the following:
Turn the "Click to view" cell into a Hyperlink with following characteristics.
Make it point to itself
The text inside the cell must always be the string Page= plus the number that you what the pdf to open in. Eg.: Page=8
Then go to the workseet module and paste the following code:
Private Sub Worksheet_FollowHyperlink(ByVal Target As Hyperlink)
If Left(ActiveCell.Value, 4) = "Page" Then
GoToPDFpage Range("A1").Value, Mid(ActiveCell.Value, 6)
'This code asumes that the file address is writen in the cell A1
End If
'
End Sub
'
The above written code will trigger every time you run a hyperlink in the worksheet.
As the hyperlink always point to itself, the "Activecell.Value" will always have the page number that you want to open.
I'm assuming that you can put the file address in the cell A1. You could modify this portion to point to any other cell. (including: The cell to the right of the current hyperlink, etc).
This might not be the best option, but if you only need a quick feature in a couple of cells, it might be enough.
Hope it helps !
EDIT:
To make each HLink reference to itself, you can select all the cells where you have the links and then run this procedure:
Sub RefHLink()
Dim xCell As Range
For Each xCell In Selection
ActiveSheet.Hyperlinks.Add Anchor:=xCell, Address:="", SubAddress:= _
xCell.Address, ScreenTip:="Click Here", TextToDisplay:="Page="
Next xCell
End Sub
how about letting excel write a batch file then running it?
*edit paths to pdf and AcroRd32.exe
Sub batfile()
Dim retVal
filePath = "path\pdf.bat"
pg = 2
Open filePath For Output As #1
Print #1, "Start /Max /w " & Chr(34) & "Current E-book" & Chr(34) & " " & Chr(34) & "C:\Program Files (x86)\Adobe\Reader 11.0\Reader\AcroRd32.exe" & Chr(34) & " /a " & Chr(34) & "page=" & pg & Chr(34) & " " & Chr(34) & "H:\Documents\RPG\Dragonlance\New folder\Sample File.pdf" & Chr(34) & ""
Close #1
retVal = Shell(strFilePath)
End Sub
Try Menu->Data->Data Validation. In the 2nd tab you can write your message.