mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-12 16:34:44 +02:00
703 lines
22 KiB
C++
703 lines
22 KiB
C++
// This file is part of Notepad++ project
|
|
// Copyright (C)2003 Don HO <don.h@free.fr>
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either
|
|
// version 2 of the License, or (at your option) any later version.
|
|
//
|
|
// Note that the GPL places important restrictions on "derived works", yet
|
|
// it does not provide a detailed definition of that term. To avoid
|
|
// misunderstandings, we consider an application to constitute a
|
|
// "derivative work" for the purpose of this license if it does any of the
|
|
// following:
|
|
// 1. Integrates source code from Notepad++.
|
|
// 2. Integrates/includes/aggregates Notepad++ into a proprietary executable
|
|
// installer, such as those produced by InstallShield.
|
|
// 3. Links to a library or executes a program that does any of the above.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
|
#include <shlwapi.h>
|
|
#include <DbgHelp.h>
|
|
#include <algorithm>
|
|
#include <cinttypes>
|
|
#include "PluginsManager.h"
|
|
#include "resource.h"
|
|
|
|
using namespace std;
|
|
|
|
const TCHAR * USERMSG = TEXT(" is not compatible with the current version of Notepad++.\n\n\
|
|
Do you want to remove this plugin from the plugins directory to prevent this message from the next launch?");
|
|
|
|
#ifdef _WIN64
|
|
#define ARCH_TYPE IMAGE_FILE_MACHINE_AMD64
|
|
const TCHAR *ARCH_ERR_MSG = TEXT("Cannot load 32-bit plugin.");
|
|
#else
|
|
#define ARCH_TYPE IMAGE_FILE_MACHINE_I386
|
|
const TCHAR *ARCH_ERR_MSG = TEXT("Cannot load 64-bit plugin.");
|
|
#endif
|
|
|
|
|
|
|
|
|
|
bool PluginsManager::unloadPlugin(int index, HWND nppHandle)
|
|
{
|
|
SCNotification scnN;
|
|
scnN.nmhdr.code = NPPN_SHUTDOWN;
|
|
scnN.nmhdr.hwndFrom = nppHandle;
|
|
scnN.nmhdr.idFrom = 0;
|
|
_pluginInfos[index]->_pBeNotified(&scnN);
|
|
|
|
//::DestroyMenu(_pluginInfos[index]->_pluginMenu);
|
|
//_pluginInfos[index]->_pluginMenu = NULL;
|
|
|
|
if (::FreeLibrary(_pluginInfos[index]->_hLib))
|
|
{
|
|
_pluginInfos[index]->_hLib = nullptr;
|
|
printStr(TEXT("we're good"));
|
|
}
|
|
else
|
|
printStr(TEXT("not ok"));
|
|
|
|
//delete _pluginInfos[index];
|
|
// printInt(index);
|
|
//vector<PluginInfo *>::iterator it = _pluginInfos.begin() + index;
|
|
//_pluginInfos.erase(it);
|
|
//printStr(TEXT("remove"));
|
|
return true;
|
|
}
|
|
|
|
static WORD getBinaryArchitectureType(const TCHAR *filePath)
|
|
{
|
|
HANDLE hFile = CreateFile(filePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
|
|
if (hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return IMAGE_FILE_MACHINE_UNKNOWN;
|
|
}
|
|
|
|
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL);
|
|
if (hMapping == NULL)
|
|
{
|
|
CloseHandle(hFile);
|
|
return IMAGE_FILE_MACHINE_UNKNOWN;
|
|
}
|
|
|
|
LPVOID addrHeader = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0);
|
|
if (addrHeader == NULL) // couldn't memory map the file
|
|
{
|
|
CloseHandle(hFile);
|
|
CloseHandle(hMapping);
|
|
return IMAGE_FILE_MACHINE_UNKNOWN;
|
|
}
|
|
|
|
PIMAGE_NT_HEADERS peHdr = ImageNtHeader(addrHeader);
|
|
|
|
// Found the binary and architecture type, if peHdr is !NULL
|
|
WORD machine_type = (peHdr == NULL) ? IMAGE_FILE_MACHINE_UNKNOWN : peHdr->FileHeader.Machine;
|
|
|
|
// release all of our handles
|
|
UnmapViewOfFile(addrHeader);
|
|
CloseHandle(hMapping);
|
|
CloseHandle(hFile);
|
|
|
|
return machine_type;
|
|
}
|
|
|
|
#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
|
|
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
|
|
|
|
int PluginsManager::loadPlugin(const TCHAR *pluginFilePath)
|
|
{
|
|
const TCHAR *pluginFileName = ::PathFindFileName(pluginFilePath);
|
|
if (isInLoadedDlls(pluginFileName))
|
|
return 0;
|
|
|
|
NppParameters& nppParams = NppParameters::getInstance();
|
|
|
|
PluginInfo *pi = new PluginInfo;
|
|
try
|
|
{
|
|
pi->_moduleName = pluginFileName;
|
|
|
|
if (getBinaryArchitectureType(pluginFilePath) != ARCH_TYPE)
|
|
throw generic_string(ARCH_ERR_MSG);
|
|
|
|
const DWORD dwFlags = GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory") != NULL ? LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0;
|
|
pi->_hLib = ::LoadLibraryEx(pluginFilePath, NULL, dwFlags);
|
|
if (!pi->_hLib)
|
|
{
|
|
generic_string lastErrorMsg = GetLastErrorAsString();
|
|
if (lastErrorMsg.empty())
|
|
throw generic_string(TEXT("Load Library has failed.\nChanging the project's \"Runtime Library\" setting to \"Multi-threaded(/MT)\" might solve this problem."));
|
|
else
|
|
throw generic_string(lastErrorMsg.c_str());
|
|
}
|
|
|
|
pi->_pFuncIsUnicode = (PFUNCISUNICODE)GetProcAddress(pi->_hLib, "isUnicode");
|
|
if (!pi->_pFuncIsUnicode || !pi->_pFuncIsUnicode())
|
|
throw generic_string(TEXT("This ANSI plugin is not compatible with your Unicode Notepad++."));
|
|
|
|
pi->_pFuncSetInfo = (PFUNCSETINFO)GetProcAddress(pi->_hLib, "setInfo");
|
|
|
|
if (!pi->_pFuncSetInfo)
|
|
throw generic_string(TEXT("Missing \"setInfo\" function"));
|
|
|
|
pi->_pFuncGetName = (PFUNCGETNAME)GetProcAddress(pi->_hLib, "getName");
|
|
if (!pi->_pFuncGetName)
|
|
throw generic_string(TEXT("Missing \"getName\" function"));
|
|
pi->_funcName = pi->_pFuncGetName();
|
|
|
|
pi->_pBeNotified = (PBENOTIFIED)GetProcAddress(pi->_hLib, "beNotified");
|
|
if (!pi->_pBeNotified)
|
|
throw generic_string(TEXT("Missing \"beNotified\" function"));
|
|
|
|
pi->_pMessageProc = (PMESSAGEPROC)GetProcAddress(pi->_hLib, "messageProc");
|
|
if (!pi->_pMessageProc)
|
|
throw generic_string(TEXT("Missing \"messageProc\" function"));
|
|
|
|
pi->_pFuncSetInfo(_nppData);
|
|
|
|
pi->_pFuncGetFuncsArray = (PFUNCGETFUNCSARRAY)GetProcAddress(pi->_hLib, "getFuncsArray");
|
|
if (!pi->_pFuncGetFuncsArray)
|
|
throw generic_string(TEXT("Missing \"getFuncsArray\" function"));
|
|
|
|
pi->_funcItems = pi->_pFuncGetFuncsArray(&pi->_nbFuncItem);
|
|
|
|
if ((!pi->_funcItems) || (pi->_nbFuncItem <= 0))
|
|
throw generic_string(TEXT("Missing \"FuncItems\" array, or the nb of Function Item is not set correctly"));
|
|
|
|
pi->_pluginMenu = ::CreateMenu();
|
|
|
|
GetLexerCountFn GetLexerCount = (GetLexerCountFn)::GetProcAddress(pi->_hLib, "GetLexerCount");
|
|
// it's a lexer plugin
|
|
if (GetLexerCount)
|
|
{
|
|
GetLexerNameFn GetLexerName = (GetLexerNameFn)::GetProcAddress(pi->_hLib, "GetLexerName");
|
|
if (!GetLexerName)
|
|
throw generic_string(TEXT("Loading GetLexerName function failed."));
|
|
|
|
GetLexerStatusTextFn GetLexerStatusText = (GetLexerStatusTextFn)::GetProcAddress(pi->_hLib, "GetLexerStatusText");
|
|
|
|
if (!GetLexerStatusText)
|
|
throw generic_string(TEXT("Loading GetLexerStatusText function failed."));
|
|
|
|
// Assign a buffer for the lexer name.
|
|
char lexName[MAX_EXTERNAL_LEXER_NAME_LEN];
|
|
lexName[0] = '\0';
|
|
TCHAR lexDesc[MAX_EXTERNAL_LEXER_DESC_LEN];
|
|
lexDesc[0] = '\0';
|
|
|
|
int numLexers = GetLexerCount();
|
|
|
|
ExternalLangContainer *containers[30];
|
|
|
|
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
|
|
for (int x = 0; x < numLexers; ++x)
|
|
{
|
|
GetLexerName(x, lexName, MAX_EXTERNAL_LEXER_NAME_LEN);
|
|
GetLexerStatusText(x, lexDesc, MAX_EXTERNAL_LEXER_DESC_LEN);
|
|
const TCHAR *pLexerName = wmc.char2wchar(lexName, CP_ACP);
|
|
if (!nppParams.isExistingExternalLangName(pLexerName) && nppParams.ExternalLangHasRoom())
|
|
containers[x] = new ExternalLangContainer(pLexerName, lexDesc);
|
|
else
|
|
containers[x] = NULL;
|
|
}
|
|
|
|
TCHAR xmlPath[MAX_PATH];
|
|
wcscpy_s(xmlPath, nppParams.getNppPath().c_str());
|
|
PathAppend(xmlPath, TEXT("plugins\\Config"));
|
|
PathAppend(xmlPath, pi->_moduleName.c_str());
|
|
PathRemoveExtension(xmlPath);
|
|
PathAddExtension(xmlPath, TEXT(".xml"));
|
|
|
|
if (!PathFileExists(xmlPath))
|
|
{
|
|
lstrcpyn(xmlPath, TEXT("\0"), MAX_PATH );
|
|
wcscpy_s(xmlPath, nppParams.getAppDataNppDir() );
|
|
PathAppend(xmlPath, TEXT("plugins\\Config"));
|
|
PathAppend(xmlPath, pi->_moduleName.c_str());
|
|
PathRemoveExtension( xmlPath );
|
|
PathAddExtension( xmlPath, TEXT(".xml") );
|
|
|
|
if (! PathFileExists( xmlPath ) )
|
|
{
|
|
throw generic_string(generic_string(xmlPath) + TEXT(" is missing."));
|
|
}
|
|
}
|
|
|
|
TiXmlDocument *pXmlDoc = new TiXmlDocument(xmlPath);
|
|
|
|
if (!pXmlDoc->LoadFile())
|
|
{
|
|
delete pXmlDoc;
|
|
pXmlDoc = NULL;
|
|
throw generic_string(generic_string(xmlPath) + TEXT(" failed to load."));
|
|
}
|
|
|
|
for (int x = 0; x < numLexers; ++x) // postpone adding in case the xml is missing/corrupt
|
|
{
|
|
if (containers[x] != NULL)
|
|
nppParams.addExternalLangToEnd(containers[x]);
|
|
}
|
|
|
|
nppParams.getExternalLexerFromXmlTree(pXmlDoc);
|
|
nppParams.getExternalLexerDoc()->push_back(pXmlDoc);
|
|
const char *pDllName = wmc.wchar2char(pluginFilePath, CP_ACP);
|
|
::SendMessage(_nppData._scintillaMainHandle, SCI_LOADLEXERLIBRARY, 0, reinterpret_cast<LPARAM>(pDllName));
|
|
|
|
}
|
|
addInLoadedDlls(pluginFilePath, pluginFileName);
|
|
_pluginInfos.push_back(pi);
|
|
return static_cast<int32_t>(_pluginInfos.size() - 1);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
pluginExceptionAlert(pluginFileName, e);
|
|
return -1;
|
|
}
|
|
catch (generic_string s)
|
|
{
|
|
s += TEXT("\n\n");
|
|
s += pluginFileName;
|
|
s += USERMSG;
|
|
if (::MessageBox(NULL, s.c_str(), pluginFilePath, MB_YESNO) == IDYES)
|
|
{
|
|
::DeleteFile(pluginFilePath);
|
|
}
|
|
delete pi;
|
|
return -1;
|
|
}
|
|
catch (...)
|
|
{
|
|
generic_string msg = TEXT("Failed to load");
|
|
msg += TEXT("\n\n");
|
|
msg += pluginFileName;
|
|
msg += USERMSG;
|
|
if (::MessageBox(NULL, msg.c_str(), pluginFilePath, MB_YESNO) == IDYES)
|
|
{
|
|
::DeleteFile(pluginFilePath);
|
|
}
|
|
delete pi;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
bool PluginsManager::loadPluginsV2(const TCHAR* dir)
|
|
{
|
|
if (_isDisabled)
|
|
return false;
|
|
|
|
vector<generic_string> dllNames;
|
|
|
|
NppParameters& nppParams = NppParameters::getInstance();
|
|
generic_string nppPath = nppParams.getNppPath();
|
|
|
|
generic_string pluginsFolder;
|
|
if (dir && dir[0])
|
|
{
|
|
pluginsFolder = dir;
|
|
}
|
|
else
|
|
{
|
|
pluginsFolder = nppPath;
|
|
PathAppend(pluginsFolder, TEXT("plugins"));
|
|
}
|
|
generic_string pluginsFolderFilter = pluginsFolder;
|
|
PathAppend(pluginsFolderFilter, TEXT("*.*"));
|
|
|
|
WIN32_FIND_DATA foundData;
|
|
HANDLE hFindFolder = ::FindFirstFile(pluginsFolderFilter.c_str(), &foundData);
|
|
HANDLE hFindDll = INVALID_HANDLE_VALUE;
|
|
|
|
// get plugin folder
|
|
if (hFindFolder != INVALID_HANDLE_VALUE && (foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
generic_string foundFileName = foundData.cFileName;
|
|
if (foundFileName != TEXT(".") && foundFileName != TEXT("..") && generic_stricmp(foundFileName.c_str(), TEXT("Config")) != 0)
|
|
{
|
|
generic_string pluginsFullPathFilter = pluginsFolder;
|
|
PathAppend(pluginsFullPathFilter, foundFileName);
|
|
generic_string pluginsFolderPath = pluginsFullPathFilter;
|
|
generic_string dllName = foundFileName;
|
|
dllName += TEXT(".dll");
|
|
PathAppend(pluginsFullPathFilter, dllName);
|
|
|
|
// get plugin
|
|
hFindDll = ::FindFirstFile(pluginsFullPathFilter.c_str(), &foundData);
|
|
if (hFindDll != INVALID_HANDLE_VALUE && !(foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
dllNames.push_back(pluginsFullPathFilter);
|
|
|
|
PluginList & pl = nppParams.getPluginList();
|
|
pl.add(foundFileName, false);
|
|
}
|
|
}
|
|
// get plugin folder
|
|
while (::FindNextFile(hFindFolder, &foundData))
|
|
{
|
|
generic_string foundFileName2 = foundData.cFileName;
|
|
if (foundFileName2 != TEXT(".") && foundFileName2 != TEXT("..") && generic_stricmp(foundFileName2.c_str(), TEXT("Config")) != 0)
|
|
{
|
|
generic_string pluginsFullPathFilter2 = pluginsFolder;
|
|
PathAppend(pluginsFullPathFilter2, foundFileName2);
|
|
generic_string pluginsFolderPath2 = pluginsFullPathFilter2;
|
|
generic_string dllName2 = foundFileName2;
|
|
dllName2 += TEXT(".dll");
|
|
PathAppend(pluginsFullPathFilter2, dllName2);
|
|
|
|
// get plugin
|
|
if (hFindDll)
|
|
{
|
|
::FindClose(hFindDll);
|
|
hFindDll = INVALID_HANDLE_VALUE;
|
|
}
|
|
hFindDll = ::FindFirstFile(pluginsFullPathFilter2.c_str(), &foundData);
|
|
if (hFindDll != INVALID_HANDLE_VALUE && !(foundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
|
{
|
|
dllNames.push_back(pluginsFullPathFilter2);
|
|
|
|
PluginList & pl = nppParams.getPluginList();
|
|
pl.add(foundFileName2, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
::FindClose(hFindFolder);
|
|
::FindClose(hFindDll);
|
|
|
|
for (size_t i = 0, len = dllNames.size(); i < len; ++i)
|
|
{
|
|
loadPlugin(dllNames[i].c_str());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// return true if cmdID found and its shortcut is enable
|
|
// false otherwise
|
|
bool PluginsManager::getShortcutByCmdID(int cmdID, ShortcutKey *sk)
|
|
{
|
|
if (cmdID == 0 || !sk)
|
|
return false;
|
|
|
|
const vector<PluginCmdShortcut> & pluginCmdSCList = (NppParameters::getInstance()).getPluginCommandList();
|
|
|
|
for (size_t i = 0, len = pluginCmdSCList.size(); i < len ; ++i)
|
|
{
|
|
if (pluginCmdSCList[i].getID() == (unsigned long)cmdID)
|
|
{
|
|
const KeyCombo & kc = pluginCmdSCList[i].getKeyCombo();
|
|
if (kc._key == 0x00)
|
|
return false;
|
|
|
|
sk->_isAlt = kc._isAlt;
|
|
sk->_isCtrl = kc._isCtrl;
|
|
sk->_isShift = kc._isShift;
|
|
sk->_key = kc._key;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// returns false if cmdID not provided, true otherwise
|
|
bool PluginsManager::removeShortcutByCmdID(int cmdID)
|
|
{
|
|
if (cmdID == 0) { return false; }
|
|
|
|
NppParameters& nppParam = NppParameters::getInstance();
|
|
vector<PluginCmdShortcut> & pluginCmdSCList = nppParam.getPluginCommandList();
|
|
|
|
for (size_t i = 0, len = pluginCmdSCList.size(); i < len; ++i)
|
|
{
|
|
if (pluginCmdSCList[i].getID() == (unsigned long)cmdID)
|
|
{
|
|
//remove shortcut
|
|
pluginCmdSCList[i].clear();
|
|
|
|
// inform accelerator instance
|
|
nppParam.getAccelerator()->updateShortcuts();
|
|
|
|
// set dirty flag to force writing shortcuts.xml on shutdown
|
|
nppParam.setShortcutDirty();
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void PluginsManager::addInMenuFromPMIndex(int i)
|
|
{
|
|
vector<PluginCmdShortcut> & pluginCmdSCList = (NppParameters::getInstance()).getPluginCommandList();
|
|
::InsertMenu(_hPluginsMenu, i, MF_BYPOSITION | MF_POPUP, (UINT_PTR)_pluginInfos[i]->_pluginMenu, _pluginInfos[i]->_funcName.c_str());
|
|
|
|
unsigned short j = 0;
|
|
for ( ; j < _pluginInfos[i]->_nbFuncItem ; ++j)
|
|
{
|
|
if (_pluginInfos[i]->_funcItems[j]._pFunc == NULL)
|
|
{
|
|
::InsertMenu(_pluginInfos[i]->_pluginMenu, j, MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
|
|
continue;
|
|
}
|
|
|
|
_pluginsCommands.push_back(PluginCommand(_pluginInfos[i]->_moduleName.c_str(), j, _pluginInfos[i]->_funcItems[j]._pFunc));
|
|
|
|
int cmdID = ID_PLUGINS_CMD + static_cast<int32_t>(_pluginsCommands.size() - 1);
|
|
_pluginInfos[i]->_funcItems[j]._cmdID = cmdID;
|
|
generic_string itemName = _pluginInfos[i]->_funcItems[j]._itemName;
|
|
|
|
if (_pluginInfos[i]->_funcItems[j]._pShKey)
|
|
{
|
|
ShortcutKey & sKey = *(_pluginInfos[i]->_funcItems[j]._pShKey);
|
|
PluginCmdShortcut pcs(Shortcut(itemName.c_str(), sKey._isCtrl, sKey._isAlt, sKey._isShift, sKey._key), cmdID, _pluginInfos[i]->_moduleName.c_str(), j);
|
|
pluginCmdSCList.push_back(pcs);
|
|
itemName += TEXT("\t");
|
|
itemName += pcs.toString();
|
|
}
|
|
else
|
|
{ //no ShortcutKey is provided, add an disabled shortcut (so it can still be mapped, Paramaters class can still index any changes and the toolbar wont funk out
|
|
Shortcut sc(itemName.c_str(), false, false, false, 0x00);
|
|
PluginCmdShortcut pcs(sc, cmdID, _pluginInfos[i]->_moduleName.c_str(), j); //VK_NULL and everything disabled, the menu name is left alone
|
|
pluginCmdSCList.push_back(pcs);
|
|
}
|
|
::InsertMenu(_pluginInfos[i]->_pluginMenu, j, MF_BYPOSITION, cmdID, itemName.c_str());
|
|
|
|
if (_pluginInfos[i]->_funcItems[j]._init2Check)
|
|
::CheckMenuItem(_hPluginsMenu, cmdID, MF_BYCOMMAND | MF_CHECKED);
|
|
}
|
|
}
|
|
|
|
HMENU PluginsManager::setMenu(HMENU hMenu, const TCHAR *menuName, bool enablePluginAdmin)
|
|
{
|
|
const TCHAR *nom_menu = (menuName && menuName[0])?menuName:TEXT("&Plugins");
|
|
size_t nbPlugin = _pluginInfos.size();
|
|
|
|
if (!_hPluginsMenu)
|
|
{
|
|
_hPluginsMenu = ::CreateMenu();
|
|
::InsertMenu(hMenu, MENUINDEX_PLUGINS, MF_BYPOSITION | MF_POPUP, (UINT_PTR)_hPluginsMenu, nom_menu);
|
|
|
|
int i = 1;
|
|
|
|
if (nbPlugin > 0)
|
|
::InsertMenu(_hPluginsMenu, 0, MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
|
|
|
|
if (enablePluginAdmin)
|
|
{
|
|
::InsertMenu(_hPluginsMenu, i++, MF_BYPOSITION, IDM_SETTING_PLUGINADM, TEXT("Plugins Admin..."));
|
|
::InsertMenu(_hPluginsMenu, i++, MF_BYPOSITION | MF_SEPARATOR, 0, TEXT(""));
|
|
}
|
|
|
|
::InsertMenu(_hPluginsMenu, i, MF_BYPOSITION, IDM_SETTING_OPENPLUGINSDIR, TEXT("Open Plugins Folder..."));
|
|
}
|
|
|
|
for (size_t i = 0; i < nbPlugin; ++i)
|
|
{
|
|
addInMenuFromPMIndex(static_cast<int32_t>(i));
|
|
}
|
|
return _hPluginsMenu;
|
|
}
|
|
|
|
|
|
void PluginsManager::runPluginCommand(size_t i)
|
|
{
|
|
if (i < _pluginsCommands.size())
|
|
{
|
|
if (_pluginsCommands[i]._pFunc != NULL)
|
|
{
|
|
try
|
|
{
|
|
_pluginsCommands[i]._pFunc();
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
::MessageBoxA(NULL, e.what(), "PluginsManager::runPluginCommand Exception", MB_OK);
|
|
}
|
|
catch (...)
|
|
{
|
|
TCHAR funcInfo[128];
|
|
generic_sprintf(funcInfo, TEXT("runPluginCommand(size_t i : %zd)"), i);
|
|
pluginCrashAlert(_pluginsCommands[i]._pluginName.c_str(), funcInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void PluginsManager::runPluginCommand(const TCHAR *pluginName, int commandID)
|
|
{
|
|
for (size_t i = 0, len = _pluginsCommands.size() ; i < len ; ++i)
|
|
{
|
|
if (!generic_stricmp(_pluginsCommands[i]._pluginName.c_str(), pluginName))
|
|
{
|
|
if (_pluginsCommands[i]._funcID == commandID)
|
|
{
|
|
try
|
|
{
|
|
_pluginsCommands[i]._pFunc();
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
pluginExceptionAlert(_pluginsCommands[i]._pluginName.c_str(), e);
|
|
}
|
|
catch (...)
|
|
{
|
|
TCHAR funcInfo[128];
|
|
generic_sprintf(funcInfo, TEXT("runPluginCommand(const TCHAR *pluginName : %s, int commandID : %d)"), pluginName, commandID);
|
|
pluginCrashAlert(_pluginsCommands[i]._pluginName.c_str(), funcInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// send the notification to a specific plugin
|
|
void PluginsManager::notify(size_t indexPluginInfo, const SCNotification *notification)
|
|
{
|
|
if (indexPluginInfo >= _pluginInfos.size())
|
|
return;
|
|
|
|
if (_pluginInfos[indexPluginInfo]->_hLib)
|
|
{
|
|
// To avoid the plugin change the data in SCNotification
|
|
// Each notification to pass to a plugin is a copy of SCNotification instance
|
|
SCNotification scNotif = *notification;
|
|
try
|
|
{
|
|
_pluginInfos[indexPluginInfo]->_pBeNotified(&scNotif);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
pluginExceptionAlert(_pluginInfos[indexPluginInfo]->_moduleName.c_str(), e);
|
|
}
|
|
catch (...)
|
|
{
|
|
TCHAR funcInfo[256];
|
|
generic_sprintf(funcInfo, TEXT("notify(SCNotification *notification) : \r notification->nmhdr.code == %d\r notification->nmhdr.hwndFrom == %p\r notification->nmhdr.idFrom == %" PRIuPTR), \
|
|
scNotif.nmhdr.code, scNotif.nmhdr.hwndFrom, scNotif.nmhdr.idFrom);
|
|
pluginCrashAlert(_pluginInfos[indexPluginInfo]->_moduleName.c_str(), funcInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
// broadcast the notification to all plugins
|
|
void PluginsManager::notify(const SCNotification *notification)
|
|
{
|
|
if (_noMoreNotification) // this boolean should be enabled after NPPN_SHUTDOWN has been sent
|
|
return;
|
|
_noMoreNotification = notification->nmhdr.code == NPPN_SHUTDOWN;
|
|
|
|
for (size_t i = 0, len = _pluginInfos.size() ; i < len ; ++i)
|
|
{
|
|
notify(i, notification);
|
|
}
|
|
}
|
|
|
|
|
|
void PluginsManager::relayNppMessages(UINT Message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
for (size_t i = 0, len = _pluginInfos.size(); i < len ; ++i)
|
|
{
|
|
if (_pluginInfos[i]->_hLib)
|
|
{
|
|
try
|
|
{
|
|
_pluginInfos[i]->_pMessageProc(Message, wParam, lParam);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
pluginExceptionAlert(_pluginInfos[i]->_moduleName.c_str(), e);
|
|
}
|
|
catch (...)
|
|
{
|
|
TCHAR funcInfo[128];
|
|
generic_sprintf(funcInfo, TEXT("relayNppMessages(UINT Message : %u, WPARAM wParam : %" PRIuPTR ", LPARAM lParam : %" PRIiPTR ")"), Message, wParam, lParam);
|
|
pluginCrashAlert(_pluginInfos[i]->_moduleName.c_str(), funcInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool PluginsManager::relayPluginMessages(UINT Message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
const TCHAR * moduleName = (const TCHAR *)wParam;
|
|
if (!moduleName || !moduleName[0] || !lParam)
|
|
return false;
|
|
|
|
for (size_t i = 0, len = _pluginInfos.size() ; i < len ; ++i)
|
|
{
|
|
if (_pluginInfos[i]->_moduleName == moduleName)
|
|
{
|
|
if (_pluginInfos[i]->_hLib)
|
|
{
|
|
try
|
|
{
|
|
_pluginInfos[i]->_pMessageProc(Message, wParam, lParam);
|
|
}
|
|
catch (std::exception& e)
|
|
{
|
|
pluginExceptionAlert(_pluginInfos[i]->_moduleName.c_str(), e);
|
|
}
|
|
catch (...)
|
|
{
|
|
TCHAR funcInfo[128];
|
|
generic_sprintf(funcInfo, TEXT("relayPluginMessages(UINT Message : %u, WPARAM wParam : %" PRIuPTR ", LPARAM lParam : %" PRIiPTR ")"), Message, wParam, lParam);
|
|
pluginCrashAlert(_pluginInfos[i]->_moduleName.c_str(), funcInfo);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
bool PluginsManager::allocateCmdID(int numberRequired, int *start)
|
|
{
|
|
bool retVal = true;
|
|
|
|
*start = _dynamicIDAlloc.allocate(numberRequired);
|
|
|
|
if (-1 == *start)
|
|
{
|
|
*start = 0;
|
|
retVal = false;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
bool PluginsManager::allocateMarker(int numberRequired, int *start)
|
|
{
|
|
bool retVal = true;
|
|
*start = _markerAlloc.allocate(numberRequired);
|
|
if (-1 == *start)
|
|
{
|
|
*start = 0;
|
|
retVal = false;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
generic_string PluginsManager::getLoadedPluginNames() const
|
|
{
|
|
generic_string pluginPaths;
|
|
for (size_t i = 0; i < _loadedDlls.size(); ++i)
|
|
{
|
|
pluginPaths += _loadedDlls[i]._fileName;
|
|
pluginPaths += TEXT(" ");
|
|
}
|
|
return pluginPaths;
|
|
}
|
|
|