<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="https://mg.to" xmlns:dc="https://purl.org/dc/elements/1.1/">
<channel>
 <title>mg.to - Ruby iterators and C callback functions - Comments</title>
 <link>https://mg.to/2004/08/09/ruby-iterators-and-c-callback-functions</link>
 <description>Comments for &quot;Ruby iterators and C callback functions&quot;</description>
 <language>en</language>
<item>
 <title>Building Win32 guitest</title>
 <link>https://mg.to/2004/08/09/ruby-iterators-and-c-callback-functions#comment-4453</link>
 <description>&lt;p&gt;Building win32 guitest in May of 2007 is non-trivial.  I posted a recipie at &lt;a href=&quot;https://www.kleinfelter.com/build-ruby-guitest-win32&quot;&gt;https://www.kleinfelter.com/build-ruby-guitest-win32&lt;/a&gt;&lt;/p&gt;</description>
 <pubDate>Fri, 25 May 2007 01:28:58 +0000</pubDate>
 <dc:creator>Visitor</dc:creator>
 <guid isPermaLink="false">comment 4453 at https://mg.to</guid>
</item>
<item>
 <title>Hi Frank! :-) Yep, I&#039;m stuck with Ruby forever, I guess.</title>
 <link>https://mg.to/2004/08/09/ruby-iterators-and-c-callback-functions#comment-20</link>
 <description>&lt;p&gt;Hi Frank! :-) Yep, I&amp;#8217;m stuck with Ruby forever, I guess.&lt;/p&gt;

&lt;p&gt;Anyone who wonders what the heck Frank is talking about, here is &lt;a href=&quot;https://www.cooper.com/alan/father_of_vb.html&quot;&gt;the full story&lt;/a&gt;.&lt;/p&gt;</description>
 <pubDate>Wed, 01 Sep 2004 21:45:04 +0000</pubDate>
 <dc:creator>Michael Geary</dc:creator>
 <guid isPermaLink="false">comment 20 at https://mg.to</guid>
</item>
<item>
 <title>Just can&#039;t get away from that</title>
 <link>https://mg.to/2004/08/09/ruby-iterators-and-c-callback-functions#comment-19</link>
 <description>&lt;p&gt;Just can&amp;#8217;t get away from that Ruby code, eh, Mike?&lt;/p&gt;</description>
 <pubDate>Tue, 17 Aug 2004 23:33:41 +0000</pubDate>
 <dc:creator>Frank</dc:creator>
 <guid isPermaLink="false">comment 19 at https://mg.to</guid>
</item>
<item>
 <title>Ruby iterators and C callback functions</title>
 <link>https://mg.to/2004/08/09/ruby-iterators-and-c-callback-functions</link>
 <description>&lt;p&gt;&lt;a href=&quot;https://www.sax.net/live/&quot;&gt;Mike Sax&lt;/a&gt; wonders what&amp;#8217;s the fuss about iterators. Aren&amp;#8217;t they just a &lt;a href=&quot;https://www.sax.net/live/?date=8/3/2004#at10:20PM&quot;&gt;fancy use of function pointers&lt;/a&gt;? Indeed, Mike has hit the nail on the head. Consider the window iterator that&amp;#8217;s been built into Windows since 1.0:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-c&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;BOOL EnumWindows&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; WNDENUMPROC lpEnumFunc, LPARAM lParam &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This function iterates through all of the top-level windows (children of the desktop window) and calls &lt;code&gt;lpEnumFunc&lt;/code&gt; for each one, passing it the &lt;code&gt;HWND&lt;/code&gt; of each window and the &lt;code&gt;lParam&lt;/code&gt; that you passed to &lt;code&gt;EnumWindows&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;lParam&lt;/code&gt; is how you get to provide some state that the enumeration function can make use of. Suppose you wanted to write a function that counted the number of visible top-level windows. Your C code might look like this:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-c&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #993333;&quot;&gt;struct&lt;/span&gt; MyEnumWindowState&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #993333;&quot;&gt;int&lt;/span&gt; nVisible;&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt;;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
