Index: plugin.hpp
===================================================================
--- plugin.hpp	(revision 6817)
+++ plugin.hpp	(working copy)
@@ -1817,6 +1817,9 @@
 	PCTL_LOADPLUGIN         = 0,
 	PCTL_UNLOADPLUGIN       = 1,
 	PCTL_FORCEDLOADPLUGIN   = 2,
+	PCTL_GETPLUGINS         = 3,
+	PCTL_GETPLUGININFO      = 4,
+	PCTL_FINDPLUGIN         = 5
 };
 
 enum FAR_PLUGIN_LOAD_TYPE
@@ -1824,6 +1827,26 @@
 	PLT_PATH = 0,
 };
 
+enum FAR_PLUGIN_FIND_MODE
+{
+	PFM_GUID = 0,
+	PFM_MODULENAME = 1
+};
+
+typedef unsigned __int64 FAR_PLUGIN_FLAGS;
+static const FAR_PLUGIN_FLAGS
+	FPF_NONE           = 0,
+	FPF_FAR1           = 0x0000000000000001ULL,
+	FPF_FAR2           = 0x0000000000000002ULL,
+	FPF_LOADED         = 0x0000000000000004ULL;
+
+// PCTL_GETPLUGINS
+struct FarPlugins
+{
+	size_t StructSize;
+	int PluginsCount;
+};
+
 enum FAR_FILE_FILTER_CONTROL_COMMANDS
 {
 	FFCTL_CREATEFILEFILTER          = 0,
@@ -2310,7 +2333,17 @@
 };
 
 
+// PCTL_GETPLUGININFO
+struct FarGetPluginInfo
+{
+	size_t Size;
+	const wchar_t *ModuleName;
+	FAR_PLUGIN_FLAGS Flags;
+	struct GlobalInfo Info1;
+	struct PluginInfo Info2;
+};
 
+
 struct InfoPanelLine
 {
 	const wchar_t *Text;
Index: plugins.hpp
===================================================================
--- plugins.hpp	(revision 6817)
+++ plugins.hpp	(working copy)
@@ -228,6 +228,9 @@
 		bool SetHotKeyDialog(Plugin *pPlugin, const GUID& Guid, PluginsHotkeysConfig::HotKeyTypeEnum HotKeyType, const wchar_t *DlgPluginTitle);
 		void ShowPluginInfo(Plugin *pPlugin, const GUID& Guid);
 
+		// Запрос информации о плагине через API межплагинного взаимодействия (PCTL_GETPLUGININFO)
+		int GetPluginInfo(Plugin *pPlugin, FarGetPluginInfo *pInfo);
+
 		// $ .09.2000 SVS - Функция CallPlugin - найти плагин по ID и запустить OpenFrom = OPEN_*
 		int CallPlugin(const GUID& SysID,int OpenFrom, void *Data, int *Ret=nullptr);
 		Plugin *FindPlugin(const GUID& SysID);
Index: plugapi.cpp
===================================================================
--- plugapi.cpp	(revision 6817)
+++ plugapi.cpp	(working copy)
@@ -2403,6 +2403,49 @@
 
 			break;
 		}
+
+		case PCTL_GETPLUGINS:
+		{
+			FarPlugins* Info = (FarPlugins*)Param2;
+			if ((Info) && (Info->StructSize == sizeof(FarPlugins)))
+			{
+				Info->PluginsCount = CtrlObject->Plugins.GetPluginsCount();
+				return true;
+			}
+			break;
+		}
+
+		case PCTL_GETPLUGININFO:
+		{
+			FarGetPluginInfo* Info = (FarGetPluginInfo*)Param2;
+			/* Если Info = null - только подсчет необходимого места */
+			if ((!Info) || (Info->Size >= sizeof(FarGetPluginInfo)))
+			{
+				Plugin* Plug = CtrlObject->Plugins.GetPlugin(Param1);
+				if (Plug)
+					{ return CtrlObject->Plugins.GetPluginInfo(Plug, Info); }
+			}
+			break;
+		}
+
+		case PCTL_FINDPLUGIN:
+		{
+			for (int i = 0; i < CtrlObject->Plugins.GetPluginsCount(); i++)
+			{
+				Plugin* Plug = CtrlObject->Plugins.GetPlugin(i);
+				if (Param1 == PFM_GUID)
+				{
+					if (Plug->GetGUID() == *(GUID*)Param2)
+						{ return i; }
+				}
+				else if (Param1 == PFM_MODULENAME)
+				{
+					if (StrCmpI(Plug->GetModuleName(), (wchar_t*)Param2) == 0)
+						{ return i; }
+				}
+			}
+			return -1;
+		}
 	}
 
 	return 0;
Index: plugins.cpp
===================================================================
--- plugins.cpp	(revision 6817)
+++ plugins.cpp	(working copy)
@@ -1903,6 +1903,164 @@
 	Builder.ShowDialog();
 }
 
