全局variables是空的,如果2个相同的xls文件具有相同的macros打开
Excel中有macros已经被写入,并有错误报告,我必须解决这个问题。 初步调查如下…有macro
ABC.xls
文件。
现在,这个macros有一个名为changeTheCode
的sub
changeTheCode
,当我按下Ctrl + M
时,它将被调用。
这个小组将打开一个Open File Dialog
,用户可以select一个CSV文件。 我存储在全局variables中的CSV文件的path声明在所有函数之外
Public txtFileNameAndPath As String
当用户closuresexcel时,将使用此全局variables将更改保存到CSV文件中。
Private Sub Workbook_BeforeClose(Cancel As Boolean) Call saveUnicodeCSV Call deleteXLS End Sub
我使用这个ABC.xls
文件来打开一个ABC123.CSV
文件。
我使用这个DEF.xls
( DEF.xls
的副本)文件来打开DEF123.CSV
文件。 但是当我用Ctrl + M
打开DEF123.CSV
时, DEF123.CSV
的sub changeTheCode
被调用, txtFileNameAndPath
的全局variablesDEF.xls
为空,当我closuresExcel时,事情并没有得到保存,因为这个。
全局variables正在被设置的代码。
Public txtFileNameAndPath As String Sub CodePageChange() Dim SheetName As Worksheet Dim fd As Office.FileDialog Dim sheetName1 As String Dim tabSheetName As String Set fd = Application.FileDialog(msoFileDialogFilePicker) With fd '.... '.... '.... If .Show = True Then txtFileNameAndPath = .SelectedItems(1) Else MsgBox "Please start over. You must select a csv file." Exit Sub End If End With
关于如何处理这个问题的input将会帮助我很多。
注意:包含macros的Excel将被提供给客户。 因此,我不能要求客户做一些registry调整,以单独的实例打开Excel。
谢谢。
我认为的问题是,当您将相同的macros名称绑定到快捷键时,打开的第一本书将被分配到该快捷键。
解决方法是使另一个macros根据工作簿名称调用正确的macros。 这可能需要您将一些工作簿和工作表replace为ActiveWorkbook或ActiveWorksheet。 但请先尝试一下。
这只是我试用的示例代码,但请编辑它以满足您的需求。 我试了两个文件a.xlsm和b.xlsm。 差异是a.xlsm在第一行有msgbox“a”,而b.xlsm在第一行有msbox“b”。 您先打开a.xlsm然后b.xls。 然后分配相同的快捷键。 你将会看到,当你在b.xlsm中运行Ctrl + M时,将运行的macros将在msgsbox为“A”的a.xlsm中,然后在b.xlsm中调用正确的macros。
简答
此代码使用从特定工作簿运行macros的Application.Run
。 创build一个帮助macros将检查文件名,然后附加macros名称。
所以,当你按Ctrl + M,无论哪个工作簿run_code运行,它将返回到activeworkbook,并从该工作簿运行macros,在这种情况下,石膏。 此外,它将使用activeworkbook值填充公共variables。
https://www.rondebruin.nl/win/s9/win001.htm application.run的一些示例
到目前为止,最简单的解决scheme只是添加来电macros
来电者macros:
Sub call_changeTheCode() ' add to all workbooks, that have changeTheCode macro then assign to Ctrl + m Application.Run ActiveWorkbook.Name & "!changeTheCode" End Sub
概念certificate,而不是你的实际代码,使用上面的调用macros:
Public varvar As String Sub run_code() 'assignt to shortcut key CTRL+M both macros in a.xlsm and b.xlsm MsgBox "a" ' to test create another workbook and change this to b file_path = ActiveWorkbook.Path 'just to check path file_name = ActiveWorkbook.Name 'gets the file name MsgBox file_path 'msgbox the file_path MsgBox file_name 'msgbox the file_name MsgBox file_name & "!plaster" 'msgbox the file name plus macro name, in your instance it would be "ABC.xlsm'!macro_name" please note the format Application.Run file_name & "!plaster" End Sub Sub plaster() 'this is the test macro that will show correct macro in workbook is called varvar = ActiveWorkbook.Name MsgBox "hi this is workbook " & varvar End Sub
如果我理解正确,用户将DEF.xls
作为顶级工作簿,因此等于ActiveWorkbook
。 然后,我的想法是添加新工作表,以非常独特的名称,如“zZzVBAdatazZz”,并使其非常隐藏(设置Sheets("zZzVBAdatazZz").Visible = xlVeryHidden
),所以用户不能用菜单命令取消隐藏。 当macros运行时,你可以在这张表中DEF123.CSV
的path,例如在单元格A1
( ActiveWorkbook.Sheets("zZzVBAdatazZz").Range(A1) = .SelectedItems(1)
)中。 在您的Private Sub Workbook_BeforeClose(Cancel As Boolean)
检查Sheets("zZzVBAdatazZz").Range(A1)
是否有值Sheets("zZzVBAdatazZz").Range(A1)
。 如果是这样,把它存储在variables(现在可以是本地),删除A1
值,并通过path来saveUnicodeCSV
。
有趣的问题,我认为问题的核心在于,工作簿的全局对象在整个应用程序空间中并不是真正的全局对象。 此后我写全球为“全球”来突出这个错误。
我相信你的macros将始终从一个地方运行,所以如何为每个工作簿确定一个“全局”variables的范围,但仍然从另一个工作簿的代码库中获取。
我的解决scheme是使用ThisWorkbook
模块作为放置“全局”variables的地方。 所以在ThisWorkbook
模块中放置下面的代码
Option Explicit Public NJMRGlobalVar As Variant
那么在macros代码模块中,您将需要一个函数来testing给定的工作簿是否支持/导出这个新的“全局”variables。 所以像这样(与unit testing一起给出)
Private Function WorkbookHasNJMRGlobalVar(ByVal wb As Excel.Workbook) As Boolean If wb Is Nothing Then WorkbookHasNJMRGlobalVar = False Else Dim vTest As Variant vTest = CVErr(xlErrName) 'Requires VBA IDE->Tools->Options->General->Error Trapping->Break on Unhandled Errors On Error Resume Next vTest = CallByName(wb, "NJMRGlobalVar", VbGet) Dim lSaveError As Long lSaveError = Err.Number On Error GoTo 0 WorkbookHasNJMRGlobalVar = (lSaveError = 0) End If End Function Private Sub TestWorkbookHasNJMRGlobalVar() Debug.Assert WorkbookHasNJMRGlobalVar(ThisWorkbook) = True Dim wbUnsuitable As Excel.Workbook Set wbUnsuitable = Workbooks.Item("VBA Fileshare.xlsm") '*<---- different for you! Debug.Assert WorkbookHasNJMRGlobalVar(wbUnsuitable) = False End Sub
最后一步是重写您的代码不是根据ThisWorkbook,而是ActiveWorkbook或与Application.Workbooks.Item(“foo.xlsm”)获取目标工作簿。 所以这里有一些代码(适用于ActiveWorkbook)。
Sub CodePageChange() Dim SheetName As Worksheet Dim fd As Office.FileDialog Dim sheetName1 As String Dim tabSheetName As String If Not WorkbookHasNJMRGlobalVar(ActiveWorkbook) Then MsgBox "Currently Active Workbook not a suitable candidate for that macro." Else Dim wbGlobalVarEnabled As Excel.Workbook Set wbGlobalVarEnabled = ActiveWorkbook Set fd = Application.FileDialog(msoFileDialogFilePicker) With fd '.... '.... '.... If .Show = True Then wbGlobalVarEnabled.NJMRGlobalVar = .SelectedItems(1) Else MsgBox "Please start over. You must select a csv file." Exit Sub End If End With End If End Sub
所以,现在每个工作簿都有一个“全局”variables,只需通过获取对Excel.Workbook的引用即可从一个代码自由访问。 这是有效的,因为Excel.Workbook不会在接口中禁止扩展性,这意味着可以添加额外的方法和属性(但并不是所有的工作簿都会支持它们,因此您需要检测一个函数,例如上面的WorkbookHasNJMRGlobalVar
)。
请发表反馈,如果不够,我会修改,我有VBA问题99/100我想获得我的青铜VBA徽章:)
编辑:阅读你的个人资料,你有C / C + +技能,所以我可以进一步在低层次的解释,如何工作。 在Excel的types库中,“nonextensible”IDL关键字装饰了大多数接口,禁止使用额外的方法和属性,但是interface _Workbook
这样的interface _Workbook
所以你可以。 这里是OleView.exe的截图
唯一的快捷方式只能分配给工作簿中的单个过程。 再次设置相同的快捷方式会覆盖以前的任务。
要在不同的工作簿中处理相同的快捷方式,请在工作簿激活时指定快捷方式:
' ThisWorkbook ' Private Sub Workbook_Activate() Application.OnKey "^m", "CodePageChange" End Sub ' Module ' Public Sub CodePageChange() MsgBox ThisWorkbook.Name End Sub
或者在接收到的工作簿中处理callback,然后调用目标工作簿上的过程:
' ThisWorkbook ' Private Sub Workbook_Open() Application.OnKey "^m", "OnHotkeyCtrlM" End Sub ' Module ' Public Sub OnHotkeyCtrlM() Application.Run "'" & ActiveWorkbook.Name & "'!CodePageChange" End Sub Public Sub CodePageChange() MsgBox ThisWorkbook.Name End Sub
使用自定义属性作为全局variables
Private Sub Workbook_BeforeClose(Cancel As Boolean) Debug.Print ActiveWorkbook.CustomDocumentProperties("xyz") End Sub Sub changeTheCode() On Error Resume Next ActiveWorkbook.CustomDocumentProperties("xyz").Delete ActiveWorkbook.CustomDocumentProperties.Add Name:="xyz", LinkToContent:=False, Type:=msoPropertyTypeString, Value:=ActiveWorkbook.Name Debug.Print ActiveWorkbook.CustomDocumentProperties("xyz") End Sub
我同意S Meaden,你不能在几个工作簿中有一个全局variables,而没有指定存储“全局”variables的工作簿。
另一种方法:在带有macros的Excel文件中,“全局”variables的设置完成:将设置replace为
Shell ("Cmd.Exe /C SetX txtFileNameAndPath thePath")
将pathreplace为实际path或值。 运行这个macros之后,您可以运行您的Excel文件并通过检索真正的全局值
txtFileNameAndPath = Environ("txtFileNameAndPath")
将全局variables放入ThisWorkbook
类模块。
Public txtFileNameAndPath As String Private Sub Workbook_BeforeClose(Cancel As Boolean) Debug.Print Me.Name & ":" & txtFileNameAndPath End Sub
然后在程序CodePageChange
循环遍历所有的工作簿,并检查使用ActiveWorkbook.Name
应该使用哪个全局variables。 HTH
If .Show = True Then Dim w As Workbook On Error Resume Next For Each w In Workbooks If ActiveWorkbook.Name = w.Name Then w.txtFileNameAndPath = .SelectedItems(1) Exit For End If Next w On Error GoTo 0 Else MsgBox "Please start over. You must select a csv file." Exit Sub End If
用户友好的解决方法:切断键盘快捷方式并将命令button添加到工作表或自定义function区选项卡到工作簿以调用过程。 他们保证从他们自己的工作簿中调用该过程,并且更方便用户使用。