Community
    • Login

    How to get the scintilla view0/view1 HWNDs

    Scheduled Pinned Locked Moved Notepad++ & Plugin Development
    31 Posts 7 Posters 6.8k 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.
    • Alan KilbornA
      Alan Kilborn @Ekopalypse
      last edited by

      @Ekopalypse

      Looks good; however, I would put a u in front of 'Scintilla'.

      :)

      1 Reply Last reply Reply Quote 1
      • Michael VincentM
        Michael Vincent
        last edited by

        @PeterJones

        I’ve always wanted a PerlScript plugin

        Yeah, me too …

        There’s this: NPPRunPerl, “A Notepad++ plugin to comfortably create and run a perl script to transform the current file or selection”.

        I tried it in the past and it wasn’t quite as robust or reliable as I’d hoped.

        Cheers.

        1 Reply Last reply Reply Quote 2
        • Alan KilbornA
          Alan Kilborn @PeterJones
          last edited by

          @PeterJones

          So it would be interesting to keep reading about your marriage-of-npp-and-perl saga here in this thread. Do keep us posted.

          I presume that once you have the scintilla_hwnds, you’ll proceed by creating a wrapper function for each of the Scintilla functions, like the Pythonscript Editor class provides in that language for the instantiated objects editor1 and editor2.

          Maybe something like this Python, but translated into Perl:

          sci_GetDirectPointer = 2185
          sci_GetMargins = 2253
          scintilla_direct_pointer = [ SendMessage(scintilla_hwnd[0], sci_GetDirectPointer, 0, 0), SendMessage(scintilla_hwnd[1], sci_GetDirectPointer, 0, 0) ]
          scintilla_direct_function = ctypes.WinDLL('SciLexer.dll', use_last_error=True).Scintilla_DirectFunction
          
          def editor_GetMargins(view): return scintilla_direct_function(scintilla_direct_pointer[view], sci_GetMargins, 0, 0)
          

          which leads into usage:

          print('view 0 number_of_margins:', editor_GetMargins(0))
          

          (I use the get-margins example function here because I have code like the above in use, because the Pythonscript API doesn’t have anything for it, or I can’t find it.)

          Anyway, definitely looking forward to reading more about the Perl thing here!

          1 Reply Last reply Reply Quote 2
          • PeterJonesP
            PeterJones
            last edited by PeterJones

            @Alan-Kilborn said:

            you’ll proceed by creating a wrapper function for each of the Scintilla functions, like the Pythonscript Editor class

            Yes, my goal would be to get as many of the Messages (Notepad++ or Scintilla) as I can. Though full implementation (or even matching all of PythonScript’s available messages) will take a while.

            once you have the scintilla_hwnds

            I’ve thought of a fallback, though it’s not elegant. I might be able to launch my ExternalPerlScript automator from Notepad++ (maybe through NppExec, or irony of ironies, through PythonScript), and pass along the scintilla HWNDs as arguments.
            Or, if I don’t need a dockable component, maybe @Michael-Vincent could get me to the point he mentioned here, with a gcc-compiled plugin, as long as it doesn’t need a dockable component. Because really, if I have a plugin that just responds to a couple of queries, I might be able to send NPPM_MSGTOPLUGIN from the external perl process to talk with the internal simple-plug.

            Hmm, how about it, @Michael-Vincent? Do you still have a super-simple plugin that just uses gcc/g++ and gmake/dmake to get an about-box? If I could start with that, I’d have a new direction to explore (and might eventually figure out how to get more fancy, and learn more about the plugins, even if I never go dockable…)

            1 Reply Last reply Reply Quote 0
            • Michael VincentM
              Michael Vincent
              last edited by

              @PeterJones

              When I started the simple plugins I “wrote” (read: liberally borrowed others’ code and put into the provided N++ plugin template), I started with gcc / gmake (provided from Strawberry Perl). As that other thread indicates, once I started to add dockable components, it wouldn’t work. There were also some other issues in that I wasn’t statically linking the libc so if I compiled for 32-bit but then had my 64-bit Perl in my path, my plugin wouldn’t load in 32-bit N++.

              Anyway, to see examples of some simple plugin with a Makefile for gcc:

              https://github.com/vinsworldcom/nppGitSCM/releases/tag/1.0.1.1
              https://github.com/vinsworldcom/nppColumnTools/releases/tag/1.0.1.2

              1 Reply Last reply Reply Quote 2
              • PeterJonesP
                PeterJones
                last edited by

                @PeterJones said:

                I’ll run some experiments to see if the order is consistently the same

                So far, so good.

                At first, I was seeing the Find Results scintilla window (and PythonScript scintilla window) show up in my enumeration before the first, but when I’d run @Ekopalypse’s python-based enumeration, it always only listed the four, and the first two always matched the two editors. I eventually determined that the Find Results and Python Script have an intermediate generation between the NPP hwnd and the scintilla hwnd; Eko’s python enumeration correctly checked whether their immediate parent was NPP, and ignored it if not; once I added that to my enumeration, it seems to keep the two editors as the first two.

                I’ll probably make that assumption for now, and move forward.

                Again, thank you all.

                1 Reply Last reply Reply Quote 1
                • EkopalypseE
                  Ekopalypse
                  last edited by

                  @Alan-Kilborn

                  Looks good; however, I would put a u in front of ‘Scintilla’.

                  Ahh, python2 :-D can handle this :-D

                  @PeterJones
                  I don’t have access to my windows pc at the moment, but I played a little bit trying to embed perl in a c++ program. Seems to be pretty straightforward.
                  On linux afer installing libperl-dev this compiled.

                  #include <EXTERN.h>
                  #include <perl.h>
                  
                  static PerlInterpreter *my_perl;
                  
                  
                  void run(char ** filename)
                  {
                      my_perl = perl_alloc();
                      perl_construct(my_perl);
                      perl_parse(my_perl, NULL, 0, filename, (char **)NULL);
                      perl_run(my_perl);
                      perl_destruct(my_perl);
                      perl_free(my_perl);
                  
                  }
                  
                  
                  int main(int argc, char **argv, char **env)
                  {
                      char* filename[] = {"", "/home/eko/Documents/c_c++/test.pl"};
                      run(filename);
                  }
                  

                  Next week when I’m at home again, I could try to see if this can be embedded into a win dll if no one else found/reported how to do it in the meantime.

                  1 Reply Last reply Reply Quote 3
                  • PeterJonesP
                    PeterJones
                    last edited by

                    UPDATE: repo for the perl module is now publicly available at https://github.com/pryrt/Win32-Mechanize-NotepadPlusPlus …

                    So far:

                    • I can get the HWND for the Notepad++ GUI as well as the first two child-Scintilla windows, which are assumed to be editor1 and editor2
                    • I can send generic messages to the Notepad++ object. There are wrappers for grabbing an integer or a single string from the LPARAM. Still need to work on other LPARAM and/or WPARAM return-data-types
                    • Still need to write all the Perl wrappers for Notepad++ and Scintilla messages (ie, the bulk of it)

                    Once I got it to the point that I had the editor HWNDs, and was able to convert the NPP and Scintilla messages from the .h files to Perl sub-modules (to give Perl easy access to a hash of messages for each window type), I decided it was sufficient to move from my private subversion repo to a public GitHub repo.

                    It shows the general structure, and the whole look-and-feel of my coding, though there’s not much there.

                    EkopalypseE 1 Reply Last reply Reply Quote 3
                    • EkopalypseE
                      Ekopalypse @PeterJones
                      last edited by Ekopalypse

                      @PeterJones @michael-vincent

                      I need some advice.
                      I cloned the perl github repo and built, tested and installed perl - so far so good, got some interpreter which seems to do what it should.
                      Now, when trying to build an embedded perl with the same, except for the path of the test script, c++ code as posted before it crashes when doing perl_parse.
                      It looks like the issue is that it is looking for a path or perl module called MSWin32-x64-multi-thread like
                      …EmbeddedPerl\x64\Debug\lib\MSWin32-x64-multi-thread.
                      Searching the web seems to indicate that MSWin32-x64-multi-thread is only the constructed architecture name used to build unique
                      interpreters but not that there is something created in .\lib directory called MSWin32-x64-multi-thread. Did you faced some similar issue
                      when working with perl? Do you have some good mailing lists, forums etc… where I could ask for clarification about this?

                      Thank you

                      1 Reply Last reply Reply Quote 1
                      • PeterJonesP
                        PeterJones
                        last edited by

                        I cloned the perl github repo and built, tested and installed perl

                        On Windows? Wow, that’s impressive. I always use Strawberry Perl. (But from what little I know of embedding Perl in other apps/libraries/etc, I think you need to use the same compiler – or at least compatible compiler options – so it might be a necessary evil.)

                        Do you have some good mailing lists, forums etc… where I could ask for clarification about this?

                        Michael and I are both on perlmonks.org (he’s vinsworldcom, I’m pryrt), and that’s where I’d recommend asking.

                        EkopalypseE 1 Reply Last reply Reply Quote 2
                        • EkopalypseE
                          Ekopalypse @PeterJones
                          last edited by

                          @PeterJones

                          that’s where I’d recommend asking.

                          Thanks, and that’s what I did :-)

                          1 Reply Last reply Reply Quote 1
                          • PeterJonesP
                            PeterJones
                            last edited by

                            @Ekopalypse said:

                            what I did

                            For future readers, here’s a link to his post: https://perlmonks.org/?node_id=11103649

                            1 Reply Last reply Reply Quote 0
                            • Teespring TeesT
                              Teespring Tees
                              last edited by

                              This post is deleted!
                              1 Reply Last reply Reply Quote -1
                              • PeterJonesP
                                PeterJones
                                last edited by PeterJones

                                I see that @Ekopalypse is making progress on his embedding-perl-using-VS2017, per his posts on perlmonks. That’s great.

                                Semi-OT, but related to my implementation of perl modules to talk with Notepad++: I’m finding problems, because the perl-wrapper-library around SendMessage that I’m using (Win32::GuiTest) is truncating the 64-bit return-value of some Notepad++ messages (like GET_CURENTBUFFERID, which when talking with 64bit Notepad++ can return ID’s > 0xFFFFFFFF)

                                I’m hoping to file a bug report with the module author, but it would go better if I could give a concrete example of a message that will return >32bits, but doesn’t require the module author to install/download Notepad++. (I have made a dummy windows app which just listens for a message and returns a 64bit number; so if necessary, I can send that code in my bug report, so that there’s a known tool to give the example of the failing condition. But if there were a standard windows program that responded to a specific message with a 64-bit-filling number, that would be an easier example to show the module author.)

                                So I’ll ask an OT question here: do any users here with more Win32-API experience than I have know of a standard application (that most or all windows users can be expected to have, like notepad.exe) that has a message that returns* a number that requires more than 32 bits? (I’d prefer one that returns something other than 0xFFFFFFFF_FFFFFFFF, because the failure mechanism extends the 32nd bit to the left to fill all 64bits.) *: by “return”, I mean the retval from retval = SendMessage(...); it can correctly return 64bit values through LPARAM and WPARAM as pointers.

                                EkopalypseE 1 Reply Last reply Reply Quote 1
                                • EkopalypseE
                                  Ekopalypse @PeterJones
                                  last edited by

                                  @PeterJones

                                  I don’t know a message which returns an 64bit integer but may I ask you whether your perl is a 64bit application? I mean, LRESULT is defined as LONG_PTR which itself is defined as

                                  #if defined(_WIN64)
                                   typedef __int64 LONG_PTR; 
                                  #else
                                   typedef long LONG_PTR;
                                  #endif
                                  

                                  So in case you are using a 32bit perl it might explain the behavior.

                                  1 Reply Last reply Reply Quote 1
                                  • PeterJonesP
                                    PeterJones
                                    last edited by

                                    @Ekopalypse said:

                                    So in case you are using a 32bit perl it might explain the behavior.

                                    I am using 64bit strawberry perl.

                                    I know exactly where the bug is: in the “XS” glue (which is a pseudo-c wrapper language that binds DLL function names into perl subroutine namespace), the module declares SendMessage as int SendMessage, where int is still 32bits, rather than using a 64bit type (due to the restrictions of XS, it cannot be LRESULT, but there is an XS equivalent, IV, which is the type of that perl’s integer value; in the 64bit perl, it’s an 8-byte type, as it needs to be to line up with LRESULT).

                                    I just want an easy way to show the author how the bug and the fix both work, to try to encourage a prompt release of the fix. (Though, given that it’s been a few years since that module was last updated, I don’t know how “prompt” it will be.)

                                    I can, and probably soon will, submit the bug report and pull request with my suggested fix, but it would be nice if I had a simple way to replicate the problem with the bug.

                                    Alan KilbornA EkopalypseE 3 Replies Last reply Reply Quote 1
                                    • Alan KilbornA
                                      Alan Kilborn @PeterJones
                                      last edited by

                                      @PeterJones said:

                                      in the “XS” glue (which is a pseudo-c wrapper language that binds DLL function names into perl subroutine namespace), the module declares SendMessage as int SendMessage, where int is still 32bits, rather than using a 64bit type (due to the restrictions of XS, it cannot be LRESULT, but there is an XS equivalent, IV, which is the type of that perl’s integer value; in the 64bit perl, it’s an 8-byte type, as it needs to be to line up with LRESULT).

                                      You nerdy (Perl) geeks have lost me (by roughly half of the discussion), but it is fascinating reading. Pray continue. :)

                                      1 Reply Last reply Reply Quote 1
                                      • EkopalypseE
                                        Ekopalypse @PeterJones
                                        last edited by

                                        @PeterJones

                                        I see, what about using something like this

                                        use Win32::API;
                                        use Encode;
                                        
                                        # HWND FindWindowExW(
                                          # HWND    hWndParent,
                                          # HWND    hWndChildAfter,
                                          # LPCWSTR lpszClass,
                                          # LPCWSTR lpszWindow
                                        # );
                                        
                                        my $FindWindow = new Win32::API::More('User32', 'FindWindowExW', 'qqPP', 'q');
                                        if(not defined $FindWindow) {
                                            die "Can't import API FindWindowExW: $^E\n";
                                        }
                                        
                                        # LRESULT SendMessageW(
                                          # HWND   hWnd,
                                          # UINT   Msg,
                                          # WPARAM wParam,
                                          # LPARAM lParam
                                        # );
                                        
                                        my $SendMessage = new Win32::API::More('User32', 'SendMessageW', 'qIQq', 'q');
                                        if(not defined $SendMessage) {
                                            die "Can't import API SendMessageW: $^E\n";
                                        }
                                        
                                        my $npp_hwnd = $FindWindow->Call(0, 0, encode('UTF-16le',"Notepad++\0"), 0);
                                        print "hwnd: $npp_hwnd\n";
                                        
                                        my $NPPMSG = 2024;
                                        my $NPPM_GETCURRENTBUFFERID = $NPPMSG + 60;
                                        my $current_buffer_id = $SendMessage->Call($npp_hwnd, $NPPM_GETCURRENTBUFFERID, 0, 0);
                                        print "current_buffer_id: $current_buffer_id\n";
                                        

                                        I’m not 100% certain about the datatypes but seems to work.

                                        1 Reply Last reply Reply Quote 1
                                        • EkopalypseE
                                          Ekopalypse @PeterJones
                                          last edited by

                                          @PeterJones

                                          just for fun

                                          use strict;
                                          use warnings;
                                          use Win32::API;
                                          use Win32::API::Callback;
                                          use Encode;
                                          
                                          # HWND FindWindowExW(
                                            # HWND    hWndParent,
                                            # HWND    hWndChildAfter,
                                            # LPCWSTR lpszClass,
                                            # LPCWSTR lpszWindow
                                          # );
                                          
                                          my $FindWindow = new Win32::API::More('User32', 'FindWindowExW', 'qqPP', 'q');
                                          if(not defined $FindWindow) {
                                              die "Can't import API FindWindowExW: $^E\n";
                                          }
                                          
                                          # LRESULT SendMessageW(
                                            # HWND   hWnd,
                                            # UINT   Msg,
                                            # WPARAM wParam,
                                            # LPARAM lParam
                                          # );
                                          
                                          my $SendMessage = new Win32::API::More('User32', 'SendMessageW', 'qIQq', 'q');
                                          if(not defined $SendMessage) {
                                              die "Can't import API SendMessageW: $^E\n";
                                          }
                                          
                                          # BOOL EnumChildWindows(
                                            # HWND        hWndParent,
                                            # WNDENUMPROC lpEnumFunc,
                                            # LPARAM      lParam
                                          # );
                                          my $EnumChildWindows = new Win32::API::More('User32', 'EnumChildWindows', 'qKq', 'I');
                                          if(not defined $EnumChildWindows) {
                                              die "Can't import API EnumChildWindows: $^E\n";
                                          }
                                          
                                          # int GetClassNameW(
                                            # HWND   hWnd,
                                            # LPWSTR lpClassName,
                                            # int    nMaxCount
                                          # );
                                          my $GetClassName = new Win32::API::More('User32', 'GetClassNameW', 'qPI', 'I');
                                          if(not defined $GetClassName) {
                                              die "Can't import API GetClassNameW: $^E\n";
                                          }
                                          
                                          # HWND GetParent(
                                            # HWND hWnd
                                          # );
                                          my $GetParent = new Win32::API::More('User32', 'GetParent', 'q', 'q');
                                          if(not defined $GetParent) {
                                              die "Can't import API GetParent: $^E\n";
                                          }
                                          
                                          
                                          my $npp_hwnd = $FindWindow->Call(0, 0, encode('UTF-16le',"Notepad++"), 0);
                                          print "npp_hwnd: $npp_hwnd\n";
                                          
                                          # my $sci1_hwnd = $FindWindow->Call($npp_hwnd, 0, encode('UTF-16le',"Scintilla"), 0);
                                          # print "sci1_hwnd: $sci1_hwnd\n";
                                          my %scintilla_hwnd = (0, 0, 1, 0);
                                          my $callback = Win32::API::Callback->new(
                                          	sub {
                                          		my($hwnd, $lParam) = @_;
                                          		my $curr_class    = " " x 1024;
                                          		my $result = $GetClassName->Call($hwnd, $curr_class, 1024);
                                          
                                          		if (substr(decode('UTF-16le',$curr_class), 0, $result) eq 'Scintilla') {
                                                      if ($GetParent->Call($hwnd) == $npp_hwnd) {
                                                          if ($scintilla_hwnd{0} == 0) {
                                                              $scintilla_hwnd{0} = $hwnd;
                                          				} elsif ($scintilla_hwnd{1} == 0) {
                                                              $scintilla_hwnd{1} = $hwnd;
                                                              return 0;
                                          				}
                                          			}
                                          		}
                                                  return 1;
                                          	}, "qq", "I",
                                          );
                                          
                                          $EnumChildWindows->Call($npp_hwnd, $callback, 0);
                                          print "first scintilla hwnd $scintilla_hwnd{0}\n";
                                          print "second scintilla hwnd $scintilla_hwnd{1}\n";
                                          
                                          1 Reply Last reply Reply Quote 1
                                          • EkopalypseE
                                            Ekopalypse
                                            last edited by

                                            Some news - not embedded as to disturbing :-)
                                            Currently this function calls a, hardcoded, script from the disc. No interaction yet as
                                            it seems win32::api is not part of the standard distribution and must be installed via
                                            e.g. cpan but having difficulties making this work. :-(
                                            But at least, an embedded perl interpreter as a npp plugin.
                                            Btw. thx to @dail for his cookiecuter template which I used for this :-)

                                            Alan KilbornA 1 Reply Last reply Reply Quote 3
                                            • First post
                                              Last post
                                            The Community of users of the Notepad++ text editor.
                                            Powered by NodeBB | Contributors