Implement IDownloadManger for my application only - c#

I'm using the WebBrowsercontrol in a WinForms application and have implemented my own download manager by following the instructions here.
My custom download manager works, but also overrides the download manager for Internet Explorer, too*. Is there a way to only have the custom download manager appear when my application is running? Or is there a way to unregistered it when my application closes?
*I appreciate that is precisely the point of implementing IDownloadManager, and the WebBrowser control is just, essentially, Internet Explorer (which is why I have gone down this route). The custom download manager provides exactly what I need, by allowing me to know what has been downloaded and where it has been downloaded to.

After weeks of research, I have finally managed to piece it together. Posting this here in the hopes that it will save someone the trauma I've been through.
IServiceProvider.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace BrowserExample
{
[ComImport, ComVisible(true)]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IServiceProvider
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryService(
[In] ref Guid guidService,
[In] ref Guid riid,
[Out] out IntPtr ppvObject);
}
}
IDownloadManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace BrowserExample
{
[ComVisible(false), ComImport]
[Guid("988934A4-064B-11D3-BB80-00104B35E7F9")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDownloadManager
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Download(
[In, MarshalAs(UnmanagedType.Interface)] IMoniker pmk,
[In, MarshalAs(UnmanagedType.Interface)] IBindCtx pbc,
[In, MarshalAs(UnmanagedType.U4)] UInt32 dwBindVerb,
[In] int grfBINDF,
[In] IntPtr pBindInfo,
[In, MarshalAs(UnmanagedType.LPWStr)] string pszHeaders,
[In, MarshalAs(UnmanagedType.LPWStr)] string pszRedir,
[In, MarshalAs(UnmanagedType.U4)] uint uiCP);
}
}
DownloadManagerImplementation.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices.ComTypes;
using System.Windows.Forms;
namespace BrowserExample
{
[System.Runtime.InteropServices.ComVisible(true)]
[System.Runtime.InteropServices.Guid("bdb9c34c-d0ca-448e-b497-8de62e709744")]
public class DownloadManagerImplementation : IDownloadManager
{
/// <summary>
/// Return S_OK (0) so that IE will stop to download the file itself.
/// Else the default download user interface is used.
/// </summary>
public int Download(IMoniker pmk, IBindCtx pbc, uint dwBindVerb, int grfBINDF,
IntPtr pBindInfo, string pszHeaders, string pszRedir, uint uiCP)
{
// Get the display name of the pointer to an IMoniker interface that specifies
// the object to be downloaded.
string name = string.Empty;
pmk.GetDisplayName(pbc, null, out name);
if (!string.IsNullOrEmpty(name))
{
Uri url = null;
bool result = Uri.TryCreate(name, UriKind.Absolute, out url);
if (result)
{
//Implement your custom download manager here
//Example:
//WebDownloadForm manager = new WebDownloadForm();
//manager.FileToDownload = url.AbsoluteUri;
//manager.Show();
MessageBox.Show("Download URL is: " + url);
return 0; //Return S_OK
}
}
return 1; //unspecified error occured.
}
}
ExtendedBrowser.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace BrowserExample
{
public class ExtendedBrowser : WebBrowser
{
protected sealed class WebBrowserControlSite : WebBrowser.WebBrowserSite, IServiceProvider
{
DownloadManagerImplementation manager;
public WebBrowserControlSite(WebBrowser host)
: base(host)
{
manager = new DownloadManagerImplementation();
}
public int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject)
{
Guid SID_SDownloadManager = new Guid("988934A4-064B-11D3-BB80-00104B35E7F9");
Guid IID_IDownloadManager = new Guid("988934A4-064B-11D3-BB80-00104B35E7F9");
if ((guidService == IID_IDownloadManager && riid == IID_IDownloadManager))
{
ppvObject = Marshal.GetComInterfaceForObject(manager, typeof(IDownloadManager));
return 0; //S_OK
}
ppvObject = IntPtr.Zero;
return unchecked((int)0x80004002); //NON_INTERFACE (use the default, please)
}
}
protected override WebBrowserSiteBase CreateWebBrowserSiteBase()
{
return new WebBrowserControlSite(this);
}
}
}
To use it, just instantiate the ExtendedBrowser.
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace BrowserExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
var browser = new ExtendedBrowser();
this.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
browser.Navigate("http://stackoverflow.com");
}
}
}

Related

