mirror of
https://github.com/notepad-plus-plus/notepad-plus-plus.git
synced 2025-07-26 07:15:21 +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,25 +20,22 @@
|
|||||||
#include "clipboardFormats.h"
|
#include "clipboardFormats.h"
|
||||||
|
|
||||||
|
|
||||||
#define CLIPBOARD_TEXTFORMAT CF_UNICODETEXT
|
|
||||||
#define MAX_DISPLAY_LENGTH 64
|
#define MAX_DISPLAY_LENGTH 64
|
||||||
|
|
||||||
ClipboardData ClipboardHistoryPanel::getClipboadData()
|
ClipboardDataInfo ClipboardHistoryPanel::getClipboadData()
|
||||||
{
|
{
|
||||||
ClipboardData clipboardData;
|
ClipboardDataInfo clipboardData;
|
||||||
if (!IsClipboardFormatAvailable(CLIPBOARD_TEXTFORMAT))
|
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
|
||||||
return clipboardData;
|
return clipboardData;
|
||||||
|
|
||||||
if (!OpenClipboard(NULL))
|
if (!OpenClipboard(NULL))
|
||||||
return clipboardData;
|
return clipboardData;
|
||||||
|
|
||||||
HGLOBAL hglb = GetClipboardData(CLIPBOARD_TEXTFORMAT);
|
HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT);
|
||||||
if (hglb != NULL)
|
if (hglb != NULL)
|
||||||
{
|
{
|
||||||
char *lpchar = (char *)GlobalLock(hglb);
|
unsigned char* pData = static_cast<unsigned char*>(GlobalLock(hglb));
|
||||||
wchar_t *lpWchar = (wchar_t *)GlobalLock(hglb);
|
if (pData != NULL)
|
||||||
|
|
||||||
if (lpchar != NULL)
|
|
||||||
{
|
{
|
||||||
UINT cf_nppTextLen = RegisterClipboardFormat(CF_NPPTEXTLEN);
|
UINT cf_nppTextLen = RegisterClipboardFormat(CF_NPPTEXTLEN);
|
||||||
if (IsClipboardFormatAvailable(cf_nppTextLen))
|
if (IsClipboardFormatAvailable(cf_nppTextLen))
|
||||||
@ -46,36 +43,48 @@ ClipboardData ClipboardHistoryPanel::getClipboadData()
|
|||||||
HGLOBAL hglbLen = GetClipboardData(cf_nppTextLen);
|
HGLOBAL hglbLen = GetClipboardData(cf_nppTextLen);
|
||||||
if (hglbLen != NULL)
|
if (hglbLen != NULL)
|
||||||
{
|
{
|
||||||
unsigned long *lpLen = (unsigned long *)GlobalLock(hglbLen);
|
HGLOBAL hglb_binText = GetClipboardData(CF_TEXT);
|
||||||
if (lpLen != NULL)
|
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);
|
wchar_t* lpwchar = (wchar_t*)pData;
|
||||||
for (int i = 0 ; i < nbBytes ; ++i)
|
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);
|
||||||
GlobalUnlock(hglb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CloseClipboard();
|
CloseClipboard();
|
||||||
return clipboardData;
|
return clipboardData;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteArray::ByteArray(ClipboardData cd)
|
ByteArray::ByteArray(ClipboardDataInfo cd)
|
||||||
{
|
{
|
||||||
_length = cd.size();
|
_length = cd._data.size();
|
||||||
if (!_length)
|
if (!_length)
|
||||||
{
|
{
|
||||||
_pBytes = NULL;
|
_pBytes = NULL;
|
||||||
@ -84,20 +93,22 @@ ByteArray::ByteArray(ClipboardData cd)
|
|||||||
_pBytes = new unsigned char[_length];
|
_pBytes = new unsigned char[_length];
|
||||||
for (size_t i = 0 ; i < _length ; ++i)
|
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;
|
_pBytes = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCompleted = (cd.size() <= maxLen);
|
bool isCompleted = (len <= maxLen);
|
||||||
_length = isCompleted?cd.size():maxLen;
|
_length = isCompleted?len:maxLen;
|
||||||
|
|
||||||
|
|
||||||
_pBytes = new unsigned char[_length+(isCompleted?0:2)];
|
_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))
|
else if (!isCompleted && (i == _length-6 || i == _length-4 || i == _length-2))
|
||||||
_pBytes[i] = '.';
|
_pBytes[i] = '.';
|
||||||
else
|
else
|
||||||
_pBytes[i] = cd[i];
|
_pBytes[i] = cd._data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isCompleted)
|
if (!isCompleted)
|
||||||
@ -121,17 +132,17 @@ StringArray::StringArray(ClipboardData cd, size_t maxLen)
|
|||||||
|
|
||||||
// Search clipboard data in internal storage
|
// Search clipboard data in internal storage
|
||||||
// return -1 if not found, else return the index of internal array
|
// 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;
|
int iFound = -1;
|
||||||
bool found = false;
|
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;
|
found = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -150,40 +161,49 @@ int ClipboardHistoryPanel::getClipboardDataIndex(ClipboardData cbd)
|
|||||||
return iFound;
|
return iFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClipboardHistoryPanel::addToClipboadHistory(ClipboardData cbd)
|
void ClipboardHistoryPanel::addToClipboadHistory(ClipboardDataInfo cbd)
|
||||||
{
|
{
|
||||||
int i = getClipboardDataIndex(cbd);
|
int i = getClipboardDataIndex(cbd);
|
||||||
if (i == 0) return;
|
if (i == 0) return;
|
||||||
if (i != -1)
|
if (i != -1)
|
||||||
{
|
{
|
||||||
_clipboardDataVector.erase(_clipboardDataVector.begin() + i);
|
_clipboardDataInfos.erase(_clipboardDataInfos.begin() + i);
|
||||||
::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_DELETESTRING, i, 0);
|
::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);
|
::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(L"")); // String will be added in drawItem()
|
||||||
TCHAR *displayStr = (TCHAR *)sa.getPointer();
|
|
||||||
::SendDlgItemMessage(_hSelf, IDC_LIST_CLIPBOARD, LB_INSERTSTRING, 0, reinterpret_cast<LPARAM>(displayStr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClipboardHistoryPanel::drawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
|
void ClipboardHistoryPanel::drawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
|
||||||
{
|
{
|
||||||
if (lpDrawItemStruct->itemID >= _clipboardDataVector.size())
|
UINT i = lpDrawItemStruct->itemID;
|
||||||
|
if (i >= _clipboardDataInfos.size())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
//printStr(TEXT("OK"));
|
//printStr(TEXT("OK"));
|
||||||
COLORREF fgColor = _lbFgColor == -1?black:_lbFgColor; // fg black by default
|
COLORREF fgColor = _lbFgColor == -1?black:_lbFgColor; // fg black by default
|
||||||
COLORREF bgColor = _lbBgColor == -1?white:_lbBgColor; // bg white by default
|
COLORREF bgColor = _lbBgColor == -1?white:_lbBgColor; // bg white by default
|
||||||
|
|
||||||
StringArray sa(_clipboardDataVector[lpDrawItemStruct->itemID], MAX_DISPLAY_LENGTH);
|
ClipboardDataInfo& cbd = _clipboardDataInfos[i];
|
||||||
TCHAR *ptStr = (TCHAR *)sa.getPointer();
|
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);
|
::SetTextColor(lpDrawItemStruct->hDC, fgColor);
|
||||||
::SetBkColor(lpDrawItemStruct->hDC, bgColor);
|
::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)
|
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 :
|
case WM_DRAWCLIPBOARD :
|
||||||
{
|
{
|
||||||
ClipboardData clipboardData = getClipboadData();
|
ClipboardDataInfo clipboardData = getClipboadData();
|
||||||
if (clipboardData.size())
|
if (clipboardData._data.size())
|
||||||
|
{
|
||||||
addToClipboadHistory(clipboardData);
|
addToClipboadHistory(clipboardData);
|
||||||
|
}
|
||||||
if (_hwndNextCbViewer)
|
if (_hwndNextCbViewer)
|
||||||
::SendMessage(_hwndNextCbViewer, message, wParam, lParam);
|
::SendMessage(_hwndNextCbViewer, message, wParam, lParam);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -244,18 +266,27 @@ intptr_t CALLBACK ClipboardHistoryPanel::run_dlgProc(UINT message, WPARAM wParam
|
|||||||
else
|
else
|
||||||
codepage = SC_CP_UTF8;
|
codepage = SC_CP_UTF8;
|
||||||
|
|
||||||
ByteArray ba(_clipboardDataVector[i]);
|
|
||||||
char* c = nullptr;
|
char* c = nullptr;
|
||||||
try {
|
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];
|
c = new char[nbChar + 1];
|
||||||
WideCharToMultiByte(codepage, 0, (wchar_t *)ba.getPointer(), static_cast<int32_t>(ba.getLength()), c, nbChar + 1, NULL, NULL);
|
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_REPLACESEL, 0, reinterpret_cast<LPARAM>(""));
|
||||||
(*_ppEditView)->execute(SCI_ADDTEXT, strlen(c), reinterpret_cast<LPARAM>(c));
|
(*_ppEditView)->execute(SCI_ADDTEXT, strlen(c), reinterpret_cast<LPARAM>(c));
|
||||||
(*_ppEditView)->getFocus();
|
(*_ppEditView)->getFocus();
|
||||||
delete[] c;
|
delete[] c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
|
@ -23,14 +23,17 @@
|
|||||||
|
|
||||||
#define CH_PROJECTPANELTITLE TEXT("Clipboard History")
|
#define CH_PROJECTPANELTITLE TEXT("Clipboard History")
|
||||||
|
|
||||||
typedef std::vector<unsigned char> ClipboardData;
|
|
||||||
|
|
||||||
class ScintillaEditView;
|
class ScintillaEditView;
|
||||||
|
|
||||||
|
struct ClipboardDataInfo {
|
||||||
|
std::vector<unsigned char> _data;
|
||||||
|
bool _isBinaryContained = false;
|
||||||
|
};
|
||||||
|
|
||||||
class ByteArray {
|
class ByteArray {
|
||||||
public:
|
public:
|
||||||
ByteArray() = default;
|
ByteArray() = default;
|
||||||
explicit ByteArray(ClipboardData cd);
|
explicit ByteArray(ClipboardDataInfo cd);
|
||||||
|
|
||||||
~ByteArray() {
|
~ByteArray() {
|
||||||
if (_pBytes)
|
if (_pBytes)
|
||||||
@ -45,7 +48,7 @@ protected:
|
|||||||
|
|
||||||
class StringArray : public ByteArray {
|
class StringArray : public ByteArray {
|
||||||
public:
|
public:
|
||||||
StringArray(ClipboardData cd, size_t maxLen);
|
StringArray(ClipboardDataInfo cd, size_t maxLen);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ClipboardHistoryPanel : public DockingDlgInterface {
|
class ClipboardHistoryPanel : public DockingDlgInterface {
|
||||||
@ -61,9 +64,9 @@ public:
|
|||||||
_hParent = parent2set;
|
_hParent = parent2set;
|
||||||
};
|
};
|
||||||
|
|
||||||
ClipboardData getClipboadData();
|
ClipboardDataInfo getClipboadData();
|
||||||
void addToClipboadHistory(ClipboardData cbd);
|
void addToClipboadHistory(ClipboardDataInfo cbd);
|
||||||
int getClipboardDataIndex(ClipboardData cbd);
|
int getClipboardDataIndex(ClipboardDataInfo cbd);
|
||||||
|
|
||||||
virtual void setBackgroundColor(COLORREF bgColour) {
|
virtual void setBackgroundColor(COLORREF bgColour) {
|
||||||
_lbBgColor = bgColour;
|
_lbBgColor = bgColour;
|
||||||
@ -79,7 +82,7 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ScintillaEditView **_ppEditView = nullptr;
|
ScintillaEditView **_ppEditView = nullptr;
|
||||||
std::vector<ClipboardData> _clipboardDataVector;
|
std::vector<ClipboardDataInfo> _clipboardDataInfos;
|
||||||
HWND _hwndNextCbViewer = nullptr;
|
HWND _hwndNextCbViewer = nullptr;
|
||||||
int _lbBgColor = -1;
|
int _lbBgColor = -1;
|
||||||
int _lbFgColor= -1;
|
int _lbFgColor= -1;
|
||||||
|
@ -20,6 +20,6 @@
|
|||||||
|
|
||||||
#define CF_HTML TEXT("HTML Format")
|
#define CF_HTML TEXT("HTML Format")
|
||||||
#define CF_RTF TEXT("Rich Text 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
|
#endif //CLIPBOARDFORMATS_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user