Where I can get information about internal working of clipboard? - c#

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

The docs for SetClipboardData() say quite clearly that it does not copy the data you provide - instead, the clipboard owns the data handle and although you can still read from it until the clipboard is closed, you must not write to or free the data once the SetClipboardData() call has succeeded.
Once you've closed the clipboard you no longer own the clipboard and the data object is not safe to use at all, even for reading, as another process may have changed the clipboard contents. Your tests at modifying the data after closing the clipboard worked by luck, not because they are supposed to.
If SetClipboardData succeeds, the system owns the object identified by
the hMem parameter. The application may not write to or free the data
once ownership has been transferred to the system, but it can lock and
read from the data until the CloseClipboard function is called. (The
memory must be unlocked before the Clipboard is closed.)
Edit: Because you seem to have trouble with the concept of resource ownership and undefined behaviour, maybe this analogy will help.
// allocate 1 byte of memory
char* ptr = malloc(sizeof(char));
// set the byte to the letter A
*ptr = 'A';
// free the memory
free(ptr);
// set the byte to B
*ptr = 'B';
// verify that the byte is set to B
printf("byte contains %c\n", *ptr);
// allocate another byte of memory
char* ptr2 = malloc(sizeof(char));
// are they the same byte? maybe
printf("byte contains %c - first was %lx, second is %lx\n", *ptr2, ptr, ptr2);
I hope you will see that this code is completely wrong. We allocate memory, write to it, free it, and then after that, we write to it and read from it again. And yet if you compile and run this code, there's a good chance it will work. There's also a good chance that the second allocation will return the same address as the first allocation. What's going on?
This is called undefined behaviour. The language doesn't define what happens in a situation like this. When you free memory, you no longer own it, and you must not write to it nor read from it. If it works, or appears to work, it's a coincidence, nothing more. There is no guarantee it will always work. There is no point continually performing tests to try to prove that somehow it does work - nothing alters the fact that the behaviour is undefined. It might work, it might not. Don't do it.

SetClipboardData copies the data in the given global handle. Once the clipboard is closed, the global handle should be freed (and not before). GetClipboardData returns the (internal) memory handle; you should treat this handle as a read-only buffer.

Related

How to access sys.stderr after calling PyErr_Print with python c-api

I am trying to use the python c-api from a c# project via dll import.
I am getting an ModuleNotFoundError when importing some modules, which I thought are builtin.
(Note: I compiled python myself)
I am a bit stuck right now, but my hope is to get some extra information when calling PyErr_Print() in the code below.
Code:
IntPtr modulePtr = NativeInterface.PyImport_ExecCodeModuleEx(moduleName,compiledModule, path);
if (modulePtr == IntPtr.Zero)
{
NativeInterface.PyErr_Print();
PythonException exception = PythonException.Query();
throw exception;
}
The docs for PyErr_Print state that it will populate sys.stderr with some error information.
What would be the easiest way to read this variable from my c# application?
This answer gives C code because I understand C and not C#, but I think it should be pretty transferable.
By default sys.stderr writes to some console somewhere and so you can't meaningfully try to read from it. However, it's perfectly possible to replace it to redirect the output. Two sensible options include writing to a file, and writing to a StringIO object that can later be queried.
The C code to run is basically equivalent to:
import sys
from io import StringIO # Python 3
sys.stderr = StringIO()
or in C:
int setup_stderr() {
PyObject *io = NULL, *stringio = NULL, *stringioinstance = NULL;
int success = 0;
io = PyImport_ImportModule("io");
if (!io) goto done;
stringio = PyObject_GetAttrString(io,"StringIO");
if (!stringio) goto done;
stringioinstance = PyObject_CallFunctionObjArgs(stringio,NULL);
if (!stringioinstance) goto done;
if (PySys_SetObject("stderr",stringioinstance)==-1) goto done;
success = 1;
done:
Py_XDECREF(stringioinstance);
Py_XDECREF(stringio);
Py_XDECREF(io);
return success;
}
You run this once at the start of your program.
To query the contents of sys.stderr you'd then do the equivalent of:
value = sys.stderr.getvalue()
encoded_value = value.encode() # or you could just handle the unicode output
In C:
char* get_stderr_text() {
PyObject* stderr = PySys_GetObject("stderr"); // borrowed reference
PyObject *value = NULL, *encoded = NULL;
char* result = NULL;
char* temp_result = NULL;
Py_ssize_t size = 0;
value = PyObject_CallMethod(stderr,"getvalue",NULL);
if (!value) goto done;
// ideally should get the preferred encoding
encoded = PyUnicode_AsEncodedString(value,"utf-8","strict");
if (!encoded) goto done;
if (PyBytes_AsStringAndSize(encoded,&temp_result,&size) == -1) goto done;
size += 1;
// copy so we own the memory
result = malloc(sizeof(char)*size);
for (int i = 0; i<size; ++i) {
result[i] = temp_result[i];
}
done:
Py_XDECREF(encoded);
Py_XDECREF(value);
return result;
}
There's a bit of effort spent copying the string. You might consider working directly with unicode and using PyUnicode_AsUCS4Copy.
You probably then want to look at clearing the string after you've written it, just done by replacing sys.stderr with a fresh StringIO object.
I could not find a way to acces sys.stderr via C-Api. But I realized that I can run python scripts via the c-api (See PyRun_String in the docs).
So I am debugging now by writing sys.path to a textfile.
import sys
file = open('log.txt','w')
for path in sys.path:
file.write(i+'\n')

