I have create an xla (excel add-in) that have a function to protect the document (so that user could protect the document without knowing the password). This xla is added in every excel file that need this functionality.
when the xla is installed or added to excel, the protect button will be added in last menu. but when i click the button, an error occur show that
"Cannot run the macro Pivot Add-In 0.2'!protectSheet'". The macro may not be available in this workbook or all macros may be disabled."
The code that event handler onclicked is protectSheet, please see the source below:
Could anyone pointed my why this problem occur?
on ThisWorkbook
'main function'
Public Sub protectSheet()
ActiveWorkbook.ActiveSheet.protect Password:="password", AllowUsingPivotTables:=True
End Sub
Public Sub ShowToolbar()
' Assumes toolbar not already loaded '
Application.CommandBars.Add Module1.TOOLBARNAME
AddButton "Proteksi Sheet", "Memproteksi Pivot", 3817, "protectSheet"
' call AddButton more times for more buttons '
With Application.CommandBars(Module1.TOOLBARNAME)
.Visible = True
.Position = msoBarTop
End With
End Sub
Public Sub AddButton(caption As String, tooltip As String, faceId As Long, methodName As String)
Dim Btn As CommandBarButton
Set Btn = Application.CommandBars(Module1.TOOLBARNAME).Controls.Add
With Btn
.Style = msoButtonIcon
.faceId = faceId ' choose from a world of possible images in Excel: see http://www.ozgrid.com/forum/showthread.php?t=39992 '
.OnAction = methodName
.TooltipText = tooltip
End With
End Sub
Public Sub DeleteCommandBar()
Application.CommandBars(TOOLBARNAME).Delete
End Sub
'called when add-in installed
Private Sub Workbook_AddinInstall()
Call ShowToolbar
End Sub
'called when add-in uninstalled
Private Sub Workbook_AddinUninstall()
Call DeleteCommandBar
End Sub
On module1
Public Const TOOLBARNAME = "PivotTools"
After moving all function to module1 , then retain caller function on ThisWorkbook the error now gone. Seem that i have to define all functionality that call/ use constant (Public Const TOOLBARNAME = "PivotTools") in the same file (in my case in module1)
on module1 file
Public Const TOOLBARNAME = "PivotTools"
'caller method'
Public Sub protectDoc()
On Error GoTo errorInfo
protectSheet
'if success, show msg box'
MsgBox ("Report berhasil diproteksi")
Exit Sub
errorInfo:
MsgBox Err.Description & vbCrLf & Err.Number
End Sub
Public Sub protectSheet()
ActiveWorkbook.ActiveSheet.protect Password:="password", AllowUsingPivotTables:=True
End Sub
Public Sub refreshDoc()
On Error GoTo errorInfo
refreshConnection
protectSheet
'if success, show msg box'
MsgBox ("Report berhasil diperbaharui")
Exit Sub
errorInfo:
MsgBox Err.Description & vbCrLf & Err.Number
End Sub
Private Sub refreshConnection()
ActiveWorkbook.ActiveSheet.Unprotect Password:="password"
ActiveWorkbook.RefreshAll
End Sub
Public Sub ShowToolbar()
' Assumes toolbar not already loaded '
Application.CommandBars.Add TOOLBARNAME
AddButton "Proteksi Sheet", "Memproteksi Pivot", 225, "protectDoc"
AddButton "Refresh Data", "Refresh Pivot", 459, "refreshDoc"
' call AddButton more times for more buttons '
With Application.CommandBars(TOOLBARNAME)
.Visible = True
.Position = msoBarTop
End With
End Sub
Public Sub AddButton(caption As String, tooltip As String, faceId As Long, methodName As String)
Dim Btn As CommandBarButton
Set Btn = Application.CommandBars(TOOLBARNAME).Controls.Add
With Btn
.Style = msoButtonIcon
.faceId = faceId
' choose from a world of possible images in Excel: see http://www.ozgrid.com/forum/showthread.php?t=39992 '
.OnAction = methodName
.TooltipText = tooltip
End With
End Sub
Public Sub DeleteCommandBar()
Application.CommandBars(TOOLBARNAME).Delete
End Sub
on ThisWorkbook
'called when add-in installed
Private Sub Workbook_AddinInstall()
Call Module1.ShowToolbar
End Sub
'called when add-in uninstalled
Private Sub Workbook_AddinUninstall()
Call Module1.DeleteCommandBar
End Sub
I had this issue, but found that I had my module named the same as my sub (e.g. module named as "InsertLineID" and the sub was "InsertLineID").
Changing the module name to "LineID" and leaving the sub as "InsertLineID" worked a treat for me!
Related
My sub Workbook_BeforeClose runs twice, because in my Sub CloseWBFromSharePointFolder, I either check in my file, discard it or cancel and do nothing (see code below). Both the check in and the discarding of the file trigger Workbook_BeforeClose to run again.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
CloseWBFromSharePointFolder
End Sub
Both snippets from CloseWBFromSharePointFolder which trigger Workbook_BeforeClose
Check in
ActiveWorkbook.CheckIn SaveChanges:=True, Comments:="Checked-In by " & Application.Username
Discard
Application.ActiveWorkbook.CheckIn False
Any help would be appreciated.
P.s. I also tried to use a public variable to track if it runs again. This does not work because the public variable got reset. The explanation I found is because Workbook_BeforeClose calls CloseWBFromSharePointFolder, which then triggers Workbook_BeforeClose. This resets everything and the public variable becomes empty
P.s.2 for more details.
CloseWBFromSharePointFolder Code
Sub CloseWBFromSharePointFolder()
Dim myForm1 As UserForm1
Set myForm1 = UserForm1
myForm1.Caption = "Choose before closing:"
myForm1.Show
End Sub
UserForm1 Code
Dim Buttons() As New BtnClass
Private Sub UserForm_Initialize()
Dim ButtonCount As Integer
Dim ctl As Control
' Create the Button objects
ButtonCount = 0
For Each ctl In UserForm1.Controls
If TypeName(ctl) = "CommandButton" Then
'Skip the OKButton
If ctl.Name <> "OKButton" Then
ButtonCount = ButtonCount + 1
ReDim Preserve Buttons(1 To ButtonCount)
Set Buttons(ButtonCount).ButtonGroup = ctl
End If
End If
Next ctl
Me.CommandButton1.Caption = "Check in"
Me.CommandButton2.Caption = "Discard check-out"
Me.CommandButton3.Caption = "Keep checked-out"
Me.CommandButton4.Caption = "Cancel"
End Sub
BtnClass Code
Public WithEvents ButtonGroup As MsForms.CommandButton
Private Sub ButtonGroup_Click()
If UserForm1.Visible = True Then
Select Case ButtonGroup.Name
Case "CommandButton1" 'check in
CheckIn
Case "CommandButton2" 'Discard check-out
Discard
Case "CommandButton3" 'Keep checked-out
KeepCheckedOut
Case Else ' Cancel
'Do Nothing
End Select
Unload UserForm1
ElseIf UserForm2.Visible = True Then
Select Case ButtonGroup.Name
Case "CommandButton1" 'check out
CheckOut
Case "CommandButton2" 'Read only
'Do Nothing
Case Else ' Cancel
'Do Nothing
End Select
Unload UserForm2
End If
End Sub
Sub CheckIn()
If ActiveWorkbook.CanCheckIn = True Then
'Check In, Save and Close
ActiveWorkbook.CheckIn SaveChanges:=True, Comments:="Checked-In by " & Application.Username
MsgBox ("File sucessfully checked in")
Else
MsgBox ("File could not be checked in!")
End If
End Sub
I have a button in the "code module" which runs a request. Next to the Button is a label included which shows a check mark a soon as the button has finished running.
The button code is in the code modul. The codes for the label with the check mark is inlcuded in the workbook and sheet modul.
Now, the issue is when I push the button it runs perfectly fine and does what it supposed to but the label with the check mark does not get activated. The reason might be because I have not included/referenced the workbook/sheet modul in my code modul. Hope for a bit help.
Code in workbook Module:
Option Explicit
Private Sub Workbook_Open()
Call Tabelle1.prcResetLabels
End Sub
Code in Sheet Module:
Option Explicit
Private Sub Schaltfläche2_Klicken()
Call prcSetLabel(probjLabel:=Label1)
End Sub
Private Sub prcSetLabel(ByRef probjLabel As MSForms.Label)
With probjLabel
.Caption = "P"
End With
End Sub
Friend Sub prcResetLabels()
Dim objOLEObject As OLEObject
For Each objOLEObject In OLEObjects
With objOLEObject
If .progID = "Forms.Label.1" Then _
.Object.Caption = vbNullString
End With
Next
End Sub
Code in Codemodul:
Public Sub Schaltfläche2_Klicken()
With Sheets("Table1")
.Range("A1").End(xlUp).Offset(1, 0).Value = Environ("USERNAME")
End With
End Sub
The answer ist simple this:
Sub Schaltfläche2_Klicken()
Call prcResetLabels
With Sheets("Table1")
.Range("A1").End(xlUp).Offset(1, 0).Value = Environ("USERNAME")
End With
Call prcSetLabel(probjLabel:=Table1.Label1)
End Sub
Private Sub prcSetLabel(ByVal probjLabel As Object)
With probjLabel
.Object.Caption = "P"
End With
End Sub
Public Sub prcResetLabels()
Dim objOLEObject As OLEObject
For Each objOLEObject In Table1.OLEObjects
With objOLEObject
If .progID = "Forms.Label.1" Then _
.Object.Caption = vbNullString
End With
Next
End Sub
EDIT: To clarify, the code seen below is within a module and the UserForm is all contained within its own code.
I have the following code. When I go to run it, Excel throws me a compile error: Method or data member not found and highlights the following piece of code: .showInputsDialog. I have no idea how to resolve this error.
To give more information, the sub sportUserForm is supposed to call up a UserForm sportsUsrFrm. Any help with this issue is greatly appreciated.
Option Explicit
Sub sportUserForm()
Dim sSport As String, sPreference As String
If sportsUsrFrm.showInputsDialog(sSport, sPreference) Then
MsgBox "Your favorite sport is " & sSport & ", and you usually " _
& sPreference & "."
Else
MsgBox "Sorry you don't want to play."
End If
End Sub
Public Function showInputsDialog(sSports As String, sPreference As String) As Boolean
Call Initialize
Me.Show
If Not cancel Then
If optBaseball.Value Then sSport = "Baseball"
ElseIf optBasketball.Value Then sSport = "Basketball"
Elss sSport = "Football"
End If
If optTV.Value Then sPreference = "watch on TV" _
Else: sPreference = "go to games"
End If
showInputsDialog = Not cancel
Unload Me
End Function
UserForm code for sportUsrFrm
Option Explicit
Private Sub cmdCnl_Click()
Me.Hide
cancel = True
End Sub
Private Sub cmdOK_Click()
If Valid Then Me.Hide
cancel = False
End Sub
You're getting the error because showInputsDialog isn't a member of the form, it's a member of the module you're calling it from. You should also be getting compiler errors on these two lines...
Call Initialize
Me.Show
...because you seem to be getting the module and form code mixed up.
That said, you're overthinking this. A UserForm is a class module, and it can be stored in a variable (or in this case, in a With block), and can have properties. I'd add a Cancelled property to the form:
'In sportsUsrFrm
Option Explicit
Private mCancel As Boolean
Public Property Get Cancelled() As Boolean
Cancelled = mCancel
End Property
Private Sub cmdCnl_Click()
Me.Hide
mCancel = True
End Sub
Private Sub cmdOK_Click()
If Valid Then Me.Hide '<-- You still need to implement `Valid`
End Sub
And then call it like this:
Sub sportUserForm()
With New sportsUsrFrm
.Show
Dim sSport As String, sPreference As String
If Not .Cancelled Then
If .optBaseball.Value Then
sSport = "Baseball"
ElseIf .optBasketball.Value Then
sSport = "Basketball"
Else
sSport = "Football"
End If
If .optTV.Value Then
sPreference = "watch on TV"
Else
sPreference = "go to games"
End If
MsgBox "Your favorite sport is " & sSport & ", and you usually " _
& sPreference & "."
Else
MsgBox "Sorry you don't want to play."
End If
End With
End Sub
I'm trying to make an Excel Add-In to create a simple button when any workbook is opened, but I'm getting
Object variable or With Block variable not set
I think this is happening because technically there is no 'ActiveWorkbook' yet.
First thing I want to do is delete any buttons currently on the sheet. Then I want to place a button.
Anyone know how to make that happen?
Code
Private Sub Workbook_Open()
ActiveWorkbook.ActiveSheet.Buttons.Delete
Dim CommandButton As Button
Set CommandButton = ActiveWorkbook.ActiveSheet.Buttons.Add(1200, 100, 200, 75)
With CommandButton
.OnAction = "Test_Press"
.Caption = "Press for Test"
.Name = "Test"
End With
End Sub
I then have a Private Sub Test_Press() to display a MsgBox. The button is not being created though.
Credit goes to http://www.jkp-ads.com/Articles/FixLinks2UDF.asp
Note: I have another module I didn't post below, which houses the macro Project_Count I tied to the button I place on the workbook only if the workbook name is TT_GO_ExceptionReport
I also have a VBScript that downloads the Add-In, places it in the users addin folder, and installs it. If you want to know how to do that, leave a comment.
Code of Add-In that solved the problem:
ThisWorkbook
Option Explicit
Private Sub Workbook_Open()
' Purpose : Code run at opening of workbook
'-------------------------------------------------------------------------
'Initialise the application
InitApp
modProcessWBOpen.TimesLooped = 0
Application.OnTime Now + TimeValue("00:00:03"), "CheckIfBookOpened"
End Sub
Module 1 named modInit
Option Explicit
'Create a module level object variable that will keep the instance of the
'event listener in memory (and hence alive)
Dim moAppEventHandler As cAppEvents
Sub InitApp()
'Create a new instance of cAppEvents class
Set moAppEventHandler = New cAppEvents
With moAppEventHandler
'Tell it to listen to Excel's events
Set .App = Application
End With
End Sub
Module 2 named modProcessWBOpen
Option Explicit
'Counter to keep track of how many workbooks are open
Dim mlBookCount As Long
'Counter to check how many times we've looped
Private mlTimesLooped As Long
' Purpose : When a new workbook is opened, this sub will be run.
' Called from: clsAppEvents.App_Workbook_Open and ThisWorkbook.Workbook_Open
'-------------------------------------------------------------------------
Sub ProcessNewBookOpened(oBk As Workbook)
If oBk Is Nothing Then Exit Sub
If oBk Is ThisWorkbook Then Exit Sub
If oBk.IsInplace Then Exit Sub
CountBooks
'This checks to make sure the name of the new book matches what I
'want to place the button on
If oBk.Name = "TT_GO_ExceptionReport.xlsm" Then
Dim CommandButton As Button
Set CommandButton = Workbooks("TT_GO_ExceptionReport.xlsm").Sheets(1).Buttons.Add(1200, 100, 200, 75)
With CommandButton
.OnAction = "Project_Count"
.Caption = "Press for Simplified Overview"
.Name = "Simplified Overview"
End With
End If
End Sub
Sub CountBooks()
mlBookCount = Workbooks.Count
End Sub
Function BookAdded() As Boolean
If mlBookCount <> Workbooks.Count Then
BookAdded = True
CountBooks
End If
End Function
' Purpose : Checks if a new workbook has been opened
' (repeatedly until activeworkbook is not nothing)
'-------------------------------------------------------------------------
Sub CheckIfBookOpened()
If BookAdded Then
If ActiveWorkbook Is Nothing Then
mlBookCount = 0
TimesLooped = TimesLooped + 1
'May be needed if Excel is opened from Internet explorer
Application.Visible = True
If TimesLooped < 20 Then
Application.OnTime Now + TimeValue("00:00:01"), "CheckIfBookOpened"
Else
TimesLooped = 0
End If
Else
ProcessNewBookOpened ActiveWorkbook
End If
End If
End Sub
Public Property Get TimesLooped() As Long
TimesLooped = mlTimesLooped
End Property
Public Property Let TimesLooped(ByVal lTimesLooped As Long)
mlTimesLooped = lTimesLooped
End Property
Class Module named cAppEvents
' Purpose : Handles Excel Application events
'-------------------------------------------------------------------------
Option Explicit
'This object variable will hold the object who's events we want to respond to
Public WithEvents App As Application
Private Sub App_WorkbookOpen(ByVal Wb As Workbook)
'Make sure newly opened book is valid
ProcessNewBookOpened Wb
End Sub
Private Sub Class_Terminate()
Set App = Nothing
End Sub
something like this?
Option Explicit
Sub Button()
Dim cButton As Button
Dim rng As Range
Dim i As Long
ActiveSheet.Buttons.Delete
For i = 2 To 3 Step 2
Set rng = ActiveSheet.Range(Cells(i, 2), Cells(i, 2))
Set cButton = ActiveSheet.Buttons.Add(rng.Left, rng.Top, rng.Width, rng.Height)
With cButton
.OnAction = "Test_Press"
.Caption = "Press for Test " & i
.Name = "Test" & i
End With
Next i
End Sub
See Example here
Trying out Tim Lovell-Smiths' UltimateTimer project.
http://blogs.msdn.com/b/tilovell/archive/2014/01/29/a-light-weight-net-threadpool-timer-class.aspx
http://blogs.msdn.com/b/tilovell/archive/2014/01/31/sample-using-ultimatetimer-threadpooltimer.aspx
Trying to convert his C# to VB.net but his function(lambda??) in Sub Main Line 2 is not correct translation / syntax ?? - "EXPRESSION DOES NOT PRODUCE A VALUE"
1) How do I fix that Function Error in Line Two of Sub Main in VB.net
2) Is My Code properly set up to start the Timer from my SheetBeforeDoubleClick Event ?
3) Is My Code properly set up to end the Timer from my SheetBeforeDoubleClick Event ?
Imports Microsoft.Office.Interop.Excel
Imports Microsoft.Office.Core
Imports ExcelDna.Integration
Imports System.Threading
Imports UltimateTimer
Public Class AddIn
WithEvents Application As Application
Shared timer As ThreadPoolTimer
Private Shared Sub Main(ByVal args() As String)
'ERROR NEXT LINE "EXPRESSION DOES NOT PRODUCE A VALUE" - OnTimer(timer)
timer = ThreadPoolTimer.Create(Function() OnTimer(timer))
timer.SetTimer(DateTime.Now.AddSeconds(3), msPeriod:=0, acceptableMsDelay:=0)
Console.WriteLine("Press any key to stop timer")
Console.ReadLine()
timer.Dispose()
End Sub
Private Shared Sub OnTimer(timer As ThreadPoolTimer)
Console.WriteLine("Timer was called back! Resetting timer. The time is now " & DateTime.Now.ToString())
timer.SetTimer(DateTime.Now.AddSeconds(3), 0, 0)
End Sub
Private Shared Sub Endtimer(timer As ThreadPoolTimer)
timer.Dispose()
End Sub
Private Sub Application_SheetBeforeDoubleClick(Sh As Object, Target As Range, ByRef Cancel As Boolean) Handles Application.SheetBeforeDoubleClick
If Target.Address = "$A$1" Then
OnTimer(timer)
MsgBox("TIME Is On My Side!!", , "Yeppers")
ElseIf Target.Address = "$Z$1" Then
Endtimer(timer)
MsgBox("I Stopped TIME !!", , "Oh-Ho")
End If
End Sub
End Class
Thanks… :o)
EDIT: Oct 12, 2014
Okay with Dave D's help I got Tim's UltimateTimer working for me in vb.net and as part of my Excel ExcelDNA xLL AddIn.
Here is the Imports, code and sample Framework (and other code i am using for my xLL AddIN tests) for this timer to work inside a packed xLL for Excel use.
I am calling it from a double click but it could be called from a right click menu... etc.
Public Module MyFunctions
<ExcelFunction(Description:="My first .NET function")> _
Public Function dnaHello(name As String) As String
Return "Hello " & name
End Function
End Module
Public Class AddIn
Implements IExcelAddIn
WithEvents Application As Application
WithEvents Button As CommandBarButton
Public Sub AutoOpen() Implements IExcelAddIn.AutoOpen
Application = ExcelDnaUtil.Application
' Add Cell context menu
Dim ContextMenu As CommandBar
ContextMenu = Application.CommandBars("Cell")
Button = ContextMenu.Controls.Add(Type:=MsoControlType.msoControlButton, Before:=ContextMenu.Controls.Count, Temporary:=True)
With Button
.Caption = "Excel-DNA Test Button"
.Tag = "EXCEL-DNA-Test"
End With
End Sub
Public Sub AutoClose() Implements IExcelAddIn.AutoClose
Button.Delete()
End Sub
Shared timer As ThreadPoolTimer
Private Shared Sub TimerMain()
timer = ThreadPoolTimer.Create(Sub() OnTimer(timer))
timer.SetTimer(DateTime.Now.AddSeconds(3), msPeriod:=0, acceptableMsDelay:=0)
End Sub
Private Shared Sub OnTimer(timer As ThreadPoolTimer)
MsgBox("TIME Is On My Side!!" & DateTime.Now.ToString(), , "Yeppers")
timer.SetTimer(DateTime.Now.AddSeconds(3), 0, 0)
End Sub
Private Shared Sub Endtimer(timer As ThreadPoolTimer)
timer.Dispose()
End Sub
Private Sub Application_SheetBeforeDoubleClick(Sh As Object, Target As Range, ByRef Cancel As Boolean) Handles Application.SheetBeforeDoubleClick
If Target.Address = "$A$1" Then
MsgBox("TIME Is On My Side!!", , "Yeppers")
TimerMain()
ElseIf Target.Address = "$E$1" Then
Endtimer(timer)
MsgBox("I Stopped TIME !", , "Oh-Ho")
End If
End Sub
Private Sub Button_Click(Ctrl As CommandBarButton, ByRef CancelDefault As Boolean) Handles Button.Click
Application.StatusBar = "Excel-DNA Test Button - Clicked!"
End Sub
End Class