I might be bad at googling as I couldn't find the answer to below question:
Sub TEST()
Dim sthstring as string
sthstring = "Hello World"
end sub
While we all know it's easy to use msgbox to print "Hello world", is it possible to print out the variable's name (which in this case, "sthstring") and how?
EDIT: please do not provide with answer such as:
Dim someotherstring as string
someotherstring = "sthstring"
as I meant to find a way to print the 'name' of the variable, thanks
After reading comments I think you may find this answer useful.
VBA doesn't support reflection just like #Monty Wild has mentioned already but adding references to Microsoft Visual Basic for Applications Extensibility 5.3 grants you the access the VBE object. You can then iterate object modules in your VBA Project and retrieve the entire code for a module in a String format.
Consider the following (Stick it in a new workbook's Module1)
Sub Main()
Dim code As String
code = GetCodeModule("Module1")
Debug.Print code
End Sub
Private Function GetCodeModule(ByVal codeModuleName As String) As String
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim CodeMod As VBIDE.CodeModule
Set VBProj = ThisWorkbook.VBProject
Set VBComp = VBProj.VBComponents(codeModuleName)
Set CodeMod = VBComp.CodeModule
GetCodeModule = CodeMod.Lines(1, CodeMod.CountOfLines)
End Function
Your code variable now stores the exact code that is in your Module1 you can check that by opening the Immediate Window ctrl+g.
You may want to write/use some sort of a Find function to disassemble the String components to retrieve variable names and values but I wouldn't recommend doing it as it's can get quite tricky.
You can go a step further that simply accessing the code.
Updating the excellent code from Pearson to
show that setting the reference to Microsoft Visual Basic for Applications Extensibility 5.3 isnt a pre-requisite to access the VBIDE
actually parse out any Dim XX As String in any codemodule and report it
sample output
Dim sthstring As String (Module1 at: Line: 2)
Dim strSub As String (Module2 at: Line: 2)
Dim FindWhat As String (Module2 at: Line: 11)
Dim ProcName As String (Module3 at: Line: 9)
code
Sub GetVariable()
Dim strSub As String
strSub = "As String"
Call SearchCodeModule(strSub)
End Sub
Function SearchCodeModule(ByVal strSub)
Dim VBProj As Object
Dim VBComp As Object
Dim CodeMod As Object
Dim FindWhat As String
Dim SL As Long ' start line
Dim EL As Long ' end line
Dim SC As Long ' start column
Dim EC As Long ' end column
Dim Found As Boolean
Set VBProj = ActiveWorkbook.VBProject
For Each VBComp In VBProj.VBComponents
Set CodeMod = VBComp.CodeModule
With CodeMod
SL = 1
EL = .CountOfLines
SC = 1
EC = 255
Found = .Find(target:=strSub, StartLine:=SL, StartColumn:=SC, _
EndLine:=EL, EndColumn:=EC, _
wholeword:=False, MatchCase:=False, patternsearch:=False)
Do Until Found = False
If Left$(Trim(.Lines(SL, 1)), 3) = "Dim" Then Debug.Print Trim(.Lines(SL, 1) & " (" & CStr(VBComp.Name) & " at: Line: " & CStr(SL)) & ")"
EL = .CountOfLines
SC = EC + 1
EC = 255
Found = .Find(target:=strSub, StartLine:=SL, StartColumn:=SC, _
EndLine:=EL, EndColumn:=EC, _
wholeword:=True, MatchCase:=False, patternsearch:=False)
Loop
End With
Next VBComp
End Function
This is difficult to do directly, as VBA does not have reflection, i.e. cannot directly reference itself.
However;
Since in a comment you mention that you want to write code that references itself, you can do so by referencing Microsoft Visual Basic for Applications Extensibility 5.3 in the tools/references dialog. This gives you the ability to reference VBA code, and from there you could write code that prints itself out.
See
MSFT reference 1, and
MSFT reference 2
That is likely impossible, as variable names are just pointers to data. You can have several variables that all point to the same object (although in VBA I do not believe strings are treated as objects so that would not be possible, with the exception of a ByRef function call).
Related
This may sound a little bit dumb, but I have never experienced anything like this before with SolidWorks macro. I have written a SolidWorks macro that inserts a BOM table into an assembly saves it as excel, and adds needed formulas to an excel file. However it works 1 time out of 2- 1st time- all good, 2nd time I get an error- "Run-time error '1004' Method 'Rows' of object '_Global' Failed", 3rd time- all good, 4th time I get the same error and so on and so on. I'm really new to excel macro so I don't know if I'm missing something or just stupid?
Option Explicit
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swBOMAnnotation As SldWorks.BomTableAnnotation
Dim i As Integer
Dim nNumRow As Variant
Dim swTableAnn As SldWorks.TableAnnotation
Dim swAnn As SldWorks.Annotation
Dim swModelDocExt As SldWorks.ModelDocExtension
Dim template As String
Dim fType As String
Dim configuration As String
'excel variables
Dim x1App As Excel.Application
Dim xlWB As Excel.Workbook
Dim NextRow As Long
Sub main()
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
Set swModelDocExt = swModel.Extension
template = "C:\Program Files\SOLIDWORKS Corp\SOLIDWORKS\lang\english\bom-all.sldbomtbt"
fType = swBomType_PartsOnly
configuration = "Default"
Set swBOMAnnotation = swModelDocExt.InsertBomTable3(template, 770, 240, fType, configuration, False, 2, True)
Dim path As String
path = Left(swModel.GetPathName, InStrRev(swModel.GetPathName, "\"))
Dim fpath As String
fpath = Format(path & "BOM\")
On Error Resume Next
MkDir (fpath)
On Error GoTo 0
Dim fName As String
fName = Format(fpath & "TEST.xls")
swBOMAnnotation.SaveAsExcel fName, False, False
Set swTableAnn = swBOMAnnotation
Set swAnn = swTableAnn.GetAnnotation
swAnn.Select3 False, Nothing
swModel.EditDelete
'Excel part
Set x1App = New Excel.Application
x1App.Visible = True
Set xlWB = x1App.Workbooks.Open(fName)
With Range("G3:G" & Cells(Rows.Count, "C").End(xlUp).Row)
.Formula = "=C3*F3"
End With
NextRow = Range("G" & Rows.Count).End(xlUp).Row + 1
Range("G" & NextRow).Formula = "=SUM(G2:G" & NextRow - 1 & ")"
End Sub
Not sure what's causing the behavior you're describing but here are a few thoughts that might point you in the right direction.
Objects in macros are persistent, meaning swModel (and other objects) will still exist after the macro is run. This is why you need to set it to 'Nothing' before using it again.
"Rows" is not defined anywhere so I'm surprised that code works at all. It must be late binding it to something... Rows is a method for an excel range but you're not using it that way. (range.Rows)
Try getting the row count explicitly in a double and using that instead. I suspect that will fix your issue.
I'm writing some code for a client which pulls data from many differently laid out files. I wanted to write something which was quite flexible for him in the future.
Therefore, he will be able to write for example y.offset(0,1) in a cell depending where in regards to the variable y the data will be.
The reason I haven't just made the the variable 1 is because it, and therefore the cell, may or may not include multiple & "blah blah"
Basically, I'm wondering if it's possible to write parts of code in a cell then pull them up and incorporate them into code.
For instance:
Dim y as range
Dim x as range
Dim c as string
Set Y = Sheet1.range("G4")
c = sheet1.range("A1") [which contains the words y.offset(0,4)
Set x = c
This doesn't work, however I'm wondering if there's anything that can be done to get the same result.
Your need is kind of a recursive and dangerous one
then it deserves such a recursive and dangerous answer
you could use the VBA Project Object Model (see here for info) and act as follows:
Set your project to handle VBA Object Model
follow all the steps you can see in the Introduction of the above given link to cpearson website Add reference to your project
Disclaimer: please also read the CAUTION note in there
add "helper" module
add to your project a new Module and call it after "HelperModule" (you can call it as you like, but then be consistent with the chosen name)
then add this code into this new module
Function GetRange(refRng As Range) As Range
Set GetRange = refRng
End Function
Function SetToCellContent(refRng As Range, cellContent As String) As Range
UpdateCodeModule cellContent
Set SetToCellContent = HelpModule.GetRange(refRng)
End Function
Sub UpdateCodeModule(cellContent As String)
Dim CodeMod As VBIDE.CodeModule
Dim LineNum As Long
Set CodeMod = ActiveWorkbook.VBProject.VBComponents("HelperModule").CodeModule
LineNum = SearchCodeModuleLine(CodeMod, "Set GetRange")
CodeMod.ReplaceLine LineNum, " Set GetRange = " & cellContent
End Sub
Function SearchCodeModuleLine(CodeMod As VBIDE.CodeModule, FindWhat As String) As Long
Dim SL As Long ' start line
Dim SC As Long ' start column
Dim EL As Long ' end line
Dim EC As Long ' end column
Dim Found As Boolean
With CodeMod
SL = 1
EL = .CountOfLines
SC = 1
EC = 255
Found = .Find(Target:=FindWhat, StartLine:=SL, StartColumn:=SC, EndLine:=EL, EndColumn:=EC, wholeword:=True, MatchCase:=False, patternsearch:=False)
End With
SearchCodeModuleLine = SL
End Function
Add this code to your main code
Set x = SetToCellContent(y, c) '<--| call the function that will take care of updating code in 'GetRange()' function and returns a range relative to 'y' as per the "code" in 'c'
I got a tricky issue with my VBA-code. The situation is that I have a manual created userform. I add controls to the userform with a macro and it works fine for me. But now I also need to add event-code to the userform. Following code I want to add with .CodeModule.InsertLines. The important part is that the textboxes, which I want to call should work variably, but it doesn't work, any ideas how to fix this? (Textboxes are named like this: textbox_0, textbox_1 and following)
Dim iMaxColumns As Integer
Dim iCount As Integer
iMaxColumns = Tabelle4.Cells(8, 2).Value
Dim vArray(0 To iMaxColumns - 1) As String
For iCount = 0 To iMaxColumns - 1
vArray(iCount) = textbox_ & iCount &.Value
Next
'do sth. with the arrray
I assume the problem is that I can't add variables to my textbox object. I also could work with the complete path to my textbox calling it with .Designer.Controls("textbox_" & iCount & "") but that is a bunch of code and I hope to avoid that.
I figured out a quite easy way to solve my problem. I wrote all the necessary code in a seperate module. There I can address all the variables and information I need. After that when creating the UserForm I just copy all the code into the UserForms code block.
Public Function edit_userform(strUserForm As String, _
strUserFormEvents As String)
Dim VBProj As VBIDE.VBProject
Dim VBComp As VBIDE.VBComponent
Dim VBComp_Event As VBIDE.VBComponent
Dim strCode As String
Set VBProj = ActiveWorkbook.VBProject
Set VBComp = VBProj.VBComponents(strUserForm)
Set VBComp_Event = VBProj.VBComponents(strUserFormEvents)
With VBComp_Event.CodeModule
strCode = .Lines(1, .CountOfLines)
End With
VBComp.CodeModule.AddFromString strCode
End Function
I am updating an excel app written by someone else (of course :)
I found lots of unused Sub CommandButtonXX_Click() subs, and I am not always sure if the button still exists. Is there a way (program, VBE interface, external tool) to do some cleanup while avoiding to delete the still in use code ?
The list at the top of the properties box does seem to be reliable, since it is kind of context sensitive: if you're in a tab, it displays only items of that tab.
An interesting question!
I have significantly modified Pearson's code Listing All Procedures In A Module to find all CommandButtonXX_Click code on each worksheet (excluding other subs),
then tried to match each CommandButtonXX_Click code to an actual button on that sheet.
If there is no match the button is deleted, and a Msgbox at the end lists all deletions
Coding the VBA Editor can be problematic so pls save your work beforehand. I have avoided early binding with the Extensibility library that Pearson has used.
[4 Oct 2012: Updated to work on UserForms rather than Sheets]
SConst vbext_ct_MSForm = 3
Sub ListProcedures()
Dim VBProj
Dim VBComp
Dim CodeMod
Dim LineNum As Long
Dim NumLines As Long
Dim ProcName As String
Dim ObjButton
Dim ProcKind
Dim strBadButtons As String
Set VBProj = ActiveWorkbook.VBProject
For Each VBComp In VBProj.vbcomponents
If VBComp.Type = vbext_ct_MSForm Then
Set CodeMod = VBComp.CodeModule
With CodeMod
LineNum = .CountOfDeclarationLines + 1
Do Until LineNum >= .CountOfLines
ProcName = .ProcOfLine(LineNum, 0)
If ProcName Like "CommandButton*_Click" Then
Set ObjButton = Nothing
On Error Resume Next
Set ObjButton = VBComp.Designer.Controls(Replace(ProcName, "_Click", vbNullString))
On Error GoTo 0
If ObjButton Is Nothing Then
strBadButtons = strBadButtons & CodeMod.Name & "-" & Replace(ProcName, "_Click", vbNullString) & vbNewLine
.DeleteLines .ProcStartLine(ProcName, 0), .ProcCountLines(ProcName, 0)
End If
End If
LineNum = LineNum + 1
Loop
End With
End If
Next
If Len(strBadButtons) > 0 Then MsgBox "Bad Buttons deleted" & vbNewLine & strBadButtons
End Sub
There's a free add-in tool called MZ-Tools that can be used to identify unused procedures (it can do a lot more as well). Here is the link: http://www.mztools.com/v3/download.aspx
I'm developing Rubberduck, an open-source COM add-in for the VBE written in C# that has a code inspections feature that, as of version 1.3 (next release!), will include an inspection that does exactly that:
This inspection isn't specifically looking for unused click handlers as the accepted answer is doing (and if any CommandButtonX was renamed to anything meaningful, then the accepted answer will not find them - but that's not what the original post was about) - it's looking for procedures that are never called, assuming Public procedures and functions in a standard module (i.e. exposed to the host application as "macros" or "user-defined functions"), are used outside of the VBA code.
This version only finds controls on forms, not on worksheets - so handler procedures for ActiveX controls located on a worksheet would actually show up as false positives.
I have to know how can i link the excel database of Instrument loop Diagram in AutoCad format. I have AutoCad Template for a loop typical and Excel Database in which i have 100 Loops information for particular typical.I have AutoCad 2006,2007 and 2011 with me. please suggest idea for linking and generating he AutoCAD Drawings automatically.
The easiest way would be to learn a bit of AutoLisp, which is really worth learning if you're into generating drawings or automating your processes within AutoCAD.
Here's a great website for learning AutoLisp:
http://www.afralisp.net/index.php
AutoDesk's Lisp forum is also a great source of help.
As for extracting the data from Excel, here is a library which really facilitates access from AutoLisp:
http://download.cnet.com/KozMos-VLXLS/3000-2077_4-94214.html
'General rule: excel and acad have to be same like both 64bit or both 32 bit !!!
' You will need to add a reference to the AutoCAD
' Type Library to run this example book. Use the "Tools -
' References" menu. If you prefere you can switch to late
' binding by changeing the AutoCAD types to generic objects
Public Sub Excel_drives_acadPolyline_import_POINTs()
Dim objApp As AcadApplication
Dim objDoc As AcadDocument
Dim objEnt As AcadEntity
Dim varPnt As Variant
Dim strPrmpt As String
Dim intVCnt As Integer
Dim varCords As Variant
Dim varVert As Variant
Dim varCord As Variant
Dim varNext As Variant
Dim intCrdCnt As Integer
On Error GoTo Err_Control
Set objApp = AINTERFACE.Iapp
Set objDoc = objApp.activedocument
AppActivate objApp.CAPTION
objDoc.Utility.GetEntity objEnt, varPnt
If TypeOf objEnt Is AcadLWPolyline Then
AppActivate ThisDrawing.applicaTION.CAPTION
varCords = objEnt.COORDINATES
For Each varVert In varCords
intVCnt = intVCnt + 1
Next
For intCrdCnt = 0 To intVCnt / 2 - 1
varCord = objEnt.COORDINATE(intCrdCnt)
Excel.applicaTION.Cells(intCrdCnt + 1, 1).value = varCord(0)
Excel.applicaTION.Cells(intCrdCnt + 1, 2).value = varCord(1)
Next intCrdCnt
Else
MsgBox "Selected entity was not a LWPolyline"
End If
Exit_Here:
If Not objApp Is Nothing Then
Set objApp = Nothing
Set objDoc = Nothing
End If
Exit Sub
Err_Control:
'debug.print err.DESCRIPTION
Resume Exit_Here
End Sub
'----------------------------------------------------------------
' You will need to add a reference to the Excel
' Type Library to run this.In case of excel excel.exe is the library !
Sub acad-drives_excel()
Dim xAP As Excel.applicaTION
Dim xWB As Excel.Workbook
Dim xWS As Excel.WorkSheet
Set xAP = Excel.applicaTION
Set xWB = xAP.Workbooks.Open(SLOPEDIR.PROJECT & "\A2K2_VBA\IUnknown.xls")
Set xWS = xWB.Worksheets("Sheet1")
MsgBox "Excel says: """ & Cells(1, 1) & """"
Dim A2K As AcadApplication
Dim A2Kdwg As AcadDocument
Set A2K = AINTERFACE.Iapp
Set A2Kdwg = A2K.applicaTION.documents.Add
MsgBox A2K.NAME & " version " & A2K.version & _
" is running."
Dim HEIGHT As Double
Dim p(0 To 2) As Double
Dim TxtObj As ACADTEXT
Dim TxtStr As String
HEIGHT = 1
p(0) = 1: p(1) = 1: p(2) = 0
TxtStr = Cells(1, 1)
Set TxtObj = A2Kdwg.modelspace.AddText(TxtStr, _
p, HEIGHT)
A2Kdwg.SaveAs SLOPEDIR.PROJECT & "\A2K2_VBA\IUnknown.dwg"
A2K.documents.Close
A2K.Quit
Set A2K = Nothing
xAP.Workbooks.Close
xAP.Quit
Set xAP = Nothing
End Sub
Whatever way you choose now you can draw into the autocad drawing by using VBA.
There is another way for non programmers.
AUTOCAD SCRIPT
in fact you can create a excel table which creates this things and then you can export them to a text file. For simple task a solution but crap if you hase more complex things to do.
And last but not least you can create dynamic blocks and use vba to insert them and set the values of their parameters according to your excel sheet. But this would explode this tiny post