I am trying to paste text, image and pdf documents to clipboard first and then to whatsapp textbox control.
1) For Text.
Clipboard.SetText(message);
Ctrl + v pastes the text into the whatsapp textbox.
2) For Image
var imagePath = "E:\Downloads_SSD\goodmorning.jpg";
Clipboard.SetImage(Image.FromFile(#imagePath ));
Ctrl + v pastes the Image into whatsapp.
3) For Documents.
StringCollection paths = new StringCollection();
paths.Add(#"E:\Downloads_SSD\Hatred-in-the-belly_-Politics-behind-the-appropriation-of-Dr-Ambedkars-writings.pdf");
Clipboard.SetFileDropList(paths);
Ctrl + v works when copying into a folder, but does not work for copying into whatsapp message textbox.
How do I make it to work in case of pdf documents.
To directly answer your question - copying & pasting .pdf files from the clipboard will not work - that is not the way WhatsApp web does it. Surprisingly there is a way to achieve something similar which does not involve pasting.
Basically you have to trigger a click event on that clip-button and run some javascript.
You did not mention what programing language you are using so I will use what works for me. In this example I am using C# PuppeteerSharp.
// load your pdf bytes here
byte[] fileBytes = YourFunctionToGetFileBytes("https://link-to-pdf-file");
if (fileBytes != null)
{
// first, we get the clip-button
var clipImage = _whatsAppPage.QuerySelectorAsync("div[data-testid=\"conversation-clip\"]").Result;
// focus and click on that button
await clipImage.FocusAsync();
Thread.Sleep(600);
await clipImage.ClickAsync();
Thread.Sleep(600);
// wait for the documents button to become available
await _whatsAppPage.WaitForSelectorAsync("li[data-testid=\"mi-attach-document\"]");
// this is where the real magic happens
// see the next block of code for full details
await SetPdfBlobFile(fileBytes, "test-file-name.pdf", "document.querySelector(\"li[data-testid='mi-attach-document']\").querySelector(\"input[type='file']\")");
Thread.Sleep(600);
// after the pdf is finally set, we need to wait for the send button to become available
await _whatsAppPage.WaitForSelectorAsync("div[role=\"button\"][aria-label=\"Send\"]");
var sendButtonPic = _whatsAppPage.QuerySelectorAsync("div[role=\"button\"][aria-label=\"Send\"]").Result;
Thread.Sleep(600);
await sendButtonPic.ClickAsync();
Thread.Sleep(1600);
}
If you inspect the "documents" button, you will see it contains a hidden input button which is in reality the one responsible for loading your files. My "SetPdfBlobFile" function is simply targeting that input button.
Please note that the next code block is basically setting our .pdf file into that hidden "input" file element. You must understand that it is not possible to simply set the "value" field of the input button to the path of your .pdf file. But it is possible to set a .pdf file from a blob. Here's the code for accomplishing that:
private async Task<Newtonsoft.Json.Linq.JToken> SetPdfBlobFile(byte[] pdfBytes, string fileName, string selector)
{
var pasteResults = await _whatsAppPage.EvaluateFunctionAsync(#"(pdfBytes, fileName) => {
return new Promise(async (resolve, reject) => {
// logic to create our blob
const base64Response = await fetch(pdfBytes);
const pdfBlob = await base64Response.blob();
try {
const fileInput = " + selector + #";
const dataTransfer = new DataTransfer();
// create a new file using our pdf blob
const file = new File([pdfBlob], fileName, { type: 'application/pdf' });
// add our file to the hidden input button
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
// our file has been added to the hidden input button
// but lastly we need to trigger a 'change' event
// so WhatsApp loads the send button
fileInput.dispatchEvent(new window.Event('change', { bubbles: true }));
resolve(true);
} catch (ex) {
resolve(ex.message);
}
});
}"
, "data:application/pdf;base64," + Convert.ToBase64String(pdfBytes), fileName);
return pasteResults;
}
That's it! Have fun sending .pdf files!
Related
Context:
I am able to copy (using CTRL-C) and paste programmatically a file from the clipboard when the file copied to the clipboard is for example a file on the desktop. This is simple enough using the following syntax:
File.Copy(Clipboard.GetFileDropList()[0], savePath)
where Clipboard.GetFileDropList()[0] returns the path of the copied file and savePath is the paste location.
However, i find that the above syntax does NOT work if the copied file (using CTRL-C) is a file attachment in an Outlook email. In that scenario, Clipboard.ContainsFileDropList() returns false and Clipboard.GetFileDropList()[0] results in the following error message:
"ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index"
This is despite the fact that pressing CTRL-V does successfully paste the file, confirming that the file was initially successfully copied to the clipboard.
Question:
Sorry if i missed something very basic. My question is how to programmatically paste/save an email attachment (PDF, Word, etc...) from the clipboard to a file location when that email attachment was copied into the clipboard using CTRL-C from within Outlook.
Note that i do understand that what i am trying to do can be solved by skipping the Clipboard and interacting programmatically with Outlook to access a selected email attachment. However, my goal here is to learn how to interact programmatically with the Clipboard under different scenario.
You are using the wrong DataFormat. You can always get a list of currently present data formats by calling Clipboard.GetDataObject().GetFormats().
You need to use:
"FileGroupDescriptor" to retrieve the file names
private static async Task<List<string>> GetAttachedFileNamesFromClipboardAsync(IDataObject clipboardData)
{
if (!clipboardData.GetDataPresent("FileGroupDescriptor"))
{
return new List<string>();
}
using (var descriptorStream = clipboardData.GetData("FileGroupDescriptor", true) as MemoryStream)
{
using (var streamReader = new StreamReader(descriptorStream))
{
var streamContent = await streamReader.ReadToEndAsync();
string[] fileNames = streamContent.Split(new[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);
return new List<string>(fileNames.Skip(1));
}
}
}
"FileContents" to retrieve the raw file contents
// Returns the attachment file content as string
private static async Task<string> GetAttachmentFromClipboardAsync(IDataObject clipboardData)
{
if (!clipboardData.GetDataPresent("FileContents"))
{
return string.Empty;
}
using (var fileContentStream = clipboardData.GetData("FileContents", true) as MemoryStream)
{
using (var streamReader = new StreamReader(fileContentStream))
{
return await streamReader.ReadToEndAsync();
}
}
}
// Returns the attachment file content as MemoryStream
private static MemoryStream GetAttachmentFromClipboard(IDataObject clipboardData)
{
if (!clipboardData.GetDataPresent("FileContents"))
{
return null;
}
return clipboardData.GetData("FileContents", true) as MemoryStream;
}
Save attached file to disk
Since Windows only adds the first selected attachment to the system clipboard, this solution can only save a single attachment. Apparently the office clipboard is not accessible.
private static async Task SaveAttachmentFromClipboardToFileAsync(IDataObject clipboardData, string destinationFilePath)
{
if (!clipboardData.GetDataPresent("FileContents"))
{
return;
}
using (var attachedFileStream = clipboardData.GetData("FileContents", true) as MemoryStream)
{
using (var destinationFileStream = File.Open(destinationFilePath, FileMode.OpenOrCreate))
{
await attachedFileStream.CopyToAsync(destinationFileStream);
}
}
}
Save attached files to disk using the Office API
Requires to reference Microsoft.Office.Interop.Outlook.dll. This solution does not depend on the system clipboard. It just reaads the selected attachments from the currently open message item in the Outlook explorer.
You still can monitor the system clipboard to trigger the process to save the attachments.
private static void SaveSelectedAttachementsToFolder(string destinationFolderPath)
{
var outlookApplication = new Microsoft.Office.Interop.Outlook.Application();
Explorer activeOutlookExplorer = outlookApplication.ActiveExplorer();
AttachmentSelection selectedAttachments = activeOutlookExplorer.AttachmentSelection;
foreach(Attachment attachment in selectedAttachments)
{
attachment.SaveAsFile(Path.Combine(destinationFolderPath, attachment.FileName));
}
}
I have a scenario in which user is giving input file name and on back end I am searching that file if that is present on server or not , If the file is present i am loading it on browser else giving error , The problem is that the end user can download that PDF file as well as print that file , I want to stop that both scenarios.
I tried couple of online tutorials and libraries like spire.pdf and I also tried that scenario by converting my PDF in to images and than showing images to the client but that is not the good solution .
Public Action File(string filename)
{
if(user is authorize)
{
Search file on server
if(File Is present)
{
return file. // user can see , download and print right now , i want to prevent downloading and printing scenarios
}
}
}
I just want to stop user to download and print , how can i get the desire result ?
You cannot full prevent the pdf download (right click - download),
you have a lot of choices...
1) You can open the document in borwser as default option, then the document will be displayed in browser page and not downloaded as first option. Return your document inline, the document will be opened in borwser and not downloaded
Public Action File(string filename)
{
if(user is authorize)
{
Search file on server
if(File Is present)
{
var file = "filename.pdf";
// Response...
System.Net.Mime.ContentDisposition cd = new System.Net.Mime.ContentDisposition
{
FileName = file,
Inline = true
// false = prompt the user for downloading;
// true = browser to try to show the file inline
};
Response.Headers.Add("Content-Disposition", cd.ToString());
Response.Headers.Add("X-Content-Type-Options", "nosniff");
return File(System.IO.File.ReadAllBytes(file), "application/pdf");
}
}
}
2) when you create your PDF file you can set permission FLAGS,
3) Watermark, when your user download a PDF personalize the pdf before download writing in each page the Name, Surname, Email address of the user.
this is an excellent deterrent.
here an example: https://code.msdn.microsoft.com/windowsdesktop/Add-a-text-watermark-on-e56799cf
PdfDocument doc = new PdfDocument();
doc.LoadFromFile(#"..\..\Sample1.pdf");
foreach (PdfPageBase page in doc.Pages)
{
PdfTilingBrush brush
= new PdfTilingBrush(new SizeF(page.Canvas.ClientSize.Width / 2, page.Canvas.ClientSize.Height / 3));
brush.Graphics.SetTransparency(0.3f);
brush.Graphics.Save();
brush.Graphics.TranslateTransform(brush.Size.Width / 2, brush.Size.Height / 2);
brush.Graphics.RotateTransform(-45);
brush.Graphics.DrawString("MSDN Samples",
new PdfFont(PdfFontFamily.Helvetica, 24), PdfBrushes.Violet, 0, 0,
new PdfStringFormat(PdfTextAlignment.Center));
brush.Graphics.Restore();
brush.Graphics.SetTransparency(1);
page.Canvas.DrawRectangle(brush, new RectangleF(new PointF(0, 0), page.Canvas.ClientSize));
}
doc.SaveToFile("TextWaterMark.pdf");
Yes you can but you will need to:
Create Images for each page
Present those to the user on the web via your own interface (html,
flash etc)
A print screen will allow someone to recreate the low res image you present, and in this case, you could add a watermark to the image.
I am new to Xamarin. I have simple app; Where I have notes field and take picture functionality. I am using media plugin to take pictures. The picture obviously get saved in phone gallery.
But I also wanted to save the text file which contains the input from notes field in phone.
I am struggling to save the text file.
The is the product structure. I am using shared project.
File structure and classes image
Sample app image
I have an save button. What I want to do is when save button is clicked; save the text file which has user input from notes field.
Here is action of my save button
I was looking on this website
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/files?tabs=windows
I tried some code but nothing worked.
private async void Take_Photo_Button_Clicked(object sender, EventArgs e)
{
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
SaveToAlbum = true,
Name = jobnoentry.Text + "-" + Applicationletterentry + "-" + signnoentry.Text + "-" + SignType,
});
if (file == null)
return;
MainImage.Source = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
return stream;
});
//Save text field
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp.txt");
File.WriteAllText(fileName, "Hello World");
}
First, where exactly a file gets saved depends on the platform, but you can always print the string for the filename to see the actual path, e.g.
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp.txt");
Console.WriteLine(filename); // will write the actual path to the application output.
In any case the path you are using, Environment.SpecialFolder.LocalApplicationData, will save the text file to a location only accessible by the app itself, you won't see it in a file browser. If you need to have the text files available outside of your app, how to do that will vary based on platform and you will need to use a dependency service to get the correct file paths.
However you can verify if you have saved and can read a file as follows:
string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "temp.txt");
File.WriteAllText(fileName, "Hello World");
The above is code from your post. If you don't get an exception, chances are it worked. To verify:
var text = File.ReadAllText(filename);
if (text == "Hello World")
Console.WriteLine("File contents verified and correct");
else
Console.WriteLine("File contents do not match saved string");
I want to use/read attached files from an outlook email into a WinForm solution.
Ex: the email has a TXT file attached; I want to perform a Drag&Drog of the TXT file into the WinForm and read the TXT at the same time.
This is an old question, but I'll provide another answer anyhow that doesn't involve using the Outlook objects.
This URL provides working code that is about 13 years old, but still seems to work, on how to handle the "FileGroupDescriptor" and "FileContents" data that Outlook passes to the DropDrop event. Just in case that link dies, here is the relevant code, copy/pasted directly:
DragEnter event:
private void Form1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
// for this program, we allow a file to be dropped from Explorer
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{ e.Effect = DragDropEffects.Copy;}
// or this tells us if it is an Outlook attachment drop
else if (e.Data.GetDataPresent("FileGroupDescriptor"))
{ e.Effect = DragDropEffects.Copy;}
// or none of the above
else
{ e.Effect = DragDropEffects.None;}
}
DragDrop event:
private void Form1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
string [] fileNames = null;
try
{
if ( e.Data.GetDataPresent(DataFormats.FileDrop,false) == true)
{
fileNames = (string []) e.Data.GetData(DataFormats.FileDrop);
// handle each file passed as needed
foreach( string fileName in fileNames)
{
// do what you are going to do with each filename
}
}
else if (e.Data.GetDataPresent("FileGroupDescriptor"))
{
//
// the first step here is to get the filename
// of the attachment and
// build a full-path name so we can store it
// in the temporary folder
//
// set up to obtain the FileGroupDescriptor
// and extract the file name
Stream theStream = (Stream) e.Data.GetData("FileGroupDescriptor");
byte [] fileGroupDescriptor = new byte[512];
theStream.Read(fileGroupDescriptor,0,512);
// used to build the filename from the FileGroupDescriptor block
StringBuilder fileName = new StringBuilder("");
// this trick gets the filename of the passed attached file
for(int i=76; fileGroupDescriptor[i]!=0; i++)
{ fileName.Append(Convert.ToChar(fileGroupDescriptor[i]));}
theStream.Close();
string path = Path.GetTempPath();
// put the zip file into the temp directory
string theFile = path+fileName.ToString();
// create the full-path name
//
// Second step: we have the file name.
// Now we need to get the actual raw
// data for the attached file and copy it to disk so we work on it.
//
// get the actual raw file into memory
MemoryStream ms = (MemoryStream) e.Data.GetData(
"FileContents",true);
// allocate enough bytes to hold the raw data
byte [] fileBytes = new byte[ms.Length];
// set starting position at first byte and read in the raw data
ms.Position = 0;
ms.Read(fileBytes,0,(int)ms.Length);
// create a file and save the raw zip file to it
FileStream fs = new FileStream(theFile,FileMode.Create);
fs.Write(fileBytes,0,(int)fileBytes.Length);
fs.Close(); // close the file
FileInfo tempFile = new FileInfo(theFile);
// always good to make sure we actually created the file
if ( tempFile.Exists == true)
{
// for now, just delete what we created
tempFile.Delete();
}
else
{ Trace.WriteLine("File was not created!");}
}
}
catch (Exception ex)
{
Trace.WriteLine("Error in DragDrop function: " + ex.Message);
// don't use MessageBox here - Outlook or Explorer is waiting !
}
}
Note that this code doesn't Dispose of objects that it should, such as the MemoryStream and FileStream objects.
You can get the running Outlook instance by using the GetActiveObject method which allows to obtain a running instance of the specified object from the running object table (ROT). Then you can automate Outlook to get the currently selected or opened item from which an attachment might be dragged. See C# app automates Outlook (CSAutomateOutlook) for the sample code.
i know this question seems simple but it is giving me a headache.
I have a programm from where i want to show a pdf and this works fine and dandy
but when i want to change the pdf it won't work.
The application has two two tabpages, one for the PDF and one for the design etc.
I can click on Print and a pdf is created and it loads.
When changing the pdf, because i changed something in the first tab, it doesn't delete the old one and it won't load the new pdf file.
Here is my code:
//The PdfFile variable is the path to the old pdf file
//and file variable is the path to the new pdf file
if (wbPdfViewer != null)
{
wbPdfViewer.AllowNavigation = true;
wbPdfViewer.Navigate(new Uri("http://www.google.de")); //this should navigate
wbPdfViewer.Url = new Uri("http://www.google.de"); //this is just a try
bool isallowed = wbPdfViewer.AllowNavigation; //check during debbuging if it is set
string url = wbPdfViewer.Url.ToString(); //see if it works during debbuging
}
if (pdfViewer.Document != null) //this is an optional viewer ... nevermind that
{
pdfViewer.Document.Close();
pdfViewer.Document.Dispose();
}
try
{
DHIO.File.Delete(PdfFile);
}
catch(Exception ex)
{
#if DEBUG
MessageBox.Show("PdfViewer 02002: Couldn't delete PDF file");
#endif
}
if (wbPdfViewer != null)
{
GC.Collect();
if (string.IsNullOrEmpty(file) || !DHIO.File.Exists(file))
return;
wbPdfViewer.Navigate(new Uri(file));
ShowNavigationControls();
return;
}
As you can see i want to delete the PdfFile and it shouldn't be in access because i changed the page (in a later version google.de is replaced with about:blank or something else).
So my question is how to change the URL so that my program isn't accessing the pdf file anymore ?
i tried it with the navigationComplete event but this won't fire
and as always thanks in advance
Set the wbPdfViewer.Url to null.