GeckoFx 60 Download + Open File - c#

I want the embedded GeckoFx 60 to download a file and then open it with the default app.
By default it seems like GeckoFx does not do anything when the client requests to download a file.
To handle the download request I enabled an event handler:
LauncherDialog.Download += LauncherDialog_Download;
Then I found two possibilities to download or open a file via the HelperAppLauncher.
This one saves the requested file to a temp folder and opens it:
private void LauncherDialog_Download(object sender, LauncherDialogEvent e)
{
// direct open, file will be stored in C:\Users\Username\AppData\Local\Temp\
e.HelperAppLauncher.LaunchWithApplication(null, false);
}
I did not find a way to configure the save path. This other possible solution allows me to set the save path myself:
private void LauncherDialog_Download(object sender, LauncherDialogEvent e)
{
nsILocalFileWin objTarget = Xpcom.CreateInstance<nsILocalFileWin>("#mozilla.org/file/local;1");
var downloadPath = #Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\CustomFolder\\" + e.Filename;
using (nsAString tmp = new nsAString(downloadPath))
{
objTarget.InitWithPath(tmp);
}
e.HelperAppLauncher.SaveToDisk(objTarget, false);
Task.Run(() =>
{
Thread.Sleep(3000);
System.Diagnostics.Process.Start(downloadPath);
});
}
That Task.Run() works, but is quite ugly and error prone. I could not find a better solution though. I tried adding a WebProgressListener like this:
var webProgressListener = new WebProgressListener();
webProgressListener.OnStatusChangeCallback+= OnStatusChangeCallback;
e.HelperAppLauncher.SetWebProgressListener(webProgressListener);
webProgressListener.IsListening is true, but my method OnStatusChangeCallback is never called. Am I doing something wrong? Is there a newer way?
How can I get notified that the download is completed?
Or how do I set the path for LaunchWithApplication?

Not the best solution but here is my solution :
Task.Run(() =>
{
long sizefirst = 0;
while (true)
{
Thread.Sleep(1000);
if (File.Exists(downloadPath))
{
if (sizefirst == 0)
{
sizefirst = new FileInfo(downloadPath).Length;
continue;
}
long len_now = new FileInfo(downloadPath).Length;
if (len_now > sizefirst)
{
sizefirst = len_now;
continue;
}
else
{
System.Diagnostics.Process.Start(downloadPath);
break;
}
}
}
});

Related

How to rename downloaded file using selenium c# webdriver

