<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; VBA: Excel обход ограничений UDF]]></title>
		<link>https://forum.script-coding.com/viewtopic.php?id=9522</link>
		<atom:link href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=9522&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «VBA: Excel обход ограничений UDF».]]></description>
		<lastBuildDate>Wed, 23 Apr 2014 01:31:29 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[VBA: Excel обход ограничений UDF]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=82159#p82159</link>
			<description><![CDATA[<p>Всем доброго времени суток! Как известно, пользовательсие функции, вызываемые из формул в ячейках листа Excel (UDF), не могут никоим образом изменять среду приложения. А при попытке модификации - функция просто прерывается и возвращает #ЗНАЧ!. Хочу предложить вашему вниманию метод обхода данного ограничения. Метод основан на отложенном выполнении целевых функций по событию Workbook_SheetCalculate, в то время как вызов UDF лишь заносит необходимые данные в список отложенных. Данный метод позволит, например, изменять формат ячейки c UDF, или содержимое соседних ячеек, листов, или даже <em>любых доступных данных приложения, не переступая ограничения UDF</em>. Я рассмотрю его реализацию на примере задачи, в которой UDF принимает в качестве аргументов название листа и путь к закрытой книге, и возвращает первую использующуюся строку на этом листе.</p><p><em>Данный код разместить в одном из модулей VBAProject:</em></p><div class="codebox"><pre><code>
Public Tasks, Permit, Transfer

Function GetFirstRowSched(FileName, SheetName) &#039; UDF откладывает занесение значения в ячейку до выполнения всех UDF
    If IsEmpty(Tasks) Then TasksInit
    If Permit Then Tasks.Add Application.Caller, Array(FileName, SheetName) &#039; упаковывает аргументы в массив, ключом словаря является сам объект ячейки UDF
    GetFirstRowSched = Transfer
End Function

Sub TasksInit() &#039; задаются начальные параметры
    Set Tasks = CreateObject(&quot;Scripting.Dictionary&quot;)
    Transfer = &quot;&quot;
    Permit = True
End Sub

Function GetFirstRowConv(FileName, SheetName) &#039; функция работает без ограничений UDF, как обычные процедуры, фактически, расчеты выполняются в данной функции
    With Application.Workbooks.Open(FileName)
        GetFirstRowConv = .Sheets(SheetName).UsedRange.Row
        .Close
    End With
End Function
</code></pre></div><p><em>Данный код разместить в разделе VBAProject - Microsoft Excel Objects - ThisWorkbook:</em></p><div class="codebox"><pre><code>
Private Sub Workbook_SheetCalculate(ByVal Sh As Object) &#039; событие пересчета листа, выполняющее все отложенные вызовы, и помещающее значения в ячейки с UDF
    Dim Task, TempFormula
    If IsEmpty(Tasks) Then TasksInit
    Application.EnableEvents = False
    Permit = False
    For Each Task In Tasks &#039; цикл по объектам всех вызванных ячеек с UDF
        TempFormula = Task.FormulaR1C1
        Transfer = GetFirstRowConv(Tasks(Task)(0), Tasks(Task)(1)) &#039; распаковывает аргументы из массива для выполнения вычислений
        Task.FormulaR1C1 = TempFormula &#039; после данной строки повторно вызывается UDF ячейки Task, и в качестве результата в ячейку возвращается Transfer
        Tasks.Remove Task
    Next
    Application.EnableEvents = True
    Transfer = &quot;&quot;
    Permit = True
End Sub
</code></pre></div><p>Впрочем, для решения конкретно данной задачи, было достаточно составить следующую UDF, использующую позднее связывание, без применения столь витиеватого вышеописанного метода:</p><div class="codebox"><pre><code>
Function GetFirstRowLbind(FileName, SheetName)
    On Error Resume Next
    With CreateObject(&quot;Excel.Application&quot;)
        .Workbooks.Open (FileName)
        GetFirstRowLbind = .Sheets(SheetName).UsedRange.Row
        .Quit
    End With
End Function
</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (omegastripes)]]></author>
			<pubDate>Wed, 23 Apr 2014 01:31:29 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=82159#p82159</guid>
		</item>
	</channel>
</rss>
