Creating a docked window from a background thread
-
Did anyone try to do the following? -
- Create a thread;
- In that thread, create a modeless dialog;
- In that thread, call NPPM_DMMREGASDCKDLG, MODELESSDIALOGADD and NPPM_DMMSHOW for that modeless dialog.
After I do that, Notepad++ seems to hang :(
Do I understand correctly that a docked dialog must not be created and registered from within another thread?
-
Well, yes, I think it was not a good idea to create it in another thread.
Once I move the dialog creation & registering as a docked dialog to the main thread, everything works OK.
Though, the question remains.
Why doing it in another thread causes Notepad++ to hang? -
For me it sounds like you are running into some kind of race condition.
One thread might receives the window messages whereas the other
threads expect it. Did you check this?Cheers
Claudia -
That must be it. MSDN says “GetMessage - Retrieves a message from the calling thread’s message queue”:
https://msdn.microsoft.com/en-us/library/ms644936(VS.85).aspx
Anyway, creating a dialog in a main thread and then calling NPPM_DMMREGASDCKDLG and NPPM_DMMSHOW from another thread does the trick.Though there’s another thing I don’t understand, this time in Notepad++. Why a docked dialog becomes visible immediately after NPPM_DMMREGASDCKDLG and MODELESSDIALOGADD? I mean, logically MODELESSDIALOGADD means “add a dialog” - correct? - so a dialog should not be shown before NPPM_DMMSHOW is sent explicitly!
-
AFAIK it is not shown by default. You might check your
config.xml
file because it stores information about docked dialogs (position, visibility, etc). It might think it is supposed to be open already. -
Nope! In the “config.xml” there is:
isVisible="no".
And here is some verification code:
::OutputDebugStringA(::IsWindowVisible(hDialogWnd) ? "1. Visible\n" : "1. Not visible\n"); SendNppMsg( NPPM_DMMREGASDCKDLG, 0, (LPARAM) &dockData ); SendNppMsg( NPPM_MODELESSDIALOG, (WPARAM) MODELESSDIALOGADD, (LPARAM) hDialogWnd ); ::OutputDebugStringA(::IsWindowVisible(hDialogWnd) ? "2. Visible\n" : "2. Not visible\n");
It shows:
1. Not visible 2. Visible
If there was isVisible=“yes” in the “config.xml”, there would be an additional explicit call of the function which functionId was specified as the dockData.dlgID. But in my case isVisible=“no”, there was no explicit call of the plugin’s function - but the docked window became visible…
-
My LuaScript plugin uses a docked dialog and is not shown by default (assuming the config.xml doesn’t contain any info about it).
Take a look at this section of code which is how I’ve been doing it.
-
that is strange, indeed.
Npp, does more or less the same checkings before creating the dialogcase NPPM_DMMREGASDCKDLG: { tTbData *pData = reinterpret_cast<tTbData *>(lParam); int iCont = -1; bool isVisible = false; getIntegralDockingData(*pData, iCont, isVisible); _dockingManager.createDockableDlg(*pData, iCont, isVisible); return TRUE; }
…
bool Notepad_plus::getIntegralDockingData(tTbData & dockData, int & iCont, bool & isVisible) { DockingManagerData & dockingData = (DockingManagerData &)(NppParameters::getInstance())->getNppGUI()._dockingData; for (size_t i = 0, len = dockingData._pluginDockInfo.size(); i < len ; ++i) { const PluginDlgDockingInfo & pddi = dockingData._pluginDockInfo[i]; if (!generic_stricmp(pddi._name.c_str(), dockData.pszModuleName) && (pddi._internalID == dockData.dlgID)) { iCont = pddi._currContainer; isVisible = pddi._isVisible; dockData.iPrevCont = pddi._prevContainer; if (dockData.iPrevCont != -1) { int cont = (pddi._currContainer < DOCKCONT_MAX ? pddi._prevContainer : pddi._currContainer); RECT rc; if (dockingData.getFloatingRCFrom(cont, rc)) dockData.rcFloat = rc; } return true; } } return false; }
…
void DockingManager::createDockableDlg(tTbData data, int iCont, bool isVisible) { ... // if floated rect not set if (memcmp(&data.rcFloat, &rc, sizeof(RECT)) == 0) { // set default rect state ::GetWindowRect(data.hClient, &data.rcFloat); // test if dialog is first time created if (iCont == -1) { // set default visible state isVisible = (::IsWindowVisible(data.hClient) == TRUE); ...
This would lead to the assumption that you might, maaayyyybeeee, checked
the false config.xml?? I know you are familiar with npps configuration
but, at least for me, sometimes you don’t see the wood for the trees.Cheers
Claudia -
Ah, looks I’ll need to debug Notepad++ to understand what is wrong.
Which is not straightforward because I’m having exactly the same issues with VS 2013 Express as mentioned here:
https://notepad-plus-plus.org/community/topic/11388/errors-building-current-repository
If you ask my opinion, I’d rather suggest to get rid of these CStringW in Notepad++'s code - these things are not true and pure Win API way! -
If you aren’t concerned about the new license agreements I would use the community edition
as this should behave like the pro versions.
If you still want to use express - didn’t the changes help?Cheers
Claudia -
Try calling
NPPM_MODELESSDIALOG
first. -
Actually, if you look in Notepad++'s source where it uses these messages internally it normally calls:
NPPM_MODELESSDIALOG
withMODELESSDIALOGADD
NPPM_MODELESSDIALOG
withMODELESSDIALOGREMOVE
NPPM_DMMREGASDCKDLG
I think 1 and 2 are just a side effect of how the class inheritance works within Notepad++. So, it would appear that
NPPM_MODELESSDIALOG
may not even be needed for docked dialogs. I will look into this more if I get a chance. -
@Claudia,
Yes, installing the WinDDK fixes that.
Though, as I said, I really don’t like Notepad++ to use ATL. Moreover, it’s just for a small feature, which could be rewritten.@Dail,
I’ve found the root cause. It’s because my plugin has a toolbar icon and here is what Notepad++ does with it:in DockingManager::createDockableDlg:
_vContainer[iCont]->createToolbar(data);
where DockingCont::createToolbar calls DockingCont::viewToolbar, where the following is done:
// show dialog and notify parent to update dialog view if (isVisible() == false) { this->doDialog(); ::SendMessage(_hParent, WM_SIZE, 0, 0); }
So the docked dialog is forced to be shown by that code :(
-
That’s interesting. Can’t say I know for sure why that is calling
createToolbar()
. My plugin also uses a toolbar icon but it registers it duringNPPN_TBMODIFICATION
.