My shortcut key will not allow me to run a message box - vba

Previous versions of this code had no message box, which sometimes resulted in the wrong workbook being closed. I added an okcancel message box to keep this from happening, but the message box doesn't show up when I use a shortcut key to open it. What am I missing?
Sub openerQuick()
Dim myfile As String
Dim clientID As String
Dim PDSfilename As String
Dim myopener As Variant
clientID = ActiveCell
PDSfilename = ActiveCell.Offset(0, 1)
myfile = "N:\DOWNLOAD\FILEDIR\" & clientID & "\original\" & PDSfilename
Set wbOpener = Workbooks.Open(myfile)
If MsgBox("Okay to close?", vbOKCancel) = vbOK Then
ActiveWorkbook.Close
End If
End Sub

I doubt the MsgBox itself has anything to do with losing the macro shortcut key.
Shortcut keys are defined by a hidden member attribute value, and the VBE has a tendency to lose member attributes when you rewrite a method's signature, or rewrite a module*; it's possible that modifying the code caused the previously existing attribute to somehow get lost.
Remove the module from the project, pick "Yes" when prompted whether to export or not
Open the exported file in Notepad++ your favorite text editor
Locate the procedure
Add the attribute if it's not there
Save the file if it was changed, re-import into the project
The member attribute should look something like this:
Public Sub OpenerQuick()
Attribute OpenerQuick.VB_ProcData.VB_Invoke_Func = "A\n14"
'...code....
End Sub
That exact attribute associates Ctrl+Shift+A to the macro; change the A for whichever letter rocks your boat to change the shortcut.
When you record a macro in Excel and specify A for a shortcut key, the macro recorder automatically adds this hidden attribute for you.
* Rubberduck's module rewriters have that very problem and it's driving me nuts.

In a module write the following 2 subs:
Public Sub OpenerQuick()
If MsgBox("Okay to close?", vbOKCancel) = vbOK Then ActiveWorkbook.Close
End Sub
Public Sub InitiateMe()
Application.OnKey "{a}", "OpenerQuick"
End Sub
Run only InitiateMe. Now, when you press a, InitiateMe would be triggered.

Related

VBA Word Macro to Allow User to Select and Copy Text Multiple Times

