I am trying to open a pdf file using the below working code I previously used on another app,
but this time I am getting System.Runtime.InteropServices.COMException when the flow hits this line: Windows.System.Launcher.LaunchFileAsync(pdffile);
What is the meaning of this exception and how to get rid of it?
Please note that without caring about this exception (disabling it),
the file still cannot be opened.
Please note: the file exists in my isolated folder (checked with wpowertool),
I tried with 2 different files so it shouldnt be a matter of file corruption.
public void openFile(string options)
{
System.Diagnostics.Debug.WriteLine("options: " + options);
string optVal = JsonHelper.Deserialize<string[]>(options)[0];
asyncOpen(optVal);
}
public async Task asyncOpen(string filename)
{
filename = filename.Substring(2, filename.Length - 2);
filename = filename.Replace("//", "/").Replace("/", "\\");
Windows.Storage.StorageFolder local = Windows.Storage.ApplicationData.Current.LocalFolder;
Debug.WriteLine("local: " + local.Path);
Windows.Storage.StorageFile pdffile = await local.GetFileAsync(filename);
Debug.WriteLine("pdffile: " + pdffile.Name);
//// Launch the pdf file.
Windows.System.Launcher.LaunchFileAsync(pdffile);
}
this MSDN post belongs to me. Yes, the file is installed and I have acrobat reader.
Please note that this C# code is a phonegap/cordova plugin which is called via javascript in my hybrid application.
Pay attention to the remarks in this MSDN Article - Launcher.LaunchFileAsync(IStorageFile):
The calling app must be visible to the user when the API is invoked.
This API must be called from an ASTA thread (also known as a UI
thread).
Huge ups to the OP for sharing the solution. The following code should help others get around this issue:
Deployment.Current.Dispatcher.BeginInvoke(() => { asyncOpenFile(options); });
Related
I have a question regarding accessing data from another application.
I need access to files that are inside another, already installed, application on iPhone so they can be uploaded via REST POST method.
When we tried testing this with simple picker [FileData fileData = await CrossFilePicker.Current.PickFile();] and navigating to the other application we got something along the lines of 'access denied' message.
We've done this on Android while using Android.App.Application.Context(StartActivity and StartActivityForResault) and Intents (ActionGetContent).
I've read a few articles on Accessing data from another application but I did not fully understand the concept of 'application sandbox'.
Is it even possible? If so, can you give me an example or link to follow so I can see how it's done?
You can have a try with Xamarin.Essentials: Share to share data between apps.
Files:
var fn = "Attachment.txt";
var file = Path.Combine(FileSystem.CacheDirectory, fn);
File.WriteAllText(file, "Hello World");
await Share.RequestAsync(new ShareFileRequest
{
Title = Title,
File = new ShareFile(file)
});
I am working on a project where I am required to create multiple revit files, zip them all together and download the zip file as the output in design automation API for Revit.
My project is completely working as expected on my local machine, but when I upload my appbundle and execute my workitem, I get a "failedInstructions" status.
I am not aware whether it is possible to create multiple revit files in design automation API
Following is what I have tried:
This is my workitem json, you see I am passing a json array with sample data for the wall.
"arguments":{
"ElementParams":{
"url":"{'elementdata':[[{'Keys':'Sytème','Value':'Wall_1'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_2'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_3'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_4'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}]]}"
},
"resultFamily":{
"verb":"put",
"url":"https://storage.googleapis.com/bucketname/RevitObjects.zip?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"headers": {
"Authorization": "",
"Content-Type": "application/octet-stream"
}
}
}
In my code, I create a new document in a loop.
Document doc = app.NewProjectDocument(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + "DefaultTemplates.rte");
and save and close the current document
SaveAsOptions options = new SaveAsOptions();
options.OverwriteExistingFile = true;
doc.SaveAs(Assembly.GetExecutingAssembly().Location) + "\\" + fileName, options);
doc.Close(); //Closing the document
List<string> files = Directory.GetFiles(Assembly.GetExecutingAssembly().Location) + "\\").Where(a => a.Contains(Path.GetFileNameWithoutExtension(fileName)) && a.Split('.').Count() > 2).ToList();
foreach (var fl in files)
{
if (File.Exists(fl))
File.Delete(fl);
}
byte[] filebytes = File.ReadAllBytes(GlobalData.TemplatePath + "\\" + GlobalData.DestinationFile);
GlobalData.FileList.Add(GlobalData.DestinationFile, filebytes);
Here fileName is Wall_1, Wall_2, Wall_3 and Wall_4 which will appear in a loop
Here what I am doing is saving the created revit file example Wall_1
After closing the document, there is a copy of the file created example Wall_1.0001.rvt. I delete all the additional files created and keep one final version and add it to file bytes.
The data added in byte[] filebytes is then used to create a zip file of name "RevitObjects.zip"
After which I delete all the files.
This process works perfect on my local machine, but when I execute the workitem the log created states the following:
[07/03/2019 13:47:38] Error: An unexpected error happened during phase CoreEngineExecution of job.
[07/03/2019 13:47:38] Job finished with result FailedExecution
[07/03/2019 13:47:38] Job Status:
{
"status": "failedInstructions",
No other error message is stated in the log.
Let me know if multiple revit document creation is possible in design automation api for revit
Are we not allowed to perform delete operation in the working directory.
I tried by creating a folder and performing the same operation mentioned above, but I got an access denied message.
Let me know where I have gone wrong. Also any guidance to achieve the task will be appreciated
Thank you
First of all, Yes, multiple revit file output is supported by Design Automation system, it's very easy that you just need to set the parameter zip to "true" of your output, and within your plugin, save all your output file to a folder as you named in your output parameter of "localName", please check my blog post at https://forge.autodesk.com/blog/how-generate-dynamic-number-output-design-automation-revit-v3 for all the details.
You are not allowed to access any other folders except the current working folder, you can create subfolder under current working folder and put all your files there.
Hope it helps.
If the json argument is very large, you may provide a "inputParameters.json" as an input file, instead of passing everything in the WorkItem payload
Following code works to open an online URL. But it does NOT work for a web page (an HTML file) from local disk:
Question: It seems I'm missing something here. How can we make it for an html file from a local drive?
NOTE: No error is return, only the value of success variable is returned
false. I've verified that the HTML file exist by successfully opening it manually.
async void DefaultLaunch()
{
// The URI to launch. NOTE: It works only for online URLs, http://www.bing.com etc.
var uriTest = new Uri(#"file:///C:/DotNET2017/Test.html");
// Launch the URI
try
{
var success = await Windows.System.Launcher.LaunchUriAsync(uriTest);
}
catch(Exception ex)
{
string st = ex.Message;
}
}
Screenshot of uriTest value in debug mode:
You can't use "file///..." to lunch a local file.
you should use the launch file function and since it's an .html it will open in in the browser
first Get your IStorageFile from:
GetFileFromPathAsync
and then just launch your file:
Windows.System.Launcher.LaunchFileAsync(myStorageFile)
According to the documentation:
LaunchUriAsync(Uri)
Returns true if the default app for the URI scheme was launched; false otherwise.
So there must be an app registered to handle the scheme. There is no app in the system that is registered to handle the file: scheme, it is rather handled by the system itself which is not the app. So if you take this into account it returns false as expected.
You should rather use Launcher.LaunchFileAsync method. But please note that if you don't define the broadFileSystemAccess capability you will not be able to get the StorageFile out of the arbitrary path to send as the parameter for that method.
I am struggling to create my first UWP program in C#. I have run into a problem with reading/writing .rtf files and have not been able to work out a solution nor find one in the forums.
My program is an application for reading and writing a daily journal. The daily journal entries are displayed and edited in a RichEditBox. Next to the RichEditBox is a CalendarDatePicker.
When the CalendarDatePicker value changes, the program creates a file name based on the CalendarDatePicker date. For example, if the CalendarDatePicker's value was 7/22/2018, my program would turn that into the following file name: "2018_7_22.rtf" and then assign that to a string named fileName.
All of the above is working as desired. Here is the problem I am having:
When the value of the CalendarDatePicker changes, the program is supposed to immediately load the .rtf file (if it exists) from storage into the RichEditBox. And, when I press the SAVE button, the program is
supposed to save the RichEditBox contents to storage. Both reading and writing the file is supposed to
use the name derived from the CalendarDatePicker value rather than opening up a picker for either
opening or saving the file.
I have not been able to find any documentation about how to read and write a .rtf file for the RichEditBox without using a picker. I do not want to use a picker because I want that the given journal entry can only be read or written according to the file name that is based on the current value of the CalendarDatePicker.
Here is what I am trying to do:
String filePath = Windows.Storage.ApplicationData.Current.LocalFolder.toString;
// this returns error: "cannot convert method group 'ToString' to non-delegate type string"
String fileName = "2018_22_7.rtf"
// this is an example of a string my program would create according to the CalendarDatePicker's value.
At the end of my question is the code from the RichEditBox documentation. I want do away with the portion that uses the picker and replace the following line:
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
with:
Windows.Storage.StorageFile file = filePath + fileName;
Is it possible to do this or am I forced to use a picker with the RichEditBox?
I will deeply appreciate any help I can get in solving this problem. I am
melting from frustration! Thank you!
Here is the code from the RichEditBox documentation:
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.Pickers.FileSavePicker savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
// Dropdown of file types the user can save the file as
savePicker.FileTypeChoices.Add("Rich Text", new List<string>() { ".rtf" });
// Default file name if the user does not type one in or select a file to replace
savePicker.SuggestedFileName = "New Document";
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
// Prevent updates to the remote version of the file until we
// finish making changes and call CompleteUpdatesAsync.
Windows.Storage.CachedFileManager.DeferUpdates(file);
// write to file
Windows.Storage.Streams.IRandomAccessStream randAccStream =
await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
editor.Document.SaveToStream(Windows.UI.Text.TextGetOptions.FormatRtf, randAccStream);
// Let Windows know that we're finished changing the file so the
// other app can update the remote version of the file.
Windows.Storage.Provider.FileUpdateStatus status = await Windows.Storage.CachedFileManager.CompleteUpdatesAsync(file);
if (status != Windows.Storage.Provider.FileUpdateStatus.Complete)
{
Windows.UI.Popups.MessageDialog errorBox =
new Windows.UI.Popups.MessageDialog("File " + file.Name + " couldn't be saved.");
await errorBox.ShowAsync();
}
}
}
Universal Windows Apps (apps) can access certain file system locations by default.
Before window version 17134, if you don't want use a picker to access the file, your UWP app only can access the files in the Application install directory, Application data locations, Removable devices and some Locations that UWP apps can access with specific Capability such as the Music and Pictures Libraries. But you can not write into the Application install directory. In this case, you can try to save the file in above location except the Application install directory. Such as the Application data locations then you can create and get the file using the following code. Please see the File access permissions for more details.
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
//Createa file
StorageFile fileToSave = await localFolder.CreateFileAsync("YourFileName");
//Get file
StorageFile file = await localFolder.GetFileAsync("YourFileName");
If your app target on version 17134 and later, you can access all files that the user has access to using the broadFileSystemAccess Capability, this capability works for APIs in the Windows.Storage namespace, you can get the file using the path as following code, here is a sample.
StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(path);
I'm writing this Windows Form Application in Visual Studio 2010 using C#.
There is a Execute button on the form, the user will hit the button, the program will generate some files and are stored in the Output folder (which is created by the program using Directory.CreateDirectory())
I want to create an Archive folder to save the output files from previous runs.
In the beginning of each run, I try to move the existing Output folder to the Archive folder, then create a new Output folder. Below is the function I ran to move directory.
static void moveToArchive()
{
if (!Directory.Exists("Archive")) Directory.CreateDirectory("Archive");
string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
try
{
Directory.Move("Output", "Archive\\" + timestamp);
}
catch(Exception e)
{
Console.WriteLine("Can not move folder: " + e.Message);
}
}
The problem I ran into confuses me a lot...
There are some times that I can successfully move the Output folder to archive, but sometimes it fails.
The error message I got from catching the exception is Access to path 'Output' is denied.
I have checked that all the files in the Output folder are not in use. I don't understand how access is denied sometimes and not all the times.
Can someone explain to me and show me how to resolve the problem?
--Edit--
After HansPassant comment, I modified the function a little to get the current directory and use the full path. However, I'm still having the same issue.
The function now looks like this:
static void moveToArchive()
{
string currentDir = Environment.CurrentDirectory;
Console.WriteLine("Current Directory = " + currentDir);
if (!Directory.Exists(currentDir + "\\Archive")) Directory.CreateDirectory(currentDir + "\\Archive");
string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
try
{
Directory.Move(currentDir + "\\Output", currentDir + "\\Archive\\" + timestamp);
}
catch(Exception e)
{
Console.WriteLine("Can not move folder: " + e.Message);
}
}
I printed out the current directory and it is just as what I was expecting, and I'm still having trouble using full path. Access to path 'C:\Users\Me\Desktop\FormApp\Output' is denied.
--Edit--
Thank you everyone for answering and commenting.
I think some of you miss this part so I'm going stress it a bit more.
The Directory.Move() sometimes work and sometimes fails.
When the function succeed, there was no problem. Output folder is moved to Archive
When the function fails, the exception message I got was Access to path denied.
Thank you all for the replies and help. I have figured out what the issue was.
It is because there was a file that's not completely closed.
I was checking the files that were generated, and missed the files the program was reading from.
All files that were generated were closed completely. It was one file I used StreamReader to open but didn't close. I modified the code and am now not having problem, so I figure that's were the issue was.
Thanks for all the comments and answers, that definitely help me with thinking and figuring out the problem.
See http://windowsxp.mvps.org/processlock.htm
Sometimes, you try to move or delete a file or folder and receive access violation or file in use - errors. To successfully delete a file, you will need to identify the process which has locked the file. You need to exit the process first and then delete the particular file. To know which process has locked a file, you may use one of the methods discussed in this article.
Using Process Explorer - download from http://download.sysinternals.com/files/ProcessExplorer.zip
Process Explorer shows you information about which handles and DLLs processes have opened or loaded.
Download Process Explorer from Microsoft site and run the program.
Click the Find menu, and choose Find Handle or DLL...
Type the file name (name of the file which is locked by some process.)
After typing the search phrase, click the Search button
You should see the list of applications which are accessing the file.
I bumped on the same problem recently. Using PE I'd figured that only process using that particular directory was explorer.exe. I'd opened few windows with explorer, one pointing to parent directory of one that I was about to move.
It appeared, that after I visited that sub-folder and then returned (even to root level!) the handle was still being kept by explorer, so C# was not able to modify it in any way (changing flags, attributes etc.).
I had to kill that explorer window in order to made C# operate properly.
File.SetAttributes(Application.dataPath + "/script", FileAttributes.Normal);
Directory.Move(Application.dataPath + "/script", Application.dataPath + "/../script");
This fixed my problem.
Try this:
If this does not solve, maybe check/change the antivirus, or the some other program is locking some file in or the folder.
static object moveLocker = new object();
static void moveToArchive()
{
lock (moveLocker)
{
System.Threading.Thread.Sleep(2000); // Give sometime to ensure all file are closed.
//Environment.CurrentDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
string applicationPath = System.AppDomain.CurrentDomain.BaseDirectory;
string archiveBaseDirectoryPath = System.IO.Path.Combine(applicationPath, "Archive");
if (!Directory.Exists(archiveBaseDirectoryPath)) Directory.CreateDirectory(archiveBaseDirectoryPath);
String timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
String outputDirectory = System.IO.Path.Combine(Environment.CurrentDirectory, "Output");
String destinationTS = System.IO.Path.Combine(archiveBaseDirectoryPath, timestamp);
try
{
Directory.Move(outputDirectory, destinationTS);
}
catch (Exception ex)
{
Console.WriteLine("Can not move folder " + outputDirectory + " to: " + destinationTS + "\n" + ex.Message);
}
}
}
I had the same problem, it failed sometimes but not all the time. I thought I'd wrap it in a Try Catch block and present the user with an Access Denied message and once I wrapped it in the Try Catch block it stopped failing. I can't explain why.
If existingFile.FileName <> newFileName Then
Dim dir As New IO.DirectoryInfo(existingFile.FilePath)
Dim path As String = System.IO.Path.GetDirectoryName(dir.FullName)
newFileName = path & "\" & newFileName
File.SetAttributes(existingFile.FilePath, FileAttributes.Normal)
Try
IO.File.Move(existingFile.FilePath, newFileName)
Catch ex As Exception
End Try
End If
I had a similar problem. Renamed many directories in a loop when following the certain template. From time to time the program crashed on different directories. It helped to add a sleep thread before Directory.Move. I need to create some delay.
But it slows down the copying process.
foreach (var currentFullDirPath in Directory.GetDirectories(startTargetFullDirectory, "*", SearchOption.AllDirectories))
{
var shortCurrentFolderName = new DirectoryInfo(currentFullDirPath).Name.ToLower();
if (shortCurrentFolderName.Contains(shortSourceDirectoryName))
{
// Add Thread.Sleep(1000);
Thread.Sleep(1000);
var newFullDirName = ...;
Directory.Move(currentFullDirPath, newFullDirName);
}
}