New cross-platform plugin template for Delphi developers
-
@rdipardo, great thanks for this very detailed initial help!
- Position and size:
For the size i could change it by modifying the width parameter(s) in "<GUIConfig name=“DockingManager”.
For the position i could change it by a) removing the “PluginDlg” line (-> dock. window will then appear at bottom) and b) then modifying the newly recreated value: from curr=“3” to curr=“0”. Just as:
<GUIConfig name="DockingManager" leftWidth="390" rightWidth="340" topHeight="200" bottomHeight="200"> <PluginDlg pluginName="HelloWorld.dll" id="2" curr="0" prev="-1" isVisible="yes" />
Solved …
- TreeView’s dark mode
First i try with the punctual SendMessage of NPPM_DARKMODESUBCLASSANDTHEME with the treeview’s handle as of the example.
procedure THelloWorldDockingForm.FormCreate(Sender: TObject); var DmFlag: Cardinal; DarkModeColors: TDarkModeColors; begin // -- Not work. -> Do changes in config.xml instead: self.NppDefaultDockingMask := DWS_DF_CONT_LEFT; // <PluginDlg pluginName="HelloWorld.dll" ... curr="0" self.Width := 390; // GUIConfig name="DockingManager" leftWidth="390" //inherited SubclassAndTheme(DmfMask); // Should have been already done if Npp.IsDarkModeEnabled then begin DmFlag := dmfInit; // dmfHandleChange // DmFlag: dmfInit or dmfHandleChange SendMessage(Npp.NppData.NppHandle, NPPM_DARKMODESUBCLASSANDTHEME, DmFlag, Self.TreeView1.Handle); DarkModeColors := Default(TDarkModeColors); // Only for test (i don't believe it influences here, Colors are already set) Npp.GetDarkModeColors(@DarkModeColors); TreeView1.Color := TColor(DarkModeColors.PureBackground); TreeView1.Font.Color := TColor(DarkModeColors.Text); ....
- Right, TreeView’s scrollbars are not changed yet.
- TreeView’s unselected item’s font color is a Todo too.
Basically i don’t know if i understand your last sentence right (" … not the Lazarus runtime").
The treeview targeted at the end is a LCL custom treeview, with custom drawing for specific things, but regarding the dark theme mainly using the metadarkstyle mechanism (Windows theme API operations based on UXTheme.dll). But only at runtime (the package is intentionally Not installed).
The component (beneath other controls) does all dark stuff itself with the help of metadarkstyle.
So, my alternative approach would be: switch, for this docking window, all NPP dark theme handling off and let me do that with metadarkstyle and custom drawing.
Is this possible? - Position and size:
-
A little thing besides: if i remove (set in comment), in the demo some menu items from the plugin’s menu,
so that e.g. the menu only contains ‘Load docking form’, separator, About box, then i get strange results
at next restart(s). E.g. N++ starts with the plugin’s About box. Even after having removed the session.xml.
Somewhere a limit, or an index to a last used id, or a defaulting action might be stored. But where? -
Check your config.xml.
The ID of your plugin must match the zero-based ID of the function array that you specify in getFuncsArray. -
@Ekopalypse said in New cross-platform plugin template for Delphi developers:
The ID of your plugin must match the zero-based ID of the function array that you specify in getFuncsArray.
Hm - but in the demo DLLExports’ getFuncsArray is provided, but never is called afais?
Where might one have set this ID unintentionally?Try the Demo (compiled with Laz. 3.6 64bit), remove from THelloWorldPlugin.Create some of the AddFuncItems except Load docking form, separator and About and restart one or two times …
-
getFuncsArray is called by Npp itself to find out which methods your plugin provides and the ID defined there must match the one when the dialog is registered.
Unfortunately I have no idea about Delphi. -
As a quick&dirty check i wrote a “halt” inside the function, but the process didn’t stop it’s execution; so i assumed it’s not called from outside.
-
that sounds strange if
halt
is supposed to terminate the running process, but I can assure you that without calling getFuncsArray through Npp you will not see your plugin being loaded. -
@Ekopalypse Coming back to npp plugin stuff again first time after, oh, 11 years later (now with Lazarus), i’m now still unsure about debugging it. A second quick&dirty check instead therefore for now, had been to skip the contents of function getFuncsArray completely - for to see if anything changes at all. No changes in behaviour …
-
@klaus101
Unfortunately, I can’t help you with Delphi, but I will try to explain what is going on under the hood.
Npp calls getFuncsArray in your plugin to find out which functions and therefore which menu items your plugin provides.
As the name suggests, this is an array of FuncItem structures and in each FuncItem structure a field called _cmdID is filled with an ID and a field _pFunc with the function pointer of the respective plugin function.
Later Npp checks via the config.xml and the DockingManager section whether your plugin is listed there and if so, the ID from the config.xml is compared with the ID from the FuncsArray and if something is found, the corresponding function is called via the function pointer.
If you have now removed all the menu items (FuncItems) except for the about entry and an entry with ID 0 for your plugin is found in the config.xml, the about function pointer is then called. -
@Ekopalypse said in New cross-platform plugin template for Delphi developers:
that sounds strange if
halt
is supposed to terminate the running process […]Like @klaus101 observed, it does not kill the
notepad++.exe
process because the Free Pascal version of the template does not own the main application handle (the way the Delphi version — unfortunately — does, for reasons that go back to Delphi’s history as the precursor to .NET, as .NET plugins likewise share the notepad++ process ID).@klaus101 said in New cross-platform plugin template for Delphi developers:
i’m now still unsure about debugging it.
That’s a problem with DLLs in general and with plugin DLLs in particular. For example, the
getFuncsArray
function is called bynotepad++.exe
through a function pointer, i.e., a memory address pointing to where the compiled Pascal code is sitting in the DLL. I don’t know if the Lazarus IDE’s debugger can even trace that; you would have to first of all attach it to the runningnotepad++.exe
process, and the function call happens so early you will miss it.In general, the stuff in the template’s DllExports unit should be considered read-only, except for the
DLL_ATTACH
hook where you construct your plugin object.As for tooling, I suggest using GNU Debug if you want to monitor every step of the DLL lifecycle. My personal setup uses VS Code with the C++ Tools extension. All I do is create a launch profile based on the
cppdbg
template, e.g.,{ "version": "0.2.0", "configurations": [ { "name": "Notepad++", "request": "launch", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "type": "cppdbg", "MIMode": "gdb", "miDebuggerPath": "${env:LAZARUS_DIR}\\mingw\\x86_64-win64\\bin\\gdb.exe", "setupCommands": [ { "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true }, { "description": "Set Disassembly Flavor to Intel", "text": "-gdb-set disassembly-flavor intel", "ignoreFailures": true } ], "logging": { "moduleLoad": true }, "program": "${full_path_to}\\notepad++.exe" } ] }
Save this as
.vscode/launch.json
and open the root source folder in VS Code. Replace"${full_path_to}\\notepad++.exe"
to the one where the plugin is installed. Every Lazarus toolchain comes with a compatible version of gdb, so replace${env:LAZARUS_DIR}\\mingw\\x86_64-win64\\bin\\gdb.exe
with the actual path on your PC.After that, you should be able to set breakpoints (by clicking on the line number margin) and start the editor with the
F5
key. -
@rdipardo and @Ekopalypse,
many thanks for your valuable explanations!In Lazarus, for debugging DLLs, one can set a ‘host application’ to execute with; so one is able to set breakpoints in the pascal code etc.
All plugin templates i tried before, crashed … at addresses outside the scope of the pascal code though.
Your template rdipardo was the first one i found that showed up as a really fine working example :-) :-). Unfortunately, after setting the host application, the “run” functionality is not enabled. For all crashing templates, it had been enabled. I just kicked a question in the Laz. newsgroup what’s required to enable it.Could you at least, for the moment, confirm (or maybe not confirm, so that’s my fault) if you could reproduce? By commenting a few lines, and retry?
I try to describe more precise what happens:
-
First, a session with the unchanged / full menu. - config.xml says:
<PluginDlg pluginName=“HelloWorld.dll” id=“2” curr=“0” prev=“-1” isVisible=“yes” /> -
Then, shrinked menu creation to the three items “Load docking form”, Separator, “About”
-
Removed the old entry for pluginName=“HelloWorld.dll” from the config.xml for to have a clean restart
-
Start NPP with the new compiled DLL and click menu item “Load docking form”, and close NPP again
-
NPP rewrites the new line:
<PluginDlg pluginName=“HelloWorld.dll” id=“2” curr=“0” prev=“-1” isVisible=“yes” />
So far all looks fine! -
Now restart NPP again … and, what will appear at first, is the demo About box.
-
Afterwards, config.xml entry showed up unchanged:
<PluginDlg pluginName=“HelloWorld.dll” id=“2” curr=“0” prev=“-1” isVisible=“yes” />
I understand that, if some first pointers a invalid, but the last one (for About) keeps to be valid, this last one will be used.
But who stored the unbalanced info where?–> Btw: i fear that this specific issue - and the question about the dark theme - will run extremely out of scope of this specific topic, which wants to inform about the new template. Better to continue in/as a new topic if needed?
-
-
@klaus101 said in New cross-platform plugin template for Delphi developers:
Btw: i fear that this specific issue - and the question about the dark theme - will run extremely out of scope of this specific topic, which wants to inform about the new template. Better to continue in/as a new topic if needed?
If @rdipardo wants it to be split off, to avoid cluttering the main Delphi-plugin-template Topic, I could use my moderator power to split off all the recent posts to that new topic, if you give me a meaningful name to use for the new Topic. But if @rdipardo doesn’t mind it staying here, that’s fine by me.
-
@PeterJones, thank you for your proposal!
It’s related to Delphi as well as Lazarus development environments (would be interesting to know btw if the issue (if any) does show up with Delphi too).If @rdipardo wants it to be split off, i’d see two topics here:
Plugin template for Delphi and Lazarus developers: question about modifying the plugin’s demo menu (Lazarus)
Plugin template for Delphi and Lazarus developers: question about possibility to skip dark mode theme handling -
@PeterJones: the wiki is now up, so this thread can be locked 🔒, please and thank you.
-
-