How to change clipboard data in Windows - c++

I have the following clipboard data:
Can I somehow change indexes of these records?
Also can I remove / make zero-length some of them?
Is it possible via WinAPI?
As for the first question, I don't see any function for this purpose.
As for the second question, I wrote the following code:
#include <Windows.h>
int main()
{
OpenClipboard(NULL);
HGLOBAL hdst = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, sizeof(int));
int* dst = (int*)GlobalLock(hdst);
dst[0] = 0;
GlobalUnlock(hdst);
SetClipboardData(49166, hdst);
CloseClipboard();
}
but it didn't zeroed the record of the 49166 format.
How can I do it?

This is a method to do that. First, obtain the clipboard data string by use GetClipboardData api, and then modify the data string by your way. Second, rewrite string to cliboard by use SetClipboardData api.
You don't call GetClipboardData first from you code, you can do that like this:
char *buffer = NULL;
CString fromClipboard;
//open the cliboard
if (OpenClipboard())
{
HANDLE hData = GetClipboardData(CF_TEXT);
char* buffer = (char *)GlobalLock(hData);
fromClipboard = buffer;
//modify fromClipboard string by your method and rewrite to clipboard
//maybe like this
fromCliboard.Replace("hello", "world");
HGLOBAL clipbuffer;
char* buffer;
EmptyClipboard();
clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.GetLength()+1);
buffer = (char*)GlobalLock(clipbuffer);
strcpy(buffer, LPCSTR(source));
GlobalUnlock(hData);
GlobalUnlock(clipbuffer);
SetClipboardData(CF_TEXT,clipbuffer);
CloseClipboard();
}

Related

IPC through windows clipboard using c++

This is how you can get last text item from clipboard:
OpenClipboard(nullptr);
HANDLE hData = GetClipboardData(CF_TEXT);
char* pszText = static_cast<char*>(GlobalLock(hData));
std::string text;
if (pszText != nullptr)
{
text.assign(pszText);
}
GlobalUnlock(hData);
CloseClipboard();
std::cout << text;
This is how you can set an text item from clipboard:
std::string source("text");
if (OpenClipboard(nullptr))
{
HGLOBAL clipbuffer;
char* buffer;
EmptyClipboard();
clipbuffer = GlobalAlloc(GMEM_DDESHARE, source.length() + 1);
buffer = (char*)GlobalLock(clipbuffer);
strcpy(buffer, source.c_str());
GlobalUnlock(clipbuffer);
SetClipboardData(CF_TEXT, clipbuffer);
CloseClipboard();
}
But I don't know how to delete last text item from clipboard, I would like to be able to not let the user see that I am using the clipboard or change his clipboard so he cant paste last thing he copied...
How can I do this, delete an text item from windows clipboard using c++ ?
This is the strangest way to pass text from one app to another! Sending e-mail also comes to mind.
There is a Windows-native way to do that: send a WM_COPYDATA message.
See https://learn.microsoft.com/en-us/windows/win32/dataxchg/wm-copydata for details.

LPSTREAM unable to read into CString

