在Workbook中工作。在VBA中打开Bug

时间:2014-02-04 19:16:41

标签: excel vba excel-vba

我正在尝试将数据从一个唯一的工作簿传输到另一个唯一的工作簿(即文件名是静态的)。我找到了一些示例代码,它创建了2个类型工作簿的变量(每个代表一个示例工作簿),然后将这些变量设置为Workbooks.Open(“Filename”)。我尝试实现这一点只是为了发现我的代码在第一个workbook.open(“filename”)变量定义之后立即停止执行。在搜索到这个问题的答案后,我意识到这是VBA中的一个错误,它是由错误检测到Shift键的按下而产生的。微软支持网站上有一些代码,如果按下shift键,基本上不会让你的代码运行。我实现了这个代码,果然,当实际上没有时,Shift键被检测为物理压抑。这似乎是迄今为止我在这个主题上找到的唯一可用的“帮助”。我似乎无法找到workbooks.open的替代方法来设置我的工作簿变量等于唯一的文件路径。首先,是否有针对此错误的解决方法,以便Shift键未被检测为被抑制?或者,第二,是否有另一种方法可以将工作簿变量设置为等于特定文件路径而不使用workbooks.open功能?

提前感谢您的帮助。

'Declare API
Declare Function GetKeyState Lib "User32" (ByVal vKey As Integer) As Integer
Const SHIFT_KEY = 16

Function ShiftPressed() As Boolean
'Returns True if shift key is pressed
    ShiftPressed = GetKeyState(SHIFT_KEY) < 0
End Function

Public Sub Initialization()
    Do While ShiftPressed()
        Application.ScreenUpdating = False
        DoEvents
        'Public Variable Definition
        'Set Tracking = Workbooks.Open("\\Server2013\NETWORK_SHARED\QC SHARED\P&Q Tracking New Template.xls")
        Set Tracking = Workbooks.Open("\\Qc\shareddocs\P&Q Tracking New Template.xls")
        'Set Data = Workbooks.Open("\\Server2013\NETWORK_SHARED\QC SHARED\Production & Quality Raw Data.xls")
        Set Data = Workbooks.Open("\\Qc\shareddocs\Production & Quality Raw Data.xls")
        DataLastRow = Data.Sheets("P&Q Raw Data").UsedRange.Rows.Count
        WS_Count = Tracking.Worksheets.Count
        Day_Array() = Array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
        Name_Array() = Array("Angel", "Tony", "Bandy", "Jorge", "Ray")
        'Unprotect Sheets
        For WS_Iter = 1 To WS_Count
            With Tracking.Worksheets(WS_Iter)
                .Activate
                .Unprotect
            End With
            'Tracking.Worksheets(WS_Iter).Activate
            'Tracking.Worksheets(WS_Iter).Unprotect
            'ActiveSheet.Unprotect
        Next WS_Iter
        'Clear Contents
        Sheets("P&Q Weekly Summary").Activate
        For WL_Row_Num = 24 To 72 Step 12
            Sheets("P&Q Weekly Summary").Range(Cells(WL_Row_Num, 3), Cells(WL_Row_Num + 4, 6)).ClearContents
            Sheets("P&Q Weekly Summary").Range(Cells(WL_Row_Num, 10), Cells(WL_Row_Num + 4, 10)).ClearContents
        Next WL_Row_Num
        'Reprotect Sheet 1
        Sheets("P&Q Weekly Summary").Protect UserInterfaceOnly:=True
        'Variable Initialization
        WL_Row_Num = 0
        WS_Num = 0
        SBName_Row_Num = 12
        Name_Row_Num = 20
        Weekly_Score_Row = 24
        'Userform Input
        Vacation_Options_Form.Show
    Loop
End Sub

我做了一些改变我的代码并发现了一个有趣的观察结果。以下是我的简化代码片段:

Public Sub Initialization()
Application.EnableEvents = True
Application.ScreenUpdating = False
Set Data = Workbooks.Open("\\Qc\shareddocs\Production & Quality Raw Data.xls")
MsgBox "The Data Workbook Is Now Open."
Set Tracking = Workbooks.Open("\\Qc\shareddocs\P&Q Tracking New Template.xls")
MsgBox "The Tracking Workbook Is Now Open."
DataLastRow = Data.Sheets("P&Q Raw Data").UsedRange.Rows.Count
WS_Count = Tracking.Worksheets.Count
Day_Array() = Array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
Name_Array() = Array("Angel", "Tony", "Bandy", "Jorge", "Ray")