BOOL CALLBACK MyEnumWindowsProc&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; HWND hwnd, LPARAM lParam &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; MyEnumWindowState* pState = &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;MyEnumWindowState*&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;lParam;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; IsWindowVisible&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;hwnd&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; pState-&amp;gt;nVisible++;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #993333;&quot;&gt;int&lt;/span&gt; CountVisibleWindows&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; MyEnumWindowState state;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; state.&lt;span style=&quot;color: #202020;&quot;&gt;nVisible&lt;/span&gt; = &lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt;;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; EnumWindows&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; MyEnumWindowsProc, &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;LPARAM&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&amp;amp;state &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;return&lt;/span&gt; state.&lt;span style=&quot;color: #202020;&quot;&gt;nVisible&lt;/span&gt;;&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This works, but it is rather tedious. So Windows 2.0 added the &lt;code&gt;GetWindow&lt;/code&gt; function, which lets you simply ask for a window&amp;#8217;s child or next sibling. That simplifies the overall structure of the code, especially if you use the &lt;code&gt;GetFirstChild&lt;/code&gt; and &lt;code&gt;GetNextSibling&lt;/code&gt; macros defined in &lt;code&gt;windowsx.h&lt;/code&gt;:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-c&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #993333;&quot;&gt;int&lt;/span&gt; CountVisibleWindows&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #993333;&quot;&gt;int&lt;/span&gt; nVisible = &lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; HWND hwnd = GetDesktopWindow&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; hwnd = GetFirstChild&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;hwnd&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;hwnd;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;hwnd = GetNextSibling&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;hwnd&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; IsWindowVisible&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;hwnd&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nVisible++;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;return&lt;/span&gt; nVisible;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That&amp;#8217;s it, just one function, no callback function or struct definition needed. We don&amp;#8217;t need the struct because the code inside the loop can directly reference the &lt;code&gt;nVisible&lt;/code&gt; variable defined in the function.&lt;/p&gt;

&lt;p&gt;But the simplification came at a price: We had to write the loop ourselves, asking explicitly for the first child of the desktop window and then the next sibling of each child window.&lt;/p&gt;

&lt;p&gt;Also, it doesn&amp;#8217;t work.&lt;/p&gt;

&lt;p&gt;What if another application creates or destroys a top-level window, or just changes a window&amp;#8217;s &lt;a href=&quot;https://en.wikipedia.org/wiki/Z-order&quot;&gt;Z-order&lt;/a&gt;, while you&amp;#8217;re in the loop? You&amp;#8217;ll either miss a window, count one twice, or crash with an invalid window handle.&lt;/p&gt;

&lt;p&gt;To handle these cases, you need a bit more complexity. If you had a way to temporarily lock all window creation and destruction, you could quickly create a list of all the windows and then release the lock, then enumerate from that list, perhaps also doing a last-minute check when you enumerate each window to skip any that get destroyed during enumeration. Or, you might set a Windows hook to notify you of any windows created, destroyed, or moved in the Z-order, so you could deal with them appropriately.&lt;/p&gt;

&lt;p&gt;Whatever you did, it would be enough code that you wouldn&amp;#8217;t want to duplicate it each time you wanted to write a window loop. The &lt;code&gt;GetFirstChild&lt;/code&gt;/&lt;code&gt;GetNextSibling&lt;/code&gt; style of loop doesn&amp;#8217;t really facilitate that kind of code isolation. The &lt;code&gt;EnumWindows&lt;/code&gt; style enumerator completely separates the code that does the iterating  (&lt;code&gt;EnumWindows&lt;/code&gt; itself) from the code that receives the iteration (your callback function). But, it makes it harder to share state between the callback function and the code that called &lt;code&gt;EnumWindows&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you had a way to use a callback function, but have it more easily share state with the calling function, you&amp;#8217;d have a winner. In &lt;a href=&quot;https://en.wikipedia.org/wiki/C_Sharp&quot;&gt;C#&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Javascript&quot;&gt;JavaScript&lt;/a&gt;, you can do this by using an anonymous callback function nested inside the surrounding code. Because of &lt;a href=&quot;https://en.wikipedia.org/wiki/Lexical_scoping&quot;&gt;lexical scoping&lt;/a&gt;, the callback function can access variables in the parent function as easily as it can access its own.&lt;/p&gt;

&lt;p&gt;Both those language have enough extra syntactic cruft that when you look at a simple example using nested anonymous functions, it&amp;#8217;s easy to be unimpressed. The payoff shows up in more complicated, real-life coding situations.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Ruby_programming_language#Blocks_and_iterators&quot;&gt;Code blocks&lt;/a&gt; in Ruby simplify this technique down to its essence, making it useful even for simple cases. Assuming a good Rubyesque Windows interface library, our function might be something like:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-ruby&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;def&lt;/span&gt; countVisibleWindows&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; nVisible = &lt;span style=&quot;color:#006666;&quot;&gt;0&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; Win.&lt;span style=&quot;color:#9900CC;&quot;&gt;enumWindows&lt;/span&gt; &lt;span style=&quot;color: #C00000;&quot;&gt;do&lt;/span&gt; |window|&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nVisible += &lt;span style=&quot;color:#006666;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #C00000;&quot;&gt;if&lt;/span&gt; window.&lt;span style=&quot;color:#9900CC;&quot;&gt;visible&lt;/span&gt;?&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; nVisible&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this code, the &lt;code&gt;enumWindows&lt;/code&gt; function takes a code block argument and calls that code block for each window, passing it the window as an argument. Because the code block is nested inside the &lt;code&gt;countVisibleWindows&lt;/code&gt; function, it can access the &lt;code&gt;nVisible&lt;/code&gt; variable directly.&lt;/p&gt;

