Community
    • Login

    First menu item unexpectedly being called on startup

    Scheduled Pinned Locked Moved Notepad++ & Plugin Development
    13 Posts 4 Posters 943 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.
    • ThosRTannerT
      ThosRTanner
      last edited by

      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
      • Thomas KnoefelT
        Thomas Knoefel
        last edited by Thomas Knoefel

        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);
        
        ThosRTannerT 1 Reply Last reply Reply Quote 0
        • ThosRTannerT
          ThosRTanner @Thomas Knoefel
          last edited by

          @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

          Thomas KnoefelT 1 Reply Last reply Reply Quote 0
          • Thomas KnoefelT
            Thomas Knoefel @ThosRTanner
            last edited by Thomas Knoefel

            @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.

            rdipardoR 1 Reply Last reply Reply Quote 1
            • rdipardoR
              rdipardo @Thomas Knoefel
              last edited by

              This post is deleted!
              1 Reply Last reply Reply Quote 1
              • ThosRTannerT
                ThosRTanner
                last edited by

                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.

                CoisesC 1 Reply Last reply Reply Quote 0
                • CoisesC
                  Coises @ThosRTanner
                  last edited by

                  @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.

                  ThosRTannerT 1 Reply Last reply Reply Quote 0
                  • ThosRTannerT
                    ThosRTanner @Coises
                    last edited by ThosRTanner

                    @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.

                    ThosRTannerT 1 Reply Last reply Reply Quote 0
                    • ThosRTannerT
                      ThosRTanner @ThosRTanner
                      last edited by ThosRTanner

                      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.

                      rdipardoR 1 Reply Last reply Reply Quote 1
                      • rdipardoR
                        rdipardo @ThosRTanner
                        last edited by

                        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.

                        ThosRTannerT 1 Reply Last reply Reply Quote 5
                        • ThosRTannerT
                          ThosRTanner @rdipardo
                          last edited by

                          @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

                          rdipardoR 1 Reply Last reply Reply Quote 1
                          • rdipardoR
                            rdipardo @ThosRTanner
                            last edited by

                            @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++
                            ThosRTannerT 1 Reply Last reply Reply Quote 1
                            • ThosRTannerT
                              ThosRTanner @rdipardo
                              last edited by

                              @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
                              • First post
                                Last post
                              The Community of users of the Notepad++ text editor.
                              Powered by NodeBB | Contributors