Share windows Clipboard through Web Service

Source: Internet
Author: User

Http://www.microsoft.com/china/MSDN/library/WebServices/WebServices/WebServices.mspx? MFR = true
Have you ever worked on multiple computers? Do you want to copy the clipboard content from one computer to another? I have always hoped to have a fast and easy way to move text code segments, screen snapshots, and even files to other computers by simply copying and pasting them. If you are interested in this topic, continue to read this article.

I hope that this operation can be implemented no matter whether the two computers are online or not, and will not be stopped by firewalls or Nat. Therefore, I chose a server-based architecture rather than a peer-to-peer architecture. This architecture includes client applications (Transfer clipboard content to the server by calling Web Services), Web Services (Cache clipboard content) and another client component (retrieves the clipboard content from the server and places them on the clipboard of the local computer ).

To solve this problem, we need to programmatically access the clipboard on the two computers that serve as the replication source and replication target. Fortunately,. NET provides a managed package in the local Windows clipboard API, which we can access. The relevant namespaces are C # clipboard and my. Computer. clipboard. Since we are interested in moving the clipboard object from one computer to another, we need to first determine which types of objects should be placed on the clipboard, this allows us to perform various operations on it (copying text, images, and files ). By using the clipboard namespace to write a brief code snippet, We can traverse all the objects on the clipboard for which we want to perform various types of operations to understand what we are processing.

Visual C #

Idataobject clipdata = clipboard. getdataobject (); // retrieves an array of all available formats on the clipboard. String [] formats = clipdata. getformats (); // traverse the list of available clipboard formats foreach (string format in formats) {// Add each object to an array list, so that we can check the object type object dataobject = clipdata. getdata (format );}

Visual Basic

Dim clipdata as idataobject = clipboard. getdataobjectdim formats () as string = clipdata. getformats' traverses the list of available clipboard formats for each format as string in formats 'and adds each object to an array list so that we can check the object type dim dataobject as object = clipdata. getdata (Format) Next

The following screen snapshot shows the result of copying text in Word to the clipboard. Each format in the string array represents the data in the clipboard. Because the target application (which we will paste to) is still unknown, there are multiple formats in the clipboard, each of which contains the same data. The purpose of this project is to copy all these formats on the clipboard of the target computer.

After checking the text, images, and object objects on the clipboard, it is easy to determine the main object types that we need to pay attention. They are "system. Io. memorystream", "system. Io. filestream", "system. Drawing. Bitmap", and "system. String ". Because all this information is transmitted to the server through Web Services, a simple method is to serialize all objects into bytes for transmission. There are many reasons for this operation. one fact is that complex objects (such as memorystream) cannot be simply serialized as strings and sent through Web Services. In addition, some objects are large and beyond the scope permitted by web service calls. Therefore, the objects must be broken down into smaller parts during transmission, then re-assemble on the server in the correct order. Similarly, when the client requests a clipboard project, we need to break down each object, then return the result to the client through the Web service, and then re-assemble it.

The first item to be created is a basic function, which splits these large streams into more manageable byte Arrays for transmission to Web Services. The following function sends a memorystream block to execute this task. The block size is limited by the "bytecount" constant. After the limit value is reached, the content in the buffer zone will be sent by calling the Web Service for storage and assembly on the server. Once the content to be sent is 0 bytes or the number of bytes is less than the number of "bytecount" constants, we will send the remaining elements in the buffer, use the isfinaltransaction flag to notify the Web Service that the specified object has been transferred.

Visual C #

