ExtendingInsensibility into Code modules. Copy table contents to VBIDE VB Editor code modules. ..
ExtendingInsensibility into Code modules. Copy table contents to VBIDE VB Editor code modules.
This idea came from a forum question. http://www.eileenslounge.com/viewtopic.php?f=30&t=31395
The idea is basically to use a code module for a temporary storage of the values from a spreadsheet range. So effectively a code module would be used as a pseudo simple text file.
I have a requirement where I have a back up of spreadsheet string values in a text file. As the capacity for holding text in the code window seems to be quite large, I thought I might consider the alternative. I expect other methods , such as the text file storage , will more often be appropriate, but I thought it was a useful additional option to have to hand.
I am sharing some of the coding here.
Initially, however, in these first two Posts, a review of coding applied to the coding environment itself, “coding coding”, as it were.. I won’t do a thorough review, but will try to cover all things relevant to the final coding of this Thread
Post #1: Extensifying VB Editor ability:
Security settings to allow modifying EB Editor things
Extensifying in the VB Editor direction of things might need something checked in security settings:
somehow you may need to “allow access to VBA Projects” or similar.
The exact steps vary a bit in different Excel versions. The steps are similar. Here a few screenshots of the steps in a few different excel versions.
Excel 2007 Options.jpg : https://i.imgur.com/k41o135.jpg http://i.imgur.com/SWlX72z.jpg
Security Center Security Center Settings.JPG : http://i.imgur.com/i1DVr6M.jpg https://i.imgur.com/nzTvpCs.jpg
Macro Setting Access to VBA Project.JPG : http://i.imgur.com/AlCtUeA.jpg http://i.imgur.com/Y9KMHr1.jpg
Excel2003 Tools Macros Security.JPG : http://i.imgur.com/bxfK3ws.jpg http://i.imgur.com/MxfEdfb.jpg
Excel2010 Home Options.JPG : http://i.imgur.com/9K3shBy.jpg http://i.imgur.com/vdjXoFN.jpg
Security Center Security Centre Settings.JPG : http://i.imgur.com/y98yqyM.jpg http://i.imgur.com/j02AY2p.jpg
Security center Settings for macros Access to VBA project.JPG : http://i.imgur.com/WMtcikh.jpg http://i.imgur.com/FPoBiX6.jpg
VBIDE. VBA Projects . Active Workbook, Active project
Sometimes you come across “VBIDE” when looking at these things, which probably comes from an earlier all encompassing idea of the Visual Basic Integrated Development Environment. The visual basic window that you get via Alt+F11 from Excel is more or less something like that development environment type idea.
It is probably best to avoid confusion to have active the workbook whose codes you are manipulating.
It would appear that the word project is used loosely when talking about code related things. By default most “Projects” have the default code name of VBAProject, as seen in the VBA Project explorer window. If you want to keep a slightly better order to your Projects, then you can change that name
VBA Project rename.JPG : http://i.imgur.com/hTzH7NT.jpg http://i.imgur.com/CHKxCrg.jpg
The VB Editor window and components therein appear to have been “built” from some large Class object with the name VBIDE. So in a similar way to that in which we have , for example, Worksheets already instantiated ( “built”) for us from type/ class Worksheet, we also have objects from the VBIDE Class available to us. If we make this Class available to us, as shown below, then we find that we can do a few more things programmatically. For the things done in this Thread, we do not need to do that.. But just for completeness, here are some ways to do that …
Manuel: Tools Extra ScrollTo Extensibility5.3.JPG : http://i.imgur.com/FyXT99z.jpg http://i.imgur.com/mP9gDjv.jpg
Using Coding: VBIDE programmatically.JPG : http://i.imgur.com/FSG1ZMo.jpg http://i.imgur.com/s9Sw1Kk.jpg
Code:
Sub CheckReferrence()
Dim Tool As Object, FlagGotIt As Boolean, strOut As String
' Check if referrence is already there
For Each Tool In ThisWorkbook.VBProject.References
If Tool.GUID = "{0002E157-0000-0000-C000-000000000046}" Then
Let strOut = "Had it already" & vbCrLf
Let FlagGotIt = "True"
Exit For ' Needed to keep Tool Set if found
Else
End If
Next Tool
' Check(Add) referrence if not there
If FlagGotIt = False Then
ThisWorkbook.VBProject.References.AddFromGuid GUID:="{0002E157-0000-0000-C000-000000000046}", Major:=5, Minor:=3
Set Tool = ThisWorkbook.VBProject.References("VBIDE") '
Else
End If
Let strOut = strOut & "Description: " & Tool.Description & vbCr & "Class Name: " & Tool.Name & vbCr & "Buitin: " & Tool.BuiltIn & vbCr & "FullPath: " & Tool.FullPath & vbCr & "Type: " & Tool.Type & vbCr & "Isbroken: " & Tool.IsBroken
' c00 = c00 & vbCr & "Minor:" & vbTab & vbTab & It.Minor ' (version)
' Display info about Tool ' c00 = c00 & vbCr & "Major:" & vbTab & vbTab & It.Major ' (version)
MsgBox Prompt:=strOut: Debug.Print strOut
End Sub
Referencing code project things
For the purposes of this Thread, we appear to be able to get easily, even without the above Class VBIDE reference, at the code module which we wish to use. Hard coding to any code module name is possible. The Me property can be used for all but normal code modules for making a code more easy to share and use in any code module. Alternatively the active code module can be referenced. Here are a few ways to assign a variable to use in order to keep the later coding a bit tidier:
Code:
Sub referringToVBEthings()
Dim VBIDEVBAProj As Object
Set VBIDEVBAProj = ThisWorkbook.VBProject.VBComponents(Me.CodeName).CodeModule 'This will work on all but normal code modules. It will cause a complie error
Set VBIDEVBAProj = ThisWorkbook.VBProject.VBComponents.VBE.ActiveCodePane.CodeModule
Set VBIDEVBAProj = ThisWorkbook.VBProject.VBE.ActiveCodePane.CodeModule
End Sub
The next posts looks at a few extra code code writing techniques
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
3) Copy table contents to VBE module
Example
Post #4 Copy table contents to VBE module (Part#4 Re Paste back to spreadsheet)
3) Copy table contents to VBE module
The idea of these codes are to allow for a temporary storage of spreadsheet values to a code module.
_ One code will add a table of values to the end of a code module, and an extra start and end line will be added which contains range and date info. This code uses the selected range. So a range must be selected before running this code.
and
_ a second code can be used to paste those values back to the same range.
Optionally a date of entry can be given to search for, otherwise all table values are pasted in
The codes are somewhat detailed and inefficient. They work in many places "line by line". There are some more simpler and more efficient codes here. http://www.eileenslounge.com/viewtop...=31395#p243002
Sub PubProliferous_Let_RngAsString__()
This code puts a selected range of values into the code module in which the code at the position of just after this coding. The table data values will be added to ( or taken from in following codes ) the module in which the code is run.
Here a brief walk through the code. There are more details in the 'comments
Rem 0 Sets for convenience, a variable to the code module in which the code is placed/ run from
Rem 1
A code module used for storing a table will be given the extension to its code name of "_txt" No special reason for doing this, I just thought it might be useful for later reference to know that the code module is being used in such a way. ( If no more table data is in the code module, then the extension , "_txt" , will be removed. This will be done , for example in following codes after the data is removed.)
Rem 2
Before running the code, a spreadsheet range should be selected. The range is copied to the clipboard, and the text of that put in a string variable, strIn
Rem 3
The string format is changes slightly to allow better display in this code ( and to aid in manipulation in the codes which re copy the data back to the spreadsheet, http://www.eileenslounge.com/viewtop...=31395#p242941
Rem 4
This adds an "extra line" to the start of the string with range information and current date, and an extra line at the end of the string with the same date. (I use date format of 10 digits as DD MM YYYY. ( This needs to be added to the data retrieving codes if looking for data from a specific date ) )
As demo example, say I copied a 2 row x 2 cell range, B2:C3 to the clipboard. Say the range looked like this
A B
C D
At this point in the routine, after Rem 4 , I will have in strIn , something of this approximate/pseudo form, ( say for a date of 12th December, 2018 ):
Code:
= " '_-20 12 2018 Worksheets("Tabelle2").Range("B2:C3") " & vbCr & vbLf & "|" & "A" & "|" & "B" & vbCr & vbLf & "|" & "C" & "|" & "D" & vbCr & vbLf & " '_-20 12 2018 "
Rem 5
The above string is converted to an array by splitting by the & vbCr & vbLf & . So effectively , I would end up with something of this form , for the above example , a 4 element, 1 Dimensional array:
{ SpltRws(0) , SpltRws(1) , SpltRws(2) , SpltRws(3) }
where
SpltRws(0) = " '_-20 12 2018 Worksheets("Tabelle2").Range("B2:C3") "
SpltRws(1) = "|" & "A" & "|" & "B"
SpltRws(2) = "|" & "C" & "|" & "D"
SpltRws(3) = " '_-20 12 2018 " "
Rem 6
We examine the dimensions of the array and determine which lines will be used at the end of the code module
Rem 7
'7a) '7d) The extra start and end lines are added as simple lines.
'7b) This is the main loop for inserting/(actually adding**) data lines
'7c) this second inner loop builds up the actual line to be outputted from the columns/cells: The row is first split into each cell/column , and then a string of all cell/columns rebuilt. This is done so that we can add some formatting to each cell/column. In this code we effectively add each cell/column string into a fixed length string variable, so that in the VB editor it looks a bit neater with the cell/columns being of equal with regardless of how many characters are in each cell/column
**Note: As discussed in the last post ( https://excelfox.com/forum/showthrea...ll=1#post15229 ) , we use the code line of this form:
___.insertlines Line:=____, String:=”____”
We actually use a value in the argument Line:=____ which is 1 greater than the last line. It is not possible to “Insert” a line where no line currently is. But for any value 1 or more greater than the last line, the code line appears to add** a new line. That line will then eventually / indirectly become the line number which is 1 greater than the last line number. So we achieve what we want, but are not doing it as directly as it might appear at first glance:- We can only insert lines at up to and including the last current line. If we try to insert anywhere above the last current line, then the ___.insertlines _ will add** a new line directly after the last current line.
_.___________________
Example of code run.
Consider that this spreadsheet range is highlighted,…._
_____ Workbook: Uebersicht Aktuelle.xls ( Using Excel 2007 32 bit )
Row\Col |
A |
B |
C |
D |
E |
F |
2492 |
24 11 2018 |
GH |
GT |
2136.25 |
30 |
30.04 |
2493 |
25 11 2018 |
GH |
GT |
|
|
|
2494 |
26 11 2018 |
GH |
GT |
2150.17 |
51 |
51.1 |
2495 |
27 11 2018 |
GH |
GT |
2146.47 |
31 |
31 |
Worksheet: Tabelle1
_... and then run the code Sub PubProliferous_Let_RngAsString__()
After doing this, you should see this towards the end of the code module in which the code is placed
Code:
'7d) End row
VBIDEVBAProj.insertlines Line:=CdTblStp, String:=SpltRws(UBound(SpltRws())) ' Note: this line would not go further than last line, so it must be done here ***
End Sub
'_-21 12 2018 Worksheets("Tabelle1").Range("$A$2492:$F$2495")
'_-24 11 201 | GH | GT | 2136.25 | 30 | 30.04
'_-25 11 201 | GH | GT | | |
'_-26 11 201 | GH | GT | 2150.17 | 51 | 51.1
'_-27 11 201 | GH | GT | 2146.47 | 31 | 31
'_-21 12 2018
You will note that you have lost a digit in the column A dates – the 8 in 2018 is missing. This is because the formatting is set to 9 characters by this variable
__TabulatorSyncrenator = "123456789" ' any lengthed string will do
You can overcome that problem by increasing the character length of that variable by 1 digit. Any character will do, for example
__TabulatorSyncrenator = "1234W56789"
Re run the code on the same range and you will now see this:
Why Tabulator SinkCranartor.JPG : https://imgur.com/i6VsFRP
( TabulatorSyncrenator = "12345Y6789" )
Code:
End Sub
'_-21 12 2018 Worksheets("Tabelle1").Range("$A$2492:$F$2495")
'_-24 11 201 | GH | GT | 2136.25 | 30 | 30.04
'_-25 11 201 | GH | GT | | |
'_-26 11 201 | GH | GT | 2150.17 | 51 | 51.1
'_-27 11 201 | GH | GT | 2146.47 | 31 | 31
'_-21 12 2018
'_-21 12 2018 Worksheets("Tabelle1").Range("$A$2492:$F$2495")
'_-24 11 2018 | GH | GT | 2136.25 | 30 | 30.04
'_-25 11 2018 | GH | GT | | |
'_-26 11 2018 | GH | GT | 2150.17 | 51 | 51.1
'_-27 11 2018 | GH | GT | 2146.47 | 31 | 31
'_-21 12 2018
Codes are here:
http://www.excelfox.com/forum/showth...0847#post10847
Note, the code line to clear the range is currently commented out
' rngSel.ClearContents ' range is cleared after copying table values to clipboard
_._____________________-
In the next posts we consider ways to Get at that data range in a code module, and re paste it into the spreadsheet at the original range
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
https://www.youtube.com/channel/UCnxwq2aGJRbjOo_MO54oaHA
Part4a) Re Paste back to spreadsheet
Example
Copy table contents to VBE module Post#4, Part4a) Re Paste back to spreadsheet
4) Paste range values held in VBE module back to spreadsheet
So the last code, having been run when a range, such as this was selected, …._
_____ Workbook: Uebersicht Aktuelle.xls ( Using Excel 2007 32 bit )
Row\Col |
G |
H |
2503 |
223.38 |
FH |
2504 |
194.67 |
FH |
Worksheet: Tabelle1
_... would result in the '_-commented lines like these appearing at the last rows of the code module in which that code was run
Code:
End Sub
'_-23 12 2018 Worksheets("Tabelle1").Range("$G$2503:$H$2504")
'_-223.38 | FH
'_-194.67 | FH
'_- EOF 23 12 2018
In this post a code is presented for re pasting the original data values back into the original spreadsheet range. ( The code also removes the data from the code module ). If there is more than one range of data values , then all ranges will be pasted back out into the respective original spreadsheet range.
Code description.
It is a bit difficult to give a detailed walk through description as the code goes around in circles ( it does Do Loops) a bit. So here is just a general description of the full code:
It is convenient to work backwards, deleting the lines in the VB Editor as we go: Unlike in a spreadsheet we always know in a code module that the last line is the last line of data, in other words the pseudo code module sheet has a last cell at the last data entry: We don't have empty rows. Rows only exist as data is/ was entered
__1A Main outer Loop keeps going While we are not at the End of a routine ===============
_____Immediately within that is another Loop which keeps going While we have not reached the start line of a data section ( A start of a data section will look like this sort of form '_-21 12 2018 Worksheets("Sht_1").Range("$B$15:$D$16") )
It is not obvious from the routine layout, but the main action which is done first at every loop and initially after the routine begins is that which does the reading of the next line back from the end, in other words the current last line
____Let ReedLineIn = VBIDEVBAProj.Lines(StartLine:=VBIDEVBAProj.countof lines, Count:=1)
Immediately after that, the code will end if a routine End _____ type statement was read, or Else the line is deleted. Initially when the code starts we are directed immediately to this lower part of the code by virtue of
____If ReedLineIn = "" Then
'for an empty line we do nothing apart from having already deleted it ( for all but the first time here at the code start)
At this lower routine section, a code line is read, we will quickly leave the routine If we have read an End __ type statement. This is because the Loop While condition to keep looping is no longer met because we set the Boolean variable, EndOFSub , to True:
Code:
Let ReedLineIn = VBIDEVBAProj.Lines(StartLine:=VBIDEVBAProj.countoflines, Count:=1)
If ReedLineIn = "End Sub" Or ReedLineIn = "End Function" Then
Let EndOFSub = True
Else ' after reading in any line, we delete it, unless it was the End of a routine
VBIDEVBAProj.DeleteLines StartLine:=VBIDEVBAProj.countoflines, Count:=1
End If
Loop While Not EndOFSub = True And FOB = False
Loop While EndOFSub = False '
End Sub
If we do not have the ReedLineIn = "" condition then we are at the part where things are done in each inner loop, ----|
The first thing that is done is to see
____If we have got, ( as a result of looping backwards "down" the code module occupied lines), to the point of a start section of a data section which will have a code line something like '_-22 12 2018 Worksheets("Tabelle1").Range("$A$2515") If that is the case Then we are at the ' Section to prepare data for, and to do, the paste out of a data value range
Various manipulation is then done to convert the collected information so far ( in String variable arrOut ) , into a form which will paste out to a spreadsheet range from the clipboard
____The Else situation here is ( If we are not at an end line of the data range ( like '_- EOF 22 12 2018 ) ) is simply to collect all the range text as a continual string, held in variable arrOut
____ We have now arrived at the end of doing things in the inner loop, and the code goes on to reading the next line, then checking for If at an End __ of routine, Else then deleting the line and
____We are now at the point of moving to the next loop of action to analyse and possibly do something with the last copied line held now in string variable ReedLineIn
_.___________________-
4b) Multi range data
The same code will paste out many ranges held in the code module. All ranges will be pasted back to their original spreadsheet range, and be removed from the code module
So for example , with this data in the same code as the routine Sub PubProliferous_Get_Rng__AsString() , will result in the following worksheet ranges being filled, (and also the data from the code module will be removed)
Worksheet "Tabelle1" , Range F2504:I2505
Worksheet "Tabelle2" , Range B392:D394
Worksheet "Globies" , Range F24:G25
Code:
Loop While EndOFSub = False ' ================================================================
End Sub
'_-23 12 2018 Worksheets("Tabelle2").Range("$B$392:$D$394")
'_-gramms | Kcal | Fett
'_-300g | 198Kcal | 0
'_-51g | 183,09K | 4,08
'_- EOF 23 12 2018
'_-23 12 2018 Worksheets("Tabelle1").Range("$F$2504:$I$2505")
'_-41.09 | 194.67 | FH | WH
'_-55.07 | 233.32 | FH | WH
'_- EOF 23 12 2018
'_-23 12 2018 Worksheets("Globies").Range("$F$24:$G$25")
'_-GF F | GG G
'_-Eiweiß | Koh
'_- EOF 23 12 2018
After running the routine, Sub PubProliferous_Get_Rng__AsString() , the end of that code module will then look like this:
Code:
Loop While EndOFSub = False ' ================================================================
End Sub
_.______________
Final routine is here:
http://www.excelfox.com/forum/showth...0848#post10848
In the next post, a slightly different routine will be presented. This routine will
not remove the range value data in the code module
and
only look for data corresponding to a given date.
4b) Paste range values held in VBE module back to spreadsheet ( without deleting values from code module
Example
Copy table contents to VBE module Part#4b ( Post #5) Re Paste back to spreadsheet
4b) Paste range values held in VBE module back to spreadsheet ( without deleting values from code module and selection of data range based on date
Post #5 Sub PubeProFannyTeas__GLetner("____")
This posts differs from that in the previous post in that it searches for a data range held towards the end of a code module, based on a given date.
The date should have a 10 digit “DD MM YYYY” type format.
For example, for the 23rd December, 2018 a calling code would look like this
Code:
Sub TestCall()
Call PubeProFannyTeas__GLetner("23 12 2018")
End Sub
If the following data…._
Code:
Next Cnt ' next date range
End Sub
'_-23 12 2018 Worksheets("Tabelle1").Range("$G$2513:$H$2514")
'_-91.01 | FH
'_-163.73 | FH
'_- EOF 23 12 2018
'_-23 12 2018 Worksheets("Tabelle1").Range("$I$2513:$J$2514")
'_-WH | MH
'_-WH | MH
'_- EOF 23 12 2018
_.... were in the code module, ( for example after running code, Sub PubProliferous_Let_RngAsString__() ), then running the above would result in the range…___
WH MH
WH MH
_... being pasted into worksheet with name “Tabelle1” starting top left at cell I2513. In other words the result would be in the worksheet something like:
_____ Workbook: Uebersicht Aktuelle.xls ( Using Excel 2007 32 bit )
Row\Col |
I |
J |
2513 |
WH |
MH |
2514 |
WH |
MH |
Worksheet: Tabelle1
Notes:
_ Only values are pasted, so the cells in the above example must have been previously in those text color formats
_ For more than one matching date, the range furthest down will be used by the code
Code description: (Sub PubeProFannyTeas__GLetner(ByVal strDte As String) )
Rem 0 Code module as object
As in previous codes, for convenience an object variable is set to the active code window.
Rem 1 complete data range from end of code module
'1a) This section effectively progresses “back down” the code window until an end routine is encountered and thereby counts to determine the number of data rows/lines
'1b) A similar code line is used as previously for reading single lines, but by choosing more than 1 in the second argument a long single string, strIn , is returned with a vbCr & vbLf pair which are pseudo between*** the lines of data. ( This vbCr & vbLf pair seems to be characteristically “ there “ at the next line which is not in use or counted, such that it gets “tacked on” the start of new lines***
A major characteristic of this routine is the manipulation of that single string using various VBA Strings collections functions.
At this point the string might include more than one data range.
'1c) Because we have a “line free” between data ranges held in the code window, this means that the string at these positions will have the usual pair of vbCr & vbLf pair, but because no data is on the line next part of the string will be the next vbCr & vbLf pair. Hence we have characteristically at this position vbCr & vbLf & vbCr & vbLf pair. Using vbCr & vbLf & vbCr & vbLf as separator is therefore a convenient way to split the complete string into an array where each array element is a single string of a complete data range
Rem 2 manipulation of found date range
We start here with a found range ( in a single long string format ) currently in the chosen array of ranges, and for no particular reason put that array element into a simple string variable. (There is no check for no matching date. The code will simply end after all ranges have been looped through.)
'2a) The range information at the start of the string is easy to obtain from simple string manipulation , - in the 'comments example and detail is given )
'2b)
Further manipulation brings the string into the typical for which we find is what Excel gives and takes to paste in a range from the clipboard, For example for a 2 row x 3 column range like this…_
Cell1 Cell2 Cell3
_cell4 cell5 cell6
_
_... has a simple long single string form of
“Cell1 & vbTab & Cell2 & vbTab & Cell3 & vbCr & vbLf & cell4 & vbTab & cell5 & vbTab & cell6 & vbCr & vbLf”
Rem 3 range output to worksheet range
The final prepared range string is given to a “Data object” . That “Data object” has a method , ( PutInClipboard ) , which we use to put that string into the clipboard.
A simple Paste is then all that is needed to put the data range of values into the worksheet.
Final code is here:
http://www.excelfox.com/forum/showth...0849#post10849
Rem Ref
' http://www.eileenslounge.com/viewtopic.php?f=30&t=31395
' http://www.cpearson.com/excel/vbe.aspx
http://www.excelfox.com/forum/showth...ll=1#post10971
http://www.excelfox.com/forum/showth...1011#post11011
Spare Post for later notes
Spare Post for misc. notes
Before doing this, select File > Options > Trust Center > Trust Center Settings... > Macro Settings.
Make sure that the check box 'Trust access to the VBA project object model' is ticked, then click OK.
Use the following as starting point and edit it as you like.
Code:
Sub CreateXLSM()
Dim wbk As Workbook
Dim vbc As Object ' VBComponent
Dim mdl As Object ' CodeModule
Set wbk = Workbooks.Add(xlWBATWorksheet)
Set vbc = wbk.VBProject.VBComponents.Add(1) ' vbext_ct_StdModule
Set mdl = vbc.CodeModule
mdl.AddFromString _
"Sub Test()" & vbCrLf & _
" MsgBox ""Hello World!"", vbInformation" & vbCrLf & _
"End Sub"
wbk.SaveAs Filename:="Test.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
wbk.Close
End Sub
https://eileenslounge.com/viewtopic.php?f=30&t=36283
http://www.excelfox.com/forum/showth...0849#post10849
Rem Ref
' http://www.eileenslounge.com/viewtopic.php?f=30&t=31395
' http://www.cpearson.com/excel/vbe.aspx
http://www.excelfox.com/forum/showth...ll=1#post10971
http://www.excelfox.com/forum/showth...1011#post11011
Spare Post for later notes
Spare Post for misc. notes
Before doing this, select File > Options > Trust Center > Trust Center Settings... > Macro Settings.
Make sure that the check box 'Trust access to the VBA project object model' is ticked, then click OK.
Use the following as starting point and edit it as you like.
Code:
Sub CreateXLSM()
Dim wbk As Workbook
Dim vbc As Object ' VBComponent
Dim mdl As Object ' CodeModule
Set wbk = Workbooks.Add(xlWBATWorksheet)
Set vbc = wbk.VBProject.VBComponents.Add(1) ' vbext_ct_StdModule
Set mdl = vbc.CodeModule
mdl.AddFromString _
"Sub Test()" & vbCrLf & _
" MsgBox ""Hello World!"", vbInformation" & vbCrLf & _
"End Sub"
wbk.SaveAs Filename:="Test.xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled
wbk.Close
End Sub
https://eileenslounge.com/viewtopic.php?f=30&t=36283
http://www.excelfox.com/forum/showth...0849#post10849
Rem Ref
' http://www.eileenslounge.com/viewtopic.php?f=30&t=31395
' http://www.cpearson.com/excel/vbe.aspx
http://www.excelfox.com/forum/showth...ll=1#post10971
http://www.excelfox.com/forum/showth...1011#post11011
Spare Post for later notes