I am working on a VBA script with Microsoft Word that allows the user to select text that will be be copied to the clipboard so that it can exported to an Excel file. The user will make a number of selections and finally indicate he/she is done when the contents of the clipboard will be copied to a template Excel file.
There are two forms: the first (UserForm1 in the code below) queries the user for the Word filename. The filename variable is passed to the second form. The second form (frmModeLessForInput) is a modeless form. The behavior I need is that program control goes to the second form with two buttons "Continue" and "Done".
The user is allowed to navigate the document and place the cursor anywhere in the document. Then when "Continue" is pressed the form will call a subroutine (Highlight_Sentence) to copy the selected text to a "clipboard" variable. When "Done" is pressed control will be passed to called main module which will then copy the clipboard to the Excel file.
Below is the code. I have noted with comments where I am trouble with the code. One problem is the variables defined as Public in the ThisDocument module are not defined in the userforms and their subroutines.
The second problem is in the main module that the frmModelessForInput is supposed to be displayed and control is not supposed to be transferred to next statement {MsgBox "Sentences will now be copied to Excel file"....this is where I will put the code to copy the clipboard to the Excel file.} but the message appears before the frmModelessForInput form is run...thus the clipboard will be empty.
The third problem is that in frmModelessForInput form the statement str_clipboard = str_clipboard + str_clipboard_line is not working. Each time the "Continue" button is pushed str_clipboard loses it previous contents.
Any assistance in resolving these problems is appreciated. As VBA programming is a sideline for me I am still learning.
Note this an updated question Pause VBA Word macro, allow user to make a selection, and restart where it left off adding some more detail on the requirement and the sample code.
MAIN MODULE:
Option Explicit
Public str_clipboard As String
Public txt_active_document As String
Public i_how_many_sentences As Integer
Private Sub Test_master_macro()
UserForm1.Show
i_how_many_sentences = 0
Call DisplayModeless
MsgBox "Sentences will now be copied to Excel file" 'Problem: this msg displays before the frmModelessForInput is displayed
End Sub
Sub DisplayModeless()
Dim frm As frmModelessForInput
Set frm = New frmModelessForInput
With frmModelessForInput
.str_word_doc_filename = txt_active_document
.str_no_copied = "0"
.Show False
End With
Set frm = Nothing
End Sub
USERFORM1: form has field for user entering the document filename to user (str_filename) and a command button to close form (cmd_start_selecting_text)
Private Sub cmd_start_selecting_text_Click()
'User enters filename on form for use in frmModelessForInput subroutine
txt_active_document = UserForm1.str_filename 'Problem: VBA reports txt_active_document as undefined even though it is a Public variable
Unload Me
End Sub
FRMMODELESSFORINPUT: Form displays filename of Word file entered in UserForm1 and how many sentences have been copied to the clipboard
Option Explicit
Private Sub cmdContinue_Click()
Dim str_clipboard, str_clipboard_line As String
Call Highlight_Sentence(str_clipboard_line)
i_how_many_sentences = i_how_many_sentences + 1 'Problem: VBA reports i_how_many_sentences as undefined even though it is a Public variable
frmModelessForInput.str_no_copied = i_how_many_sentences 'Same Problem
str_clipboard = str_clipboard + str_clipboard_line 'Problem: each time I select a new text/sentence str_clipboard does not contain the contents of the previous selection
End Sub
Private Sub cmdDone_Click()
Me.Hide
End Sub
Private Sub UserForm_Activate()
'Position the form near the top-left of the window
'So that the user can work with the document
Me.Top = Application.ActiveWindow.Top + 15
Me.Left = Application.ActiveWindow.Left + 15
End Sub
Private Sub Highlight_Sentence(clipboard As String)
'This sub extends the selection to the entire sentence and copies the selection, the page number on which the selection is contained and the filename to the clipboard variable
Dim txt_sentence, txt_page_no As String
With Selection
' Collapse current selection.
.Collapse
' Expand selection to current sentence.
.Expand Unit:=wdSentence
End With
txt_sentence = Selection.Text
txt_page_no = Selection.Information(wdActiveEndPageNumber)
clipboard = txt_active_document & vbTab & txt_page_no & vbTab & txt_sentence & vbCrLf 'Problem: VBA reports txt_active_document as undefined even though it is a Public variable
End Sub
From what you stated you are running this from the ThisDocument Class Module and unless you fully qualify your references to those Public variables with the Class Name that is why you cannot access them from the UserForms Class Modules.
If you are going to leave your "Main Module" code in the ThisDocument Class Module then whenever you reference those Public variable you need to add ThisDocument.str_clipboard to the command.
I recommend however, to place your Main Module in a general Module such as NewModule and if you need to run it at a Document_Open event that you put a call to the Main Module and its Public variables in the Private Sub Document_Open event of the ThisDocument Class Module.
Your Msgbox is appearing at the wrong time because you are displaying a modeless user form, which means the VBA script thread continues to run after the UserForm is displayed. Move the Msgbox to the UserForm_Activate routine of the second UserForm you are displaying or move it to the Click_Done routine of the first UserForm before you Hide or Unload it.
Finally, you are not really using the Clipboard and using that term makes your code confusing in my opinion. I think you should rename it. Your code also appears to just be building one continuous string of text. Is that really what you want to do? Or, do you really mean to capture each selected text string and ultimately place each into separate cells within an Excel Worksheet? If that is the case, use an Array for the separate text strings.

VBA code crashes after saving - says the situation lies with the XML "Run-time error '429'