Private void uploadstreamblock (string format, string objecttype, memorystream memstream) {// each time we input this function, a new transaction is started. A transaction represents a complete object on the clipboard, // we use it on the server side to know how to return exile together string transactionguid = system. guid. newguid (). tostring (); memstream. position = 0; byte [] buffer = new byte [bytecount]; bool isfinaltransaction = false; // when the current stream position plus our byte count is less than the stream length, try to // continue sending. While (memstream. position + bytecount) <= memstream. length) {// if it happens to be the last byte of the stream, the final transaction flag is set to true so that the server // knows that this is the last bit of the required transaction. If (memstream. Position + bytecount = memstream. Length) {isfinaltransaction = true;} // read the stream into the buffer for transmission through Web Services. Memstream. read (buffer, 0, bytecount); ws. insertmessagestream (buffer, format, objecttype, transactionguid, isfinaltransaction, clipboardguid);} Long remainingbytes = memstream. length-memstream. position; // if there are remaining bytes, calculate the number of remaining bytes and transmit the last bit of this object through the web service. If (INT) remainingbytes> 0) {byte [] remainingbuffer = new byte [(INT) remainingbytes]; memstream. read (remainingbuffer, 0, (INT) remainingbytes); ws. insertmessagestream (remainingbuffer, format, objecttype, transactionguid, true, clipboardguid );}}

Visual Basic

Private sub uploadstreamblock (byval format as string, byval objecttype as string, byval memstream as memorystream) 'each time we input this function, a new transaction is started. A transaction represents a complete object on the clipboard, 'we use it on the server side to know how to return exile together dim transactionguid as string = system. guid. newguid. tostringmemstream. position = 0dim buffer () as byte = new byte (bytecount)-1) {} dim isfinaltransaction as Boolean = false 'when the current stream position plus our byte count is smaller than the stream length, try to 'continue sending as much as possible. While (memstream. position + bytecount) _ <= memstream. length) 'if it happens to be the last byte of the stream, the final transaction flag is set to true so that the Server' knows this is the last bit of the required transaction. If (memstream. Position + bytecount) _ = memstream. Length) thenisfinaltransaction = trueend if 'reads the stream into the buffer zone for transmission through Web Services. Memstream. read (buffer, 0, bytecount) clipservice. insertmessagestream (buffer, format, objecttype, transactionguid, isfinaltransaction, clipboardguid) end whiledim remainingbytes as long = (memstream. length-memstream. position) 'if there are remaining bytes, calculate the number of remaining bytes and transmit the 'last byte of this object through the web service. If (ctype (remainingbytes, integer)> 0) thendim remainingbuffer () as byte = new byte (ctype (remainingbytes, integer)-1) {} memstream. read (remainingbuffer, 0, ctype (remainingbytes, integer) clipservice. insertmessagestream (remainingbuffer, format, objecttype, transactionguid, true, clipboardguid) end ifend sub

The Web Service server needs to re-combine all the clipboard content from a large number of byte arrays, therefore, retaining all objects, object types, and formats is crucial for the clipboard to work properly on the target computer. We use clipboardguid to determine whether we are posting a new clipboard or adding an object to an existing instance. Use the isfinaltranaction flag to check whether the byte array is part of an existing transaction or the first one in a new transaction. All clipboard items are saved to the disk for retrieval by any client requesting them later. The following code executes this function.

Visual C #