I'm attempting to read text into a CString using an LPSTREAM, but it doesn't seem to be working correctly, here is the code that I'm calling:
static HRESULT UTL_ReadStreamTxt(MyStorage* pSrcStg, const char* pszStream, CString* myCStr, int size)
{
HRESULT hrRet = STG_E_INVALIDPARAMETER;
LPSTREAM lpSrc = NULL;
ULONG ul;
TRY
{
USES_CONVERSION;
HRESULT hrSrc = pSrcStg->GetStg()->OpenStream(CT2COLE(strSrc),
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
0,
&lpSrc);
if (hrSrc != NOERROR)
{
hrRet = hrSrc;
}
else
{
hrRet = lpSrc->Read(&myCStr, size, NULL); // Read into CString
}
}
CATCH_ALL(e)
{
hrRet = STG_E_UNKNOWN;
}
END_CATCH_ALL
_AfxRelease((LPUNKNOWN*)&lpSrc);
return hrRet;
}
When it reads into the string, Visual Studio says that the data in the CString is corrupted.
The compound storage's stream contents are the following:
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
I'm not entirely sure I'm using Read() correctly, How do I fix this issue?
The main problem is that you are passing a bad pointer to Read(). You are passing the memory address of the myCStr parameter itself, not the address of the CString being pointed at, or more accurately, the memory address of a character buffer that the CString owns. The code compiles only because Read() takes a simple void* pointer to a buffer, and any pointer is implicitly convertible to void*.
Also note that CString is based on TCHAR, which maps to either char or wchar_t depending on whether you are compiling your project for ANSI/MBCS or Unicode. So, reading from the stream directly into a CString will only work correctly if:
the stream contains ANSI characters and TCHAR maps to char.
the stream contains UTF-16 characters and TCHAR maps to wchar_t.
If the stream's character type does not match the character type used by CString, you would have to first read the stream into an intermediate buffer and then convert that to TCHAR before it can be stored in the CString.
Try something more like this:
static HRESULT UTL_ReadStreamTxt(MyStorage* pSrcStg, const char* pszStream, CString* myCStr, int size)
{
HRESULT hrRet = STG_E_INVALIDPARAMETER;
LPSTREAM lpSrc = NULL;
ULONG ul;
LPVOID buffer;
TRY
{
USES_CONVERSION;
HRESULT hrSrc = pSrcStg->GetStg()->OpenStream(CT2COLE(strSrc),
NULL,
STGM_READ | STGM_SHARE_EXCLUSIVE,
0,
&lpSrc);
if (hrSrc != S_OK)
{
hrRet = hrSrc;
}
else
{
// if the stream's character type matches TCHAR...
buffer = myCStr->GetBuffer(size / sizeof(TCHAR));
hrRet = lpSrc->Read(buffer, size, &ul);
myCStr->ReleaseBuffer(ul / sizeof(TCHAR));
// else, if the stream's character type is 'char' and TCHAR is 'wchar_t'...
CStringA tmp;
buffer = tmp.GetBuffer(size);
hrRet = lpSrc->Read(buffer, size, &ul);
tmp.ReleaseBuffer(ul);
*myCStr = CString((LPSTR)tmp, tmp.GetLength());
// else, if the stream's character type is 'wchar_t' and TCHAR is 'char'...
CStringW tmp;
buffer = tmp.GetBuffer(size / sizeof(wchar_t));
hrRet = lpSrc->Read(buffer, size, &ul);
tmp.ReleaseBuffer(ul / sizeof(wchar_t));
*myCStr = CString((LPWSTR)tmp, tmp.GetLength());
// alternatively, you can do the above 2 cases more generically...
typedef CStringT<char or wchar_t> CStreamString;
CStreamString tmp;
buffer = tmp.GetBuffer(size / sizeof(CStreamString::XCHAR));
hrRet = lpSrc->Read(buffer, size, &ul);
tmp.ReleaseBuffer(ul / sizeof(CStreamString::XCHAR));
*myCStr = CString((CStreamString::PXSTR)tmp, tmp.GetLength());
}
}
CATCH_ALL(e)
{
hrRet = STG_E_UNKNOWN;
}
END_CATCH_ALL
_AfxRelease((LPUNKNOWN*)&lpSrc);
return hrRet;
}

Using CImage.Save (InMemory)

