I would like to read some articles or books about how works windows clipboard inside, but I can't find at least one article that was deeper than standard API references or examples of using .
I'm working with windows clipboard over standart winapi and I obtain some strange results.
Case 1: I write to clipboard some unicode string and remember address of that string. Then I close clipboard, and repeat following procedure:
open clipboard, get address of my unicode string, close clipboard.
I think that I must receive same addresses of clipboard content but it isn't. Why?
//1.) Copying string to clipboard
if (WinAPI.OpenClipboard(owner))
{
WinAPI.EmptyClipboard();
IntPtr exampleStringPtr = Marshal.StringToHGlobalUni("Example");
Console.WriteLine("setting address: {0}", exampleStringPtr.ToInt32());
WinAPI.SetClipboardData(WinAPI.CF_UNICODETEXT, exampleStringPtr);
WinAPI.CloseClipboard();
}
//2.) Getting string from clipboard
for (int i = 0; i < 100; i++ )
if (WinAPI.OpenClipboard(owner))
{
IntPtr exampleStringPtr = WinAPI.GetClipboardData(WinAPI.CF_UNICODETEXT);
Console.WriteLine("getting address: {0}", exampleStringPtr.ToInt32());
WinAPI.GlobalLock(exampleStringPtr);
var s = Marshal.PtrToStringUni(exampleStringPtr);
WinAPI.GlobalUnlock(exampleStringPtr);
WinAPI.CloseClipboard();
}
case 2: I write to clipboard some string, close clipboard, change string (in unmanaged memory) and again open clipboard and read this string. To my surprise, I obtain SAME string address and my UNCHANGED string.
//1.) Copying string to clipboard
if (WinAPI.OpenClipboard(owner))
{
WinAPI.EmptyClipboard();
IntPtr exampleStringPtr = Marshal.StringToHGlobalUni("Loooooooooooonng String Example");
Console.WriteLine("setting address: {0}", exampleStringPtr.ToInt32());
WinAPI.SetClipboardData(WinAPI.CF_UNICODETEXT, exampleStringPtr);
WinAPI.CloseClipboard();
//2.) Change string - replace first 10 characters on one any symbol
for (int i = 0; i < 10; i++)
{
Marshal.WriteByte(exampleStringPtr + i, 50);
}
//3.) Obtain string and make sure that string was changed
Console.WriteLine("changed string: {0}", Marshal.PtrToStringUni(exampleStringPtr));
}
//2.) Getting string from clipboard
for (int i = 0; i < 100; i++)
if (WinAPI.OpenClipboard(owner))
{
IntPtr exampleStringPtr = WinAPI.GetClipboardData(WinAPI.CF_UNICODETEXT);
Console.WriteLine("getting address: {0}", exampleStringPtr.ToInt32());
WinAPI.GlobalLock(exampleStringPtr);
var s = Marshal.PtrToStringUni(exampleStringPtr);
Console.WriteLine("obtained string: {0}", s);
WinAPI.CloseClipboard();
}
Now I'm thinking that clipboard copy all memory block in SetClipboardData to other memory and source block can be copied several times. I can't understand, why I can't free my unmanaged memory for string immediately after SetClipboardData execution?
I have many questions and I think that some literature will make it clear
UPDATE:
to Raymond Chen, Jonathan Potter, Eric Brown: thank's for your answers, but I edited my second test that it would be more correct and now it shows following:
I change source string BEFORE clipboard was closed and I may think it is valid operation and it removes answers that I make it after clipboard was closed. Then I get this string and results shows that is changed, then I get this string by invoking GetClipboardData and results shows that string was changed and pointer is same. Then I close clipboard open it again and read string again. What I obtain now? string address is same as address of source string but string is UNCHANGED. Here's this code:
//1.) Copying string to clipboard
if (WinAPI.OpenClipboard(owner))
{
WinAPI.EmptyClipboard();
IntPtr exampleStringPtr = Marshal.StringToHGlobalUni("Loooooooooooonng String Example");
Console.WriteLine("setting address: {0}", exampleStringPtr.ToInt32());
WinAPI.SetClipboardData(WinAPI.CF_UNICODETEXT, exampleStringPtr);
//2.) Change string while clipboard isn't closed - replace first 10 characters on one any symbol
for (int i = 0; i < 10; i++)
{
Marshal.WriteByte(exampleStringPtr + i, 50);
}
//3.) Obtain string and make sure that string was changed
Console.WriteLine("changed string: {0}", Marshal.PtrToStringUni(exampleStringPtr));
//4.) Get this string from clipboard and make sure that clipboard was changed
exampleStringPtr = WinAPI.GetClipboardData(WinAPI.CF_UNICODETEXT);
Console.WriteLine("getting address of changed string: {0}", exampleStringPtr.ToInt32());
var lockedPtr = WinAPI.GlobalLock(exampleStringPtr);
var s = Marshal.PtrToStringUni(exampleStringPtr);
WinAPI.GlobalUnlock(lockedPtr);
Console.WriteLine("obtained string: {0}", s);
WinAPI.CloseClipboard();
}
Console.WriteLine("\n-------Close and open clipboard------------------\n");
//5.) Getting string from clipboard
for (int i = 0; i < 100; i++)
if (WinAPI.OpenClipboard(owner))
{
IntPtr exampleStringPtr = WinAPI.GetClipboardData(WinAPI.CF_UNICODETEXT);
Console.WriteLine("getting address: {0}", exampleStringPtr.ToInt32());
var lockedPtr = WinAPI.GlobalLock(exampleStringPtr);
var s = Marshal.PtrToStringUni(lockedPtr);
WinAPI.GlobalUnlock(lockedPtr);
Console.WriteLine("obtained string: {0}", s);
WinAPI.CloseClipboard();
}
I run program, paused it and analyzied memory by WinDbg. Then I make screenshot of results and provide for it you. http://postimg.org/image/are6um7yv/ So, my tests and screenshot shows that:
1.) We have several copies of one source object in memory
2.) If I change source memory given to SetClipboardData invoke before closing clipboard, after opening it again clipboard restore source object even on source address.
Isn't is? Can anyone explain, whether these clauses are true or not?
UPDATE 2: Ok.. I was rewriting my third test on C++. it's here:
#include "stdafx.h"
#include "windows.h"
#include "conio.h"
int main()
{
HWND owner = GetConsoleWindow();
//1.) Copying string to clipboard
if (OpenClipboard(owner))
{
EmptyClipboard();
//WCHAR *str = L"Loooong string example";
char *str = "Loooooooong string Example";
int cch = strlen(str);
char* strptr = (char*)GlobalAlloc(GMEM_MOVEABLE, (cch + 1));
printf("setting (segment??) address: %X \n", strptr);
LPVOID lockedPtr = GlobalLock(strptr);
printf("locked setting address: %X \n", lockedPtr);
// copy
memcpy(lockedPtr, str, cch);
GlobalUnlock(strptr);
// set to clipboard
SetClipboardData(CF_TEXT, strptr);
//2.) Change string while clipboard isn't closed - replace first 10 characters on one any symbol
lockedPtr = GlobalLock(strptr);
for (int i = 0; i < 10; i++)
{
((char*)lockedPtr)[i] = 50;
}
GlobalUnlock(strptr);
//3.) Obtain string and make sure that string was changed
lockedPtr = GlobalLock(strptr);
printf("changed string: %s \n", lockedPtr);
GlobalUnlock(strptr);
//4.) Get this string from clipboard and make sure that clipboard was changed
strptr = (char*)GetClipboardData(CF_TEXT);
printf("getting address: %X \n", strptr);
lockedPtr = GlobalLock(strptr);
printf("locked getting address: %X \n", lockedPtr);
printf("obtained string: %s \n", (char*)lockedPtr );
GlobalUnlock(strptr);
CloseClipboard();
}
printf("\n-------Close and open clipboard------------------\n");
//5.) Getting string from clipboard
for (int i = 0; i < 10; i++)
{
//Sleep(1000);
if (OpenClipboard(owner))
{
HANDLE exampleStringPtr = GetClipboardData(CF_TEXT);
printf("getting address: %X \n", exampleStringPtr);
char* lockedPtr = (char*)GlobalLock(exampleStringPtr);
printf("locked getting address: %X \n", lockedPtr);
printf("obtained string: %s \n", lockedPtr);
GlobalUnlock(exampleStringPtr);
CloseClipboard();
}
}
getch();
return 0;
}
Really, now when I invoke GetClipboardData then I obtain the same pointer to the data all the time. But sometimes it was different from locked pointer of first string that I putted to the clipboard.
But although I'm writing this test on C++, I still have same effect I was writeing early.
If I change source memory block after invoking SetClipboardData and then try to invoke GetClipboardData, I obtain my changed memory block. But when I close this clipboard and then open it again, my changed memory block was overriten with some info, I don't know, and when I invoke GetClipboardData, that memory block was restored to initial state as if I didn't change it.
From where clipboard "knows" how to restore this block if it hasn't its copies and I changed source block?
I recorded little screencast that shows in what moment memory restored http://screencast.com/t/5t3wc9LS