How do I set the background of a Windows form to be the same as the user's Desktop wallpaper?

I need to set the background of a Windows form to the user's current Desktop wallpaper. How do I do this in C#?
Thanks
You can try the following code. I've tested this code on windows 8 and it works for me:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace StringFormatting
{
public partial class WallpaperTest : Form
{
private const UInt32 SPI_GETDESKWALLPAPER = 0x73;
private const int MAX_PATH = 260;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SystemParametersInfo(UInt32 uAction, int uParam, string lpvParam, int fuWinIni);
public WallpaperTest()
{
InitializeComponent();
this.BackgroundImage = GetCurrentDesktopWallpaper();
this.BackgroundImageLayout = ImageLayout.Stretch;
}
public Image GetCurrentDesktopWallpaper()
{
string currentWallpaper = new string('\0', MAX_PATH);
SystemParametersInfo(SPI_GETDESKWALLPAPER, currentWallpaper.Length, currentWallpaper, 0);
string imageAddress = currentWallpaper.Substring(0, currentWallpaper.IndexOf('\0'));
return Image.FromFile(imageAddress);
}
}
}

Capturing Logon event on local computer as a non-admin. Is there an api?

As a non-admin user, I want to detect the event when another user logs in. I cannot use System Event Notification Service (SensLogon2) since it requires the user to be part of the Administrators group. Is there another API or are there certain permission/privileges that I can grant to the current user?
We need to detect another user logging on to the terminal via RDP so that we can change the application state the current user is in.
You can do next steps to get info about session changes:
Call WTSRegisterSessionNotification with NOTIFY_FOR_ALL_SESSIONS on your form to receive WM_WTSSESSION_CHANGE message
override void WndProc(ref Message m) of the Form and filtering by WM_WTSSESSION_CHANGE (0x2b1)
Extract session id from LPARAM and session state change event from WPARAM
Call WTSQuerySessionInformation with session id to get username
Here is working example with pInvoke. I have Form1 (WinForm) in my project. It is:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MessageLoop
{
public partial class Form1 : Form
{
/// <summary>
/// WM_WTSSESSION_CHANGE message number for filtering in WndProc
/// </summary>
private const int WM_WTSSESSION_CHANGE = 0x2b1;
public Form1()
{
InitializeComponent();
NativeWrapper.WTSRegisterSessionNotification(this, SessionNotificationType.NOTIFY_FOR_ALL_SESSIONS);
}
protected override void OnClosing(CancelEventArgs e)
{
NativeWrapper.WTSUnRegisterSessionNotification(this);
base.OnClosing(e);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WTSSESSION_CHANGE)
{
int eventType = m.WParam.ToInt32();
int sessionId = m.LParam.ToInt32();
WtsSessionChange reason = (WtsSessionChange)eventType;
Trace.WriteLine(string.Format("SessionId: {0}, Username: {1}, EventType: {2}",
sessionId, NativeWrapper.GetUsernameBySessionId(sessionId), reason));
}
base.WndProc(ref m);
}
}
}
Here is NativeWrapper.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MessageLoop
{
public enum WtsSessionChange
{
WTS_CONSOLE_CONNECT = 1,
WTS_CONSOLE_DISCONNECT = 2,
WTS_REMOTE_CONNECT = 3,
WTS_REMOTE_DISCONNECT = 4,
WTS_SESSION_LOGON = 5,
WTS_SESSION_LOGOFF = 6,
WTS_SESSION_LOCK = 7,
WTS_SESSION_UNLOCK = 8,
WTS_SESSION_REMOTE_CONTROL = 9,
WTS_SESSION_CREATE = 0xA,
WTS_SESSION_TERMINATE = 0xB
}
public enum SessionNotificationType
{
NOTIFY_FOR_THIS_SESSION = 0,
NOTIFY_FOR_ALL_SESSIONS = 1
}
public static class NativeWrapper
{
public static void WTSRegisterSessionNotification(Control control, SessionNotificationType sessionNotificationType)
{
if (!Native.WTSRegisterSessionNotification(control.Handle, (int)sessionNotificationType))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
public static void WTSUnRegisterSessionNotification(Control control)
{
if (!Native.WTSUnRegisterSessionNotification(control.Handle))
throw new Win32Exception(Marshal.GetLastWin32Error());
}
public static string GetUsernameBySessionId(int sessionId)
{
IntPtr buffer;
int strLen;
var username = "SYSTEM"; // assume SYSTEM as this will return "\0" below
if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSUserName, out buffer, out strLen) && strLen > 1)
{
username = Marshal.PtrToStringAnsi(buffer); // don't need length as these are null terminated strings
Native.WTSFreeMemory(buffer);
if (Native.WTSQuerySessionInformation(IntPtr.Zero, sessionId, Native.WTS_INFO_CLASS.WTSDomainName, out buffer, out strLen) && strLen > 1)
{
username = Marshal.PtrToStringAnsi(buffer) + "\\" + username; // prepend domain name
Native.WTSFreeMemory(buffer);
}
}
return username;
}
}
}
And the last file is Native.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace MessageLoop
{
public static class Native
{
public enum WTS_INFO_CLASS
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
WTSIdleTime,
WTSLogonTime,
WTSIncomingBytes,
WTSOutgoingBytes,
WTSIncomingFrames,
WTSOutgoingFrames,
WTSClientInfo,
WTSSessionInfo
}
[DllImport("wtsapi32.dll", SetLastError = true)]
internal static extern bool WTSRegisterSessionNotification(IntPtr hWnd, [MarshalAs(UnmanagedType.U4)] int dwFlags);
[DllImport("wtsapi32.dll", SetLastError = true)]
internal static extern bool WTSUnRegisterSessionNotification(IntPtr hWnd);
[DllImport("Wtsapi32.dll")]
internal static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out IntPtr ppBuffer, out int pBytesReturned);
[DllImport("Wtsapi32.dll")]
internal static extern void WTSFreeMemory(IntPtr pointer);
}
}