+
+char* BufReserve(char*& Buf, int Count, int& Rest, int& Size)
+{
+	char* Res = nullptr;
+
+	if (Buf)
+	{
+		if (Rest >= Count)
+		{
+			Res = Buf;
+			Buf += Count;
+			Rest -= Count;
+		}
+		else
+		{
+			Buf += Rest;
+			Rest = 0;
+		}
+	}
+
+	Size += Count;
+	return Res;
+}
+
+
+wchar_t* StrToBuf(const string& Str, char*& Buf, int& Rest, int& Size)
+{
+	int Count = (Str.GetLength() + 1) * sizeof(wchar_t);
+	wchar_t* Res = (wchar_t*)BufReserve(Buf, Count, Rest, Size);
+
+	if (Res)
+		{ wcscpy(Res, Str);	}
+
+	return Res;
+}
+
+
+void ItemsToBuf(PluginMenuItem& Menu, TArray<string> &NamesArray, TArray<string> &GuidsArray, char*& Buf, int& Rest, int& Size)
+{
+  	Menu.Count = NamesArray.getSize();
+	Menu.Strings = nullptr;
+	Menu.Guids = nullptr;
+
+	if (Menu.Count)
+	{
+		wchar_t** Items = (wchar_t**)BufReserve(Buf, Menu.Count * sizeof(wchar_t*), Rest, Size);
+		GUID* Guids = (GUID*)BufReserve(Buf, Menu.Count * sizeof(GUID), Rest, Size);
+  		Menu.Strings = Items;
+		Menu.Guids = Guids;
+
+		for (int i = 0; i < Menu.Count; i++)
+		{
+  			wchar_t* pStr = StrToBuf(*NamesArray.getItem(i), Buf, Rest, Size);
+			if (Items) 
+				Items[i] = pStr;
+
+			GUID Guid;
+  			if (StrToGuid(*GuidsArray.getItem(i), Guid))
+				Guids[i] = Guid;
+		}
+	}
+}
+
+
+int PluginManager::GetPluginInfo(Plugin *pPlugin, FarGetPluginInfo *pInfo)
+{
+	string Prefix;
+	PLUGIN_FLAGS Flags = 0;
+	TArray<string> MenuNames, MenuGuids, DiskNames, DiskGuids, ConfNames, ConfGuids;
+
+	if (pPlugin->CheckWorkFlags(PIWF_CACHED))
+	{
+		int i;
+		string Name, Guid;
+		unsigned __int64 id = PlCacheCfg->GetCacheID(pPlugin->GetCacheName());
+
+		Flags = PlCacheCfg->GetFlags(id);
+  		Prefix = PlCacheCfg->GetCommandPrefix(id);
+
+		i = 0;
+		while (PlCacheCfg->GetPluginsMenuItem(id, i++, Name, Guid))
+			{ MenuNames.addItem(Name); MenuGuids.addItem(Guid); }
+
+		i = 0;
+		while (PlCacheCfg->GetDiskMenuItem(id, i++, Name, Guid))
+			{ DiskNames.addItem(Name); DiskGuids.addItem(Guid); }
+
+		i = 0;
+		while (PlCacheCfg->GetPluginsConfigMenuItem(id, i++, Name, Guid))
+			{ ConfNames.addItem(Name); ConfGuids.addItem(Guid); }
+	}
+	else
+	{
+		PluginInfo Info = {sizeof(Info)};
+		if (pPlugin->GetPluginInfo(&Info))
+		{
+			Flags = Info.Flags;
+			Prefix = Info.CommandPrefix;
+
+			for (int i = 0; i < Info.PluginMenu.Count; i++)
+				{ MenuNames.addItem(Info.PluginMenu.Strings[i]); MenuGuids.addItem(GuidToStr(Info.PluginMenu.Guids[i])); }
+
+			for (int i = 0; i < Info.DiskMenu.Count; i++)
+				{ DiskNames.addItem(Info.DiskMenu.Strings[i]); DiskGuids.addItem(GuidToStr(Info.DiskMenu.Guids[i])); }
+
+			for (int i = 0; i < Info.PluginConfig.Count; i++)
+				{ ConfNames.addItem(Info.PluginConfig.Strings[i]); ConfGuids.addItem(GuidToStr(Info.PluginConfig.Guids[i])); }
+		}
+	}
+
+	//------------------------------------
+
+	FarGetPluginInfo Temp;
+	char* Buf = nullptr;
+	int Rest = 0;
+
+	if (pInfo)
+	{
+		Rest = pInfo->Size - sizeof(FarGetPluginInfo);
+		Buf = (char*)pInfo + sizeof(FarGetPluginInfo);
+	}
+	else
+	{
+		pInfo = &Temp;
+	}
+
+	int Size = sizeof(FarGetPluginInfo);
+
+	pInfo->ModuleName = StrToBuf(pPlugin->GetModuleName(), Buf, Rest, Size);
+
+	pInfo->Flags = 0;
+#ifndef NO_WRAPPER
+	if (pPlugin->IsOemPlugin())
+		pInfo->Flags |= FPF_FAR1;
+#endif // NO_WRAPPER
+	if (pPlugin->m_hModule)
+		pInfo->Flags |= FPF_LOADED;
+
+	pInfo->Info1.StructSize = sizeof(GlobalInfo);
+	pInfo->Info1.Guid = pPlugin->GetGUID();
+	pInfo->Info1.Version = pPlugin->GetVersion();
+	pInfo->Info1.Title = StrToBuf(pPlugin->strTitle, Buf, Rest, Size);
+	pInfo->Info1.Description = StrToBuf(pPlugin->strDescription, Buf, Rest, Size);
+	pInfo->Info1.Author = StrToBuf(pPlugin->strAuthor, Buf, Rest, Size);
+
+	pInfo->Info2.StructSize = sizeof(PluginInfo);
+	pInfo->Info2.Flags = Flags;
+	pInfo->Info2.CommandPrefix = StrToBuf(Prefix, Buf, Rest, Size);
+
+	ItemsToBuf(pInfo->Info2.DiskMenu, DiskNames, DiskGuids, Buf, Rest, Size);
+	ItemsToBuf(pInfo->Info2.PluginMenu, MenuNames, MenuGuids, Buf, Rest, Size);
+	ItemsToBuf(pInfo->Info2.PluginConfig, ConfNames, ConfGuids, Buf, Rest, Size);
+
+	return Size;
+}
+
+
+
 bool PluginManager::GetDiskMenuItem(
      Plugin *pPlugin,
      int PluginItem,