[Webmethod] public void insertmessagestream (byte [] buffer, string format, string objecttype, string transactionguid, bool isfinaltransaction, string clipboardguid) {// the current directory is always based on the clipboard being sent. String clipboardguiddirectory = system. web. httpcontext. current. request. physicalapplicationpath + clipboardguid; try {// If the directory does not exist, delete all other directories (Clipboard instance) and create a new directory // If the directory already exists, then this specific transaction is part of the same clipboard, so do not do anything. // This works because clipboarddirectory is not the guid sent from the client. If (! Directory. exists (clipboardguiddirectory) {string [] dirs = directory. getdirectories (system. web. httpcontext. current. request. physicalapplicationpath); foreach (string dir in dirs) {directory. delete (Dir, true);} directory. createdirectory (clipboardguiddirectory);} catch {} // create a file name based on the current transaction, format, and object type. We will resolve this issue later, // to know how to add it back to the target clipboard. String filename = clipboardguiddirectory + "\" + transactionguid + "_" + format + "_" + objecttype; filestream FS = new filestream (filename, filemode. append, fileaccess. write); FS. position = FS. length; FS. write (buffer, 0, buffer. length); FS. close ();}

Visual Basic

<Webmethod ()> _ Public sub insertmessagestream (byval buffer () as byte, byval format as string, byval objecttype as string, byval transactionguid as string, byval isfinaltransaction as Boolean, byval clipboardguid as string) 'the current directory is always based on the clipboard currently being sent. Dim clipboarddatadirectory as string = (system. web. httpcontext. current. request. physicalapplicationpath + "\ clipboard_data") dim clipboardguiddirectory as string = (clipboarddatadirectory + ("\" + clipboardguid) Try 'If the directory does not exist, delete all other directories (Clipboard instances) and create a new directory. If this directory already exists, this specific transaction is part of the same clipboard, so do not do anything. 'This works because clipboarddirectory is not based on the guid sent from the client. If not directory. exists (clipboardguiddirectory) thendim dirs () as string = directory. getdirectories (clipboarddatadirectory) for each dir as string in dirsdirectory. delete (Dir, true) nextdirectory. createdirectory (clipboardguiddirectory) end ifcatchend try 'creates a file name based on the current transaction, format, and object type. We will resolve this later to know how to add it back to the target clipboard. Dim filename as string = (clipboardguiddirectory + ("\" _ + (transactionguid + ("_" _ + (format + ("_" + objecttype )))))) dim FS as filestream = new filestream (filename, filemode. append, fileaccess. write) FS. position = FS. lengthfs. write (buffer, 0, buffer. length) FS. close () end sub

Each type of clipboard format object is stored on the disk for later retrieval by the client. Note how to use the file name in the following screen snapshot to store the object, the object type, and the unique transactionid In the clipboard format. All these information fragments are essential for correctly assembling items and placing them on the target clipboard.

Now the server has a corresponding representation for each type of clipboard format object, we need a way to re-return each item to the target clipboard. The following web service method provides the returned results of the type "clipboardstream. The clipboardstream object contains all relevant information required to reassemble items to the target clipboard. Because the Web Service is a request-response relationship, the Web Service expects the client to continue calling the Web service until all clipboard items are successfully received. In addition, greater complexity is introduced because each individual clipboard item may be split into multiple items (when they exceed the maximum length set by the constant "bytecount ), therefore, the target computer must track each request and notify the server of the location where the last transaction stops using the variable "currentbyte. The Web Service Code is as follows.

Visual C #

[Webmethod] public clipboardstream getmessagestream (string transactionguid, string [] previoustransactionguids, string clipboardguid, long currentbyte) {string clipboarddatadirectory = system. web. httpcontext. current. request. physicalapplicationpath + "clipboard_data"; string clipboardguiddirectory = clipboarddatadirectory + "\" + clipboardguid; string currenttransaction = ""; bool islasttransaction = Fal Se; // If the clipboardguid is not empty, you only need to ensure that the directory still exists. If (clipboardguid! = "") {// If the directory does not exist, an exception is thrown and it must have been deleted. If (! Directory. exists (clipboardguiddirectory) {Throw new exception ("the requested clipboard does not exist. It must have been deleted. ") ;}}// If clipboardguid is null, this is the first contact between the client and the server. We need to // select the available clipboard guid and return it to the user. Else {string [] availableclipboard = directory. getdirectories (clipboarddatadirectory) [0]. split ('\'); clipboardguid = availableclipboard [availableclipboard. length-1]; clipboardguiddirectory + = clipboardguid;} // we need to obtain the next transaction. Every time a transaction is completed, we add it to previoustransactionguids on the client, // let us know that we don't need to send it again. Currenttransaction = getcurrenttransaction (clipboardguiddirectory, previoustransactionguids); // if the current transaction is empty, our work has been completed and no content needs to be sent to the client if (currenttransaction = NULL) {return NULL;} // open the file stream and set it to the location required by the client. Filestream FS = new filestream (currenttransaction, filemode. Open); FS. Position = currentbyte; // determine whether this is the last transaction of the object to notify the client. Long numbytestoread = FS. length-currentbyte; If (numbytestoread> bytecount) {numbytestoread = bytecount; islasttransaction = false;} else {islasttransaction = true ;} // read the file stream byte into the buffer and fill in the object to return to the client. Byte [] buffer = new byte [numbytestoread]; FS. read (buffer, 0, (INT) numbytestoread); FS. close (); fileinfo Fi = new fileinfo (currenttransaction); clipboardstream = new clipboardstream (); clipboardstream. buffer = buffer; clipboardstream. clipboardid = clipboardguid; clipboardstream. format = Fi. name. split ('_') [1]; clipboardstream. objecttype = Fi. name. split ('_') [2]; clipboardstream. islasttransaction = islasttransaction; clipboardstream. transactionid = currenttransaction; return clipboardstream ;}

Visual Basic

    <WebMethod()> _Public Function GetMessageStream(ByVal transactionGUID As String, ByVal previousTransactionGUIDs() As String, ByVal clipBoardGUID As String, ByVal currentByte As Long) As ClipboardStreamDim clipBoardDataDirectory As String = (System.Web.HttpContext.Current.Request.PhysicalApplicationPath + "Clipboard_Data")Dim clipBoardGUIDDirectory As String = clipBoardDataDirectoryDim currentTransaction As String = ""Dim isLastTransaction As Boolean = False'if the clipBoardGUID is not empty then we only need to make sure that the directory still exists.If (clipBoardGUID <> "") Then'if the directory does not exist throw an exception, it must have already been deleted.If Not Directory.Exists(clipBoardGUIDDirectory) ThenThrow New Exception("Requested clipboard does not exist.  It must have been deleted.")End IfEnd If'if the clipboardGUID is empty then this is the client's first contact with the server and we need'to select the available clipboard GUID to return to the user.Dim availableClipBoard() As String = Directory.GetDirectories(clipBoardDataDirectory)(0).Split(Microsoft.VisualBasic.ChrW(92))clipBoardGUID = availableClipBoard((availableClipBoard.Length - 1))clipBoardGUIDDirectory = (clipBoardGUIDDirectory + "\" + clipBoardGUID)'we need to get the next transaction.  Each time we finish a transaction we add it to previousTransactionGUIDs'at the client end so we know not to send it again.currentTransaction = GetCurrentTransaction(clipBoardGUIDDirectory, previousTransactionGUIDs)'if the current transaction is null then we're done and there are no more to send to the clientIf (currentTransaction Is Nothing) ThenReturn NothingEnd If'open the filestream and set it to the position requested by the client.Dim fs As FileStream = New FileStream(currentTransaction, FileMode.Open)fs.Position = currentByte'determind if this is the last transaction or not for this object so we can let the client know.Dim numBytesToRead As Long = (fs.Length - currentByte)If (numBytesToRead > byteCount) ThennumBytesToRead = byteCountisLastTransaction = FalseElseisLastTransaction = TrueEnd If'read the filestream bytes to the buffer and populate the object to return to the client.Dim buffer() As Byte = New Byte((numBytesToRead) - 1) {}fs.Read(buffer, 0, CType(numBytesToRead, Integer))fs.Close()Dim fi As FileInfo = New FileInfo(currentTransaction)Dim clipboardStream As ClipboardStream = New ClipboardStreamclipboardStream.Buffer = bufferclipboardStream.ClipBoardID = clipBoardGUIDclipboardStream.Format = fi.Name.Split(Microsoft.VisualBasic.ChrW(95))(1)clipboardStream.ObjectType = fi.Name.Split(Microsoft.VisualBasic.ChrW(95))(2)clipboardStream.IsLastTransaction = isLastTransactionclipboardStream.TransactionID = currentTransactionReturn clipboardStreamEnd Function
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.