function in c# bho not exposed when loading sites in localhost

I created a sample bho using c# and exposed 1 function based from this post
Calling C# BHO methods from Javascript
The bho got registered to IE 9 successfully and i can access the exposed function in javascript on sites hosted in the net.
i created a test page using my local server and my bho function is now undefined.
i tried changing the url from localhost to ip address but still no effect.
below is my code. it would be great if somebody can check if something is wrong with my code;
thanks.
BHO.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms.Design;
using SHDocVw;
using mshtml;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Expando;
using Microsoft.Win32;
namespace MySampleBHO
{
[
ComVisible(true),
Guid("7bb16759-fdfc-4e3f-a081-eb65e4683640"),
ClassInterface(ClassInterfaceType.None),
ProgId("SIV"), ComDefaultInterface(typeof(IExtension))
]
public class BHO:IObjectWithSite, IExtension
{
WebBrowser webBrowser;
HTMLDocument document;
public void OnDocumentComplete(object pDisp, ref object URL) {
document = (HTMLDocument)webBrowser.Document;
dynamic window = webBrowser.Document.parentWindow;
IExpando windowEx = (IExpando)window;
windowEx.AddProperty("sEnhancer");
window.sEnhancer = this;
}
public String goEnhance(String ImageId, int Width, int Height) {
var img = document.getElementById(ImageId);
var src = img.getAttribute("src");
return src.ToString();
}
public int SetSite(object site)
{
if (site != null)
{
webBrowser = (WebBrowser)site;
webBrowser.DocumentComplete +=
new DWebBrowserEvents2_DocumentCompleteEventHandler(
this.OnDocumentComplete);
}
else
{
webBrowser.DocumentComplete -=
new DWebBrowserEvents2_DocumentCompleteEventHandler(
this.OnDocumentComplete);
webBrowser = null;
}
return 0;
}
public int GetSite(ref Guid guid, out IntPtr ppvSite)
{
IntPtr punk = Marshal.GetIUnknownForObject(webBrowser);
int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite);
Marshal.Release(punk);
return hr;
}
public static string BHOKEYNAME =
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects";
[ComRegisterFunction]
public static void RegisterBHO(Type type)
{
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHOKEYNAME, true);
if (registryKey == null)
registryKey = Registry.LocalMachine.CreateSubKey(BHOKEYNAME);
string guid = type.GUID.ToString("B");
RegistryKey ourKey = registryKey.OpenSubKey(guid);
if (ourKey == null)
ourKey = registryKey.CreateSubKey(guid);
ourKey.SetValue("Alright", 1);
registryKey.Close();
ourKey.Close();
}
[ComUnregisterFunction]
public static void UnregisterBHO(Type type)
{
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(BHOKEYNAME, true);
string guid = type.GUID.ToString("B");
if (registryKey != null)
registryKey.DeleteSubKey(guid, false);
}
}
}
IObjectWithSite.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace MySampleBHO
{
[
ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")
]
public interface IObjectWithSite
{
[PreserveSig]
int SetSite([MarshalAs(UnmanagedType.IUnknown)]object site);
[PreserveSig]
int GetSite(ref Guid guid, out IntPtr ppvSite);
}
}
IExtension.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace MySampleBHO
{
[
ComVisible(true),
InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")
]
public interface IExtension
{
String goEnhance(String ImageId, int Width, int Height);
}
}
i already found the solution to my problem... just have to change some part in onDocumentComplete function...
Solution
Change below code:
public void OnDocumentComplete(object pDisp, ref object URL) {
document = (HTMLDocument)webBrowser.Document;
dynamic window = webBrowser.Document.parentWindow;
IExpando windowEx = (IExpando)window;
windowEx.AddProperty("sEnhancer");
window.sEnhancer = this;
}
to:
public void OnDocumentComplete(object pDisp, ref object URL) {
document = (HTMLDocument)webBrowser.Document;
dynamic window = webBrowser.Document.parentWindow;
IExpando windowEx = (IExpando)window;
PropertyInfo p = windowEx.AddProperty("sEnhancer");
p.SetValue(windowEx, this);
}
solution was based from this post BHO exposing javascript method works in IE 9+ but fails in earlier versions