&lt;p&gt;This solves both our problems: The logic for iterating through the windows is separated out into the &lt;code&gt;enumWindows&lt;/code&gt; function, and the callback function (code block) can access state variables cleanly and easily.&lt;/p&gt;

&lt;p&gt;(In Ruby, a code block is a like a callback function, but it&amp;#8217;s not quite a full-fledged function. A code block does not introduce a new scope for variables&amp;#151;it shares the scope of the enclosing function.)&lt;/p&gt;

&lt;p&gt;Unfortunately, Ruby does not seem to have a Windows interface library that works like this. Ruby&amp;#8217;s standard  &lt;code&gt;Win32&lt;/code&gt; module provides a general way to call Windows DLL functions, but it doesn&amp;#8217;t have a clean implementation of &lt;code&gt;enumWindows&lt;/code&gt; that uses a code block.&lt;/p&gt;

&lt;p&gt;However, &lt;a href=&quot;https://www.moonwolf.com/&quot;&gt;MoonWolf&lt;/a&gt; has written a &lt;a href=&quot;https://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view;name=Win32%3A%3AGuiTest&quot;&gt;Ruby port&lt;/a&gt; of &lt;a href=&quot;https://www.perl.org/&quot;&gt;Perl&amp;#8217;s&lt;/a&gt; &lt;a href=&quot;https://triumvir.org/prog/perl/guitest/&quot;&gt;Win32::GuiTest&lt;/a&gt; module that includes this kind of &lt;code&gt;enumWindows&lt;/code&gt; function. It&amp;#8217;s implemented in two parts: a low level function written in C that enumerates &lt;code&gt;HWND&lt;/code&gt; values, and a higher level function written in Ruby that constructs Ruby &lt;code&gt;window&lt;/code&gt; objects and enumerates them. The &lt;code&gt;window&lt;/code&gt; object in &lt;code&gt;Win32::GuiTest&lt;/code&gt; is a fairly thin wrapper that encapsulates an &lt;code&gt;HWND&lt;/code&gt; and other window information.&lt;/p&gt;

&lt;p&gt;The high-level &lt;code&gt;enumWindows&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-ruby&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;def&lt;/span&gt; enumWindows&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; ret = &lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; GuiTest::_enumWindows &lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt; |hwnd|&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; win = createWindow&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; hwnd &lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ret &amp;lt;&amp;lt; win&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;yield&lt;/span&gt; win &lt;span style=&quot;color: #C00000;&quot;&gt;if&lt;/span&gt; block_given?&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; ret&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This code calls the low-level &lt;code&gt;_enumWindows&lt;/code&gt; function, which passes an &lt;code&gt;HWND&lt;/code&gt; to the code block enclosed in curly braces. This code block creates the &lt;code&gt;window&lt;/code&gt; object, appends to the &lt;code&gt;ret&lt;/code&gt; array, and also yields the window object to a code block that was provided by the caller of &lt;code&gt;enumWindows&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If I were implementing this, I think I would change it a bit. Typically a function like this either yields results to a code block, or it returns a value, but not both. And I would change the confusingly named &lt;code&gt;createWindow&lt;/code&gt; function (which has no relation to the &lt;a href=&quot;https://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/Windows/WindowReference/WindowFunctions/CreateWindow.asp&quot;&gt;&lt;code&gt;CreateWindow&lt;/code&gt;&lt;/a&gt; function in Windows):&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-ruby&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;def&lt;/span&gt; enumWindows&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;if&lt;/span&gt; block_given?&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; GuiTest::_enumWindows &lt;span style=&quot;color: #C00000;&quot;&gt;do&lt;/span&gt; |hwnd|&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;yield&lt;/span&gt; newWindow&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; hwnd &lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;else&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result = &lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#91;&lt;/span&gt;&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#93;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; GuiTest::_enumWindows &lt;span style=&quot;color: #C00000;&quot;&gt;do&lt;/span&gt; |hwnd|&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result &amp;lt;&amp;lt; newWindow&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; hwnd &lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; result&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Either way, our &lt;code&gt;countVisibleWindows&lt;/code&gt; example ends up pretty much as I&amp;#8217;d imagined:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-ruby&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;def&lt;/span&gt; countVisibleWindows&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color:#006600; font-weight:bold;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; nVisible = &lt;span style=&quot;color:#006666;&quot;&gt;0&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; Win32::GuiTest.&lt;span style=&quot;color:#9900CC;&quot;&gt;enumWindows&lt;/span&gt; &lt;span style=&quot;color: #C00000;&quot;&gt;do&lt;/span&gt; |window|&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; nVisible += &lt;span style=&quot;color:#006666;&quot;&gt;1&lt;/span&gt; &lt;span style=&quot;color: #C00000;&quot;&gt;if&lt;/span&gt; window.&lt;span style=&quot;color:#9900CC;&quot;&gt;isWindowVisible&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; nVisible&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #C00000;&quot;&gt;end&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The low-level &lt;code&gt;&lt;em&gt;enumWindows&lt;/code&gt; function that enumerates &lt;code&gt;HWND&lt;/code&gt; values is implemented in C. The initialization code to add the &lt;code&gt;&lt;/em&gt;enumWindows&lt;/code&gt; function is simply:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-c&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;rb_define_module_function&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; mGuiTest, &lt;span style=&quot;color: #ff0000;&quot;&gt;&quot;_enumWindows&quot;&lt;/span&gt;, guitest_enumWindows, &lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where &lt;code&gt;mGuiTest&lt;/code&gt; is a reference to the &lt;code&gt;Win32::GuiTest&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;guitest_enumWindows&lt;/code&gt; function is:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-c&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #993333;&quot;&gt;static&lt;/span&gt; VALUE guitest_enumWindows&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; VALUE self &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; EnumWindows&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; &amp;amp;EnumWindowsProc, &lt;span style=&quot;color: #cc66cc;&quot;&gt;0&lt;/span&gt; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;return&lt;/span&gt; Qnil;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and the &lt;code&gt;EnumWindowsProc&lt;/code&gt; callback is:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div class=&quot;geshi-c&quot;&gt;&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;BOOL CALLBACK EnumWindowsProc&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; HWND hwnd, LPARAM lParam &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;
&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#123;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&amp;nbsp; &amp;nbsp; rb_yield&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt; INT2NUM&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#40;&lt;/span&gt;DWORD&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;hwnd&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#41;&lt;/span&gt;;&lt;br /&gt;&lt;/div&gt;
&amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #C00000;&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #000000; font-weight: bold;&quot;&gt;TRUE&lt;/span&gt;;&lt;br /&gt;
&lt;div style=&quot;background-color:rgb(255,234,216);&quot;&gt;&lt;span style=&quot;color: #66cc66;color: #0000FF;&quot;&gt;&amp;#125;&lt;/span&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This shows how easy it is to extend Ruby with C code, adding functions that work just like ones written in Ruby.&lt;/p&gt;

&lt;p&gt;So, how do all the calls and callbacks stack up when we run the &lt;code&gt;countVisibleWindows&lt;/code&gt; function? Something like this:&lt;/p&gt;

&lt;div style=&quot;padding: 5px !important; border: 1px solid rgb(253,187,134) !important; background-color: rgb(255,253,245) !important; font-family: Verdana,sans-serif !important;&quot;&gt;&lt;div style=&quot;background-color: rgb(255,250,238) !important;&quot;&gt;&lt;div&gt;countVisibleWindows&lt;br /&gt;
&amp;nbsp; enumWindows&lt;br /&gt;
&amp;nbsp; &amp;nbsp; _enumWindows&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; EnumWindows&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; EnumWindowsProc&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; rb_yield&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (code block in enumWindows)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; yield&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (code block in&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;countVisibleWindows)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In everyday use, of course, you don&amp;#8217;t worry about that whole call stack, just the part of it you&amp;#8217;re working with.&lt;/p&gt;
</description>
 <comments>https://mg.to/2004/08/09/ruby-iterators-and-c-callback-functions#comments</comments>
 <category domain="https://mg.to/topics/programming/c-c">C/C++</category>
 <category domain="https://mg.to/topics/programming">Programming</category>
 <category domain="https://mg.to/topics/programming/ruby">Ruby</category>
 <category domain="https://mg.to/topics/programming/win32.html">Win32</category>
 <pubDate>Mon, 09 Aug 2004 08:00:00 +0000</pubDate>
 <dc:creator>Michael Geary</dc:creator>
 <guid isPermaLink="false">11 at https://mg.to</guid>
</item>
</channel>
</rss>