I made a worksheet for the company I work for to help with pricing out custom designs. A few months ago I made a macro that can save the parts to a text file that can be pulled from at a later date if we wanted to quote out the same design. Everything was working perfectly, until one day I go to open it up and got the error message
We found a problem with some content in 'File.xlsm'. Do you want us to try
to recover as much as we can?
When I click yes, it then comes up with the worksheet the macro was on completely un-formatted and says it could only open the file by repairing or removing the following part
Repaired Part: /xl/worksheets/sheet3.xml part.
This is weird because the only xml code I use is just to create a drop-down menu when the saved design names are loaded. Nothing has changed since the final revision of the code other than the amount of designs that have been saved. The boxes I had as buttons tied to macros have been deleted and none of the code for this sheet works. What it shows when I view the code now is Sheet_Thumbnails
All other macros work, the other sheets are fully functional. When I try and run the code on this sheet I get
Run-time error '429':
ActiveX component can't create object
This has to be when compiling because I can't even debug where this is happening. The best answer I get when I look this error up is that I am not using the "New" keyword when calling a file or object from somewhere else. But I have looked through my code and don't see anywhere that applies. Luckily a co-worker saved a copy off our server to her computer so I have a backup, but when I open this and run the macros then save and re-open, the same crash happens.
Here is the code with xml:
Sub MakeList(ByRef r As Range, ByRef Config As String)
r.Clear
If Not Config = "" Then
r.Select
With Selection.Validation
.Delete
.Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, Formula1:=Config
.IgnoreBlank = True
.InCellDropdown = True
.InputTitle = ""
.ErrorTitle = ""
.InputMessage = ""
.ErrorMessage = ""
.ShowInput = True
.ShowError = True
End With
End If
End Sub
Can anyone help me? I am at a total loss for why this has happened and why it keeps happening. Is it the validation part? Why would it happen after working for months?
Thank you in advance.
EDIT 1
Exporting all of the code and creating a new workbook did not solve the problem.
Thanks to Profex, the problem has been found and is in the validation. Essentially one of my lists was too long. The formula used in validation is not supposed to be beyond 255 characters. Even though Excel doesn't give any warning on this, when I would create the drop down menus, although it would populate each item from the list, after saving closing and re-opening, apparently this would corrupt the coded sheet. So now the question lies with how to add values into a drop-down menu without clearing and re-initializing with a longer list. Should I post a new question for that?
In Excel, Cell Validation Lists have a 8191 character limit (which is way too long for a user to pick from anyway).
Anything over 254 characters will corrupt the file upon save/re-open.
Here is something similar to what I have done in the past to create Dynamic Validations lists:
It uses your MakeList() subroutine, and requires another GetList() function to get the validation list for the specified cell.
Since this code is in the Workbook module, I also added another function called IsSheetTheOneICareAboutWithValidations(). If you use the WorksSheet_SelectionChange Event from in a specific sheet module, this isn't required; but you would have to change the scope of m_ValidationCell and m_ValidationList to be Public.
This code is untested and goes in the ThisWorkbook module:
Option Explicit
Private m_ValidationCell As Excel.Range
Private m_ValidationList As String
Private Sub Workbook_BeforeSave(ByVal SaveAsUI As Boolean, Cancel As Boolean)
If Not m_ValidationCell Is Nothing Then
m_ValidationList = m_ValidationCell.Validation.Value
m_ValidationCell.Validation.Delete
End If
End Sub
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
If m_ValidationList <> vbNullString Then
With m_ValidationCell.Validation
.Add Type:=xlValidateList, Formula1:=ValidationList
End With
m_ValidationList = vbNullString
End If
End Sub
Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
If Not m_ValidationCell Is Nothing Then
m_ValidationCell.Validation.Delete
Set m_ValidationCell = Nothing
End If
If IsSheetTheOneICareAboutWithValidations(Sh) Then
' Since we're changing the Validation each time there is a new Selection;
' It's the Active Cell that matters, not the Target range
' Add a validation list to any cell in column 4, after the header (in row 1).
If ActiveCell.Column = 4 And ActiveCell.Row > 1 Then
List = GetList(ActiveCell)
MakeList ActiveCell, List
' Should probably add this next line to you MakeList() function
Set m_ValidationCell = ActiveCell
End If
End If
End Sub
Private Function GetList(Target As Range) As String
GetList = vbNullString ' or whatever you want
End Function
Private Function IsSheetTheOneICareAboutWithValidations(Sh As Object) As Boolean
IsSheetTheOneICareAboutWithValidations = (Sh.Name = "Pricing")
End Function
Recovery
It looks like you just had a bad save. Sometimes it just corrupts the file and there isn't much you can do, other then hope you have a backup.
Right Click in the Folder > Properties > Previous Versions
If you don't have a backup, it might just help to move everything to a new file.
Create a New Workbook
Select All cells from your first sheet (click above the 1, left of the A)
Press Ctrl+C to Copy
Select All cells in your New Workbook/Sheet
Press Ctrl+V to Paste
Repeat for all Worksheets
On the VB side of things, you can just Drag the Forms/Modules/Classes from the Old file to the New One.
Issue
Did you know that all New Office documents are really just ZIP files...
Go ahead, rename the file to File.xlsm.zip
Inside the file you'll see a folder structure which should have .../xl/worksheets/sheet3.xml
This is what excel is complaining about! That file is either missing or wrong.
Code
I don't know how you're calling Makelist, so I can't verify that the range R that you are passing is valid.
Please remove the Select/Selection from your code. You don't need to select anything in the front end GUI of Excel to access/change the cells. Also you didn't check if R was Nothing.
Sub MakeList(ByRef r As Range, ByRef Config As String)
If Not r Is Nothing then
r.Clear
If Not Config = "" Then
With r.Validation
...
End With
End If
End If
End Sub

Input Box on workbook open

