private void HandleReceivedFileDrop(XSelectionEvent evt) { try { int ret = XGetWindowProperty(xConnection.XDisplay, xConnection.XCbWindow, evt.property, 0, 0, false, new IntPtr(0), out IntPtr retType, out int format, out int nItems, out int dataSize, out IntPtr prop_return); XFree(prop_return); XGetWindowProperty(xConnection.XDisplay, xConnection.XCbWindow, evt.property, 0, dataSize, false, new IntPtr(0), out IntPtr returned_type, out format, out nItems, out int remBytes, out prop_return); string rawFileList = Marshal.PtrToStringAuto(prop_return, nItems); ISLogger.Write(rawFileList); string[] list = rawFileList.Split('\n'); string[] sanList = new string[list.Length]; for (int i = 0; i < list.Length; i++) { sanList[i] = list[i].Trim().Replace("file://", ""); } XFree(prop_return); //Now we need to get the data for the listed files... ClipboardVirtualFileData files = ReadFileDrop(sanList); OnClipboardDataChanged(files); }catch (Exception ex) { ISLogger.Write("An error occurred while handling a clipboard file drop: " + ex.Message); } }
/// <summary> /// Begins a file dragdrop operation, and assigns an access token to the operation /// </summary> /// <param name="cbFiles"></param> /// <param name="host"></param> /// <param name="operationId"></param> private async Task BeginFileOperationAsync(ClipboardVirtualFileData cbFiles, ISServerSocket host, Guid operationId) { Guid fileAccesstoken = Guid.Empty; DragDropOperation newOperation = new DragDropOperation(cbFiles, host, operationId); try { fileAccesstoken = await CreateAccessTokenForOperation(newOperation); } catch (Exception ex) { ISLogger.Write("DragDropController: Cancelling operation, could not generate file access token: " + ex.Message); return; } newOperation.RemoteFileAccessToken = fileAccesstoken; //Create events, incase the files are dropped on localhost if (!newOperation.Host.IsLocalhost) { for (int i = 0; i < cbFiles.AllFiles.Count; i++) { cbFiles.AllFiles[i].RemoteAccessToken = fileAccesstoken; cbFiles.AllFiles[i].ReadDelegate = File_RequestDataAsync; cbFiles.AllFiles[i].ReadComplete += VirtualFile_ReadComplete; cbFiles.AllFiles[i].FileOperationId = newOperation.OperationId; } } //If the previous dragdrop operation is still transfering files, store it so that the files can keep being transfered if (CurrentOperation != null && CurrentOperation.State == DragDropState.TransferingFiles) { previousOperationIds.Add(CurrentOperation.OperationId, CurrentOperation); } //Sets the new operation, which is automatically set to dragging state CurrentOperation = newOperation; if (currentInputClient.IsLocalhost) { ddManager.DoDragDrop(CurrentOperation.OperationData, newOperation.OperationId); } else { currentInputClient.SendDragDropData(CurrentOperation.OperationData.ToBytes(), CurrentOperation.OperationId); } }
private Guid CreateTokenForOperationLocal(DataOperation operation, int timeout) { Guid accessId = Guid.NewGuid(); ClipboardVirtualFileData file = operation.Data as ClipboardVirtualFileData; Guid[] fIds = new Guid[file.AllFiles.Count]; string[] fSources = new string[file.AllFiles.Count]; for (int i = 0; i < file.AllFiles.Count; i++) { fIds[i] = file.AllFiles[i].FileRequestId; fSources[i] = file.AllFiles[i].FullPath; } return(CreateFileReadTokenForGroup(new FileAccessController.FileAccessInfo(fIds, fSources), timeout)); }
/// <summary> /// Converts a window dataobject to an inputshare clipboard data object /// </summary> /// <param name="data"></param> /// <param name="attempt"></param> /// <returns></returns> public static ClipboardDataBase ConvertToGeneric(System.Windows.Forms.IDataObject data, int attempt = 0) { try { System.Windows.Forms.DataObject obj = data as System.Windows.Forms.DataObject; if (data.GetDataPresent(DataFormats.Bitmap, true)) { using (Image i = obj.GetImage()) { using (MemoryStream ms = new MemoryStream()) { i.Save(ms, ImageFormat.Jpeg); return(new ClipboardImageData(ms.ToArray(), true)); } } } else if (data.GetDataPresent(DataFormats.Text)) { return(new ClipboardTextData((string)data.GetData(DataFormats.Text))); } else if (data.GetDataPresent(DataFormats.FileDrop)) { ClipboardVirtualFileData fd = ReadFileDrop(data); return(fd); } else { ISLogger.Write("Debug: Could not translate dataobject: type is not implemented"); return(null); } } catch (COMException ex) { ISLogger.Write("COM exception: " + ex.Message); Thread.Sleep(25); if (attempt > 10) { throw new Exception("Could not read clipboard after 10 attempts."); } int n = attempt + 1; return(ConvertToGeneric(data, n)); } }
private Guid GenerateLocalAccessTokenForOperation(DragDropOperation operation) { if (operation.DataType != ClipboardDataType.File) { throw new ArgumentException("DateType must be file"); } ClipboardVirtualFileData file = operation.OperationData as ClipboardVirtualFileData; Guid[] fIds = new Guid[file.AllFiles.Count]; string[] fSources = new string[file.AllFiles.Count]; for (int i = 0; i < file.AllFiles.Count; i++) { fIds[i] = file.AllFiles[i].FileRequestId; fSources[i] = file.AllFiles[i].FullPath; } return(fileController.CreateFileReadTokenForGroup(new FileAccessController.FileAccessInfo(fIds, fSources), 10000)); }
public override void SetClipboardData(ClipboardDataBase data) { InputshareDataObject obj = new InputshareDataObject(data, false); if (data.DataType == ClipboardDataType.File) { //If two applications paste data, we can't know which of the two we are interacting with. //In other words, we don't know if its program A or program B calling GetData() on the InputshareDataObject //this means that files will just be corrupted if two programs try to paste the data //To fix this, as soon as the data is pasted, we put another InputshareDataObject onto the clipboard. //Each dataobject gets their own access token from the host to allow them to have seperate filestreams //and allow any number of programs to paste at the same time currentClipboardFiles = data as ClipboardVirtualFileData; obj.FilesPasted += Obj_ObjectPasted; } cbHookWindow.SetClipboardData(obj); }
public static void WriteFolderStructure(ClipboardVirtualFileData data, string rootDir) { if (!Directory.Exists(rootDir)) { Directory.CreateDirectory(rootDir); } foreach (var rootFolder in data.RootDirectory.SubFolders) { if (!Directory.Exists(Path.Combine(rootDir, rootFolder.Name))) { Directory.CreateDirectory(Path.Combine(rootDir, rootFolder.Name)); } foreach (var file in rootFolder.Files) { File.Create(Path.Combine(rootDir, rootFolder.Name, file.FileName)).Dispose(); } } WriteRecursive(data.RootDirectory, rootDir); }
private async void SetClipboardFiles(ClipboardVirtualFileData cbFiles, ISServerSocket host, Guid operationId) { if (currentOperation != null && currentOperation.DataType == ClipboardDataType.File) { previousOperationDictionary.Add(currentOperation.OperationId, currentOperation); } currentOperation = new ClipboardOperation(operationId, cbFiles.DataType, cbFiles, host); if (host == ISServerSocket.Localhost) { //TODO - We can't use the same access token for clipboard operations, as more than one client can //be reading from the stream at the same time which will cause corruption. //We need to create a new access token for each client that pastes the files to create multiple stream instances } else { //Assign virtual file events, so if localhosts pastes the files then the shell can read data from the host. foreach (var file in cbFiles.AllFiles) { file.ReadComplete += File_ReadComplete; file.ReadDelegate = File_RequestDataAsync; } //Create a token so that localhost can access files try { currentOperation.LocalhostAccessToken = await currentOperation.Host.RequestFileTokenAsync(operationId); }catch (Exception ex) { ISLogger.Write("GlobalClipboardController: Failed to get access token for clipboard content: " + ex.Message); return; } } BroadcastCurrentOperation(); }
/// <summary> /// Creates an IStream that uses a network machine as the source of data /// </summary> /// <param name="file"></param> internal ManagedRemoteIStream(FileAttributes file, ClipboardVirtualFileData parent, Guid accessToken) { sourceClipboardData = parent; this.accessToken = accessToken; SourceVirtualFile = file; }
public InputshareDataObject(ClipboardDataBase data, bool isDragDrop) { isDragDropData = isDragDrop; OperationGuid = data.OperationId; supportedFormats.Add(new FORMATETC { cfFormat = (short)InputshareClipboardFormatId, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, ptd = IntPtr.Zero, tymed = TYMED.TYMED_HGLOBAL }); if (data is ClipboardTextData cbText) { supportedFormats.Add(new FORMATETC { cfFormat = formatTextId, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, ptd = IntPtr.Zero, tymed = TYMED.TYMED_HGLOBAL }); ISLogger.Write("Stored text = " + cbText.Text); storedText = cbText.Text; } else if (data is ClipboardVirtualFileData cbFiles) { storedFiles = cbFiles; supportedFormats.Add(new FORMATETC { cfFormat = formatFileContentsId, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, ptd = IntPtr.Zero, tymed = TYMED.TYMED_ISTREAM }); supportedFormats.Add(new FORMATETC { cfFormat = formatFileDescriptorId, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, ptd = IntPtr.Zero, tymed = TYMED.TYMED_HGLOBAL }); supportedFormats.Add(new FORMATETC { cfFormat = (short)DataFormats.GetFormat("Preferred DropEffect").Id, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, ptd = IntPtr.Zero, tymed = TYMED.TYMED_HGLOBAL }); } else if (data is ClipboardImageData cbImage) { using (MemoryStream ms = new MemoryStream(cbImage.ImageData)) { storedImage = (Bitmap)Image.FromStream(ms); } supportedFormats.Add(new FORMATETC { cfFormat = formatBitmapId, dwAspect = DVASPECT.DVASPECT_CONTENT, lindex = -1, ptd = IntPtr.Zero, tymed = TYMED.TYMED_GDI }); } }