• Login
sketchucation logo sketchucation
  • Login
πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

[Code] Win32 - Get SketchUp Window Handle (WIP)

Scheduled Pinned Locked Moved Developers' Forum
40 Posts 5 Posters 10.1k Views
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    Jim
    last edited by 29 Dec 2010, 01:26

    I am not entirely sure the Win32API.so file we all have been using supports callbacks, which the windows enumerator functions require as arguments.

    Specifically, calls to EnumWindows and EnumChildWindows can not be used with Win32API.

    The win32-api ruby library does support callbacks, and we should really be using it anyway. it's more robust, and more stable (I've read.)

    Hi

    1 Reply Last reply Reply Quote 0
    • T Offline
      thomthom
      last edited by 29 Dec 2010, 02:05

      The example I saw of it:
      http://stackoverflow.com/questions/3327666/win32s-findwindow-can-find-a-particular-window-with-the-exact-title-but-what/3328209#3328209

      Seemed to use namespace Win32 as oppose to Win32API.

      So this is not a module that ships with Ruby?

      Thomas Thomassen β€” SketchUp Monkey & Coding addict
      List of my plugins and link to the CookieWare fund

      1 Reply Last reply Reply Quote 0
      • D Offline
        Dan Rathbun
        last edited by 29 Dec 2010, 02:12

        @thomthom said:

        So this is not a module that ships with Ruby?

        Correct... no it's not, because it is platform specific, AND considered an extension. You, or any user must download it from RubyForge. If you want the latest releases, as they are released. I believe you also must compile them yourself, or wait until Mr. Berger & Co decides to do it.

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • D Offline
          Dan Rathbun
          last edited by 29 Dec 2010, 02:32

          @thomthom said:

          win32-api Seemed to use namespace Win32 as oppose to Win32API.

          True it has it's own namespace... and another quirk.. Dan Berger reordered the arguments in the API calls making it a bit cumbersome to have scripts that can use either library.

          I'm not here much anymore.

          1 Reply Last reply Reply Quote 0
          • D Offline
            Dan Rathbun
            last edited by 29 Dec 2010, 02:58

            @jim said:

            I am not entirely sure the Win32API.so file we all have been using supports callbacks, which the windows enumerator functions require as arguments. ...
            Specifically, calls to EnumWindows and EnumChildWindows can not be used with Win32API.

            Actually Win32API.so is obsolete, and for some time, they have been suggesting coders migrate to using the DL library directly.

            In Ruby vers 1.9.x and up... they no longer supply a Win32API.so file, instead they have replaced it with a Win32API.rb script that mimics the old so file, and translates Win32API calls into DL library calls.

            This is the Win32API.rb file distro'd with Ruby v 1.9.1 p429

            <span class="syntaxdefault"></span><span class="syntaxcomment"># -*- ruby -*-<br /># for backward compatibility<br /></span><span class="syntaxdefault">warn </span><span class="syntaxstring">"Warning;#{caller[0].sub(/;in `.*'\z/, '')}; Win32API is deprecated after Ruby 1.9.1; use dl directly instead"</span><span class="syntaxdefault"> if $VERBOSE<br /><br />require </span><span class="syntaxstring">'dl'<br /><br /></span><span class="syntaxdefault">class Win32API<br />  DLL </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{}<br /></span><span class="syntaxdefault">  TYPEMAP </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{</span><span class="syntaxstring">"0"</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">=></span><span class="syntaxdefault"> DL</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">TYPE_VOID</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxstring">"S"</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">=></span><span class="syntaxdefault"> DL</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">TYPE_VOIDP</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxstring">"I"</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">=></span><span class="syntaxdefault"> DL</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">TYPE_LONG</span><span class="syntaxkeyword">}<br /><br /></span><span class="syntaxdefault">  def initialize</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">dllname</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> func</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> import</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> export </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxstring">"0"</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">*</span><span class="syntaxdefault">rest</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">    </span><span class="syntaxkeyword">@</span><span class="syntaxdefault">proto </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">import</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">join</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">tr</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"VPpNnLlIi"</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxstring">"0SSI"</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">sub</span><span class="syntaxkeyword">(/^(.)</span><span class="syntaxdefault">0</span><span class="syntaxkeyword">*$/,</span><span class="syntaxdefault"> </span><span class="syntaxstring">'\1'</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">    handle </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> DLL</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">dllname</span><span class="syntaxkeyword">]</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">||=</span><span class="syntaxdefault"> DL</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">dlopen</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">dllname</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">    </span><span class="syntaxkeyword">@</span><span class="syntaxdefault">func </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> DL</span><span class="syntaxkeyword">;;</span><span class="syntaxdefault">CFunc</span><span class="syntaxkeyword">.new(</span><span class="syntaxdefault">handle</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">func</span><span class="syntaxkeyword">],</span><span class="syntaxdefault"> TYPEMAP</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">export</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">tr</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"VPpNnLlIi"</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxstring">"0SSI"</span><span class="syntaxkeyword">)],</span><span class="syntaxdefault"> func</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">*</span><span class="syntaxdefault">rest</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">  end<br /><br />  def call</span><span class="syntaxkeyword">(*</span><span class="syntaxdefault">args</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">    import </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">@</span><span class="syntaxdefault">proto</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">split</span><span class="syntaxkeyword">(</span><span class="syntaxstring">""</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">    args</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">each_with_index do </span><span class="syntaxkeyword">|</span><span class="syntaxdefault">x</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> i</span><span class="syntaxkeyword">|<br /></span><span class="syntaxdefault">      args</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">i</span><span class="syntaxkeyword">],</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">x </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> 0 </span><span class="syntaxkeyword">?</span><span class="syntaxdefault"> nil </span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> x</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">pack</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"p"</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">unpack</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"l!*"</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> if import</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">i</span><span class="syntaxkeyword">]</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> </span><span class="syntaxstring">"S"<br /></span><span class="syntaxdefault">      args</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">i</span><span class="syntaxkeyword">],</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">[</span><span class="syntaxdefault">x</span><span class="syntaxkeyword">].</span><span class="syntaxdefault">pack</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"I"</span><span class="syntaxkeyword">).</span><span class="syntaxdefault">unpack</span><span class="syntaxkeyword">(</span><span class="syntaxstring">"i"</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> if import</span><span class="syntaxkeyword">[</span><span class="syntaxdefault">i</span><span class="syntaxkeyword">]</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">==</span><span class="syntaxdefault"> </span><span class="syntaxstring">"I"<br /></span><span class="syntaxdefault">    end<br />    ret</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">@</span><span class="syntaxdefault">func</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">call</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">args</span><span class="syntaxkeyword">)<br /></span><span class="syntaxdefault">    return ret </span><span class="syntaxkeyword">||</span><span class="syntaxdefault"> 0<br />  end<br /><br />  alias Call call<br />end<br /></span>
            

            It looks as though the DL library supports callbacks. Maybe we should use it ??

            I've also read that the DL library is 'on the outs', and they are planning to deprecate it and replace it with something else.

            @jim said:

            The win32-api ruby library does support callbacks, and we should really be using it anyway. it's more robust, and more stable (I've read.)

            Yes.. I agree. Dan Berger is a "sharp cookie" when it comes to both Ruby and Windows coding. He is also on several of the MAJOR Ruby development teams including RubyGems and rdoc.
            See his profile: RubyForge Profile for Daniel Berger

            I'm not here much anymore.

            1 Reply Last reply Reply Quote 0
            • T Offline
              thomthom
              last edited by 29 Dec 2010, 03:07

              @dan rathbun said:

              @jim said:

              I am not entirely sure the Win32API.so file we all have been using supports callbacks, which the windows enumerator functions require as arguments. ...
              Specifically, calls to EnumWindows and EnumChildWindows can not be used with Win32API.

              Actually Win32API.so is obsolete, and for some time, they have been suggesting coders migrate to using the DL library directly.

              In Ruby vers 1.9.x and up... they no longer supply a Win32API.so file, instead they have replaced it with a Win32API.rb script that mimics the old so file, and translates Win32API calls into DL library calls.

              Will that work for Ruby 1.8?

              Thomas Thomassen β€” SketchUp Monkey & Coding addict
              List of my plugins and link to the CookieWare fund

              1 Reply Last reply Reply Quote 0
              • D Offline
                Dan Rathbun
                last edited by 29 Dec 2010, 03:30

                @thomthom said:

                I think one can get lots of useful info if one can get the thread id of the SketchUp process. Any ideas of how one can do this.
                How about?
                Process.pid()
                Thread.main.object_id

                @thomthom said:

                I've been scanning the Win32 API a bit today looking for relevant functions.

                Well all the API functions for: [Processes and Threads](http://msdn.microsoft.com/en-us/library/ms684847(v)

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • T Offline
                  thomthom
                  last edited by 29 Dec 2010, 11:46

                  Ah - there we go, that might help.
                  GetCurrentProcessId looks promising.

                  Thomas Thomassen β€” SketchUp Monkey & Coding addict
                  List of my plugins and link to the CookieWare fund

                  1 Reply Last reply Reply Quote 0
                  • T Offline
                    thomthom
                    last edited by 29 Dec 2010, 11:49

                    pid = GetCurrentProcessId.call 4684 Process.pid() 4684
                    It seem to return the same thing.

                    Thomas Thomassen β€” SketchUp Monkey & Coding addict
                    List of my plugins and link to the CookieWare fund

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      Dan Rathbun
                      last edited by 29 Dec 2010, 13:14

                      @thomthom said:

                      pid = GetCurrentProcessId.call 4684 Process.pid() 4684
                      It seem to return the same thing.

                      Yes and it's the same as you'll see in the Task Manager, or using tlist.exe from the command line (for that Sketchup instance.)

                      I'm not here much anymore.

                      1 Reply Last reply Reply Quote 0
                      • D Offline
                        Dan Rathbun
                        last edited by 29 Dec 2010, 13:34

                        @dan rathbun said:

                        It looks as though the DL library supports callbacks. Maybe we should use it ??

                        My bad.. 😳
                        Callbacks were added in 1.9.x, both 1.8.6 and 1.8.7 DL libs don't have the callback.rb file.

                        sorry Thom

                        I'm not here much anymore.

                        1 Reply Last reply Reply Quote 0
                        • T Offline
                          thomthom
                          last edited by 29 Dec 2010, 13:56

                          GetCurrentThreadId I think this one is what we can use to get associated window handles. Just need to get callbacks working so we can use EnumThreadWindows to get the windows for the calling thread.

                          Thomas Thomassen β€” SketchUp Monkey & Coding addict
                          List of my plugins and link to the CookieWare fund

                          1 Reply Last reply Reply Quote 0
                          • T Offline
                            thomthom
                            last edited by 29 Dec 2010, 14:45

                            @jim said:

                            @thomthom said:

                            Where is the win32-api found - the one that supports callbacks?

                            http://win32utils.rubyforge.org/

                            I'm not sure if this can co-exist with Win32API or not.

                            require 'win32/api'
                            [attachment=0:26ojrmbj]<!-- ia0 -->win32.zip<!-- ia0 -->[/attachment:26ojrmbj]

                            I just tried it, works fine with Win32API.

                            Here's a bastardised proof of concept snippet where I found the SketchUp window regardless if it had focus or not.

                            
                            # http://stackoverflow.com/questions/3327666/win32s-findwindow-can-find-a-particular-window-with-the-exact-title-but-what
                            EnumWindows       = Win32;;API.new('EnumWindows', 'KP', 'L', 'user32')
                            EnumThreadWindows = Win32;;API.new('EnumThreadWindows', 'LKP', 'I', 'user32')
                            GetCurrentThreadId = Win32API.new("kernel32.dll", "GetCurrentThreadId", '', 'L')
                            
                            # Detect the toolwindows even if Hide Dialogs is active.
                            def enum_sketchup_windows
                              threadId = GetCurrentThreadId.call
                              enumWindowsProc = Win32;;API;;Callback.new('LP', 'I'){ |handle, param|
                                #puts "EnumWindows - Callback"
                                #puts "> handle; #{handle}"
                                #puts "> param; #{param.inspect}"
                                window_text = get_window_text(handle)
                                window_text.strip! # Remove trailing NULL character
                                p window_text unless window_text.empty?
                                if !window_text.index(param).nil?
                                  puts "window was found; handle #{handle}"
                                  0 # FALSE - stop looking after we find it
                                  1 # TRUE
                                else
                                  1 # TRUE
                                end
                              }
                              EnumThreadWindows.call(threadId, enumWindowsProc, 'SketchUp')
                            end
                            
                            # Takes the first enumerated window for the calling SketchUp thread and fetches
                            # the root owner which should be the SketchUp window. (Not tested against wxSU)
                            #
                            # Is the enum required to get just one window? Any other function to get an
                            # arbitrary window from the SketchUp thread?
                            def find_sketchup_window
                              threadId = GetCurrentThreadId.call
                              hwnd = 0
                              enumWindowsProc = Win32;;API;;Callback.new('LP', 'I'){ |handle, param|
                                hwnd = GetAncestor.call(handle, GA_ROOTOWNER)
                                0
                              }
                              EnumThreadWindows.call(threadId, enumWindowsProc, 'SketchUp')
                              hwnd
                            end
                            
                            

                            Remaining issues:

                            • Migrate Win32API to Win32::API for all function calls.
                            • While testing I eventually got an exception that said there was too many callbacks initiated. Seems there might be a limit. I have not looked into this further, but I think once might have to make one callback proc, and then delegate to the appropriate handling method based on param.

                            Thomas Thomassen β€” SketchUp Monkey & Coding addict
                            List of my plugins and link to the CookieWare fund

                            1 Reply Last reply Reply Quote 0
                            • T Offline
                              thomthom
                              last edited by 29 Dec 2010, 14:56

                              @unknownuser said:

                              = Documentation
                              The source file contains inline RDoc documentation. If you installed
                              this file as a gem, then you have the docs.

                              Where do you get the source code?

                              I tried to install the gem, but got this error:
                              gemInstallError.png

                              Thomas Thomassen β€” SketchUp Monkey & Coding addict
                              List of my plugins and link to the CookieWare fund

                              1 Reply Last reply Reply Quote 0
                              • J Offline
                                Jim
                                last edited by 29 Dec 2010, 15:18

                                It is a c-language based extension, and apparently isn't available already compiled for your platform. So you would need to compile it.

                                This is the advantage of using the mingw32 Ruby Installer with devkit - it automatically builds native libraries.

                                Link Preview Image
                                Downloads

                                The easy way to install Ruby on Windows This is a self-contained Windows-based installer that includes the Ruby language, an execution environment, important...

                                favicon

                                (rubyinstaller.org)

                                Hi

                                1 Reply Last reply Reply Quote 0
                                • T Offline
                                  thomthom
                                  last edited by 29 Dec 2010, 15:33

                                  But where is the source code - since it's suppose to contain the documentation?

                                  Thomas Thomassen β€” SketchUp Monkey & Coding addict
                                  List of my plugins and link to the CookieWare fund

                                  1 Reply Last reply Reply Quote 0
                                  • J Offline
                                    Jim
                                    last edited by 29 Dec 2010, 15:36

                                    For me, it is here:

                                    C:\Ruby186\lib\ruby\gems\1.8\gems\win32-api-1.4.7-x86-mingw32\ext\win32

                                    Hi

                                    1 Reply Last reply Reply Quote 0
                                    • T Offline
                                      thomthom
                                      last edited by 29 Dec 2010, 16:05

                                      hm... guess I have to look into that ming-thing...

                                      Anyway - I have produced a code which appear to return the handle for the SketchUp window of the calling thread. I created a EnumWindowsProc to delegate enumeration messages in order to avoid Error: #<Win32::API::Error: too many callbacks are defined.>. I really want to know what this limit is. This is the first draft, I expect there is a better way to deal with this.

                                      But, we do get a reliable window for the SketchUp window we want - as far as I have been able to test.


                                      Draft 1

                                      Thomas Thomassen β€” SketchUp Monkey & Coding addict
                                      List of my plugins and link to the CookieWare fund

                                      1 Reply Last reply Reply Quote 0
                                      • T Offline
                                        thomthom
                                        last edited by 29 Dec 2010, 16:08

                                        Maybe we can handle drag and drop by callbacks. Or intercept window messages so we can simulate the roll-up/down of toolwindows.

                                        Still, OSX users are out of luck here...

                                        Thomas Thomassen β€” SketchUp Monkey & Coding addict
                                        List of my plugins and link to the CookieWare fund

                                        1 Reply Last reply Reply Quote 0
                                        • D Offline
                                          Dan Rathbun
                                          last edited by 30 Dec 2010, 02:41

                                          Here's some interesting info:

                                          #
                                          #  some Sketchup window properties;
                                          #
                                          #  AutomationId  =  ""
                                          #
                                          #  CLASS   =  "Afx;00400000;b;00010011;00000006;00790557"
                                          #  *** the last octet changes each time Sketchup is run,
                                          #  examples;  "Afx;00400000;b;00010011;00000006;0012077F"
                                          #             "Afx;00400000;b;00010011;00000006;000E0699"
                                          #
                                          #  ControlType           =  "ControlType.Window"
                                          #  LocalizedControlType  =  "window"
                                          #
                                          

                                          The main application window is the only one with a classname like this, and also the only one with a LocalizedControlType that equals "window".

                                          ALL dialogs including WebDialogs, are:

                                          #
                                          #  ClassName             =  "#32770"
                                          #  ControlType           =  "ControlType.Window"
                                          #  LocalizedControlType  =  "Dialog"
                                          #
                                          

                                          I'm not here much anymore.

                                          1 Reply Last reply Reply Quote 0
                                          • 1
                                          • 2
                                          • 1 / 2
                                          1 / 2
                                          • First post
                                            19/40
                                            Last post
                                          Buy SketchPlus
                                          Buy SUbD
                                          Buy WrapR
                                          Buy eBook
                                          Buy Modelur
                                          Buy Vertex Tools
                                          Buy SketchCuisine
                                          Buy FormFonts

                                          Advertisement