How to use [DllImport("")] in C#?

I found a lot of questions about it, but no one explains how I can use this.
I have this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.FSharp.Linq.RuntimeHelpers;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
public class WindowHandling
{
public void ActivateTargetApplication(string processName, List<string> barcodesList)
{
[DllImport("User32.dll")]
public static extern int SetForegroundWindow(IntPtr point);
Process p = Process.Start("notepad++.exe");
p.WaitForInputIdle();
IntPtr h = p.MainWindowHandle;
SetForegroundWindow(h);
SendKeys.SendWait("k");
IntPtr processFoundWindow = p.MainWindowHandle;
}
}
Can someone help me to understand why it gives me an error on the DllImport line and on the public static line?
Does anyone have an idea, what can I do?
Thank you.
You can't declare an extern local method inside of a method, or any other method with an attribute. Move your DLL import into the class:
using System.Runtime.InteropServices;
public class WindowHandling
{
[DllImport("User32.dll")]
public static extern int SetForegroundWindow(IntPtr point);
public void ActivateTargetApplication(string processName, List<string> barcodesList)
{
Process p = Process.Start("notepad++.exe");
p.WaitForInputIdle();
IntPtr h = p.MainWindowHandle;
SetForegroundWindow(h);
SendKeys.SendWait("k");
IntPtr processFoundWindow = p.MainWindowHandle;
}
}
Starting with C# 9, your syntax would be valid if you remove the public keyword from the SetForegroundWindow deceleration:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.FSharp.Linq.RuntimeHelpers;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
public class WindowHandling
{
public void ActivateTargetApplication(string processName, List<string> barcodesList)
{
[DllImport("User32.dll")]
static extern int SetForegroundWindow(IntPtr point);
Process p = Process.Start("notepad++.exe");
p.WaitForInputIdle();
IntPtr h = p.MainWindowHandle;
SetForegroundWindow(h);
SendKeys.SendWait("k");
IntPtr processFoundWindow = p.MainWindowHandle;
}
}
In C# 9 local functions can have attributes, see here

How do I capture the Screensaver Event?

I'm trying to capture a Screensaver event, however when I run my application it throws the following exception;
Unable to find an entry point named 'SystemParametersinfo' in DLL 'user32.dll'.
this is my code so far, any and all help would be greatly appreciated =D
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using NLog;
using Topshelf;
using OsWatch;
using Microsoft.Win32;
using System.Runtime.InteropServices;
namespace NotifyIcon
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SystemParametersinfo(int uAction, int uParam, ref int ipvParam, int fuWinini);
const int SPI_GETSCREENSAVERRUNNING = 114;
static int screenSaverRunning = -1;
int ok = SystemParametersinfo(SPI_GETSCREENSAVERRUNNING, 0, ref screenSaverRunning, 0);
private void ScreenSaver()
{
if (ok == 0)
{
Logger.Trace("SCREENSAVER OFF");
}
if (screenSaverRunning != 0)
{
Logger.Trace("SCREENSAVER ON");
}
}

Categories

Resources