I'm working with some pictures in a MFC application, and I realized that the CImage class (from MFC) has 2 types of save, to a file and to a IStream interface. I'm trying to use that IStream interface to save to memory, using the convention features of the CImage class without another library to do that (for example bmp to jpg convertion). I don't want to save a file, just work with the memory buffers. The CImage object is already loaded with a picture file.
But I'm not able to use this IStream interface because I cannot create a object from that class and not realized how to create the buffer to use with that Save(IStream * pStream...) feature.
Any example will be very helpful.
Thanks,
Vitor
First, you should add your picture to a resource id, and to do like this:
BOOL ImageFromIDResource(UINT nID, LPCTSTR sTR, CImage * & pImg)
{
HINSTANCE hInst = AfxGetResourceHandle();
HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nID), sTR); // type
if (!hRsrc)
return FALSE;
// load resource into memory
DWORD len = SizeofResource(hInst, hRsrc);
BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
if (!lpRsrc)
return FALSE;
// Allocate global memory on which to create stream
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
memcpy(pmem, lpRsrc, len);
IStream* pstm = NULL;
CreateStreamOnHGlobal(m_hMem, FALSE, &pstm);
// load from stream
//pImg = Gdiplus::Image::FromStream(pstm);
pImg = new CImage();
pImg->Load(pstm);
DWORD err = GetLastError();
// free/release stuff
GlobalUnlock(m_hMem);
pstm->Release();
FreeResource(lpRsrc);
return TRUE;
}

Convert int to LPCWSTR by using wsprintf

As the following code:
int a = 16;
wchar_t *buffer = {0};
wsprintf(buffer,L"%d", a);
MessageBox(NULL, buffer, buffer, MB_OK);
I want to covert int to LPCWSTR in order to put MessageBox.
I really newbie in using wsprintf. Any one can help me explain clearly for me using this function??? (Please, I also read MSDN but still dont't clear)
I mean, I want to print "16" in MessageBox
You initialize your buffer to nullptr. Just create an array of wchar_ts that allocates enough space for you and you're off the hook:
int a = 16;
wchar_t buffer[256];
wsprintfW(buffer, L"%d", a);
MessageBoxW(nullptr, buffer, buffer, MB_OK);

Am I Incorrectly using the Windows Clipboard?

I have some code to copy and paste:
void WinClipboard::copy( const std::string& input )
{
LPWSTR lptstrCopy;
HGLOBAL hglbCopy;
std::wstring text;
text = _winUTF8ToUTF16(input);
// Open the clipboard, and empty it.
if (!OpenClipboard(NULL))
return;
EmptyClipboard();
// Allocate a global memory object for the text.
hglbCopy = GlobalAlloc(GMEM_MOVEABLE,
((text.length() + 1) * sizeof(WCHAR)));
if (hglbCopy == NULL)
{
CloseClipboard();
return;
}
// Lock the handle and copy the text to the buffer.
lptstrCopy = (LPWSTR)GlobalLock(hglbCopy);
memcpy(lptstrCopy, text.c_str(),
(text.length() + 1) * sizeof(WCHAR) );
lptstrCopy[(text.length() + 1) * sizeof(WCHAR)] = (WCHAR) 0; // null character
GlobalUnlock(hglbCopy);
// Place the handle on the clipboard.
SetClipboardData(CF_UNICODETEXT, hglbCopy);
// Close the clipboard.
CloseClipboard();
}
std::string WinClipboard::paste()
{
HGLOBAL hglb;
LPWSTR lptstr;
std::string result;
std::wstring input;
// get the clipboard text.
if (!IsClipboardFormatAvailable(CF_UNICODETEXT))
return result;
if (!OpenClipboard(NULL))
return result;
hglb = GetClipboardData(CF_UNICODETEXT);
if (hglb != NULL)
{
lptstr = (LPWSTR)GlobalLock(hglb);
if (lptstr != NULL)
{
GlobalUnlock(hglb);
input = lptstr;
result = _winUTF16ToUTF8(input);
}
CloseClipboard();
}
return result;
}
It works great except, when I quickly do CTRL C then CTRL-V (essentially calling the above copy and paste functions) the entire application freezes.
Am I forgetting to check for something or forgetting to release a resource?
I see two problems in your paste() function:
1) it is calling GlobalUnlock() before assigning the clipboard data to your std::wstring variable. You need to reverse those operations - call GlobalUnlock() after copying the data, not before.
2) it is not calling CloseClipboard() if GetClipboardData() fails.
Another "problem".
In the copy function:
The line
lptstrCopy[(text.length() + 1) * sizeof(WCHAR)] = (WCHAR) 0;
should be
lptstrCopy[text.length() + 1] = (WCHAR) 0;
to avoid the overflow/heap corruption.