经过进一步的实验,我意识到如果我注释掉跟踪工作簿定义但代码确实超出了数据工作簿声明,但如果我不对其进行注释,则不会执行超出跟踪工作簿声明。跟踪工作簿是我最初打开的工作簿,如果这有所作为。我已将问题与此隔离开来。如果您尝试打开的工作簿已经打开并且是您正在执行代码的主工作簿,则Workbooks.Open命令似乎不起作用。这看起来是对的吗?这是错误吗?我要做的就是正式声明我的工作簿是唯一的变量。除了Workbooks.Open之外还有其他办法吗?请帮忙。感谢。

2 个答案:

答案 0 :(得分:1)

我最后通过不使用Workbooks.Open功能来解决这个问题。我刚刚将我的基本工作簿称为ThisWorkbook,完全避免了这个问题。我试图避免使用像ThisWorkbook这样的预定义变量来获得所需的工作簿,但最终这似乎是唯一可用的,或者至少是最好的选项。

答案 1 :(得分:0)

因此,在我的情况下,问题是open方法不会打开文件且没有错误,加上代码不会停止/中断。设置objWB = Workbooks.Open(...)只会返回Nothing。

我认为,仅当您从函数调用open方法时,它才起作用。当我在一种方法中使用它时,它可以按预期工作。

我的解决方法是仅使用外部应用程序。就像用VB或C#编写代码一样。

以下是快速的C#代码,可从多个文件获取行数:

using Microsoft.Office.Interop.Excel;
using System;

namespace ExcelRowCounter
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (string arg in args)
            {
                Console.WriteLine("{0}|{1}", arg, GetWorkbookRowCount(arg, false));
            }
            Console.WriteLine("Completed");
            Console.ReadKey();
        }

        static int GetWorkbookRowCount(string strWorkbookPath, bool booAllSheets)
        {   
            int retVal = 0;
            try
            {
                Application objExcelApplication = new Application();
                objExcelApplication.Visible = false;
                Workbook objWorkBook = objExcelApplication.Workbooks.Open(strWorkbookPath, ReadOnly: true);

                foreach (Worksheet objSheet in objWorkBook.Sheets)
                {
                    retVal = objSheet.Rows.SpecialCells(XlCellType.xlCellTypeLastCell).Row;
                    if (booAllSheets == false)
                    {
                        break;
                    }
                }

                objWorkBook.Close(false);
                objWorkBook = null;

                objExcelApplication.Quit();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Bah! Find code and debug!");
                Console.WriteLine("Filepath: " + strWorkbookPath);
                Console.WriteLine("Error: " + ex.Message);
            }
            return retVal;
        }
    }
}

问题示例:

Function GetWorkbookRowCount(ByVal strWorkbookPath As String) As Integer

    Dim retVal As Integer: retVal = -1
    Dim objWorkBook As Workbook

    Set objWorkBook = Excel.Workbooks.Open(Filename:=strWorkbookPath, ReadOnly:=True) ' Fails to open file here

    If (objWorkBook Is Nothing) Then
        'Failed to open file
        Debug.Assert False

    Else
        retVal = objSheet.Rows.SpecialCells(xlCellTypeLastCell).Row

        objWorkBook.Close
        Set objWorkBook = Nothing

    End If

    GetWorkbookRowCount = retVal

End Function

(部分,因为它在函数中不起作用!)解决方案的示例:

Sub PrintWorkbookRowCount()

    Dim retVal As Integer: retVal = -1
    Dim strWorkbookPath As String: strWorkbookPath = "c:\temp\exportFile.csv"
    Dim objWorkBook As Workbook: Set objWorkBook = Workbooks.Open(Filename:=strWorkbookPath, ReadOnly:=True)

    retVal = objSheet.Rows.SpecialCells(xlCellTypeLastCell).Row

    objWorkBook.Close
    Set objWorkBook = Nothing

    Debug.Print (strWorkbookPath & "|" & retVal)

End Sub