In my web application which has some automation process to download the files from the website. To achieve that I used selenium c# chrome driver.
Sample code snippets
public void Download(string name,string pass)
{
try
{
ChromeOptions options = new ChromeOptions();
options.AddArguments("--proxy-server=http://192.168.5.62:8095");
options.AddUserProfilePreference("safebrowsing.enabled", true);
options.AddUserProfilePreference("disable-popup-blocking", "true");
options.AddUserProfilePreference("download.default_directory",#"C:\Temp");
using (var driver = new ChromeDriver(HostingEnvironment.ApplicationPhysicalPath, options)){
//driver.findElement(By.xpath("//a/u[contains(text(),'Re-Submit')]")).click();
driver.FindElementById("save").Click();
}
}
catch (Exception ex)
{
Logger.LogWriter("LAS", ex, "CusDataLogic", "Download");
}
}
above code (not complete code) works fine and save file properly. But I need to rename that file downloading or after download. Have any possible way to rename that file?
Edited: Please don't mark this as a duplicate. I'm asking for C#, not python. I saw that question too. but it not helped to me
watching directory is not always good, because sometime saved filename is different than filename in URL.
go to chrome download page and loop until all download complete, you can see below how to select special element #shadow-root with CSS selector
using (var driver = new ChromeDriver(HostingEnvironment.ApplicationPhysicalPath, options)))
{
//driver.findElement(By.xpath("//a/u[contains(text(),'Re-Submit')]")).click();
driver.FindElementById("save").Click();
// wait 5 second until download started
Thread.Sleep(5000);
// Go to chrome download page
driver.Navigate().GoToUrl("chrome://downloads/");
string oldName = "";
bool downloadcomplete = false;
string cssNames = "downloads-manager /deep/ downloads-item /deep/ [id='name']";
string cssDlProgress = "downloads-manager /deep/ downloads-item /deep/ [class*='show-progress']";
while (!downloadcomplete)
{
var progressElements = driver.FindElements(By.CssSelector(cssDlProgress));
// check until no download progress bar
if (progressElements.Count() == 0)
{
oldName = driver.FindElement(By.CssSelector(cssNames)).Text;
downloadcomplete = true;
}
else
{
// download still in progress, wait.
Thread.Sleep(1000);
}
}
// download complete
// remove downloaded file
driver.FindElement(By.CssSelector("downloads-manager /deep/ downloads-item /deep/ [id='remove']")).Click();
// rename
File.Move(#"C:\Temp\" + oldName, #"C:\Temp\newname.ext");
}
The Snippet Below Will wait Until File downloaded Then return FilePath I Wrote this as an extension method :
public static string GetDonwloadedFileName(this IWebDriver driver)
{
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("window.open()");
var allWinowHandles = driver.WindowHandles;
foreach (var winHandle in allWinowHandles)
{
//Switch to second window
if (!winHandle.Equals(driver.CurrentWindowHandle))
{
driver.SwitchTo().Window(winHandle);
}
}
// navigate to chrome downloads
driver.Navigate().GoToUrl("chrome://downloads");
IJavaScriptExecutor downloadWindowExecutor = (IJavaScriptExecutor)driver;
// Wait for Download till 100% completion
double percentageProgress = (double)0;
while (percentageProgress != 100)
{
try
{
percentageProgress = (long)downloadWindowExecutor.ExecuteScript("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('#progress').value");
Thread.Sleep(100);
}
catch (Exception)
{
break;
}
}
string fileTitle = (string)downloadWindowExecutor.ExecuteScript("return document.querySelector('downloads-manager').shadowRoot.querySelector('#downloadsList downloads-item').shadowRoot.querySelector('#show').getAttribute('title')");
downloadWindowExecutor.ExecuteScript("window.close()");
return fileTitle;
}
Then You can use file Path to rename it to whatever you need

DownloadFileAsync 'blocks' in c#?

When I use DownloadFileAsync, it seems to 'block' something. I need the program to be able to download more strings while the file is downloading (downloading a file, but user is still able to search a directory for links to download more files).
The UI is not 100% being blocked, but when the user clicks the 'search' button it doesn't work properly, nor do clicks in the DataGridView get handled. The search button however clears the DataGridView as programmed, but the await thing that I wrote to download the directory as a string (asynchronously with DownloadStringTaskAsync) does not work. However, when the download finishes, the search finally goes through and then populates the DataGridView, which seems like very abnormal behavior to me.
When I comment out the DownloadFileAsync, everything is able to perform normally again. I have also tried to comment out the event handlers that I have put in place, but this also does not fix the issue. I am not sure, thanks for any help.
Some code snippets:
Downloading the file:
var bmclient = new WebClient();
bmclient.DownloadFileAsync(new Uri(downloadURL), Path.Combine(Application.StartupPath, originalFileName + ".nexd"));
bmclient.DownloadProgressChanged += (o, e) =>
{
int rowIndex = -1;
DataGridViewRow row = form1.dataGridView2.Rows
.Cast<DataGridViewRow>()
.Where(r => r.Cells[0].Value.ToString().Equals(setID))
.First();
rowIndex = row.Index;
MethodInvoker action = () => form1.dataGridView2[2, rowIndex].Value = e.ProgressPercentage.ToString() + "%";
form1.BeginInvoke(action);
};
Searching the directory, which is being called by a button on the main form:
public static async Task<string> GetBloodcatSearch(string query)
{
var return_data = string.Empty;
try
{
using (var client = new WebClient())
{
return return_data = await client.DownloadStringTaskAsync(new Uri("directory/" + query));
}
}
catch (Exception e)
{
return null;
}
}

Anti virus interfering with auto-updater for C# application

I've been trying to create an updater app for my .NET application that gets called when an update is detected using a text file that includes the version info. I've created the said updater but it has some problems. When the file is downloaded, it seems like the anti virus software corrupts the file and it can't be opened. Sometimes the updater doesn't run at all and throws an exception ("The underlying connection was closed: The connection was closed unexpectedly.") which seems to also be caused by the local anti virus software. I figured maybe I could download the file in binary format and create the executable locally, but I am not completely sure on how I would do that (or if it would even work). I am still very much a beginner in a lot of areas. So my question is.. how can I efficiently download an update for my application without triggering the anti- virus?
My code:
public Updater()
{
InitializeComponent();
DownloadInfo.RemoteURI = "http://mywebserver.com/Application.exe";
DownloadInfo.NewExecutableName = "update.exe";
DownloadInfo.ExecutableName = "Application.exe";
DownloadInfo.LocDest = AppDomain.CurrentDomain.BaseDirectory;
InvokeUpdate();
}
private void InvokeUpdate()
{
Thread thr = new Thread(() => GetUpdate());
thr.Start();
}
private void GetUpdate()
{
Process[] proc = Process.GetProcessesByName("Application");
if (proc.Length != 0)
proc[0].Kill();
Util.DownloadFile(new Uri(DownloadInfo.RemoteURI), DownloadInfo.LocDest + DownloadInfo.NewExecutableName);
if (File.Exists(DownloadInfo.LocDest + DownloadInfo.ExecutableName))
File.Replace(DownloadInfo.LocDest + DownloadInfo.NewExecutableName, DownloadInfo.LocDest + DownloadInfo.ExecutableName, DownloadInfo.LocDest + "backup.exe");
else
File.Move(DownloadInfo.LocDest + DownloadInfo.NewExecutableName, DownloadInfo.LocDest + DownloadInfo.ExecutableName);
try
{
File.Delete(DownloadInfo.LocDest + "backup.exe");
}
catch { }
try
{
Process.Start(DownloadInfo.LocDest + DownloadInfo.ExecutableName);
}
catch { };
Invoke((MethodInvoker)(() => this.Close()));
}
And my DownloadFile method from my util class..
public static void DownloadFile(Uri remoteURI, string localDest)
{
try
{
using (WebClient webclient = new WebClient())
{
webclient.DownloadFile(remoteURI, localDest);
}
}
catch { }
}

C# code to change browser download options

I am trying to do following with c#.
1) Open Firefox Browser-->Tools-->Options-->General Tab--->Downloads--->Always ask me where to save file.
I want to do this whole process in my application with c#. I want that when download window opens, the radio button in "Always ask me where to save file" option gets checked automatically.
I have tried from various links, but all is in vain.
Here is the full code, console application.
Summary: preferences file is located in application roaming folder, something like this on windows 7:
C:\Users\MYNAME\AppData\Roaming\Mozilla\Firefox\Profiles\d9i9jniz.default\prefs.js
We alter this file so that it includes "user_pref("browser.download.useDownloadDir", false);"
Restart firefox, and done. Only run this application when firefox is not running.
static void Main(string[] args)
{
if (isFireFoxOpen())
{
Console.WriteLine("Firefox is open, close it");
}
else
{
string pathOfPrefsFile = GetPathOfPrefsFile();
updateSettingsFile(pathOfPrefsFile);
Console.WriteLine("Done");
}
Console.ReadLine();
}
private static void updateSettingsFile(string pathOfPrefsFile)
{
string[] contentsOfFile = File.ReadAllLines(pathOfPrefsFile);
// We are looking for "user_pref("browser.download.useDownloadDir", true);"
// This needs to be set to:
// "user_pref("browser.download.useDownloadDir", false);"
List<String> outputLines = new List<string>();
foreach (string line in contentsOfFile)
{
if (line.StartsWith("user_pref(\"browser.download.useDownloadDir\""))
{
Console.WriteLine("Found it already in file, replacing");
}
else
{
outputLines.Add(line);
}
}
// Finally add the value we want to the end
outputLines.Add("user_pref(\"browser.download.useDownloadDir\", false);");
// Rename the old file preferences for safety...
File.Move(pathOfPrefsFile, Path.GetDirectoryName(pathOfPrefsFile) + #"\" + Path.GetFileName(pathOfPrefsFile) + ".OLD." + Guid.NewGuid().ToString());
// Write the new file.
File.WriteAllLines(pathOfPrefsFile, outputLines.ToArray());
}
private static string GetPathOfPrefsFile()
{
// Get roaming folder, and get the profiles.ini
string iniFilePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + #"\Mozilla\Firefox\profiles.ini";
// Profiles.ini tells us what folder the preferences file is in.
string contentsOfIni = File.ReadAllText(iniFilePath);
int locOfPath = contentsOfIni.IndexOf("Path=Profiles");
int endOfPath = contentsOfIni.IndexOf(".default", locOfPath);
int startOfPath = locOfPath + "Path=Profiles".Length + 1;
int countofCopy = ((endOfPath + ".default".Length) - startOfPath);
string path = contentsOfIni.Substring(startOfPath, countofCopy);
string toReturn = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + #"\Mozilla\Firefox\Profiles\" + path + #"\prefs.js";
return toReturn;
}
public static bool isFireFoxOpen()
{
foreach (Process proc in Process.GetProcesses())
{
if (proc.ProcessName == "firefox")
{
return true;
}
}
return false;
}
What have you tried?
Firefox settings are stored in your profile, so I'd guess you can change the contents of the given file. Type about:config to find the setting you're looking for, I guess it's in the browser.download tree, alter it (after you made sure the browser isn't running) and you should be good to go.

