⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pluginmgr.cpp

📁 一款密码保险箱源码
💻 CPP
字号:
/*
  KeePass Password Safe - The Open-Source Password Manager
  Copyright (C) 2003-2007 Dominik Reichl <dominik.reichl@t-online.de>

  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.

  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "StdAfx.h"
#include <tchar.h>
#include "PluginMgr.h"
#include "../../KeePassLibCpp/Util/TranslateEx.h"
#include "../../KeePassLibCpp/Util/StrUtil.h"
#include "../../KeePassLibCpp/Util/MemUtil.h"
#include "../Util/CmdLine/CommandLineOption.h"

CPluginManager& CPluginManager::Instance()
{
	static CPluginManager singleton;
	return singleton;
}

CPluginManager::CPluginManager()
{
	m_dwFreePluginID = 0;
	m_plugins.clear();
	m_vKnownNames.clear();

	ZeroMemory(&m_kpAppInfo, sizeof(KP_APP_INFO));

	m_dwFirstCommand = 0;
	m_dwLastCommand = 0;
}

CPluginManager::~CPluginManager()
{
	CleanUp();
}

void CPluginManager::CleanUp()
{
	UnloadAllPlugins();

	m_plugins.clear();
	m_vKnownNames.clear();

	m_dwFreePluginID = 0;
	ZeroMemory(&m_kpAppInfo, sizeof(KP_APP_INFO));
}

BOOL CPluginManager::SetAppInfo(const KP_APP_INFO *pAppInfo)
{
	ASSERT(pAppInfo != NULL); if(pAppInfo == NULL) return FALSE;

	memcpy(&m_kpAppInfo, pAppInfo, sizeof(KP_APP_INFO));
	return TRUE;
}

BOOL CPluginManager::SetDirectCommandRange(DWORD dwFirstCommand, DWORD dwLastCommand)
{
	ASSERT(dwFirstCommand <= dwLastCommand);
	if(dwFirstCommand > dwLastCommand) return FALSE;

	m_dwFirstCommand = dwFirstCommand;
	m_dwLastCommand = dwLastCommand;

	return TRUE;
}

BOOL CPluginManager::AssignPluginCommands()
{
	unsigned int i;
	DWORD j, posCmd = m_dwFirstCommand;
	KP_PLUGIN_INSTANCE *p;
	BOOL bRet = TRUE;

	ASSERT(m_dwLastCommand != 0); if(m_dwLastCommand == 0) return FALSE;

	for(i = 0; i < (unsigned int)m_plugins.size(); i++)
	{
		p = &m_plugins[i];
		ASSERT(p != NULL); if(p == NULL) return FALSE;

		if((p->hinstDLL != NULL) && (p->info.dwNumCommands != 0) &&
			(p->info.pMenuItems != NULL))
		{
			for(j = 0; j < p->info.dwNumCommands; j++)
			{
				p->info.pMenuItems[j].dwCommandID = 0; // 0 = command unused

				// Check if we have haven't run out of commands yet...
				if(posCmd >= (m_dwLastCommand - 1)) continue;

				p->info.pMenuItems[j].dwCommandID = posCmd; // Assign!

				// Fix command string
				if(p->info.pMenuItems[j].lpCommandString == NULL)
					p->info.pMenuItems[j].lpCommandString = _T("");

				posCmd++;
			}
		}
	}

	ASSERT(posCmd <= (m_dwLastCommand + 1));
	return bRet;
}

BOOL CPluginManager::AddPlugin(LPCTSTR lpFile, BOOL bEnable)
{
	KP_PLUGIN_INSTANCE kppi;
	KP_PLUGIN_INSTANCE *p;

	ASSERT(lpFile != NULL); if(lpFile == NULL) return FALSE;

	ZeroMemory(&kppi, sizeof(KP_PLUGIN_INSTANCE));

	if(IsPluginValid(lpFile) == FALSE) return FALSE;

	kppi.bEnabled = bEnable;
	kppi.hinstDLL = NULL;
	_tcsncpy_s(kppi.tszFile, _countof(kppi.tszFile), lpFile, MAX_PATH - 1);

	int i;
	bool bInListAlready = false;
	for(i = 0; i < (int)m_plugins.size(); i++)
	{
		p = &m_plugins[i];

		if(_tcscmp(lpFile, p->tszFile) == 0)
		{
			bInListAlready = true;
			break;
		}
	}

	if(bInListAlready == false)
	{
		kppi.dwPluginID = m_dwFreePluginID;
		m_dwFreePluginID++;
		m_plugins.push_back(kppi);
	}

	return TRUE;
}

BOOL CPluginManager::IsPluginValid(LPCTSTR lpFile)
{
	FILE *fp = NULL;
	BOOL bInit = FALSE, bCall = FALSE, bExit = FALSE;

	_tfopen_s(&fp, lpFile, _T("rb"));
	if(fp == NULL) return FALSE;

	fseek(fp, 0, SEEK_END);
	unsigned long uFileSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	BYTE *p = new BYTE[uFileSize + 1];
	if(uFileSize != 0) fread(p, 1, uFileSize, fp);
	p[uFileSize] = 0;
	fclose(fp); fp = NULL;

	const size_t nInit = strlen(KP_I_INIT);
	const size_t nCall = strlen(KP_I_CALL);
	const size_t nExit = strlen(KP_I_EXIT);

	LPCSTR lp = (LPCSTR)p;
	for(unsigned long i = 0; i < uFileSize; i++)
	{
		if(strncmp(lp, KP_I_INIT, nInit) == 0) bInit = TRUE;
		if(strncmp(lp, KP_I_CALL, nCall) == 0) bCall = TRUE;
		if(strncmp(lp, KP_I_EXIT, nExit) == 0) bExit = TRUE;

		lp++;
	}

	SAFE_DELETE_ARRAY(p);
	if((bInit == FALSE) || (bCall == FALSE) || (bExit == FALSE)) return FALSE;
	return TRUE;
}

BOOL CPluginManager::AddAllPlugins(LPCTSTR lpBaseSearchPath, LPCTSTR lpMask, BOOL bOnlyKnown)
{
	HANDLE hFind;
	WIN32_FIND_DATA wfd;
	TCHAR tszPath[MAX_PATH];

	ASSERT(lpBaseSearchPath != NULL); if(lpBaseSearchPath == NULL) return FALSE;

	_tcscpy_s(tszPath, _countof(tszPath), lpBaseSearchPath);
	_tcscat_s(tszPath, _countof(tszPath), lpMask);

	ZeroMemory(&wfd, sizeof(WIN32_FIND_DATA));
	hFind = FindFirstFile(tszPath, &wfd);
	if(hFind == INVALID_HANDLE_VALUE) return TRUE; // Valid, but no files

	while(1)
	{
		_tcscpy_s(tszPath, _countof(tszPath), lpBaseSearchPath);
		_tcscat_s(tszPath, _countof(tszPath), wfd.cFileName);

		if(bOnlyKnown == FALSE) AddPlugin(tszPath, FALSE); // Add but don't enable
		else
		{
			for(unsigned int i = 0; i < m_vKnownNames.size(); i++)
				if(_tcscmp(wfd.cFileName, m_vKnownNames[i].c_str()) == 0)
				{
					AddPlugin(tszPath, TRUE); // Add and enable
					break;
				}
		}

		if(FindNextFile(hFind, &wfd) == FALSE) break;
	}

	FindClose(hFind); hFind = NULL;
	return TRUE;
}

BOOL CPluginManager::LoadAllPlugins()
{
	unsigned int i;
	KP_PLUGIN_INSTANCE *p;

	for(i = 0; i < (unsigned int)m_plugins.size(); i++)
	{
		p = &m_plugins[i];

		if(p->bEnabled == FALSE) continue; // Disabled?

		ASSERT(p->hinstDLL == NULL); if(p->hinstDLL != NULL) continue; // Loaded already?

		p->hinstDLL = LoadLibrary(p->tszFile);
		if(p->hinstDLL == NULL) continue;

		p->lpInit = (LPKEEPLUGININIT)GetProcAddress(p->hinstDLL, KP_I_INIT);
		if(p->lpInit == NULL) { FreeLibrary(p->hinstDLL); p->hinstDLL = NULL; continue; }

		p->lpCall = (LPKEEPLUGINCALL)GetProcAddress(p->hinstDLL, KP_I_CALL);
		if(p->lpCall == NULL) { FreeLibrary(p->hinstDLL); p->hinstDLL = NULL; continue; }

		p->lpExit = (LPKEEPLUGINEXIT)GetProcAddress(p->hinstDLL, KP_I_EXIT);
		if(p->lpExit == NULL) { FreeLibrary(p->hinstDLL); p->hinstDLL = NULL; continue; }

		// Call the initialization function of the plugin
		if(p->lpInit(&m_kpAppInfo, &p->info) == FALSE)
			{ FreeLibrary(p->hinstDLL); p->hinstDLL = NULL; continue; }

		if(p->info.dwForAppVer != m_kpAppInfo.dwAppVersion)
		{
			CString str;
			TCHAR tszTemp[20];

			str = TRL("Plugin"); str += _T(": <");
			str += p->tszFile; str += _T(">\r\n\r\n");
			str += TRL("This plugin has been designed for a different application version and may be incompatible with this one.");
			str += _T("\r\n\r\n");
			str += TRL("Application version:"); str += _T(" ");
			_stprintf_s(tszTemp, _countof(tszTemp), _T("%u.%u.%u.%u"),
				(m_kpAppInfo.dwAppVersion >> 24) & 0xFF,
				(m_kpAppInfo.dwAppVersion >> 16) & 0xFF,
				(m_kpAppInfo.dwAppVersion >> 8) & 0xFF,
				m_kpAppInfo.dwAppVersion & 0xFF);
			str += tszTemp; str += _T("\r\n");
			str += TRL("Plugin has been designed for:"); str += _T(" ");
			_stprintf_s(tszTemp, _countof(tszTemp), _T("%u.%u.%u.%u"),
				(p->info.dwForAppVer >> 24) & 0xFF,
				(p->info.dwForAppVer >> 16) & 0xFF,
				(p->info.dwForAppVer >> 8) & 0xFF,
				p->info.dwForAppVer & 0xFF);
			str += tszTemp; str += _T("\r\n\r\n");
			str += TRL("It is possible that the plugin is compatible, but it's also possible that it will crash KeePass.");
			str += _T("\r\n");
			str += TRL("Therefore save all data before you continue."); str += _T("\r\n\r\n");
			str += TRL("Do you want to load the plugin?");

			int nRet;
			nRet = MessageBox(GetDesktopWindow(), str, TRL("Plugin Manager"), MB_YESNO | MB_ICONQUESTION);

			if(nRet == IDNO)
			{
				p->lpExit(0, 0);
				p->bEnabled = FALSE;
				p->lpInit = NULL; p->lpCall = NULL; p->lpExit = NULL;
				FreeLibrary(p->hinstDLL); p->hinstDLL = NULL;
				continue;
			}
		}
	}

	return AssignPluginCommands();
}

BOOL CPluginManager::UnloadAllPlugins()
{
	unsigned int i;
	KP_PLUGIN_INSTANCE *p;

	for(i = 0; i < (unsigned int)m_plugins.size(); i++)
	{
		p = &m_plugins[i];

		if(p->hinstDLL != NULL) // Unloaded already?
		{
			ASSERT(p->lpExit != NULL);
			if(p->lpExit != NULL) p->lpExit(0, 0);
			p->lpInit = NULL; p->lpCall = NULL; p->lpExit = NULL;

			FreeLibrary(p->hinstDLL); p->hinstDLL = NULL;
		}
	}

	return TRUE;
}

BOOL CPluginManager::EnablePluginByID(DWORD dwPluginID, BOOL bEnable)
{
	unsigned int i;
	BOOL bRet = FALSE;

	for(i = 0; i < m_plugins.size(); i++)
	{
		if(m_plugins[i].dwPluginID == dwPluginID)
		{
			m_plugins[i].bEnabled = bEnable;
			bRet = TRUE;
			break;
		}
	}

	return bRet;
}

BOOL CPluginManager::EnablePluginByStr(LPCTSTR lpPluginFile, BOOL bEnable)
{
	CString strT, strShort;
	unsigned int i;
	BOOL bRet = FALSE;

	ASSERT(lpPluginFile != NULL); if(lpPluginFile == NULL) return FALSE;

	// Only plugins in the KeePass directory are allowed
	if(_tcschr(lpPluginFile, _T('\\')) != NULL) return FALSE;
	if(_tcschr(lpPluginFile, _T('/')) != NULL) return FALSE;

	for(i = 0; i < (unsigned int)m_plugins.size(); i++)
	{
		strT = m_plugins[i].tszFile;
		strShort = CsFileOnly(&strT);

		if(_tcscmp((LPCTSTR)strShort, lpPluginFile) == 0)
		{
			m_plugins[i].bEnabled = bEnable;
			bRet = TRUE;
			break;
		}
	}

	return bRet;
}

KP_PLUGIN_INSTANCE *CPluginManager::GetPluginByID(DWORD dwID)
{
	for(unsigned int i = 0; i < (unsigned int)m_plugins.size(); i++)
	{
		if(m_plugins[i].dwPluginID == dwID)
			return &m_plugins[i];
	}

	return NULL;
}

BOOL CPluginManager::CallSinglePlugin(DWORD dwPluginID, DWORD dwCode, LPARAM lParamW, LPARAM lParamL)
{
	KP_PLUGIN_INSTANCE *p = GetPluginByID(dwPluginID);
	ASSERT(p != NULL); if(p == NULL) return FALSE;

	if(p->hinstDLL != NULL)
		return p->lpCall(dwCode, lParamW, lParamL);

	return TRUE; // TRUE = continue work
}

BOOL CPluginManager::CallPlugins(DWORD dwCode, LPARAM lParamW, LPARAM lParamL)
{
	BOOL bRet = TRUE;
	unsigned int i, j;
	KP_PLUGIN_INSTANCE *p;
	KP_MENU_ITEM *pMenuItems;

	if(dwCode == KPM_DIRECT_EXEC)
	{
		for(i = 0; i < (unsigned int)m_plugins.size(); i++)
		{
			p = &m_plugins[i];

			if(p->hinstDLL == NULL) continue;

			pMenuItems = p->info.pMenuItems;
			for(j = 0; j < (unsigned int)p->info.dwNumCommands; j++)
			{
				if(pMenuItems[j].dwCommandID == (DWORD)lParamW)
					return p->lpCall(KPM_DIRECT_EXEC, lParamW, lParamL);
			}
		}
	}
	else
	{
		for(i = 0; i < (unsigned int)m_plugins.size(); i++) // Call all plugins
		{
			p = &m_plugins[i];

			if(p->hinstDLL == NULL) continue;

			bRet &= p->lpCall(dwCode, lParamW, lParamL);
		}
	}

	return bRet;
}

BOOL CPluginManager::UsesCmdArg(const std_string& argument) const
{
	typedef std::vector<KP_PLUGIN_INSTANCE>::const_iterator const_iterator;
	const const_iterator end(m_plugins.end());

	for(const_iterator it = m_plugins.begin(); it != end; ++it)
	{
		ASSERT(it->hinstDLL != NULL); // Assure plugin is loaded.

		const TCHAR* const cmdLineArgPrefix = it->info.cmdLineArgPrefix;
		if(cmdLineArgPrefix == NULL) continue; // Plugin has no command line options

		const CommandLineOption commandLineOption(cmdLineArgPrefix);
		ASSERT(_T('.') == *commandLineOption.optionName().rbegin()); // Assure option is a plugin option
		if(commandLineOption.isOption(argument)) return true;
	}

	if(argument == DUMMY_COMMAND_LINE_OPT) return true;

	return false;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -