How to create a C# plugin that uses a non-dockable dialog
-
@Coises said in How to create a C# plugin that uses a non-dockable dialog:
Are you sure about that? According to the documentation, DMM_SHOW is for dialogs that were registered as docking dialogs.
Well spotted!
I’ve edited the above post to reflect the correct way to deal with these kinds of things.
As for the correct way to hide non-docking forms, use this documentation
-
@Mark-Olson Thank you Mark and @Coises. This will definitely help. Now I have something to chew on for awhile. I’ll provide an update once I get a POC working. Much appreciated!
-
@Paul-Baker
One other warning I have about the plugin pack that you should be aware of…There are a lot of methods (29 by my count) in the
ScintillaGateway.cs
that look something like this:public unsafe string DescriptionOfStyle(int style) { byte[] descriptionBuffer = new byte[10000]; fixed (byte* descriptionPtr = descriptionBuffer) { Win32.SendMessage(scintilla, SciMsg.SCI_DESCRIPTIONOFSTYLE, (IntPtr) style, (IntPtr) descriptionPtr); return Encoding.UTF8.GetString(descriptionBuffer).TrimEnd('\0'); } }
Unsafe methods like this may be scary when you’re new to C#, but the basic idea is this:
- A buffer is allocated of size 10000
- a pointer to that buffer is passed to Scintilla as the
lParam
, and thestyle
argument to the C# method is passed in as thewParam
. - Scintilla fills the buffer that was passed in
- He decodes the string and strips off the NULL chars.
THIS IS NOT THE RIGHT WAY TO DO THESE THINGS BECAUSE 10000 MIGHT BE TOO SMALL (LEADING TO BUFFER OVERFLOW) OR TOO LARGE (LEADING TO WASTE).
Regarding methods where the user passes in a buffer to be filled (
char *
), the Scintilla documentation says:Arguments point at text buffers that Scintilla will fill with text. In some cases, another argument will tell Scintilla the buffer size. In others, you must make sure that the buffer is big enough to hold the requested text. If a NULL pointer (0) is passed then, for SCI_* calls, the length that should be allocated, not including any terminating NUL, is returned. Some calls (marked "NUL-terminated") add a NUL character to the result but other calls do not: to generically handle both types, allocate one more byte than indicated and set it to NUL.
Instead I recommend doing the following:
- add the methods shown below to
ScintillaGateway.cs
- In the above example, with
SciMsg.SCI_DESCRIPTIONOFSTYLE
as the Scintilla message andint length
as a parameter to the C# method, replace the entire body of the method withreturn GetNullStrippedStringFromMessageThatReturnsLength(SciMsg.SCI_DESCRIPTIONOFSTYLE, (IntPtr)style);
- If the C# method does not have a parameter (say for
public unsafe string GetWhitespaceChars()
, I would replace the whole body of the function with
Note that in this case the optionalreturn GetNullStrippedStringFromMessageThatReturnsLength(SciMsg.SCI_GETWHITESPACECHARS);
wParam
argument is not supplied.
In any case, here is the
GetNullStrippedStringFromMessageThatReturnsLength
method in my proposed fix./// <summary> /// returns bytes decoded from UTF-8 as a string, with all trailing NULL bytes stripped off. /// </summary> public static string Utf8BytesToNullStrippedString(byte[] bytes) { int lastNullCharPos = bytes.Length - 1; // this only bypasses NULL chars because no char // other than NULL can have any 0-valued bytes in UTF-8. // See https://en.wikipedia.org/wiki/UTF-8#Encoding for (; lastNullCharPos >= 0 && bytes[lastNullCharPos] == '\x00'; lastNullCharPos--) { } return Encoding.UTF8.GetString(bytes, 0, lastNullCharPos + 1); } /// <summary> /// Recall that all Scintilla methods have the signature /// (scintilla* scin, SciMsg msg, void* wParam, void* lParam) -> void*<br></br> /// Many of these scintilla methods are bimodal in the following way<br></br> /// * if lParam is 0, return the length of the buffer to be filled and have no side effects. The wParam may be involved in telling Scintilla how big the buffer needs to be.<br></br> /// * if lParam is greater than 0, it is assumed to be a pointer to a buffer. Now the wParam indicates what the text will need to be.<br></br><br></br> /// This sets lParam to 0 to get the length, allocates a buffer of that length,<br></br> /// uses the second mode to fill a buffer,<br></br> /// and returns a string of the UTF8-decoded buffer with all trailing '\x00' chars stripped off. /// </summary> /// <param name="msg">message to send</param> /// <param name="wParam">another parameter for defining what the buffer should contain</param> /// <returns></returns> private unsafe string GetNullStrippedStringFromMessageThatReturnsLength(SciMsg msg, IntPtr wParam=default) { int length = Win32.SendMessage(scintilla, msg, wParam, (IntPtr)Unused).ToInt32(); byte[] textBuffer = new byte[length]; fixed (byte* textPtr = textBuffer) { Win32.SendMessage(scintilla, msg, wParam, (IntPtr)textPtr); return Utf8BytesToNullStrippedString(textBuffer); } }
I could submit a PR, but kbilsted rarely actually does anything about them, so here is as good a place as any.
-
@Mark-Olson said in How to create a C# plugin that uses a non-dockable dialog:
I could submit a PR, but kbilsted rarely actually does anything about them, so here is as good a place as any.
Dude, kbilsted’s project was just archived. Maybe now’s the time to consider releasing a fresh template from your fork?
-
@rdipardo said in How to create a C# plugin that uses a non-dockable dialog:
Dude, kbilsted’s project was just archived. Maybe now’s the time to consider releasing a fresh template from your fork?
I figured it was only a matter of time…
I don’t blame him; maintaining something like that is a lot of work.As it so happens, I started working on my own take on the plugin template yesterday. I’m going to try to release it to GitHub today.
-
As it so happens, I started working on my own take on the plugin template yesterday. I’m going to try to release it to GitHub today.
The User Manual currently links to the kblisted template. Will you mind if I link it to your fork instead, once it’s ready?
-
@PeterJones said in How to create a C# plugin that uses a non-dockable dialog:
Will you mind if I link it to your fork instead, once it’s ready?
Sure!
-
I announced the new template.
-
@Mark-Olson said in How to create a C# plugin that uses a non-dockable dialog:
I announced the new template.
Your C# template and @ThosRTanner’s docking-dialog-focused C++ template will both be linked in the next published release of the user manual.
-
@Mark-Olson said in How to create a C# plugin that uses a non-dockable dialog:
One other warning I have about the plugin pack that you should be aware of…
There are a lot of methods (29 by my count) in the ScintillaGateway.cs that look something like this:
Thanks Mark. I’m still chewing on the dialog. The JSon Tools plugin is displaying a Settings input dialog which is what I want to do. I’ll be on the lookout for the unsafe methods and apply your recommendations as needed, I appreciate your comments. Thank you!