FileUpload watin

I need to upload a file in a website using watin. The problem is that setting the direction of the file, like this:
browser.FileUpload(Find.ById("ctl00_cpContent_FileUpload1")).Set(DIRECCION_XML + "plantilla.txt");
doesnt work. Because this, I need to handle the windows popup that appear and fill the direction of the file to upload. I dont know how to do it... I were searching info of FileUploadHandler, but i cant get it.
There is more option than that? Pls, help me with a possible code to do it.
Really thanks
The FileUploadHandler works great. I have it running in production mode with thousands of files being uploaded every day and I haven't had any issues with it so far.
This is the way it needs to be implemented:
EDIT: (I forgot to include the uploadDialog object)
IntPtr hwndTmp = (IntPtr)FindWindow("#32770","Select file(s) to upload"); // or whatever the window text says when you are opening that upload window)
Window uploadDialog = new Window(hwndTmp);
UploadFileDialogHandler uploadFile = new UploadFileDialogHandler(_toBeSent.FileToSent);
_browser.AddDialogHandler(uploadFile);
uploadFile.HandleDialog(uploadDialog);
uploadFile = null;
That will take care of the upload process. when you need to upload the file just those lines will take care of everything (loop thru all open dialogs, find the right one, find the text field, enter the name for you and click the Ok button. On top of that you need to create another class that will be the UploadFileDialogHandler:
public class UploadFileDialogHandler : BaseDialogHandler
{
private const int WmSettext = 0x000C;
private string fileName;
private bool _processed = false;
public override bool HandleDialog(Window window)
{
var button = GetOpenButton(window);
if (button != null)
{
if (_processed == false)
{
var fileNameHandle = NativeMethods.GetChildWindowHwnd(window.Hwnd, "Edit");
var fileNameHwnd = new Hwnd(fileNameHandle);
fileNameHwnd.SetFocus();
_processed = true;
//MessageBox.Show("About to send " + fileName);
fileNameHwnd.SendString(fileName);
button.Click();
}
return true;
}
else
{
return false;
}
}
public UploadFileDialogHandler(string file)
{
fileName = "";
fileName = file;
//MessageBox.Show("Setting filename: " + fileName);
}
public override bool CanHandleDialog(Window window)
{
return GetOpenButton(window) != null;
}
private WinButton GetOpenButton(Window window)
{
var windowButton = new WindowsEnumerator().GetChildWindows(window.Hwnd, w => w.ClassName == "Button" && new WinButton(w.Hwnd).Title == "&Open").FirstOrDefault();
if (windowButton == null)
return null;
else
return new WinButton(windowButton.Hwnd);
}
}
}
You can just copy and paste that class inside your program and with the 4 lines of code above it will take care of the rest for you. In case you need more information there's a good amount of information on the WatIn file source code but it could be a little bit challenging to follow if you don't understand the Windows API.
Hope this helps.
This command work for me fine: browser.FileUpload(Find.ById("FormImage")).Set("C:\\Pictures\\11.PNG");
Try it

Categories

Resources