How to handle SaveAs PopUp in IE in .Net - c#

I have some program that login to webSite and trying to download file,right now i am using WatIn and User32 FindWindowEx to find the SaveAs dialog and send PostMessage with tab and enter to press Save button
MainPopUp = browserToRun.hWnd.ToInt32();
int currChild = FindWindowEx(MainPopUp, 0, ClassName, WindowName);
PostMessage(currChild, WM_KEYDOWN, VK_TAB, 2);
PostMessage(currChild, WM_KEYDOWN, VK_ENTER, 2);
this works,but not all the time.
This is secured webSite sow i cant see the DownloadUrl and i can't use
[DllImport("urlmon.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern Int32 URLDownloadToFile(Int32 pCaller, string szURL, string szFileName, Int32 dwReserved, Int32 lpfnCB);
int response = URLDownloadToFile(0, browserToRun.Button(Find.ById("btnExcelExport")).Url, #"C:\Users\vladimirp\VN.xls", 0, 0);
I need some mothed that can handle this PopUp dialog,and with out UI,because the User Pc can be locked,sow this have to work even if user windows is lock.
*I dont see the downloadURL sow WebClient.DownloadFileAsync(url,Path) will not work
Do any one know how to handle IE save dialog? .Net c#

Please refer to Handling File Download PopUp post. However the solution in that post requires an active session of desktop.

Related

Clear web browser cookies winforms C#

How I can clear cookies for web browser control winforms C# , is there any way to clear cookies problematically in winforms web browser control
You can disable cache (including cookies) before navigating to the site. To do so, you can use InternetSetOption API function and set the value of INTERNET_OPTION_SUPPRESS_BEHAVIOR(81) option to INTERNET_SUPPRESS_COOKIE_PERSIST(3) value.
Example
The following example, works like starting a new session. While I've logged in to the outlook.com on my machine, but when I open this application and browse outlook.com after disabling cookies and cache, it works like starting a new session and I need to login to outlook.com:
//using System.Runtime.InteropServices;
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption,
IntPtr lpBuffer, int dwBufferLength);
private void Form1_Load(object sender, EventArgs e)
{
var ptr = Marshal.AllocHGlobal(4);
Marshal.WriteInt32(ptr, 3);
InternetSetOption(IntPtr.Zero, 81, ptr, 4);
Marshal.Release(ptr);
webBrowser1.Navigate("https://outlook.com");
}
To find more information about these flags, take a look at Windows Internet Option Flags.
Note: You can find a VB.NET version of this answer, here in my other post.

Get Open Process Windows Textbox with C#

I need to find open process or application textbox and change its value. But i wanna do it with c# way. If anyone knows could you please share with me? Or do i have to use c++ and how?
Thanks for your advices.
Like another said, UIAutomation is the way to go. http://msdn.microsoft.com/en-us/library/ms753107.aspx
The following code will open Notepad.exe, open its File dialog, then type in some text into the file name field.
Process notepad = Process.Start("notepad");
Thread.Sleep(5000);
SendKeys.SendWait("^o"); //ctrl+o to open the File Dialog
var notepadTextBox = AutomationElement.RootElement.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, "1148"));
object valuePattern = null;
if (notepadTextBox.TryGetCurrentPattern(ValuePattern.Pattern, out valuePattern))
{
((ValuePattern)valuePattern).SetValue("THERE YOU GO"); // this text will be entered in the textbox
}
else
{
//ERROR
}
So this is really a combination of sending keystrokes to control the UI (bring up the File Open dialog) & UIAutomation, but you could change it to drive the Menu like a user would if you need to.
Also you might be wondering where the magic string "1148" comes from - that is the "Automation Id" of the file name entry field in Notepad. I used inspect.exe (included in the Windows SDK) to find the automation Id, you will need that for your application to see its AutomationIds, if it has any.
One way to do this is if the application is out of your control in terms of using libraries and wrappers:
Process[] Procs = Process.GetProcessesByName("NameofProcess");
that will give you the process in question. Now this is where it will get tricky and depend upon what exactly you need to do.
You would eventually need to find where the strings are stored in memory, you could use a memory profiler to do this or something like CheatEngine to find the values, not going to get into what you use CheatEngine for or how you use it, but it is just a simple way of finding memory locations.
You could then read/write to the memory locations using something like this:
[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [In, Out] byte[] buffer, UInt32 size, out IntPtr lpNumberOfBytesRead);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] lpBuffer, uint nSize, out int lpNumberOfBytesWritten);
public static byte[] ReadMem(IntPtr MemAddy, uint bytestoread, Process Proc)
{
//
//Create new Memory buffer and pointer to that buffer
//
byte[] buffer = new byte[bytestoread];
IntPtr bufferptr;
//
//Read Process Memory and output to buffer
//
ReadProcessMemory(Proc.Handle, MemAddy, buffer, bytestoread, out bufferptr);
//
//Return the buffer
//
return buffer;
}
public static bool WriteMem(IntPtr MemAddy, byte[] buffer, Process Proc)
{
int NumWriten;
WriteProcessMemory(Proc.Handle, MemAddy, buffer, (uint)buffer.Length, out NumWriten);
if (NumWriten != buffer.Length)
{
return false;
}
else return true;
}
These two functions would allow you to read and write to some arbitrary processes memory locations.
if you want the window in question you could use:
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
Like So:
IntPtr HWND = FindWindow(null, "WinName");
Which will give you the handle to the window in question.
Another way to do this would be to find the window and then pass some events to it, like bring the window to focus and then tab through the text boxes programmatically. However without more information about what exactly you are trying to do I am not sure what else to say here.
The tool you are looking for is UI Automation. It will let you see the other program's controls and send text to those controls. I have done this in the past where I had to export data from a corrupted database and I had to click OK on a dialog every time it hit a corrupted record.
The topic is too complex to go in to depth on how to do it in the space of a SO answer, but here is a tutorial I found on CodePlex that goes over how to do it.
There are also 3rd party wrapper libraries to make it easier to do. My personal favorite is White.

