• Login
Community
  • Login

First menu item unexpectedly being called on startup

Scheduled Pinned Locked Moved Notepad++ & Plugin Development
13 Posts 4 Posters 1.0k 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.
  • T
    ThosRTanner
    last edited by Sep 16, 2023, 5:41 PM

    I’ve been playing around with https://github.com/deadem/notepad-pp-linter and discovered something odd has started happening (using notepad++ 8.5.6).

    When I start notepad++ it behaves as though I’ve clicked the first menu entry for the plugin (which calls editConfig here https://github.com/deadem/notepad-pp-linter/blob/49586fd72d54bd068fc5e8b0d085b6bac360c3e1/plugin.cpp#L93 which opens the configuration file).

    I have experimented a bit. It is ONLY the first menu entry - if I add a second one, it doesn’t get called. If I swap the order, the new first one gets called, and the 2nd one (editConfig) doesn’t get called.

    Is this something that started in 8.5.6? Or is there some variable that I’m not initialising properly and is therefore doing different things at different times? Or A.N.Other thing?

    1 Reply Last reply Reply Quote 0
    • T
      Thomas Knoefel
      last edited by Thomas Knoefel Sep 17, 2023, 9:57 AM Sep 17, 2023, 9:55 AM

      Can you show us the code for how you add the second menu entry? In the code you provided, only one entry is visible.

      I assume you add the second menu entry like this with 1:

      setCommand(0, TEXT("&FirstMenuPoint"), firstFunction, NULL, false);
      setCommand(1, TEXT("&SecondMenuPoint"), secondFunction, NULL, false);
      
      T 1 Reply Last reply Sep 17, 2023, 4:17 PM Reply Quote 0
      • T
        ThosRTanner @Thomas Knoefel
        last edited by Sep 17, 2023, 4:17 PM

        @Thomas-Knoefel

        I tried both

        setCommand(0, TEXT("&FirstMenuPoint"), firstFunction, NULL, false);
        setCommand(1, TEXT("&SecondMenuPoint"), secondFunction, NULL, false);
        

        and

        setCommand(0, TEXT("&SecondMenuPoint"), secondFunction, NULL, false);
        setCommand(1, TEXT("&FirstMenuPoint"), firstFunction, NULL, false);
        

        In both cases, command entry 0 gets called before notepad++ has displayed any windows

        T 1 Reply Last reply Sep 17, 2023, 9:07 PM Reply Quote 0
        • T
          Thomas Knoefel @ThosRTanner
          last edited by Thomas Knoefel Sep 17, 2023, 9:14 PM Sep 17, 2023, 9:07 PM

          @ThosRTanner I’ve tested ‘Linter’ with my N++ installation, and I didn’t experience this issue: no window opened before the main N++ window. I can only offer some suggestions. Have you tried deleting the N++ config.xml?
          Additionally, I would suggest updating to the 8.5.7 version.

          R 1 Reply Last reply Sep 17, 2023, 9:46 PM Reply Quote 1
          • R
            rdipardo @Thomas Knoefel
            last edited by Sep 17, 2023, 9:46 PM

            This post is deleted!
            1 Reply Last reply Reply Quote 1
            • T
              ThosRTanner
              last edited by Sep 22, 2023, 5:59 PM

              I took latest version of notepad++, built master branch of linter (in debug mode) and get the same problem.

              The call is definitely from notepad++ - not sure where though as I don’t have debug symbols for it.

              C 1 Reply Last reply Sep 22, 2023, 6:42 PM Reply Quote 0
              • C
                Coises @ThosRTanner
                last edited by Sep 22, 2023, 6:42 PM

                @ThosRTanner said in First menu item unexpectedly being called on startup:

                I took latest version of notepad++, built master branch of linter (in debug mode) and get the same problem.

                The call is definitely from notepad++ - not sure where though as I don’t have debug symbols for it.

                Forgive me if this is a dumb question, but… does the same thing happen with the release DLL from the repository? (It looks like the latest release is up to date with master, so there should be no difference.)

                If it happens with the release DLL, it’s probably worth raising an issue in that repository. If it doesn’t, the next thing I’d try is building release mode from source, to see if the problem is specific to debug build.

                T 1 Reply Last reply Sep 22, 2023, 7:04 PM Reply Quote 0
                • T
                  ThosRTanner @Coises
                  last edited by ThosRTanner Sep 22, 2023, 7:05 PM Sep 22, 2023, 7:04 PM

                  @Coises i tried removing and then installing via plugins admin and it is still happening for me.but @Thomas-Knoefel seems to have it working as normal from his post earlier.

                  It is very odd. or possibly i have a conflicting plugin. i’d really like to see the call stack explaining where this call is coming from.

                  T 1 Reply Last reply Sep 22, 2023, 7:14 PM Reply Quote 0
                  • T
                    ThosRTanner @ThosRTanner
                    last edited by ThosRTanner Sep 22, 2023, 7:22 PM Sep 22, 2023, 7:14 PM

                    Well, that was enlightening - sort of.

                    I deleted config.xml from the notepad++ appdata directory and everything started working again. Of course. all the settings make everything dreadful. So there’s clearly something in the config that causes this. It’d be nice to know what.

                    Later:

                    It appears to be the result of having created a docking window somehow. I deleted the docking window info in the config file + 3 others (one called dummy, 2 called notepad++ internal) and it’s fine.

                    R 1 Reply Last reply Sep 22, 2023, 9:25 PM Reply Quote 1
                    • R
                      rdipardo @ThosRTanner
                      last edited by Sep 22, 2023, 9:25 PM

                      On start-up, the data in config.xml is marshaled into an instance of the PluginDlgDockingInfo structure, which is used to recreate any plugin dialog windows that were left open in a previous session. To make the dialogs appear, the application executes the associated function , which is looked up by a numeric index that is parsed from the id attribute of the XML node at /NotepadPlus/GUIConfigs/GUIConfig[@name="DockingManager"]/PluginDlg[@pluginName="PLUGIN_MODULE_NAME.dll"]:

                        if (pdi._isVisible && showPanel)
                        {
                          if (isInternalFunc)
                            _internalFuncIDs.push_back(pdi._internalID);
                          else
                            _pluginsManager.runPluginCommand(pdi._name.c_str(), pdi._internalID);
                        }
                      

                      If pdi._name refers to any real module in the load path, and pdi._internalID is any real index defined in the plugin source code, the function will execute, as long as the isVisible attribute is "yes" in config.xml. This also means that a crafted config.xml can make Notepad++ execute potentially any plugin function at start-up. Keep in mind that the plugin must be already in the load path, and the menu ID of the plugin function must be valid and known beforehand.

                      Proof of Concept

                      1. Build a simple plugin from this code:
                      #define UNICODE
                      #include <windows.h>
                      
                      #define PLUGIN_CMD_ID 0ULL
                      #define NB_PLUGIN_FUNCS 1ULL
                      #define MENU_TITLE_LENGTH 64ULL
                      #define PLUGIN_FUNC extern "C" __declspec(dllexport)
                      
                      typedef void(__cdecl *PFUNCPLUGINCMD)(void);
                      
                      struct NppData {
                        HWND _nppHandle = nullptr;
                        HWND _scintillaMainHandle = nullptr;
                        HWND _scintillaSecondHandle = nullptr;
                      };
                      
                      struct ShortcutKey {
                        bool _isCtrl = false;
                        bool _isAlt = false;
                        bool _isShift = false;
                        UCHAR _key = 0;
                      };
                      
                      struct FuncItem {
                        TCHAR _itemName[MENU_TITLE_LENGTH] = { 0 };
                        PFUNCPLUGINCMD _pFunc = nullptr;
                        int _cmdID = 0;
                        bool _init2Check = false;
                        ShortcutKey *_pShKey = nullptr;
                      };
                      
                      static FuncItem funcItem[NB_PLUGIN_FUNCS];
                      static NppData nppData;
                      
                      void surprise(void) {
                        ::MessageBoxW(nppData._nppHandle, L"Surprise!", L"Message from PoC Plugin", MB_OK);
                      }
                      PLUGIN_FUNC void setInfo(NppData data) {
                        nppData = data;
                        lstrcpy(funcItem[PLUGIN_CMD_ID]._itemName, L"Surprise me!");
                        funcItem[PLUGIN_CMD_ID]._pFunc = surprise;
                        funcItem[PLUGIN_CMD_ID]._init2Check = false;
                        funcItem[PLUGIN_CMD_ID]._pShKey = nullptr;
                      }
                      PLUGIN_FUNC FuncItem *getFuncsArray(int *nbF) {
                        *nbF = (int)NB_PLUGIN_FUNCS;
                        return funcItem;
                      }
                      PLUGIN_FUNC const TCHAR *getName(void) { return L"PoC Npp Plugin"; }
                      PLUGIN_FUNC LRESULT messageProc(UINT /*na*/, WPARAM /*na*/, LPARAM /*na*/) { return 0; }
                      PLUGIN_FUNC BOOL isUnicode(void) { return TRUE; }
                      PLUGIN_FUNC void beNotified(void *) {}
                      BOOL APIENTRY DllMain(HANDLE /*na*/, DWORD /*na*/, LPVOID /*na*/) { return TRUE; }
                      
                      1. Save the compiled module as poc_plugin.dll and copy it to the correct plugin path for the given N++ installation.

                      2. Open the correct config.xml configuration file for the given N++ installation.

                      3. Edit config.xml by creating the following node under the path /NotepadPlus/GUIConfigs/GUIConfig[@name="DockingManager"]:

                      <GUIConfig name="DockingManager" leftWidth="200" rightWidth="200" topHeight="200" bottomHeight="200">
                          <PluginDlg pluginName="poc_plugin.dll" id="0" curr="1" prev="-1" isVisible="yes" />
                          <!-- . . . -->
                      </GUIConfig>
                      

                      When Notepad++ starts, the surprise() function will display a message box. This works in any N++ version, including 8.5.7.

                      T 1 Reply Last reply Sep 23, 2023, 7:40 AM Reply Quote 5
                      • T
                        ThosRTanner @rdipardo
                        last edited by Sep 23, 2023, 7:40 AM

                        @rdipardo Thanks. That’s helpful to have confirmed. One of those things that should really be in the ‘how to write your own plugin’ documentation or the C++ template doc

                        R 1 Reply Last reply Sep 24, 2023, 5:19 AM Reply Quote 1
                        • R
                          rdipardo @ThosRTanner
                          last edited by Sep 24, 2023, 5:19 AM

                          @ThosRTanner said in First menu item unexpectedly being called on startup:

                          One of those things that should really be in the ‘how to write your own plugin’ documentation or the C++ template doc

                          That would be appropriate — if what I described was a deliberate design. My impression is that it’s just an accident of a short-sighted implementation. This may be the first time anyone has ever looked into it. Fortunately it’s no more exploitable than dropping a comprised DLL into the load path (a precondition to making it work). Otherwise it would be irresponsible to publicly document it.

                          Even the supposed benefit of relaunching dialogs with saved co-ordinates is questionable, given how many times the “Folder as Workspace” or “Find” dialog seems to go missing because the dimensions became negative through naïve rounding or integer overflow:

                          • [Feature request] Solution to the “lost panel” problem
                          • not able to see the search results windows in notepad++
                          T 1 Reply Last reply Sep 24, 2023, 7:10 AM Reply Quote 1
                          • T
                            ThosRTanner @rdipardo
                            last edited by Sep 24, 2023, 7:10 AM

                            @rdipardo it’s not so much the ability to break/abuse it, it’s the fact that there is a correlation between the order of entries in your plugin menu and the docking dialogue(s) you can open from your plugin.

                            1 Reply Last reply Reply Quote 0
                            8 out of 13
                            • First post
                              8/13
                              Last post
                            The Community of users of the Notepad++ text editor.
                            Powered by NodeBB | Contributors