Реальная задача: проверить актуальность всех именованных диапазонов, используемых в VBA-проекте. То есть узнать, существует ли имя Range("данные") или [данные]… Сама проверка понятна, но нужно получить перечень используемых в коде именованных диапазонов. Кроме парсинга проекта ничего не смог придумать, но и тут маловато информации.
Нужно найти их в первую очередь в стандартных модулях, неплохо бы - в модулях листов и книги ну и, если получится, то показать, как искать в формах, классах и что там ещё есть (этого в примере нет, т.к. там редко встречается, только модули). В примере подключены библы для словарей (куда собирать имена) и работы с проектом
Function f_NameParse()
Dim dic As New Dictionary
Dim VComp As VBIDE.VBComponent
Dim x, r&
For Each VComp In ActiveWorkbook.VBProject.VBComponents
With VComp.CodeModule
r = 1
Do While .Find("Range", r, 1, 10000, 1000, False, True, True)
Debug.Print .Lines(r, 1): r = r + 1
DoEvents
Loop
End With
Next VComp
End Function
Может экспортировать весь проект в текстовый файл (подскажите как) и искать (уже гораздо проще) там?…
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Msi2102, вот и мне интересен столь очевидный метод, что батеньке пора отдыхать Тем более тут не "имеется в виду", а прямо написано аж в названии темы
Всякое бывает — может реально как-то просто всё делается, но не думаю… Ждём ответа
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Sub SearchCodeModule()
'Searching For Text In A Module
'
'The CodeModule object has a Find method that you can use to search for text within the code module.
'The Find method accepts ByRef Long parameters. Upon input, these parameters specify the range of lines and column to search.
'On output, these values will point to the found text.
'To find the second and subsequent occurence of the text, you need to set the parameters to refer to the text following the found line and column.
'The Find method returns True or False indicating whether the text was found.
'The code below will search all of the code in Module1 and print a Debug message for each found occurrence.
'Note the values set with the SL, SC, EL, and EC variables. The code loops until the Found variable is False.
Dim VBProj As VBIDE.VBProject, VBComp As VBIDE.VBComponent, CodeMod As VBIDE.CodeModule
Dim FindWhat As String, Found As Boolean
Dim SL As Long ' start line
Dim EL As Long ' end line
Dim SC As Long ' start column
Dim EC As Long ' end column
Set VBProj = ActiveWorkbook.VBProject
Set VBComp = VBProj.VBComponents("Module1")
Set CodeMod = VBComp.CodeModule
FindWhat = "findthis"
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)
Do Until Found = False
Debug.Print "Found at: Line: " & CStr(SL) & " Column: " & CStr(SC)
EL = .CountOfLines
SC = EC + 1
EC = 255
Found = .Find(target:=FindWhat, StartLine:=SL, StartColumn:=SC, _
EndLine:=EL, EndColumn:=EC, _
wholeword:=True, MatchCase:=False, patternsearch:=False)
Loop
End With
End Sub
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
БМВ, можно присвоить переменной имени, например, но этого не нужно — и то и то при проверке TypeOf Evaluate(txName) Is Range даёт True, а значит переименовывать именованный диапазон в коде не нужно. Как всегда уходишь от темы))
Если совсем просто, то мне достаточно получить текст кода всего проекта, а уже из него я строковыми смогу повыбирать, что нужно и провести прочие проверки.
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
БМВ: в теме у тебя однозначно одно, а по факту вроде просто как весь проект перебрать
А где у меня написано что-то противоречащее перебору всего проекта? Это и нужно, только способа минимум 2 - парсить сам код или вывести в txt и парсить уже оттуда. Оба варианта описаны в шапке. Если первый не получится, то попробую второй. Реальную проблему прикрепил в том числе и для вас с Игорем - вы ж не можете без этого никак Получается, что нет реального применения - будем вместо решения вопроса его искать, а есть — то смысл, якобы, уже не тот. Забавно
А за ссылки по экспорту спасибо - пусть будет ещё вариант, кроме Cpearson
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Ни хрена не поянтно по парсингу кода: Как (напрямую, без экспорта в текстовый файл и чтения из него) получить строку модуля или весь модуль в строковую переменную, например?…
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Msi2102, ещё раз спасибо за внимание и помощь Хочется всё-таки без сторонних программ понять, как без экспорта нормально парсить код… К тому же, единственное, что в теории может в этом случае помочь из плюшек, это MZ-Tools, а он платный и никакой триал или, упаси боже, пиратку, на работе не поставят
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Jack Famous написал: Как (напрямую, без экспорта в текстовый файл и чтения из него) получить строку модуля или весь модуль в строковую переменную, например?
Я не совсем понимаю, для чего это, но может так:
Код
Sub Текст_кода()
Dim VBProj As VBIDE.VBProject, VBComp As VBIDE.VBComponent, CodeMod As VBIDE.CodeModule
Dim ddd As String
Set VBProj = ActiveWorkbook.VBProject
Set VBComp = VBProj.VBComponents("Module1")
Set CodeMod = VBComp.CodeModule
With CodeMod
ddd = .Lines(1, .CountOfLines)
End With
Debug.Print ddd
End Sub
Весь код в переменную и парсите его сколько угодно
Jack Famous написал: Как (напрямую, без экспорта в текстовый файл и чтения из него) получить строку модуля или весь модуль в строковую переменную, например?
ну как всегда, в общем-то можно, кустарно...Цикл по всем модулям, а там можно от первой строки и до последней просто считывать:
Код
Sub ParseModulesAndProcedures()
Dim VBProj As Object, VBComp As Object, CodeMod As Object
Dim lLineNum&, lNumOfLines&, ll&, llines_cnt&
Dim ProcName$, sLine$, sToFindVal$
sToFindVal = "what are we looking for?"
Set VBProj = ActiveWorkbook.VBProject
'цикл по модулям
For Each VBComp In VBProj.VBComponents
Set CodeMod = VBComp.CodeModule
With CodeMod
lLineNum = .CountOfDeclarationLines + 1
llines_cnt = .CountOfLines
'цикл по каждой строке модуля(кроме деклараций)
For ll = lLineNum To llines_cnt
sLine = .Lines(ll, 1)
If InStr(1, sLine, sToFindVal, 1) > 0 Then
'выводим имя процедуры, в которой нашли значение
ProcName = .ProcOfLine(ll, 0)
Debug.Print "Module name: " & .Name & "; Proc name: " & ProcName
End If
Next
End With
Next
End Sub
процедурка выведет в дебаг имена всех модулей и процедур, в которых найдет значение, заданное переменной sToFindVal. Значения в комментариях так же учитываются, но это уже довольно легко обойти:
Код
Sub ParseModulesAndProcedures()
Dim VBProj As Object, VBComp As Object, CodeMod As Object
Dim lLineNum&, lNumOfLines&, ll&, llines_cnt&
Dim ProcName$, sLine$, sToFindVal$
sToFindVal = "Property Set"
Set VBProj = ActiveWorkbook.VBProject
'цикл по модулям
For Each VBComp In VBProj.VBComponents
Set CodeMod = VBComp.CodeModule
With CodeMod
lLineNum = .CountOfDeclarationLines + 1
llines_cnt = .CountOfLines
'цикл по каждой строке модуля(кроме деклараций)
For ll = lLineNum To llines_cnt
sLine = .Lines(ll, 1)
sLine = Trim(sLine)
If Left(sLine, 1) <> "'" Then
If InStr(1, sLine, sToFindVal, 1) > 0 Then
'выводим имя процедуры, в которой нашли значение
ProcName = .ProcOfLine(ll, 0)
Debug.Print "Module name: " & .Name & "; Proc name: " & ProcName
End If
End If
Next
End With
Next
End Sub
храни тебя Господь, добрый человек Столько перебрал, а это, оказывается, ещё в недокоде было (только поиск не нужен) Поднял, обнял, заплакал, опустил … и ушёл довольный дальше кодить
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Дмитрий(The_Prist) Щербаков, У меня не совсем корректно отработал Ваш макрос Объединил два макроса с того же ресурса из сообщения №6
Код
Код
Sub ListModules_1()
Dim VBProj As VBIDE.VBProject, VBComp As VBIDE.VBComponent, CodeMod As VBIDE.CodeModule, ProcKind As VBIDE.vbext_ProcKind
Dim WS As Worksheet, Rng As Range
Dim LineNum As Long, NumLines As Long, ProcName As String
Set VBProj = ActiveWorkbook.VBProject
Set WS = ActiveWorkbook.Worksheets("Лист3")
Set Rng = WS.Range("A1")
For Each VBComp In VBProj.VBComponents
Set CodeMod = VBComp.CodeModule
' Если нужны все объекты то раскомментировать две строки ниже и одну внизу
' Rng(1, 1).Value = VBComp.Name
' Rng(1, 2).Value = ComponentTypeToString(VBComp.Type)
With CodeMod
LineNum = .CountOfDeclarationLines + 1
Do Until LineNum >= .CountOfLines
Set Rng = Rng(2, 1)
ProcName = .ProcOfLine(LineNum, ProcKind)
Rng(1, 1).Value = VBComp.Name
Rng(1, 2).Value = ComponentTypeToString(VBComp.Type)
Rng(1, 3).Value = ProcName
Rng(1, 4).Value = ProcKindString(ProcKind)
LineNum = .ProcStartLine(ProcName, ProcKind) + _
.ProcCountLines(ProcName, ProcKind) + 1
Loop
End With
' Set Rng = Rng(2, 1)
Next VBComp
End Sub
Function ProcKindString(ProcKind As VBIDE.vbext_ProcKind) As String
Select Case ProcKind
Case vbext_pk_Get
ProcKindString = "Property Get"
Case vbext_pk_Let
ProcKindString = "Property Let"
Case vbext_pk_Set
ProcKindString = "Property Set"
Case vbext_pk_Proc
ProcKindString = "Sub Or Function"
Case Else
ProcKindString = "Unknown Type: " & CStr(ProcKind)
End Select
End Function
Function ComponentTypeToString(ComponentType As VBIDE.vbext_ComponentType) As String
Select Case ComponentType
Case vbext_ct_ActiveXDesigner
ComponentTypeToString = "ActiveX Designer"
Case vbext_ct_ClassModule
ComponentTypeToString = "Class Module"
Case vbext_ct_Document
ComponentTypeToString = "Document Module"
Case vbext_ct_MSForm
ComponentTypeToString = "UserForm"
Case vbext_ct_StdModule
ComponentTypeToString = "Code Module"
Case Else
ComponentTypeToString = "Unknown Type: " & CStr(ComponentType)
End Select
End Function
Msi2102 написал: У меня не совсем корректно отработал Ваш макрос
не очень комильфо говорить "не корректно отработал" и не приводить пример того, где и как Код писался на скорую руку, но даже так не совсем похоже на то, что там много ошибок. На вскидку, проблема может крыться только в этой строке:
Код
.ProcOfLine(ll, 0)
т.к. я взял тип процедуры за 0, хотя по хорошему надо бы её определять. Не думаю, что это самая большая проблема во всем алгоритме.
мне всё понравилось Я не запускал, а пустил на запчасти))
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄
Дмитрий(The_Prist) Щербаков написал: не очень комильфо говорить "не корректно отработал" и не приводить пример того, где и как Код писался на скорую руку,
Извиняюсь, не хотел ни кого обидеть, я не с укором это писал. Просто он не всё нашёл, а файл я приложил, там Ваш макрос на первом месте идёт и в Модуле2 их сразу два. Вот ещё скрин.
Msi2102 написал: он не всё нашёл, а файл я приложил
посмотрел файл. И где он не все нашел? Где еще в файле хоть в одной процедуре есть текст "what are we looking for?"? Я все просмотрел и нашел исключительно в двух процедурах: "Module1 - ParseModulesAndProcedures_3" и "Module2 - ParseModulesAndProcedures". Где по Вашему мнению код отработал неверно? В каких еще процедурах есть указанный текст для поиска? Даже стандартный поиск VBE ничего более не находит. Может Вы что-то другое ищете?
Msi2102 написал: У меня не совсем корректно отработал Ваш макрос
Может это мое субъективное мнение, но код или работает корректно, или нет. Не совсем верный - это результат, а код в этом случае не работает. Хотя в данном случае, как это выяснилось, код рабочий, а вот тест не очень :-)
Не нудный, а предельно точный в терминах (выборочно)
Во всех делах очень полезно периодически ставить знак вопроса к тому, что вы с давних пор считали не требующим доказательств (Бертран Рассел) ►Благодарности сюда◄