User32 API custom PostMessage for automatisation

I want to automate a program called Spotify from C#, the best way (I think) to do this is by triggering fake keypresses. I want to program to pause playback, and I don't know enough about this stuff to find another way than keypresses. So I use Visual Studio's Spy++ to see what message Spotify gets when pressing the play button on my keyboard, I copy the data from that message into my Console Application and run it, when I run I can see the PostMessage in Spy++'s Message Logging, so this is working but it doesn't pause/play my music. I guess this is because I also have to send another PostMessage with another destination, but how do I know what else to send?
Post Message call:
MessageHelper.PostMessage((int)hwndSpotify, 0x100, 0x000000B3, 0x01000001);
I hope someone is familiar with this and can help me out.
To automate Spotify, first you have to get the handle of the window with the following class name: SpotifyMainWindow (using FindWindow()).
Then, you can use the SendMessage() method to send a WM_APPCOMMAND message to the Spotify's window.
Following a simple code to do that:
internal class Win32
{
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
internal class Constants
{
internal const uint WM_APPCOMMAND = 0x0319;
}
}
public enum SpotifyAction : long
{
PlayPause = 917504,
Mute = 524288,
VolumeDown = 589824,
VolumeUp = 655360,
Stop = 851968,
PreviousTrack = 786432,
NextTrack = 720896
}
For instance, to play or pause the current track:
Win32.SendMessage(hwndSpotify, Win32.Constants.WM_APPCOMMAND, IntPtr.Zero, new IntPtr((long)SpotifyAction.PlayPause));
Pressing the "play buttion" results in a virtual key code - for an official list see http://msdn.microsoft.com/en-us/library/dd375731%28v=VS.85%29.aspx .
There you find for example VK_VOLUME_UP VK_MEDIA_PLAY_PAUSE VK_ZOOM .
Even some Remotes translate to these codes to be as compatible as possible with existing software.
These were introduced back in the day when Windows ME (!) came out and are still in use - at least when I checked the registry of my Windows 2008 R2 !
Basically Windows translates certain VK* into WM_APPCOMMAND messages with certain codes which the applications listen to...
If the key has something to do with launching an app to do (i.e. Mail, Browser etc.) then the magic happens via Windows Explorer which reads the mapping (either by association or direct exec) from the registry at Software\ Microsoft\ Windows\ CurrentVersion\ Explorer\ AppKey - either HKLM or HKCU.
Some links with old but as it seems still valid information:
http://msdn.microsoft.com/en-us/windows/hardware/gg463446.aspx
http://msdn.microsoft.com/en-us/windows/hardware/gg462991
http://msdn.microsoft.com/en-us/windows/hardware/gg463372

