mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-23 13:54:54 +02:00
Fix Clipboard History panel shows corrupted data issue
Fix #13817, fix #13844, close #13833
This commit is contained in:
parent
1943ce87b5
commit
d6b5f53a0e
@ -20,62 +20,71 @@
|
||||
#include "clipboardFormats.h"
|
||||
|
||||
|
||||
#define CLIPBOARD_TEXTFORMAT CF_UNICODETEXT
|
||||
#define MAX_DISPLAY_LENGTH 64
|
||||
|
||||
ClipboardData ClipboardHistoryPanel::getClipboadData()
|
||||
ClipboardDataInfo ClipboardHistoryPanel::getClipboadData()
|
||||
{
|
||||
ClipboardData clipboardData;
|
||||
if (!IsClipboardFormatAvailable(CLIPBOARD_TEXTFORMAT))
|
||||
ClipboardDataInfo clipboardData;
|
||||
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||
return clipboardData;
|
||||
|
||||
if (!OpenClipboard(NULL))
|
||||
return clipboardData;
|
||||
|
||||
HGLOBAL hglb = GetClipboardData(CLIPBOARD_TEXTFORMAT);
|
||||
HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT);
|
||||
if (hglb != NULL)
|
||||
{
|
||||
char *lpchar = (char *)GlobalLock(hglb);
|
||||
wchar_t *lpWchar = (wchar_t *)GlobalLock(hglb);
|
||||
|
||||
if (lpchar != NULL)
|
||||
unsigned char* pData = static_cast<unsigned char*>(GlobalLock(hglb));
|
||||
if (pData != NULL)
|
||||
{
|
||||
UINT cf_nppTextLen = RegisterClipboardFormat(CF_NPPTEXTLEN);
|
||||
if (IsClipboardFormatAvailable(cf_nppTextLen))
|
||||
{
|
||||
HGLOBAL hglbLen = GetClipboardData(cf_nppTextLen);
|
||||
if (hglbLen != NULL)
|
||||
{
|
||||
unsigned long *lpLen = (unsigned long *)GlobalLock(hglbLen);
|
||||
if (lpLen != NULL)
|
||||
{
|
||||
HGLOBAL hglb_binText = GetClipboardData(CF_TEXT);
|
||||
if (hglb_binText != NULL)
|
||||
{
|
||||
for (size_t i = 0 ; i < (*lpLen) ; ++i)
|
||||
unsigned char* pData_bin = static_cast<unsigned char*>(GlobalLock(hglb_binText));
|
||||
if (pData_bin != NULL)
|
||||
{
|
||||
clipboardData.push_back(static_cast<unsigned char>(lpchar[i]));
|
||||
unsigned long* lpLen = (unsigned long*)GlobalLock(hglbLen);
|
||||
if (lpLen != NULL) // Special copy-paste: Binary data
|
||||
{
|
||||
size_t nbBytes = (*lpLen);
|
||||
for (size_t i = 0; i < nbBytes; ++i)
|
||||
{
|
||||
clipboardData._data.push_back(static_cast<unsigned char>(pData_bin[i]));
|
||||
}
|
||||
clipboardData._isBinaryContained = true;
|
||||
GlobalUnlock(hglbLen);
|
||||
}
|
||||
|
||||
}
|
||||
GlobalUnlock(hglbLen);
|
||||
GlobalUnlock(hglb_binText);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (lpWchar != nullptr)
|
||||
else // Not internal binary clipboard data
|
||||
{
|
||||
int nbBytes = (lstrlenW(lpWchar) + 1) * sizeof(wchar_t);
|
||||
for (int i = 0 ; i < nbBytes ; ++i)
|
||||
wchar_t* lpwchar = (wchar_t*)pData;
|
||||
size_t nbBytes = (lstrlenW(lpwchar) + 1) * sizeof(wchar_t);
|
||||
for (size_t i = 0 ; i < nbBytes ; ++i)
|
||||
{
|
||||
clipboardData.push_back(static_cast<unsigned char>(lpchar[i]));
|
||||
clipboardData._data.push_back(static_cast<unsigned char>(pData[i]));
|
||||
}
|
||||
}
|
||||
GlobalUnlock(hglb);
|
||||
GlobalUnlock(hglb);
|
||||
}
|
||||
}
|
||||
CloseClipboard();
|
||||
return clipboardData;
|
||||
}
|
||||
|
||||
ByteArray::ByteArray(ClipboardData cd)
|
||||
ByteArray::ByteArray(ClipboardDataInfo cd)
|
||||
{
|
||||
_length = cd.size();
|
||||
_length = cd._data.size();
|
||||
if (!_length)
|
||||
{
|
||||
_pBytes = NULL;
|
||||
@ -84,20 +93,22 @@ ByteArray::ByteArray(ClipboardData cd)
|
||||
_pBytes = new unsigned char[_length];
|
||||
for (size_t i = 0 ; i < _length ; ++i)
|
||||
{
|
||||
_pBytes[i] = cd[i];
|
||||
_pBytes[i] = cd._data[i];
|
||||
}
|
||||
}
|
||||
|
||||
StringArray::StringArray(ClipboardData cd, size_t maxLen)
|
||||
StringArray::StringArray(ClipboardDataInfo cd, size_t maxLen)
|
||||
{
|
||||
if (!cd.size())
|
||||
size_t len = cd._data.size();
|
||||
|
||||
if (!len)
|
||||
{
|
||||
_pBytes = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
bool isCompleted = (cd.size() <= maxLen);
|
||||
_length = isCompleted?cd.size():maxLen;
|
||||
bool isCompleted = (len <= maxLen);
|
||||
_length = isCompleted?len:maxLen;
|
||||
|
||||
|
||||
_pBytes = new unsigned char[_length+(isCompleted?0:2)];
|
||||
@ -109,7 +120,7 @@ StringArray::StringArray(ClipboardData cd, size_t maxLen)
|
||||
else if (!isCompleted && (i == _length-6 || i == _length-4 || i == _length-2))
|
||||
_pBytes[i] = '.';
|
||||
else
|
||||
_pBytes[i] = cd[i];
|
||||
_pBytes[i] = cd._data[i];
|
||||
}
|
||||
|
||||
if (!isCompleted)
|
||||
@ -121,17 +132,17 @@ StringArray::StringArray(ClipboardData cd, size_t maxLen)
|
||||
|
||||
// Search clipboard data in internal storage
|
||||
// return -1 if not found, else return the index of internal array
|
||||
int ClipboardHistoryPanel::getClipboardDataIndex(ClipboardData cbd)
|
||||
int ClipboardHistoryPanel::getClipboardDataIndex(ClipboardDataInfo cbd)
|
||||
{
|
||||
int iFound = -1;
|
||||
bool found = false;
|
||||
for (size_t i = 0, len = _clipboardDataVector.size() ; i < len ; ++i)
|
||||
for (size_t i = 0, len = _clipboardDataInfos.size() ; i < len ; ++i)
|
||||
{
|
||||
if (cbd.size() == _clipboardDataVector[i].size())
|
||||
if (cbd._data.size() == _clipboardDataInfos[i]._data.size())
|
||||
{
|
||||
for (size_t j = 0, len2 = cbd.size(); j < len2 ; ++j)
|
||||
for (size_t j = 0, len2 = cbd._data.size(); j < len2 ; ++j)
|
||||
{
|
||||
if (cbd[j] == _clipboardDataVector[i][j])
|
||||
if (cbd._data[j] == _clipboardDataInfos[i]._data[j])
|
||||
found = true;
|
||||
else
|
||||
{
|
||||
@ -150,40 +161,49 @@ int ClipboardHistoryPanel::getClipboardDataIndex(ClipboardData cbd)
|
||||
return iFound;
|
||||
}
|
||||
|
||||
void ClipboardHistoryPanel::addToClipboadHistory(ClipboardData cbd)
|
||||
void ClipboardHistoryPanel::addToClipboadHistory(ClipboardDataInfo cbd)
|
||||
{
|
||||
int i = getClipboardDataIndex(cbd);
|
||||
if (i == 0) return;
|
||||
if (i != -1)
|
||||
{
|
||||
_clipboardDataVector.erase(_clipboardDataVector.begin() + i);
|
||||
_clipboardDataInfos.erase(_clipboardDataInfos.begin() + i);
|
||||
::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_DELETESTRING, i, 0);
|
||||
}
|
||||
_clipboardDataVector.insert(_clipboardDataVector.begin(), cbd);
|
||||
_clipboardDataInfos.insert(_clipboardDataInfos.begin(), cbd);
|
||||
|
||||
StringArray sa(cbd, MAX_DISPLAY_LENGTH);
|
||||
TCHAR *displayStr = (TCHAR *)sa.getPointer();
|
||||
::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(displayStr));
|
||||
::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(L"")); // String will be added in drawItem()
|
||||
}
|
||||
|
||||
|
||||
void ClipboardHistoryPanel::drawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
|
||||
{
|
||||
if (lpDrawItemStruct->itemID >= _clipboardDataVector.size())
|
||||
UINT i = lpDrawItemStruct->itemID;
|
||||
if (i >= _clipboardDataInfos.size())
|
||||
return;
|
||||
|
||||
//printStr(TEXT("OK"));
|
||||
COLORREF fgColor = _lbFgColor == -1?black:_lbFgColor; // fg black by default
|
||||
COLORREF bgColor = _lbBgColor == -1?white:_lbBgColor; // bg white by default
|
||||
|
||||
StringArray sa(_clipboardDataVector[lpDrawItemStruct->itemID], MAX_DISPLAY_LENGTH);
|
||||
TCHAR *ptStr = (TCHAR *)sa.getPointer();
|
||||
ClipboardDataInfo& cbd = _clipboardDataInfos[i];
|
||||
StringArray sa(cbd, MAX_DISPLAY_LENGTH);
|
||||
TCHAR* displayStr = nullptr;
|
||||
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
|
||||
if (cbd._isBinaryContained)
|
||||
{
|
||||
char* displayStrA = (char*)sa.getPointer();
|
||||
displayStr = (TCHAR*)wmc.char2wchar(displayStrA, SC_CP_UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
displayStr = (TCHAR*)sa.getPointer();
|
||||
}
|
||||
|
||||
//printStr(ptStr);
|
||||
::SetTextColor(lpDrawItemStruct->hDC, fgColor);
|
||||
::SetBkColor(lpDrawItemStruct->hDC, bgColor);
|
||||
|
||||
::DrawText(lpDrawItemStruct->hDC, ptStr, lstrlen(ptStr), &(lpDrawItemStruct->rcItem), DT_SINGLELINE | DT_VCENTER | DT_LEFT);
|
||||
::DrawText(lpDrawItemStruct->hDC, displayStr, lstrlen(displayStr), &(lpDrawItemStruct->rcItem), DT_SINGLELINE | DT_VCENTER | DT_LEFT);
|
||||
}
|
||||
|
||||
intptr_t CALLBACK ClipboardHistoryPanel::run_dlgProc(UINT message, WPARAM wParam, LPARAM lParam)
|
||||
@ -212,9 +232,11 @@ intptr_t CALLBACK ClipboardHistoryPanel::run_dlgProc(UINT message, WPARAM wParam
|
||||
|
||||
case WM_DRAWCLIPBOARD :
|
||||
{
|
||||
ClipboardData clipboardData = getClipboadData();
|
||||
if (clipboardData.size())
|
||||
ClipboardDataInfo clipboardData = getClipboadData();
|
||||
if (clipboardData._data.size())
|
||||
{
|
||||
addToClipboadHistory(clipboardData);
|
||||
}
|
||||
if (_hwndNextCbViewer)
|
||||
::SendMessage(_hwndNextCbViewer, message, wParam, lParam);
|
||||
return TRUE;
|
||||
@ -244,18 +266,27 @@ intptr_t CALLBACK ClipboardHistoryPanel::run_dlgProc(UINT message, WPARAM wParam
|
||||
else
|
||||
codepage = SC_CP_UTF8;
|
||||
|
||||
ByteArray ba(_clipboardDataVector[i]);
|
||||
|
||||
char* c = nullptr;
|
||||
try {
|
||||
int nbChar = WideCharToMultiByte(codepage, 0, (wchar_t *)ba.getPointer(), static_cast<int32_t>(ba.getLength()), NULL, 0, NULL, NULL);
|
||||
if (_clipboardDataInfos[i]._isBinaryContained)
|
||||
{
|
||||
(*_ppEditView)->execute(SCI_REPLACESEL, 0, reinterpret_cast<LPARAM>(""));
|
||||
(*_ppEditView)->execute(SCI_ADDTEXT, _clipboardDataInfos[i]._data.size(), reinterpret_cast<LPARAM>(&(_clipboardDataInfos[i]._data[0])));
|
||||
}
|
||||
else
|
||||
{
|
||||
ByteArray ba(_clipboardDataInfos[i]);
|
||||
int nbChar = WideCharToMultiByte(codepage, 0, (wchar_t*)ba.getPointer(), static_cast<int32_t>(ba.getLength()), NULL, 0, NULL, NULL);
|
||||
|
||||
c = new char[nbChar + 1];
|
||||
WideCharToMultiByte(codepage, 0, (wchar_t *)ba.getPointer(), static_cast<int32_t>(ba.getLength()), c, nbChar + 1, NULL, NULL);
|
||||
c = new char[nbChar + 1];
|
||||
WideCharToMultiByte(codepage, 0, (wchar_t*)ba.getPointer(), static_cast<int32_t>(ba.getLength()), c, nbChar + 1, NULL, NULL);
|
||||
|
||||
(*_ppEditView)->execute(SCI_REPLACESEL, 0, reinterpret_cast<LPARAM>(""));
|
||||
(*_ppEditView)->execute(SCI_ADDTEXT, strlen(c), reinterpret_cast<LPARAM>(c));
|
||||
(*_ppEditView)->getFocus();
|
||||
delete[] c;
|
||||
(*_ppEditView)->execute(SCI_REPLACESEL, 0, reinterpret_cast<LPARAM>(""));
|
||||
(*_ppEditView)->execute(SCI_ADDTEXT, strlen(c), reinterpret_cast<LPARAM>(c));
|
||||
(*_ppEditView)->getFocus();
|
||||
delete[] c;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -23,14 +23,17 @@
|
||||
|
||||
#define CH_PROJECTPANELTITLE TEXT("Clipboard History")
|
||||
|
||||
typedef std::vector<unsigned char> ClipboardData;
|
||||
|
||||
class ScintillaEditView;
|
||||
|
||||
struct ClipboardDataInfo {
|
||||
std::vector<unsigned char> _data;
|
||||
bool _isBinaryContained = false;
|
||||
};
|
||||
|
||||
class ByteArray {
|
||||
public:
|
||||
ByteArray() = default;
|
||||
explicit ByteArray(ClipboardData cd);
|
||||
explicit ByteArray(ClipboardDataInfo cd);
|
||||
|
||||
~ByteArray() {
|
||||
if (_pBytes)
|
||||
@ -45,7 +48,7 @@ protected:
|
||||
|
||||
class StringArray : public ByteArray {
|
||||
public:
|
||||
StringArray(ClipboardData cd, size_t maxLen);
|
||||
StringArray(ClipboardDataInfo cd, size_t maxLen);
|
||||
};
|
||||
|
||||
class ClipboardHistoryPanel : public DockingDlgInterface {
|
||||
@ -61,9 +64,9 @@ public:
|
||||
_hParent = parent2set;
|
||||
};
|
||||
|
||||
ClipboardData getClipboadData();
|
||||
void addToClipboadHistory(ClipboardData cbd);
|
||||
int getClipboardDataIndex(ClipboardData cbd);
|
||||
ClipboardDataInfo getClipboadData();
|
||||
void addToClipboadHistory(ClipboardDataInfo cbd);
|
||||
int getClipboardDataIndex(ClipboardDataInfo cbd);
|
||||
|
||||
virtual void setBackgroundColor(COLORREF bgColour) {
|
||||
_lbBgColor = bgColour;
|
||||
@ -79,7 +82,7 @@ protected:
|
||||
|
||||
private:
|
||||
ScintillaEditView **_ppEditView = nullptr;
|
||||
std::vector<ClipboardData> _clipboardDataVector;
|
||||
std::vector<ClipboardDataInfo> _clipboardDataInfos;
|
||||
HWND _hwndNextCbViewer = nullptr;
|
||||
int _lbBgColor = -1;
|
||||
int _lbFgColor= -1;
|
||||
|
@ -20,6 +20,6 @@
|
||||
|
||||
#define CF_HTML TEXT("HTML Format")
|
||||
#define CF_RTF TEXT("Rich Text Format")
|
||||
#define CF_NPPTEXTLEN TEXT("Notepad++ Binary Text Length")
|
||||
#define CF_NPPTEXTLEN TEXT("Notepad++ Binary Length")
|
||||
|
||||
#endif //CLIPBOARDFORMATS_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user