-1

New to VBA. I currently have two subs and one function running within a module which are designed to past an active worksheet into the body of an email and send it to the group. The second part of the macro is designed to save the active worksheet to a master worksheet.

Currently these subs are running independently of each other and do not all work at once when I run the macro. Any advice on how to combine the code into one sub which will run all the functions once the macro is active would be really appreciated. I've tried a few different solutions regarding the structure and syntax of the macro but haven't been able to find a fix for it.

Sub Mail_Selection_Range_Outlook_Body()
    'For Tips see: http://www.rondebruin.nl/win/winmail/Outlook/tips.htm
    'Don't forget to copy the function RangetoHTML in the module.
    'Working in Excel 2000-2016
    Dim rng As Range
    Dim OutApp As Object
    Dim OutMail As Object

    Set rng = Nothing
    On Error Resume Next
    'Only the visible cells in the selection
    Set rng = Selection.SpecialCells(xlCellTypeVisible)
    'You can also use a fixed range if you want
    'Set rng = Sheets("YourSheet").Range("D4:D12").SpecialCells(xlCellTypeVisible)
    On Error GoTo 0

    If rng Is Nothing Then
        MsgBox "The selection is not a range or the sheet is protected" & _
               vbNewLine & "please correct and try again.", vbOKOnly
        Exit Sub
    End If

    With Application
        .EnableEvents = False
        .ScreenUpdating = False
    End With

    Set OutApp = CreateObject("Outlook.Application")
    Set OutMail = OutApp.CreateItem(0)

    On Error Resume Next
    With OutMail
        .To = ""
        .CC = ""
        .BCC = ""
        .Subject = "Today's Trades" & Date
        .HTMLBody = RangetoHTML(rng)
        .send                                    'or use .Display
    End With
    On Error GoTo 0

    With Application
        .EnableEvents = True
        .ScreenUpdating = True
    End With

    Set OutMail = Nothing
    Set OutApp = Nothing
End Sub

Function RangetoHTML(rng As Range)
    ' Changed by Ron de Bruin 28-Oct-2006
    ' Working in Office 2000-2016
    Dim fso As Object
    Dim ts As Object
    Dim TempFile As String
    Dim TempWB As Workbook

    TempFile = Environ$("temp") & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"

    'Copy the range and create a new workbook to past the data in
    rng.Copy
    Set TempWB = Workbooks.Add(1)
    With TempWB.Sheets(1)
        .Cells(1).PasteSpecial Paste:=8
        .Cells(1).PasteSpecial xlPasteValues, , False, False
        .Cells(1).PasteSpecial xlPasteFormats, , False, False
        .Cells(1).Select
        Application.CutCopyMode = False
        On Error Resume Next
        .DrawingObjects.Visible = True
        .DrawingObjects.Delete
        On Error GoTo 0
    End With

    'Publish the sheet to a htm file
    With TempWB.PublishObjects.Add( _
         SourceType:=xlSourceRange, _
         Filename:=TempFile, _
         Sheet:=TempWB.Sheets(1).NAME, _
         Source:=TempWB.Sheets(1).UsedRange.Address, _
         HtmlType:=xlHtmlStatic)
        .Publish (True)
    End With

    'Read all data from the htm file into RangetoHTML
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
    RangetoHTML = ts.ReadAll
    ts.Close
    RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", _
                          "align=left x:publishsource=")

    'Close TempWB
    TempWB.Close savechanges:=False

    'Delete the htm file we used in this function
    Kill TempFile

    Set ts = Nothing
    Set fso = Nothing
    Set TempWB = Nothing

End Function

Sub CopyRangeFromMultiWorksheets()
    Dim sh As Worksheet
    Dim DestSh As Worksheet
    Dim Last As Long
    Dim CopyRng As Range

    With Application
        .ScreenUpdating = False
        .EnableEvents = False
    End With

    'Delete the sheet "RDBMergeSheet" if it exist
    Application.DisplayAlerts = False
    On Error Resume Next
    ActiveWorkbook.Worksheets("RDBMergeSheet").Delete
    On Error GoTo 0
    Application.DisplayAlerts = True

    'Add a worksheet with the name "RDBMergeSheet"
    Set DestSh = ActiveWorkbook.Worksheets.Add
    DestSh.NAME = "RDBMergeSheet"

    'loop through all worksheets and copy the data to the DestSh
    For Each sh In ActiveWorkbook.Worksheets
        If sh.NAME <> DestSh.NAME And sh.Visible = True Then

            'Find the last row with data on the DestSh
            lr = DestSheet.Cells.SpecialCells(xlCellTypeLastCell).Row

            'Fill in the range that you want to copy

            Set CopyRng = sh.UsedRange

            'Test if there enough rows in the DestSh to copy all the data
            If Last + CopyRng.Rows.Count > DestSh.Rows.Count Then
                MsgBox "There are not enough rows in the Destsh"
                GoTo ExitTheSub
            End If

            'This example copies values/formats, if you only want to copy the
            'values or want to copy everything look at the example below this macro
            CopyRng.Copy DestSh.Cells(Last + 1, "A")

        End If
    Next

ExitTheSub:

    Application.Goto DestSh.Cells(1)

    'AutoFit the column width in the DestSh sheet
    DestSh.Columns.AutoFit

    With Application
        .ScreenUpdating = True
        .EnableEvents = True
    End With
End Sub

enter image description here

Vityata
  • 42,633
  • 8
  • 55
  • 100
NHure92
  • 105
  • 2
  • 9
  • 2
    Have you tried creating a new sub that just calls each one in turn? – jamheadart Oct 01 '18 at 09:57
  • @jamheadart I have not tried that as of yet. Do you have any suggestions on how I might be able to do that? Thanks – NHure92 Oct 01 '18 at 10:00
  • @NHure92 ,,,at the end of 1st sub before code line `End Sub` just add the line `Call CopyRangeFromMultiWorksheets`. – Mikku Oct 01 '18 at 10:07

1 Answers1

4

Something simple as this one should work:

Sub Main
    Mail_Selection_Range_Outlook_Body 
    CopyRangeFromMultiWorksheets
End Sub

Sub Mail_Selection_Range_Outlook_Body()
    MsgBox "I am from Mail_Selection_Range_Outlook_Body"
End Sub

Sub CopyRangeFromMultiWorksheets()
    MsgBox "I am from CopyRangeFromMultiWorksheets"
End Sub

The word Call is not required and could be omitted. Consider renaming the sub to MailSelectionRangeOutlookBody, thus following the same name pattern as in CopyRangeFromMultiWorksheets.

Vityata
  • 42,633
  • 8
  • 55
  • 100
  • Hi, I've tried to add that to the code but it threw up a compile error: Sun or function not defined. I've included a screenshot in my question to show you, with the sub edit you suggested included at the top of the vb script – NHure92 Oct 01 '18 at 10:26
  • @NHure92 - you have missed the `End Sub` part of the code. Copy the four lines and put them at the end of your original code from the question. Then run `Main`. – Vityata Oct 01 '18 at 10:28
  • I've included end sub, I've tried it in the format you have suggested, as well as including end sub at the end of the first module or at the end of the second module. No luck so far I'm afraid – NHure92 Oct 01 '18 at 10:31
  • @NHure92 - try again, I have updated the answer. On the place of the `...` put the rest of the code from the question. – Vityata Oct 01 '18 at 10:36
  • I've followed these instructions however it still flags an error for Mail_Selection_Range_Outlook_Body at the start of the macro, saying sub not defined. I really appreciate all the help, not sure why it is giving this error though – NHure92 Oct 01 '18 at 10:43
  • 1
    @NHure92 - the problem is somewhere else then. Probably a typo in the name of the sub. Anyway, start a new Excel file and copy the answer. Then run the `Main` method, you would see that it gets into the other two, by calling the `MsgBox`-es. – Vityata Oct 01 '18 at 10:45
  • Thanks @Vityata. I've copied across the code to a new workbook however I'm getting the error "sub or function not defined" for this line of code: 'Find the last row with data on the DestSh Last = LastRow(DestSh) – NHure92 Oct 01 '18 at 11:54
  • @NHure92 - it means that there is no defined a sub or a function with one of the names, used in that specific line. Most probably `LastRow`. Thus, probably there should be a function with a head `Function LastRow(someVariable as Worksheet) as Long` However, copy only the 10 lines of code from the answer in a new workbook, to see how it works. The `DestSh Last = LastRow(DestSh)` is not part of the answer. – Vityata Oct 01 '18 at 12:00
  • Thank you for trying, unfortunately even when pasted into a new workbook it presents me with errors – NHure92 Oct 01 '18 at 14:06
  • @NHure92 - are you sure that you have pasted only the 10 lines from the answer? There should not be any errors. – Vityata Oct 01 '18 at 14:17
  • my mistake, those 10 lines work. However I am struggling to incorporate them into my current macro at the moment in order to make it work – NHure92 Oct 01 '18 at 14:21