How to read local cookies

I have an ASP.NET web application that stores a HTTP cookie when a certain action has been performed (e.g. a link has been clicked). Now, I am creating a standalone C# app which needs to watch the cookies folder and recognise when a cookie entry has been created by my web application and read the contents of the cookie.
Could anyone please guide me on how to do this in C# or show sample code?
I can't help thinking that is simply the wrong way to do it... and it reaks of security abuse. Is there no better way you could do this? Perhaps hosting the page in a WebBrowser control and using an ObjectForScripting object (of your devising) so you can talk to the C# app from javascript?
You should be able to PInvoke InternetGetCookie.
[DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)]
protected static extern bool InternetGetCookie(
string url,
string name,
StringBuilder cookieData,
ref int length);
You can then call InternetGetCookie like below assuming you are using the Rest Starter Kit.
StringBuilder cookieBuffer = new StringBuilder(1024);
int size = 1024;
bool bSuccess = InternetGetCookie("domain uri", "cookie_name", cookieBuffer, ref size);
if (!bSuccess)
{
Int32 err = Marshal.GetLastWin32Error();
//log err
}
if (cookieBuffer != null && (cookieBuffer.Length > 0))
{
Microsoft.Http.Headers.Cookie cookie = Microsoft.Http.Headers.Cookie.Parse(cookieBuffer.ToString());
HeaderValues<Microsoft.Http.Headers.Cookie> requestCookies = new HeaderValues<Microsoft.Http.Headers.Cookie>();
requestCookies.Add(cookie);
}
There is another thing you can do that could cause your local application to be invoked by the clicking of a link. You'd need to register an application to a URL protocol as seen here. Here is a tutorial and sample app you can look at.
Doing this has it's own set of security implications. However, it is an easy way to invoke your application from the web page and it allows you to pass data via command line params.

Activate existing browser window with given URL from C# application (without triggering reload)

From a C# application I want to activate (brint to front) a site that is already open in the users default browser. I want to do this in a browser agnostic way.
The difficult part (for me at least) is that I do not want the browser to open a new tab and the browser must not reload the page if it is already open.
I can open the URI in the default browser with
System.Diagnostics.Process.Start("http://foo.example");
But the exact behaviour depends on the users default browser (IE6 seems to reuse the current topmost browser window, Google Chrome will always open a new tab and so on)
Another approach I tried was to enumerate all open Windows and find the one I want based on the window title (making the assumption that most browsers set the window title to the title of the currently open page)
public delegate bool EnumThreadWindowsCallback(int hWnd, int lParam);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);
[DllImport("user32.dll")]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
private bool FindWindowByRx(int hWnd, int lParam)
{
Regex pattern = new Regex("Example Title of Page", RegexOptions.IgnoreCase);
StringBuilder windowTitle = new StringBuilder(256);
GetWindowText(hWnd, windowTitle, 255);
if (pattern.IsMatch(windowTitle.ToString()))
{
SetForegroundWindow(new IntPtr(hWnd));
return false; // abort search
}
else
{
return true; // keep on searching
}
}
using it with:
EnumWindows(new EnumThreadWindowsCallback(FindWindowByRx), new IntPtr());
This does what I need it to do, but feels very brittle and hackish, and is probably slow.
Is there a better, more elegant way?
This will work, IF the user has that site active in their browser. If they're using a tabbed browser, and the site is open, but not in the selected tab, I don't believe you will ever find the browser window. (EnumWindows only enumerates top-level windows).
If the user's started a new tab, you'll end up not finding it, and (likely) starting a second copy of the site in a new tab.
Personally, if you really need to restrict to a single browser instance, I would consider whether its possible to embed the browser in your application instead of using the default browser. If this can be made a GUI element in your application using a browser control, you'd have much more control and be able to avoid this type of workaround.

Categories