Unable to return same double using Google Protocol Buffers from C# to C++ and back

I'm trying to communicate between C# and C++ with varying amounts of success.
I am able to send a message between the two using reply/request, but the doubles that I am receiving are not correct.
For debugging purposes and understanding, I am currently running the following:
Clrzmq 3.0 rc1, Google ProtocolBuffer 2.5, Protobuf-csharp-port-2.4, ZeroMQ-3.2.3
.Proto
package InternalComm;
message Point
{
optional double x = 1;
optional double y = 2;
optional string label = 3;
}
server.cpp (the relevant part)
while (true) {
zmq::message_t request;
// Wait for next request from client
socket.recv (&request);
zmq::message_t reply (request.size());
memcpy ((void*)reply.data(), request.data(), request.size());
socket.send(reply);
}
client.cs (the relevant part)
public static Point ProtobufPoint(Point point)
{
Point rtn = new Point(0,0);
using (var context = ZmqContext.Create())
{
using (ZmqSocket requester = context.CreateSocket(SocketType.REQ))
{
requester.Connect("tcp://localhost:5555");
var p = InternalComm.Point.CreateBuilder().SetX(point.X).SetY(point.Y).Build().ToByteArray();
requester.Send(p);
string reply = requester.Receive(Encoding.ASCII);
Console.WriteLine("Input: {0}", point);
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(reply);
var message = InternalComm.Point.ParseFrom(bytes);
rtn.X = message.X;
rtn.Y = message.Y;
Console.WriteLine("Output: {0}", rtn);
}
}
return rtn;
}
On the C# side, Point is a very simple struct. Just x and y properties.
Here is what I'm getting from my unit tests as a result of running the above code.
Input (1.31616874365468, 4.55516872325469)
Output (0.000473917985115791, 4.55516872323627)
Input (274.120398471829, 274.128936418736)
Output (274.077917334613, 274.128936049925)
Input (150.123798461987, 2.345E-12)
Output (145.976459594794, 1.11014954927532E-13)
Input (150, 0)
Output (145.96875, 0)
I am thinking that the problem is my protobuf code is incorrect (doubtful this is a bug on Skeet's side). I am also running under the assumption that server.cpp is doing nothing to the message but returning it as is.
Thoughts?
The requestor.Receive(Encoding.ASCII) call is designed to receive a string, not a block of bytes. You are asking the ZmqSocket instance to return the message as an ASCII string, which is highly likely to cause modifications to the content. If you're sending a byte array, receive a byte array.
Try this:
int readSize;
byte[] reply = requester.Receive(null, out readSize);
var message = InternalComm.Point.ParseFrom(reply);
The readSize variable will contain the actual number of valid bytes in the received block, which may vary from the size of the reply array, so you may need to slice up the array to make it palatable to ProtoBuf.
Why the ASCII --> bytes --> parsing step? If you're parsing bytes, you should read bytes. If you're parsing text, you should read that.
Unnecessary charset-conversions look very likely to be erroneous.

CredUIPromptForCredentials from .NET with SecureString

I'd like to show the standard system dialog to ask the user for an account username and password to use this information to start a process with these credentials.
I've been pointed to the CredUIPromptForCredentials function that shows that dialog. It returns username and password as string. But the ProcessStartInfo structure expects a password as SecureString.
I understand that I could now use the password as string and convert it to a SecureString character by character (there's no single function for that) - but it would defeat the idea behind the SecureString entirely.
So I guess there must be some way to directly accept the password from the unmanaged call to CredUIPromptForCredentials as SecureString in .NET. After all, I really don't need to access the password in my application in any way. It's just supposed to be used to start another process and can then be forgotten as soon as possible.
So how would my P/Invoke declaration for CredUIPromptForCredentials look like with a SecureString? (I've started with the one from pinvoke.net for C#.)
Update: Oh, and if somebody has an example for the new function CredUIPromptForWindowsCredentials in Windows Vista/7, that would be cool as well, because I can't even figure out how to use that at the moment.
You can cast the IntPtr of an unmanaged string buffer to char* and use the SecureString(char*, int) constructor.
// somehow, we come into posession of an IntPtr to a string
// obviously, this would be a foolish way to come into it in
// production, since stringOriginalContents is already in managed
// code, and the lifetime can therefore not be guaranteed...
var stringOriginalContents = "foobar";
IntPtr strPtr = Marshal.StringToHGlobalUni(stringOriginalContents);
int strLen = stringOriginalContents.Length;
int maxLen = 100;
// we copy the IntPtr to a SecureString, and zero out the old location
SecureString ssNew;
unsafe
{
char* strUPtr = (char*)strPtr;
// if we don't know the length, calculate
//for (strLen = 0; *(strUPtr + strLen) != '\0'
// // stop if the string is invalid
// && strLen < maxLen; strLen++)
// ;
ssNew = new SecureString((char*)strPtr, strLen);
// zero out the old memory and release, or use a Zero Free method
//for (int i = 0; i < strLen; i++)
// *(strUPtr + i) = '\0';
//Marshal.FreeHGlobal(strPtr);
// (only do one of these)
Marshal.ZeroFreeGlobalAllocUnicode(strPtr);
}
// now the securestring has the protected data, and the old memory has been
// zeroed, we can check that the securestring is correct. This, also should
// not be in production code.
string strInSecureString =
Marshal.PtrToStringUni(
Marshal.SecureStringToGlobalAllocUnicode(ssNew));
Assert.AreEqual(strInSecureString, stringOriginalContents);

LibUsbDotNet UsbDevice.ControlTransfer hangs

I have a C# .Net Winforms application, which uses LibUsbDotNet to program firmware into an USB-device (Atmel AVR32) using "DFU_DNLOAD" transfers, which is a special kind of control-transfers. This all works, BUT: A specific kind of transfer, which causes the device to erase its internal flash, fails to send an ACK within the correct timing.
When this happens, my LibUsbDotNet connection becomes irreparably broken, which causes everything to fail.
My code does the following:
int TransferToDevice(byte request, short value, byte[] data)
{
var setup = new UsbSetupPacket(
(byte)(UsbCtrlFlags.Direction_Out | UsbCtrlFlags.RequestType_Class | UsbCtrlFlags.Recipient_Interface),
request,
value,
0,
(short)data.Length);
int n;
IntPtr unmanagedPointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(data.Length);
System.Runtime.InteropServices.Marshal.Copy(data, 0, unmanagedPointer, data.Length);
// UsbDevice obtained else-where
if (!UsbDevice.ControlTransfer(ref setup, unmanagedPointer, data.Length, out n))
{
n = 0;
}
System.Runtime.InteropServices.Marshal.FreeHGlobal(unmanagedPointer);
return n;
}
// In order to do a "DFU_DNLOAD", the method above is used as follows:
TransferToDevice(DFU_DNLOAD, Transactions++, data); // "data" is the payload
// where DFU_DNLOAD is:
private const byte DFU_DNLOAD = 1;
// Transactions is
short Transaction = 0;
The above code works (the device correctly receives the "DFU_DNLOAD" message), but the missing ACK is the problem. Once the error occurs, every attempt to communicate with the device (even if I try to re-initialize everything) fails, untill the device is disconnected and re-inserted...
I would like to be able to reset or re-initialize the USB-connection somehow, when this error occurs. Currently I am only able to re-establish communications with the device by exiting my application and re-starting it manually.
This was never solved to my satisfaction, ended up implementing my own "DFU" protocol ontop of LibUSB using plain C, and P/Invoke to that, avoiding LibUsbDotNet entirely... This solution seems to work.
Just guessing, but in case if data is array of short, than size of the buffer should be adjusted
int numberOfValues = data.Length;
int size = Marshal.SizeOf(typeof(short));
IntPtr unmanagedPointer = Marshal.AllocHGlobal(numberOfValues*size);
if (unmanagedPointer == IntPtr.Zero)
throw new OutOfMemoryException("Unable allocate memory");

c# search in another process's memory - sudden lockout

I need to keep track of another program's memory, constantly looking for a sequence of bytes to appear in there, and when they do, i need to remember their location so i later know where to write to.
I used the following post to learn how to look for byte[] in another process's memory:
C#: Search a byte[] array in another process's memory
My program is very simple: It launches process (using Process.Start), and then repeatedly runs function from the linked thread's one of the answers:
private static int GetMemoryAddressOfString(byte[] searchedBytes)
{
IntPtr hProcess = OpenProcess(ProcessAccessFlags.VMOperation | ProcessAccessFlags.VMRead | ProcessAccessFlags.VMWrite, false, Program.ArtemisProcess.Id);
if (hProcess == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
int addr = 0;
int speed = 1024 * 64;
for (int j = 0x00400000; j < 0x11000000; j += speed)
{
byte[] bigMem = new byte[speed + searchedBytes.Length];
IntPtr unmanagedPointer = Marshal.AllocHGlobal(4);
ReadProcessMemory(hProcess, (IntPtr)j, bigMem, new UIntPtr((uint)(speed + searchedBytes.Length)), unmanagedPointer);
int result = Marshal.ReadInt32(unmanagedPointer);
Marshal.DestroyStructure(unmanagedPointer, typeof(int));
for (int k = 0; k < bigMem.Length - searchedBytes.Length; k++)
{
bool found = true;
for (int l = 0; l < searchedBytes.Length; l++)
{
if (bigMem[k + l] != searchedBytes[l])
{
found = false;
break;
}
}
if (found)
{
addr = k + j;
break;
}
}
if (addr != 0)
break;
}
return addr;
}
where ArtemisProcess is the Process i ran with .Start()
Most of the times, it works fine. As soon as i do the action in the watched process that puts the searched sequence of bytes to the memory, the next search finds it. However, sometimes, it wont.
I was wondering if i'm right and used Cheat Engine to be sure that the searched data IS there.
Then i added the part where i create an unmanaged pointer to know how many bytes there were read - and thats when i found out that exactly the place in the memory where the searched bytes appear (that Cheat Engine correctly identifies) returns 0! It wont let me read memory there. This "lockout" happens for about a minute or two, and only then it allows me to read the memory (just out of sudden, the next attempt to read the memory at that location is a success and the sequence of bytes is found all right).
Now, i read on the msdn that "he function fails if the requested read operation crosses into an area of the process that is inaccessible" but how do i know which part of the process memory is accessible and which isnt?
Why is Cheat Engine able to read that memory, and my program isnt?
Why does it suddenly allow me to read the process memory again?
I am at a loss here...

Categories

Resources