📄 winutil.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 <mmsystem.h>
#ifdef _UNICODE
#include <atlbase.h>
#endif
#include "WinUtil.h"
#include "CmdLine/Executable.h"
#include "PrivateConfig.h"
#include "../../KeePassLibCpp/Util/AppUtil.h"
#include "../../KeePassLibCpp/Util/MemUtil.h"
#include "../../KeePassLibCpp/Util/StrUtil.h"
#include "../../KeePassLibCpp/Util/TranslateEx.h"
static unsigned char g_shaLastString[32];
// static LPCTSTR g_lpChildWindowText = NULL;
static UINT g_uCfIgnoreID = 0; // ID of CFN_CLIPBOARD_VIEWER_IGNORE
#ifndef _WIN32_WCE
#ifdef _UNICODE
#define CF_TTEXTEX CF_UNICODETEXT
#else
#define CF_TTEXTEX CF_TEXT
#endif
void CopyStringToClipboard(const TCHAR *lptString)
{
if(OpenClipboard(NULL) == FALSE) return;
if(EmptyClipboard() == FALSE) return;
if(lptString == NULL) // No string to copy => empty clipboard
{
CloseClipboard();
return;
}
size_t uDataSize = _tcslen(lptString) * sizeof(TCHAR); // Get length
if(uDataSize == 0)
{
CloseClipboard();
return;
}
uDataSize += sizeof(TCHAR); // Plus NULL-terminator of string
SetClipboardIgnoreFormat();
HGLOBAL globalHandle = GlobalAlloc(GHND | GMEM_DDESHARE, uDataSize);
if(globalHandle == NULL) { ASSERT(FALSE); CloseClipboard(); return; }
LPVOID globalData = GlobalLock(globalHandle);
if(globalData == NULL) { ASSERT(FALSE); CloseClipboard(); return; }
_tcscpy_s((TCHAR *)globalData, _tcslen(lptString) + 1, lptString); // Copy string plus NULL-byte to global memory
GlobalUnlock(globalHandle); // Unlock before SetClipboardData!
VERIFY(SetClipboardData(CF_TTEXTEX, globalHandle)); // Set clipboard data to our global memory block
VERIFY(CloseClipboard()); // Close clipboard, and done
RegisterOwnClipboardData((unsigned char *)lptString, uDataSize - sizeof(TCHAR));
}
void RegisterOwnClipboardData(unsigned char* pData, unsigned long dwDataSize)
{
ASSERT(pData != NULL); if(pData == NULL) return;
sha256_ctx shactx;
sha256_begin(&shactx);
if(dwDataSize > 0)
sha256_hash(pData, dwDataSize, &shactx);
sha256_end(g_shaLastString, &shactx);
}
void ClearClipboardIfOwner()
{
if(OpenClipboard(NULL) == FALSE) return;
if((IsClipboardFormatAvailable(CF_TEXT) == FALSE) &&
(IsClipboardFormatAvailable(CF_OEMTEXT) == FALSE))
{
CloseClipboard();
return;
}
HANDLE hClipboardData = GetClipboardData(CF_TTEXTEX);
if(hClipboardData == NULL) { CloseClipboard(); return; }
TCHAR *lpString = (TCHAR *)GlobalLock(hClipboardData);
if(lpString == NULL) { CloseClipboard(); return; }
sha256_ctx shactx;
unsigned char uHash[32];
sha256_begin(&shactx);
sha256_hash((unsigned char *)lpString, (unsigned long)(_tcslen(lpString) *
sizeof(TCHAR)), &shactx);
sha256_end(uHash, &shactx);
GlobalUnlock(hClipboardData);
// If we have copied the string to the clipboard, delete it
if(memcmp(uHash, g_shaLastString, 32) == 0)
{
VERIFY(EmptyClipboard());
}
VERIFY(CloseClipboard());
}
// Thanks to Gabe Martin for the contribution of the following
// two secure clipboard functions!
// http://sourceforge.net/tracker/index.php?func=detail&aid=1102906&group_id=95013&atid=609910
BOOL MakeClipboardDelayRender(HWND hOwner, HWND *phNextCB)
{
BOOL bResult = OpenClipboard(hOwner);
if(bResult != FALSE)
{
// Add a clipboard listener to the cb chain so we can block any listeners from
// knowing we are adding sensitive data to the clipboard
if(phNextCB != NULL)
if(*phNextCB == NULL)
*phNextCB = SetClipboardViewer(hOwner);
EmptyClipboard();
SetClipboardIgnoreFormat();
SetClipboardData(CF_TTEXTEX, NULL);
CloseClipboard();
}
return bResult;
}
void CopyDelayRenderedClipboardData(const TCHAR *lptString)
{
ASSERT(lptString != NULL); if(lptString == NULL) return;
SetClipboardIgnoreFormat();
const size_t cch = _tcslen(lptString);
HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE, (cch + 1) * sizeof(TCHAR));
ASSERT(hglb != NULL); if(hglb == NULL) return;
// Copy the text from pboxLocalClip
LPTSTR lptstr = (LPTSTR)GlobalLock(hglb);
if(cch > 1) memcpy(lptstr, lptString, cch * sizeof(TCHAR));
lptstr[cch] = (TCHAR)0;
GlobalUnlock(hglb);
// Put the delayed clipboard data in the clipboard.
SetClipboardData(CF_TTEXTEX, hglb);
RegisterOwnClipboardData((unsigned char *)lptString, cch * sizeof(TCHAR));
}
void SetClipboardIgnoreFormat()
{
if(g_uCfIgnoreID == 0)
{
g_uCfIgnoreID = RegisterClipboardFormat(CFN_CLIPBOARD_VIEWER_IGNORE);
}
if(g_uCfIgnoreID != 0) // Registered
{
const size_t cch = _tcslen(PWM_PRODUCT_NAME);
HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE, (cch + 1) * sizeof(TCHAR));
ASSERT(hglb != NULL); if(hglb == NULL) return;
LPTSTR lptstr = (LPTSTR)GlobalLock(hglb);
_tcscpy_s(lptstr, cch + 1, PWM_PRODUCT_NAME);
GlobalUnlock(hglb);
SetClipboardData(g_uCfIgnoreID, hglb);
}
}
#endif
#ifdef _UNICODE
#define PRPT_API_NAME "PathRelativePathToW"
#else
#define PRPT_API_NAME "PathRelativePathToA"
#endif
#ifndef _WIN32_WCE
CString MakeRelativePathEx(LPCTSTR lpBaseFile, LPCTSTR lpTargetFile)
{
LPPATHRELATIVEPATHTO lpRel;
HINSTANCE hShl;
TCHAR tszPath[MAX_PATH * 2];
BOOL bResult = FALSE;
CString str;
BOOL bMod;
if((lpBaseFile[1] == _T(':')) && (lpTargetFile[1] == _T(':')) &&
(lpBaseFile[2] == _T('\\')) && (lpTargetFile[2] == _T('\\')) &&
(lpBaseFile[0] != lpTargetFile[0]))
{
return CString(lpTargetFile);
}
else if((lpTargetFile[0] == _T('\\')) && (lpTargetFile[1] == _T('\\')))
{
return CString(lpTargetFile);
}
hShl = LoadLibrary(_T("ShlWApi.dll"));
if(hShl == NULL) return CString(lpTargetFile);
lpRel = (LPPATHRELATIVEPATHTO)GetProcAddress(hShl, PRPT_API_NAME);
if(lpRel != NULL)
{
bResult = lpRel(tszPath, lpBaseFile, 0, lpTargetFile, 0);
}
FreeLibrary(hShl); hShl = NULL;
if(bResult == FALSE) return CString(lpTargetFile);
str = tszPath;
while(1) // Remove all .\\ from the left of the path
{
bMod = FALSE;
if(str.Left(2) == _T(".\\"))
{
str = str.Right(str.GetLength() - 2);
bMod = TRUE;
}
if(bMod == FALSE) break;
}
if(bResult == TRUE) return str;
else return CString(lpTargetFile);
}
#else
CPP_FN_SHARE CString MakeRelativePathEx(LPCTSTR lpBaseFile, LPCTSTR lpTargetFile)
{
return CString(lpTargetFile);
}
#endif
CString GetShortestAbsolutePath(LPCTSTR lpFilePath)
{
CString str;
ASSERT(lpFilePath != NULL); if(lpFilePath == NULL) return str;
DWORD dwBufLen = (DWORD)_tcslen(lpFilePath) + 12, dw;
LPTSTR lpBuf = new TCHAR[dwBufLen + 1];
LPTSTR lpFilePart = NULL;
if(lpBuf != NULL)
{
lpBuf[0] = 0;
dw = GetFullPathName(lpFilePath, dwBufLen, lpBuf, &lpFilePart);
if((dw != 0) && (dw < dwBufLen)) str = lpBuf;
else str = lpFilePath;
}
else str = lpFilePath;
SAFE_DELETE_ARRAY(lpBuf);
return str;
}
#pragma warning(push)
#pragma warning(disable: 4996) // _tcscpy deprecated
BOOL GetRegKeyEx(HKEY hkeyBase, LPCTSTR lpSubKey, LPTSTR lpRetData)
{
HKEY hkey = hkeyBase;
LONG lRetVal = RegOpenKeyEx(hkeyBase, lpSubKey, 0, KEY_QUERY_VALUE, &hkey);
if(lRetVal == ERROR_SUCCESS)
{
LONG lDataSize = MAX_PATH * 4;
TCHAR tszData[MAX_PATH * 4];
lRetVal = RegQueryValue(hkey, NULL, tszData, &lDataSize);
_tcscpy(lpRetData, tszData);
RegCloseKey(hkey); hkey = NULL;
}
return (lRetVal == ERROR_SUCCESS) ? TRUE : FALSE;
}
#pragma warning(pop)
BOOL OpenUrlInNewBrowser(LPCTSTR lpURL)
{
ASSERT(lpURL != NULL); if(lpURL == NULL) return FALSE;
TCHAR tszKey[MAX_PATH * 4];
UINT uResult = 0;
_tcscpy_s(tszKey, _countof(tszKey), _T("http\\shell\\open\\command"));
if(GetRegKeyEx(HKEY_CLASSES_ROOT, tszKey, tszKey) == TRUE)
{
TCHAR *pos = _tcsstr(tszKey, _T("\"%1\""));
if(pos == NULL) // No quotes found
{
pos = _tcsstr(tszKey, _T("%1")); // Check for %1, without quotes
if(pos != NULL) *pos = _T('\0'); // Remove the parameter
}
else *pos = _T('\0'); // Remove the parameter
std::basic_string<TCHAR> strExec = tszKey;
if(pos == NULL) strExec += _T(" ");
strExec += lpURL;
uResult = TWinExec(strExec.c_str(), KPSW_SHOWDEFAULT);
}
return (uResult > 31) ? TRUE : FALSE;
}
BOOL OpenUrlUsingPutty(LPCTSTR lpURL, LPCTSTR lpUser)
{
CString strURL;
BOOL bResult = FALSE;
ASSERT(lpURL != NULL); if(lpURL == NULL) return FALSE;
strURL = lpURL;
if(strURL.Find(_T("ssh:")) >= 0)
{
TCHAR tszKey[MAX_PATH << 1];
// TODO: Make this configurable
_tcscpy_s(tszKey, _countof(tszKey), _T("PUTTY.EXE -ssh "));
// Parse out the "http://" and "ssh://"
if(strURL.Find(_T("http://")) == 0)
strURL = strURL.Right(strURL.GetLength() - (int)_tcslen(_T("http://")));
strURL = strURL.Right(strURL.GetLength() - (int)_tcslen(_T("ssh:")));
if(strURL.Left(1) == _T("/"))
strURL = strURL.Right(strURL.GetLength() - 1);
if(strURL.Left(1) == _T("/"))
strURL = strURL.Right(strURL.GetLength() - 1);
// Add pre-URL command-line parameters
if(lpUser != NULL)
{
if(_tcslen(lpUser) > 0)
{
_tcscat_s(tszKey, _countof(tszKey), lpUser);
_tcscat_s(tszKey, _countof(tszKey), _T("@"));
}
}
// Add the URL
_tcscat_s(tszKey, _countof(tszKey), (LPCTSTR)strURL);
// Execute the ssh client
bResult = (TWinExec(tszKey, KPSW_SHOWDEFAULT) > 31) ? TRUE : FALSE;
}
else if(strURL.Find(_T("telnet:")) >= 0)
{
TCHAR tszKey[MAX_PATH << 1];
// TODO: Make this configurable
_tcscpy_s(tszKey, _countof(tszKey), _T("PUTTY.EXE "));
// Parse out the "http://" and "telnet://"
if(strURL.Find(_T("http://")) == 0)
strURL = strURL.Right(strURL.GetLength() - (int)_tcslen(_T("http://")));
strURL = strURL.Right(strURL.GetLength() - (int)_tcslen(_T("telnet:")));
if(strURL.Left(1) == _T("/"))
strURL = strURL.Right(strURL.GetLength() - 1);
if(strURL.Left(1) == _T("/"))
strURL = strURL.Right(strURL.GetLength() - 1);
// Add the url
_tcscat_s(tszKey, _countof(tszKey), _T("telnet://"));
_tcscat_s(tszKey, _countof(tszKey), strURL.GetBuffer(0));
// Execute the ssh client
bResult = (TWinExec(tszKey, KPSW_SHOWDEFAULT) > 31) ? TRUE : FALSE;
}
return bResult;
}
// If hParent is not NULL, the function will show an error message if
// the URL cannot be opened
void OpenUrlEx(LPCTSTR lpURL, HWND hParent)
{
ASSERT(lpURL != NULL); if(lpURL == NULL) return;
if(_tcslen(lpURL) == 0) return; // Valid, but nothing to do
CPrivateConfig cfg(FALSE);
BOOL bPrevMethod = cfg.GetBool(PWMKEY_HTMURLMETHOD, FALSE);
if(bPrevMethod == FALSE)
{
OpenUrlShellExec(lpURL, hParent);
return;
}
if(_tcsncmp(lpURL, _T("http://"), 7) == 0)
{
if(OpenUrlInNewBrowser(lpURL) == FALSE)
ShellExecute(NULL, _T("open"), lpURL, NULL, NULL, KPSW_SHOWDEFAULT);
}
else if(_tcsncmp(lpURL, _T("https://"), 8) == 0)
{
if(OpenUrlInNewBrowser(lpURL) == FALSE)
ShellExecute(NULL, _T("open"), lpURL, NULL, NULL, KPSW_SHOWDEFAULT);
}
else if(_tcsncmp(lpURL, _T("cmd://"), 6) == 0)
{
if(_tcslen(lpURL) > 6)
{
TWinExec(&lpURL[6], KPSW_SHOWDEFAULT);
}
}
else ShellExecute(NULL, _T("open"), lpURL, NULL, NULL, KPSW_SHOWDEFAULT);
}
// Internal function
void OpenUrlShellExec(LPCTSTR lpURL, HWND hParent)
{
ASSERT(lpURL != NULL); if(lpURL == NULL) return;
CString strURL = lpURL;
strURL.TrimLeft(_T(" \t\r\n"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -