Home » excel » excel – How to declare flexible variable for workbook?

excel – How to declare flexible variable for workbook?

Posted by: admin May 14, 2020 Leave a comment

Questions:

I would like to somehow declare dynamic workbook variables so that I can change workbook file names without causing errors. My original thought was to use Set Variable = ActiveWorkbook, but that appears to give some peculiar errors:

    Set WkBk1 = ActiveWorkbook

    MsgBox (WkBk1.Name)
    WkBk1.Worksheets(1).Select

The above code works fine by itself. Afterwards, in the same procedure, I open a new workbook and run the following:

    Set WkBk2 = ActiveWorkbook

    MsgBox (WkBk2.Name)
    WkBk2.Worksheets(1).Select
    WkBk1.Worksheets(1).Select

I get an error at the last line, “Run-time error 1004; select method of worksheet class failed”. Can any one explain the source of this issue? I’m guessing that it has something to do with using ActiveWorkbook to declare variables, or a faulty method of going between workbooks.

I should mention that the opened file is a .dat file opened in excel.

Ultimately, I want to have code that will assign two worksheets, of whatever file name, to their own respective variables. I then want to copy and paste data between the two workbooks.

The actual code is below. The problem is with the copy statement in the for loop.
“Run-time error ‘438’ object doesnt support this property or method”. Ive used similar syntax before and can’t figure out why it isn’t working here.

Sub Import3()
    ' Imports TSS samples from backlog

    Dim TSS As Workbook, Backlog As Workbook
    Dim Sample As Range, SearchRange As Range
    Dim Count As Long

    Set TSS = ActiveWorkbook

    ChDir ("C:\lwuser6")
    Workbooks.OpenText Filename:="C:\lwuser6\BACKLOG.DAT", Origin:=437, _
           StartRow:=1, DataType:=xlFixedWidth, FieldInfo:=Array(Array(0, 1), Array(7, _
           1), Array(68, 1), Array(78, 1), Array(86, 1), Array(126, 1), Array(150, 1)), _
           TrailingMinusNumbers:=True
        ' for some reason _ has to be in between "Array(7, _1)"
            ' Can't be between list elements of encompassing list "Array"
    Set Backlog = ActiveWorkbook

    Set SearchRange = Backlog.Worksheets("BACKLOG").Range(Cells(1, 1), _
        Cells(Rows.End(xlDown).Row, 1))
    Count = 14

    For Each Sample In SearchRange
        Backlog.Range(Sample(1, 1), Sample(1, 3)).Copy
        TSS.Range("G" & Count).PasteSpecial (xlValues)
        Count = Count + 2
    Next

End Sub
How to&Answers:

I would warmly recommend running your code through Rubberduck inspections (it’s free & open-source; I manage the project), since it explains not only the specific error you’re asking about, but can also prevent you from stepping into a lot of common beginner traps.

The problem is that Backlog is a Workbook object, and Workbook doesn’t have a Range member:

"Member not found" inspection result

Member not found

A member access call is made against an extended interface that Rubberduck couldn’t resolve, or the member couldn’t be found. If VBA cannot resolve the type at run-time, error 438 will be raised. […]

You need a Worksheet to access a Range, a Workbook won’t work.

Note that the subsequent TSS.Range call is just as illegal 😉



Take this:

Set Backlog = ActiveWorkbook

And get rid of the reliance on the side-effect of opening a workbook, by capturing the Workbook object returned by Workbooks.Open:

Set Backlog = Workbooks.OpenText(Filename:="C:\lwuser6\BACKLOG.DAT", Origin:=437, _
       StartRow:=1, DataType:=xlFixedWidth, FieldInfo:=Array(Array(0, 1), Array(7, _
       1), Array(68, 1), Array(78, 1), Array(86, 1), Array(126, 1), Array(150, 1)), _
       TrailingMinusNumbers:=True)

Nevermind, Workbooks.OpenText doesn’t return a Workbook object reference.

Then take this:

 Backlog.Worksheets("BACKLOG")

And pull it into a local variable:

Dim backlogSheet As Worksheet
Set backlogSheet = Backlog.Worksheets("BACKLOG")

Now you can use it everywhere you need that particular sheet:

With backlogSheet
    Set SearchRange = .Range(.Cells(1, 1), .Cells(.Rows.End(xlDown).Row, 1))
End With

..and this should work, although IMO supplying Range objects to the Worksheet.Range property feels somewhat wrong (and will raise error 1004 if the Sample range isn’t on the backlogSheet):

backlogSheet.Range(Sample(1, 1), Sample(1, 3)).Copy

Not sure which specific sheet in the TSS workbook you mean to paste things, but the same principle applies. That said, you probably don’t even need to get the clipboard involved:

tssSheet.Range("G" & count & ":I" & count).Value = _
    backlogSheet.Range(Sample(1, 1), Sample(1, 3)).Value