I am trying to come up with some vba code to open an input box automatically as soon as the workbook is opened and have the user enter a date and then have the date placed in the A1 cell. I have written the code below but the input box is not pulling up at all it just opens the workbook and moves on.. not sure what is happening. Any and all help is appreciated.
Thanks!
Option Explicit
Private Sub workbook_open()
Dim cellvalue As Variant
Dim ws As Worksheet
Set ws = Worksheets("Workbench Report")
ReShowInputBox: cellvalue = Application.InputBox("Please Enter Todays Date (dd/mm/yyyy)")
If cellvalue = False Then Exit Sub
If IsDate(cellvalue) And CDate(cellvalue) < Date Then
ws.Range("A1").Value = DateValue(cellvalue)
Else: MsgBox ("Invalid Date!")
GoTo ReShowInputBox
End If
End Sub
Your code triggers upon the Workbook opening for me. Try these steps.
Open up Excel and Save As, changing the extension to .XSLM
Open up the VBA Editor (ALT + F11)
In the left-hand window, locate your macro file (the one you just created and named - it's in brackets after "VBA Project"), drilldown to "This Workbook" and double-click it.
Paste your code into the right-hand window
Save the file and re-open.
See attached diagram.
By the way, "cellValue = false" should probably be cellValue = "" since InputBox is returning a string and not a boolean value.
For Workbook_Open events the script needs to reside in the private module (ThisWorkbook)
From Ozgrid:
the Workbook_Open event is a procedure of the Workbook Object and as
such, the Workbook_Open procedure MUST reside in the private module of
the Workbook Object (ThisWorkbook).

Insert text string through other macro with Excel VBA

I'm having an issue and dont know if this is possible to be done.
I need to insert a string variable through another macro that is protected and can't access the VBA code.
At my code, I intend to send a string when call the protected macro (with application.run "macroname"). This protected macro prompts a selection window to select a file. I pretend to automatically insert at macro's prompt my string and send "ENTER" command to open the desire file.
Is this possible to be done?
If I understood you correctly, this is what you are looking for:
1) Locked workbook (VBA module is protected) contains e.g. the following macro:
Public Sub Test(sInput As String)
ActiveCell.Value = sInput
MsgBox sInput
End Sub
What you are trying to do, is to call this Test macro, but you don't know how to pass parameter (correct me if I got this wrong).
This is how you do it:
Sub RunProtectedMacro()
Dim vResult As Variant
vResult = Application.Run("'" & LockedWorkbook.Name & "'!Test", "some string argument")
End Sub

Looking for a new method to create 'check-in' and 'check-out' system

I am currently working on a database for a small building with a large number of HDDs and the system I have made so far works exactly as my employer desires it to.
My current problem is with some VBA coding using macros to sign in and sign out each hard drive, the hard drives have a row each with a 'check in' and 'check out' button at the end. At current moment the coding works for both of these buttons but I have to write out the code for every single button both 'check in' and 'check out'.
Is there a way to convert the location of the button into a string which would then add itself into the coding and I can put in some sort of array that will auto locate the output of each button for me?
The macro is a simple .Show statement.
My excel sheet is illustrated below. Most of the current cells are programmed with formulas as this system needs to be fairly automated for the less skilled computer users.
Edit:
After clicking the button my initials are added to the end of current time/date. This needs to happen for many buttons all results being in different cells.
My recommendation would be to avoid using a button, and instead override the SelectionChanged event handler for the worksheet. Change the buttons to formatted cells, which when clicked will perform the action you desire.
First, configure your UserForm to return a value. One way to do this is by placing the following code into the code-behind for the UserForm:
Public Property Get Initials() As String
Initials = txtInitials.Text
End Property
Public Property Let Initials(ByVal sInitials As String)
txtInitials.Text = sInitials
End Property
Private Sub btnOk_Click()
Me.Hide
End Sub
Next, add the following code to Sheet1:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim sInitials As String
Dim sDate As String
Dim sTime As String
Dim frmInitials As InitialsForm
If Target.Column = 13 Then
Set frmInitials = New InitialsForm
frmInitials.Show
sInitials = frmInitials.Initials
Unload frmInitials
sDate = Date
sTime = Time
Cells(Target.Row, 6).Value = sDate + " / " + sTime + " " + sInitials
End If
End Sub
When the user clicks on a cell in column 13 (M - "Check Out"), a userform will be displayed asking for the user's initials. Once they have entered them and pressed the OK button, the initials will be added to the end of the timestamp and inserted into column 6 (F) of the same row.