I am trying to drag from another windows application (EM Client, thunderbird or outlook) onto my form. When an email is dragged from the other application to windows explore it will drop as a file. If the user drags onto my application I would like to get the file contents as a file stream.
I was able to get this working with a UWP app, but I need to get it working in a Windows Form app so it will work in Windows 7.
I have found lots of examples of going the other way (dragging from App to windows).
The thing that makes this so annoying is it is easy in the UWP app.
Here is how I did it in the UWP app, the results of which is I get a new file saved in the roaming folder at name "email.eml":
XAML
<Grid AllowDrop="True" DragOver="Grid_DragOver" Drop="Grid_Drop"
Background="LightBlue" Margin="10,10,10,353">
<TextBlock>Drop anywhere in the blue area</TextBlock>
</Grid>
XAML.CS
namespace App1
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Grid_DragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Copy;
}
private async void Grid_Drop(object sender, DragEventArgs e)
{
if (e.DataView.Contains(StandardDataFormats.StorageItems))
{
var items = await e.DataView.GetStorageItemsAsync();
if (items.Count > 0)
{
var storageFile = items[0] as StorageFile;
var reader = (await storageFile.OpenAsync(FileAccessMode.Read));
IBuffer result = new byte[reader.Size].AsBuffer();
var test = await reader.ReadAsync(result, result.Length,Windows.Storage.Streams.InputStreamOptions.None);
Windows.Storage.StorageFolder storageFolder =
Windows.Storage.ApplicationData.Current.LocalFolder;
Windows.Storage.StorageFile sampleFile = await storageFolder.CreateFileAsync("email.eml",Windows.Storage.CreationCollisionOption.ReplaceExisting);
await Windows.Storage.FileIO.WriteBufferAsync(sampleFile, test);
}
}
}
}
}
I have read every article that that is listed on this answer, plus more:
Trying to implement Drag and Drop gmail attachment from chrome
Basically no matter how I attack it I end up with one of 3 results:
a exception for "Invalid FORMATETC structure (Exception from HRESULT: 0x80040064(DV_E_FORMATETC))"
my MemoryStream is null
I get a security violation
This is the Code that gets a security violation:
MemoryStream ClipboardMemoryStream = new MemoryStream();
BinaryFormatter bft = new BinaryFormatter();
bft.Serialize(ClipboardMemoryStream, e.Data.GetData("FileGroupDescriptorW", false));
byte[] byteArray = ClipboardMemoryStream.ToArray();
My guess is that I need to implement the e.Data.GetData("FileGroupDesciptorW") is returning a IStorage Class, and I need to implement that class, but I am loss on how to do it, plus I am not sure that is the case
e.Data.GetType shows its a marshalbyrefobject, I have attempted to do the Remoting manually, but I got stuck on not having an open channel.
https://learn.microsoft.com/en-us/windows/desktop/api/objidl/nn-objidl-istorage
https://learn.microsoft.com/en-us/windows/desktop/shell/datascenarios#dragging-and-dropping-shell-objects-asynchronously
So After reaching out to a professional for help I have a working example. The trick was to get "FileDescriptorW" working in the Custom ComObject class. You will find a version of this class in the Drag from Outlook example but it does not work when dragging from EM Client, this does.
Here is the Code:
Code is too Big to post
Then You can use it like this:
MyDataObject obj = new MyDataObject(e.Data);
string[] fileNames = { };
//ThunderBird Does a FileDrop
if (obj.GetDataPresent(DataFormats.FileDrop, true))
{
string[] tempFileNames = (string[])obj.GetData(DataFormats.FileDrop);
List<string> tempFileNameList = new List<string>();
foreach(string f in tempFileNames)
{
tempFileNameList.Add(Path.GetFileName(f));
}
fileNames = tempFileNameList.ToArray();
} else if (fileNames.Length == 0)
{
//EM Client uses "FileGroupDescriptorW"
fileNames = (string[])obj.GetData("FileGroupDescriptorW");
}else if (fileNames.Length == 0)
{
//Outlook Uses "FileGroupDescriptor"
fileNames = (string[])obj.GetData("FileGroupDescriptor");
}
int index = 0;
foreach (string f in fileNames)
{
File.WriteAllBytes("C:\\FilePath\\"+f, obj.GetData("FileContents", index).ToArray());
index++;
}
Related
I have a Xamarin Project where I generate a .pdf file from scratch and save it in my local storage. This works perfectly fine and can find it and open it in the disk where I saved it. However, I need to open the .pdf file immediately after creation programmatically.
I already tried different variations using Process and ProcessStartInfo but these just throw errors like "System.ComponentModel.Win32Exception: 'The system cannot find the file specified'" and "'System.PlatformNotSupportedException'".
This is basically the path I am trying to open using Process.
var p = Process.Start(#"cmd.exe", "/c start " + #"P:\\Receiving inspection\\Inspection Reports\\" + timestamp + ".pdf");
I also tried ProcessStartInfo using some variations but I'm getting the same errors all over and over.
var p = new Process();
p.StartInfo = new ProcessStartInfo(#"'P:\\Receiving inspection\\Inspection Reports\\'" + timestamp + ".pdf");
p.Start();
The better way is that use LaunchFileAsync method to open file with browser. You could create FileLauncher DependencyService to invoke uwp LaunchFileAsync method from xamarin share project.
Interface
public interface IFileLauncher
{
Task<bool> LaunchFileAsync(string uri);
}
Implementation
[assembly: Dependency(typeof(UWPFileLauncher))]
namespace App14.UWP
{
public class UWPFileLauncher : IFileLauncher
{
public async Task<bool> LaunchFileAsync(string uri)
{
var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(uri);
bool success = false;
if (file != null)
{
// Set the option to show the picker
var options = new Windows.System.LauncherOptions();
options.DisplayApplicationPicker = true;
// Launch the retrieved file
success = await Windows.System.Launcher.LaunchFileAsync(file, options);
if (success)
{
// File launched
}
else
{
// File launch failed
}
}
else
{
// Could not
}
return success;
}
}
}
Usage
private async void Button_Clicked(object sender, EventArgs e)
{
await DependencyService.Get<IFileLauncher>().LaunchFileAsync("D:\\Key.pdf");
}
Please note if you want to access D or C disk in uwp, you need add broadFileSystemAccess capability. for more please refer this .
Update
If the UWP files are network based, not local zone based, you could use Xamarin.Essentials to open file with browser. And you must specify the privateNetworkClientServer capability in the manifest. For more please refer this link.
I have been trying to link a TextBox to an external text file in a Visual Studio 2012 Windows 8 store app and eventually be able to edit the contents of this TextBox afterwards with a SAVE button, but unfortunately i get the error which is shown in the link of the screenshot. I am running Windows 8 on a virtual machine !
[1]: http://i.imgur.com/gQWlIm4.png "ERROR
[2]: http://i.imgur.com/hHj9vXx.png "Place of the error in the designer page
COde that i am using for filling the TextBox:
private void Page_Loaded(object sender, RoutedEventArgs e)
{
LoadWords(#"Assets\AdminPageKS1words.txt");
}
async private void LoadWords(string filename)
{
var wordList = new List<String>();
// this method reads line separated words from a text file and populates a List object //
Windows.Storage.StorageFolder localFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
// begin the file read operation
try
{
// open and read in the word list into an object called words
StorageFile sampleFile = await localFolder.GetFileAsync(filename);
var words = await FileIO.ReadLinesAsync(sampleFile);
// add each word returned to a list of words declared
// globally as List wordList = new List();
foreach (var word in words)
{
wordList.Add(word);
}
List1.Text = string.Join(Environment.NewLine, wordList);
}
catch (Exception)
{
// handle any errors with reading the file
}
Code that i am using for the SAVE button:
async private void SaveButton_Click(object sender, RoutedEventArgs e)
{
// locate the local storage folder on the device
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
// create a new text file in the local folder called “File.txt”
StorageFile sampleFile = await localFolder.CreateFileAsync("File.txt",CreationCollisionOption.ReplaceExisting);
// write text to the file just created – text comes from a textblock called wordlistBox
await FileIO.WriteTextAsync(sampleFile, List1.Text);
// display a message saying that file is saved.
messageLabel.Text = keystage + "File saved";
}
public string keystage { get; set; }
The code works for me, but you have a Try..Catch block which is effectively ignoring any exceptions. I'd suggest one of the following:
- Add a breakpoint to the start of Page_Loaded to check that it's actually being called, then step through the code to see whether there's an exception.
- Modify your Catch Block to write out the error information:
catch (Exception ex)
{
messageLabel.Text = ex.Message;
}
actually i am creating windows phone 8 application .,
so my application initially need to download some files from the server before application being started( that means before application get started) ., so that i want to show splash screen till the files being downloaded from the server to my application local.,
i had a code to download file and i successfully know how to download like if the button was clicked in WP8.,
But i don't know how to automatically download a file before application being started.,
i had written downloading method in App.xaml.cs file and inside "void Application_Launching(object sender, LaunchingEventArgs e)" method to initially download files.,
But my problem is the splash screen normally dislayed over 2 or 3 seconds and my main page has been shown to user before my downloads complete.,
Here is my code for download in App.xaml.cs
private void Application_Launching(object sender, LaunchingEventArgs e)
{
downloadDBFile();
}
public enum DownloadStatus { Ok, Error, fileExist };
public static async Task<DownloadStatus> DownloadFileSimle(Uri fileAdress, string fileName)
{
try
{
WebRequest request = WebRequest.Create(fileAdress);
if (request != null)
{
WebResponse response2 = await request.GetResponseAsync();
using (Stream resopnse = response2.GetResponseStream())
{
using (IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication())
{
if (ISF.FileExists(fileName))
ISF.DeleteFile(fileName);
using (IsolatedStorageFileStream file = ISF.CreateFile(fileName))
{
const int BUFFER_SIZE = 10 * 1024;
byte[] buf = new byte[BUFFER_SIZE];
int bytesread = 0;
while ((bytesread = await resopnse.ReadAsync(buf, 0, BUFFER_SIZE)) > 0)
file.Write(buf, 0, bytesread);
}
}
return DownloadStatus.Ok;
}
}
return DownloadStatus.Error;
}
catch { return DownloadStatus.Error; }
}
public async void downloadDBFile()
{
DownloadStatus fileDownloaded = await DownloadFileSimle(new Uri(#"https://dl.dropboxusercontent.com/s/nz9107khswqttyp/sample.sqlite?dl=1&token_hash=AAE7EOhKzpVlAbCUlgwToURZOg0xZzMesu_gPTcLceZzDg", UriKind.Absolute), "sample.sqlite");
switch (fileDownloaded)
{
case DownloadStatus.Ok:
MessageBox.Show(fileDownloaded.ToString());
break;
case DownloadStatus.Error:
MessageBox.Show(fileDownloaded.ToString());
break;
case DownloadStatus.fileExist:
MessageBox.Show(fileDownloaded.ToString());
break;
default:
MessageBox.Show("There was an error while downloading.");
break;
}
}
So my Question is :
1) is it right way to write code in App.xaml.cs file for download files from server before my application being shown to user ?
2) if it is wright way means " how to extend splash screen time till my file has been downloaded and before my application being shown to user "
someone please help me to solve.,
thanks in advance.,
The best suggestion to this is that you need to create a separate page for extended splash screen where splash screen with animations are shown while downloading the db takes places in another thread.
Extended splash screen is the answer for both of the questions.
Making the files download in App.xaml.cs causes the app to freeze leaves the user with nothing but to kill and it might not also not qualify the app certifications.
Using c#, Windows Store App, VS 2013
Try to open File Picker, using next simple code:
private async void OkBtnClick(IUICommand command)
{
if (this.EnsureUnsnapped())
{
FileOpenPicker fop = new FileOpenPicker();
fop.FileTypeFilter.Add(".png");
fop.FileTypeFilter.Add(".jpg");
fop.FileTypeFilter.Add(".jpeg");
fop.ViewMode = PickerViewMode.Thumbnail;
fop.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
StorageFile requestedFile = await fop.PickSingleFileAsync();
if (requestedFile != null)
{
//TODO:
}
}
}
internal bool EnsureUnsnapped()
{
// FilePicker APIs will not work if the application is in a snapped state.
// If an app wants to show a FilePicker while snapped, it must attempt to unsnap first
bool unsnapped = ((ApplicationView.Value != ApplicationViewState.Snapped)
|| ApplicationView.TryUnsnap());
if (!unsnapped)
{
Extensions.NotifyUser("Cannot unsnap app...", statusNotificationBlock);
}
return unsnapped;
}
Also add capability in appmanifest file for Pictures Library:
But during running got exception : System.UnauthorizedAccessException on line StorageFile requestedFile = await fop.PickSingleFileAsync();.
Question: Why I got this exception if all required access provided, Also i try to launch VS2013 with Administrator rights - result - same.
For creating this code use this article
this is my first post on this site and I searched high and wide to get my code to work.
Like the title says, it's a WinRT App and I'm having difficulty with File IO. What I want to do is read in a text file stored in a folder that is inside the application installation directory and that contains lines of data that I'll feed into an List<>.
public static async void GetStations()
{
try
{
using (var stream = await Windows.Storage.ApplicationData.Current.LocalFolder.OpenStreamForReadAsync(#"MyApp\Data\file.txt"))
{
using (var streamReader = new StreamReader(stream))
{
while (streamReader.Peek() >= 0)
{
string line = await streamReader.ReadLineAsync();
//do something with
}
}
}
}
catch (Exception e)
{
...
}
finally
{
...
}
}
the problem is I am getting file not found errors when trying to run it. Can anyone help? If you require that I post more information, I can...
Thanks in advance.
If you are distributing your file as a part of your application package then Package.Current.InstalledLocation is the right location. ApplicationData.Current.LocalFolder contains only files that have been put there by your application.
The correct code would be:
public static async void GetStations()
{
try
{
using (var stream = await Windows.ApplicationModel.Package.Current.InstalledLocation.OpenStreamForReadAsync(#"Data\file.txt"))
{
using (var streamReader = new StreamReader(stream))
{
while (streamReader.Peek() >= 0)
{
string line = await streamReader.ReadLineAsync();
//do something with
}
}
}
}
catch (Exception e)
{
//...
}
finally
{
//...
}
}
The file must be included in you project inside Data folder and have Build Action set to Content.
Instead of opening from ApplicationData, you probably need:
Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync
This will get the file in the package's installation folder, instead of the Application's Data folder.