I am working on building a primitive and basic web browser on which my workplace would like to host some internal applications. I"m using cefSharp in a WinForms application written in C#. I've succeeded in building the browser to navigate the application, but I'm having trouble with the download handler. I would like to download files directly to the C:\Users\[username]\Downloads folder (all of our computers are Windows computers) without having to use the dialog.
Reading from Force CEFSharp to download without showing dialog suggests that using showDialog: false should work, but when I apply this, nothing downloads. Likewise, I've made no progress by studying any of the following:
WPF : download files through CefSharp
https://github.com/cefsharp/CefSharp/blob/cd934267c65f494ceb9ee75995cd2a1ca0954543/CefSharp.Example/DownloadHandler.cs
WPF : download files through CefSharp
https://groups.google.com/forum/?nomobile=true#!topic/cefsharp/bS8PhHRlSAc
https://groups.google.com/forum/#!topic/cefsharp/3cMUHSGxPDc
As a bonus, it'd be nice to have the option to open the file, such as in Google Chrome, but this isn't strictly necessary.
The code below runs smoothly and approximates what I am attempting. This example opens to a GitHub Gist. Clicking on the "Download Zip" button on the right opens the dialog to download and save the file.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using System.IO;
namespace ShinyChrome
{
public partial class ShinyApp : Form
{
public class DownloadHandler : IDownloadHandler
{
public event EventHandler<DownloadItem> OnBeforeDownloadFired;
public event EventHandler<DownloadItem> OnDownloadUpdatedFired;
public void OnBeforeDownload(IBrowser browser, DownloadItem downloadItem, IBeforeDownloadCallback callback)
{
var handler = OnBeforeDownloadFired;
if (handler != null)
{
handler(this, downloadItem);
}
if (!callback.IsDisposed)
{
using (callback)
{
callback.Continue(downloadItem.SuggestedFileName, showDialog: true);
}
}
}
public void OnDownloadUpdated(IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
{
var handler = OnDownloadUpdatedFired;
if (handler != null)
{
handler(this, downloadItem);
}
}
}
public ShinyApp()
{
InitializeComponent();
}
ChromiumWebBrowser chrome;
private void ShinyApp_Load(object sender, EventArgs e)
{
CefSettings settings = new CefSettings();
Cef.Initialize(settings);
chrome = new ChromiumWebBrowser("https://gist.github.com/nutterb/32992747c1a69aa7a8fdcc2b5347178f");
chrome.DownloadHandler = new DownloadHandler();
this.shinyContainer.Controls.Add(chrome);
}
}
}
On TEK's advice, I replaced the if(!callback.IsDisposed) block in the question with the code below.
if (!callback.IsDisposed)
{
using (callback)
{
callback.Continue(#"C:\Users\" +
System.Security.Principal.WindowsIdentity.GetCurrent().Name. +
#"\Downloads\" +
downloadItem.SuggestedFileName,
showDialog: false);
}
}
Related
I would like to know how and if it is possible to use puppeteer-extra-plugin-stealth inside of visual studio project.
As far as I read there is a project called: puppeteer sharp but they didn't showed how to use the plugin stealth, as this is best browser which is not detectable as a "bot".
In my other puppeteer .js file compiled by Docker I have this code to load installed puppeteer-extra-plugin-stealth:
Docker puppeteer code:
const puppeteer = require('puppeteer-extra');
const stealthPlugin = require('puppeteer-extra-plugin-stealth');
const { IS_PROD } = require('../utils/constants');
puppeteer.use(stealthPlugin());
// In order to run chromium processes in parallel. https://github.com/puppeteer/puppeteer/issues/594#issuecomment-325919885
process.setMaxListeners(Infinity);
const getBrowserInstance = async (port) => {
const browser = await puppeteer.launch({
args: IS_PROD ? ['--no-sandbox', `--proxy-server=socks5://127.0.0.1:${port}`] : ['--no-sandbox'],
devtools: !IS_PROD,
executablePath: IS_PROD ? '/usr/bin/chromium-browser' : undefined,
});
const incognitoBrowserContext = browser.createIncognitoBrowserContext();
incognitoBrowserContext.close = browser.close;
return incognitoBrowserContext;
};
module.exports = {
getBrowserInstance,
};
BUT THIS is my C# Form where I don't know how to use or load or implement puppeteer-extra-plugin-stealth
My VS Code:
using PuppeteerSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace pupe
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
var page = await browser.NewPageAsync();
await page.SetViewportAsync(new ViewPortOptions
{
Width = 1920,
Height = 1080
});
await page.GoToAsync("https://bot.sannysoft.com/");
await page.ScreenshotAsync("screens/test.png", new ScreenshotOptions { Type = ScreenshotType.Png });
MessageBox.Show("screen done!");
}
}
}
Adding the stealth plugin to puppeteer-sharp may not be as simple than on the NodeJS Version. A C# port of the puppeteer-extra which works with puppeteersharp exists. Check https://github.com/Overmiind/Puppeteer-sharp-extra.
I am trying to add BLE functionality into a classic (WinForms?) C# desktop application, and have added references (Windows.winmd and System.Runtime.WindowsRuntime) to allow me to access the new BLE API recently introduced by Microsoft for Windows 10 UWP applications. I need to create a classic desktop application, as I need to use an older driver device wrapper (teVirtualMIDI) and want to create a .exe, not an app package.
I am referencing the aformentioned libraries from the following locations...
C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Facade\Windows.WinMD
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.dll
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETCore\v4.5\System.Runtime.WindowsRuntime.UI.Xaml.dll
At this point, I simply want to be able to view connected services and characteristics in the debug output window, as is done in this blog post...
https://blogs.msdn.microsoft.com/cdndevs/2017/04/28/uwp-working-with-bluetooth-devices-part-1/
It seems that I am getting errors because the BLE API needs to perform async operations, but I am honestly at a loss. The code I have written so far is included below. Essentially, I am receiving errors when trying to call the "GetGattServicesAsync()" method, as Visual Studio says that class "BluetoothLEDevice" does not contain such a definition. That method is included in the online documentation though, and I am wondering why I am not able to access it.
I hope I have given sufficient information, and any help in solving this problem will be more than appreciated. Thank you all for all the helpful advice you give!
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Windows.Devices.Bluetooth;
using Windows.Devices.Midi;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using Windows.Devices.Enumeration;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage.Streams;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
namespace BDBMidiClient
{
public class BLEHandlingDiscovery : Page
{
//private ObservableCollection<BluetoothLEAttributeDisplay> ServiceCollection = new ObservableCollection<BluetoothLEAttributeDisplay>();
//private ObservableCollection<BluetoothLEAttributeDisplay> CharacteristicCollection = new ObservableCollection<BluetoothLEAttributeDisplay>();
public ObservableCollection<BluetoothLEDeviceDisplay> KnownDevices = new ObservableCollection<BluetoothLEDeviceDisplay>();
//private List<DeviceInformation> UnknownDevices = new List<DeviceInformation>();
//private DeviceWatcher deviceWatcher;
//private BluetoothLEDevice bluetoothLeDevice = null;
//private GattCharacteristic selectedCharacteristic;
private void StartBLEDeviceWatcher()
{
string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
DeviceWatcher deviceWatcher =
DeviceInformation.CreateWatcher(
BluetoothLEDevice.GetDeviceSelectorFromPairingState(false),
requestedProperties,
DeviceInformationKind.AssociationEndpoint);
/*
DeviceWatcher deviceWatcher =
DeviceInformation.CreateWatcher(
"System.ItemNameDisplay:~~\"BDB\"",
requestedProperties,
DeviceInformationKind.AssociationEndpoint);*/
deviceWatcher.Added += DeviceWatcher_Added;
deviceWatcher.Updated += DeviceWatcher_Updated;
deviceWatcher.Removed += DeviceWatcher_Removed;
deviceWatcher.Start();
//Debug.WriteLine(requestedProperties);
}
private async void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation deviceInfo)
{
Guid gattService = new Guid();
var device = await BluetoothLEDevice.FromIdAsync(deviceInfo.Id);
var services=await device.GetGattServicesAsync();
foreach (var service in services.Services)
{
Debug.WriteLine($"Service: {service.Uuid}");
var characteristics = await service.GetCharacteristicsAsync();
foreach (var character in characteristics.Characteristics)
{
Debug.WriteLine($"Characteristic: {character.Uuid}");
}
}
}
private void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate)
{
}
private void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate)
{
}
async void ConnectToBLEDevice(DeviceInformation deviceInformation)
{
BluetoothLEDevice bluetoothLeDevice = await BluetoothLEDevice.FromIdAsync("BDB");
}
private BluetoothLEDeviceDisplay FindBluetoothLEDeviceDisplay(string id)
{
foreach (BluetoothLEDeviceDisplay bleDeviceDisplay in KnownDevices)
{
if (bleDeviceDisplay.Id == id)
{
return bleDeviceDisplay;
}
}
return null;
}
}
The doc says the API belongs to "Windows 10 Creators Update (introduced v10.0.15063.0)". So please try to add the one from "C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.15063.0\Windows.winmd"
Here is the result from my project
You can see my code works well.
I was trying to add a second tool window to a VSPackage project in Visual Studio, I have a project with a tool window already created usin the wizard provided by Visual Studio when a VSPackage project is created, I was surfing the web looking for some tutorial that can help me adding a second tool window to my existing VSPackage project. I have read several articles about tool windows but I can't get with a solution. I create a new class
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
namespace Company.VSPackage1
{
[Guid("759c7eb3-6850-4cce-b765-2d5902a90918")]
public class OtherToolWindow : ToolWindowPane
{
public OtherToolWindow() :
base(null)
{
this.Caption = Resources.OtherToolWindowTitle;
this.BitmapResourceID = 301;
this.BitmapIndex = 1;
}
}
}
And then I modify the class that inherited from Package several times but something I'm doing wrong or missing
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
namespace Company.VSPackage1
{
[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[ProvideMenuResource("Menus.ctmenu", 1)]
[ProvideToolWindow(typeof(MyToolWindow))]
[ProvideToolWindow(typeof(OtherToolWindow))]
[Guid(GuidList.guidVSPackage1PkgString)]
public sealed class VSPackage1Package : Package
{
public VSPackage1Package()
{
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
}
private void ShowToolWindow(object sender, EventArgs e)
{
ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
if ((null == window) || (null == window.Frame))
{
throw new NotSupportedException(Resources.CanNotCreateWindow);
}
IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
}
private void ShowOtherToolWindow(object sender, EventArgs e)
{
ToolWindowPane otherWindow = this.FindToolWindow(typeof(OtherToolWindow), 0, true);
if ((null == otherWindow) || (null == otherWindow.Frame))
{
throw new NotSupportedException(Resources.CanNotCreateWindow);
}
IVsWindowFrame otherWindowFrame = (IVsWindowFrame)otherWindow.Frame;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(otherWindowFrame.Show());
}
protected override void Initialize()
{
Debug.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
base.Initialize();
// Add our command handlers for menu (commands must exist in the .vsct file)
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
// Create the command for the tool window
CommandID toolwndCommandID = new CommandID(GuidList.guidVSPackage1CmdSet, (int)PkgCmdIDList.cmdidMyTool);
MenuCommand menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandID);
CommandID toolwndCommandID2 = new CommandID(GuidList.guidVSPackage1CmdSet2, (int)PkgCmdIDList.cmdidMyTool2);
MenuCommand menuToolWin2 = new MenuCommand(ShowOtherToolWindow, toolwndCommandID2);
mcs.AddCommand( menuToolWin );
mcs.AddCommand(menuToolWin2);
}
}
}
}
I just want to add more than one tool window in the same vspackage in visual studio
This is wrong for sure:
CommandID toolwndCommandID2 = new CommandID(GuidList.guidVSPackage1CmdSet2, (int)PkgCmdIDList.cmdidMyTool2);
It should be:
CommandID toolwndCommandID2 = new CommandID(GuidList.guidVSPackage1CmdSet, (int)PkgCmdIDList.cmdidMyTool2);
And you need to fix the .vsct file and Guids.cs file, which you haven't posted.
That is, a package has a single command set, which can have several commands.
FWIW, I am working on a tutorial about creating toolwindows. Here it is:
HOWTO: Create a toolwindow with a ToolWindowPane class in a Visual Studio package
http://www.visualstudioextensibility.com/2015/02/20/mz-tools-articles-series-howto-create-a-toolwindow-with-a-toolwindowpane-class-in-a-visual-studio-package/
I am working in project in which I have used vlc plugin v2. the path for my video is
axVLC.playlist.add(#"D:\My Project\Science\Resources\myvideo.mp4");
axVLC.playlist.play();
now the problem is when I build the project and give it to someone and he/she install it on his/her computer , it show exception that video path is wrong. I am sure that path is not suitable as my the video path in my project is D:... and he/she installed it on C.
So my question is that is there any way to give it common path by which user don`t face such kind of error
Import IO
Using System.IO;
then declare a string that will reference to your video folder
string AbsoluteRef;
use this code in your form load
if (System.Diagnostics.Debugger.IsAttached)
{
AbsoluteRef = Path.GetFullPath(Application.StartupPath + "\\..\\..\\Resources\\");
}
else
{
AbsoluteRef = Application.StartupPath + "\\Resources\\";
}
Now declare a string for your video or which ever file like
string vlcvideo;
now add the two together
vlcvideo = AbsoluteRef & "myvideo.mp4";
Finnally add all this into your vlc plugin
axVLC.playlist.add(vlcvideo);
Complete Code looks like so.
using Microsoft.VisualBasic;
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 System.Windows.Input;
using yournamespace.Forms;
using System.IO;
namespace yourNameSpace
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
string AbsoluteRef = null;
private void frmMain_Load(object sender, EventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
AbsoluteRef = Path.GetFullPath(Application.StartupPath + "\\..\\..\\Resources\\");
}
else
{
AbsoluteRef = Application.StartupPath + "\\Resources\\";
}
string vlcVideo = AbsoluteRef + "myvideo.mp4";
axVLC.playlist.add(vlcvideo);
}
I'm compiling code on-the-fly using System.CodeDom.Compiler. Everything inside the compiled source works well, whatever I'm putting inside this source. I know how to call my functions:
o = results.CompiledAssembly.CreateInstance("Foo.Bar");
MethodInfo mi = o.GetType().GetMethod("SayHello");
mi.Invoke(o, null);
But let's say I'm using a WebClient to retrieve a string asynchronously using WebClient.DownloadStringAsync. Or any other context where I want my compiled source to tell to the host "Hey, I got a nice string ready for you." For the example, I've used a WebBrowser. Basically, I know how to deal with each of the two instances: My hosting program and the compiled program, but I want my compiled program to communicate with the host. By the way, I'm not a super-experimented programmer, so no obvious method comes to my mind.
What I've tried:
1 . I don't really need to try it because it would work, but I could use a timer reading a strings stack or tasks queue inside the compiled source, but the purpose of my application is to have +- 60 scripts able to execute ponctual tasks, not continuous background processes, so it wouldn't be efficient on the CPU.
2 . I've passed the handler to the compiled source like if it was in the hosting app:
//In the hosting app
MethodInfo mi2 = o.GetType().GetMethod("attachCallbackToHost");
mi2.Invoke(o2, new object[] { new WebBrowserNavigatedEventHandler (wb_navigated) });
//... And the handler
public static void wb_navigated(object sender, WebBrowserNavigatedEventArgs e)
{
string browserHtmlFromCompiledSource = ((WebBrowser)sender).DocumentText;
MessageBox.Show(browserHtmlFromCompiledSource);
}
// Plain text from the compiled source code
public void attachCallbackToHost(WebBrowserNavigatedEventHandler handlerFromTheHost)
{
wb.Navigated += handlerFromTheHost;
}
And it did nothing.
3 . Maybe I could share a class or variable by passing it to the compiled assembly?
So, the question is either this or the other:
How to watch efficiently for change inside a specific variable or property inside the compiled program?
How to attach a callback to the host?
Ok. I got it: In order to access the host from the compiled source, the only thing required is to add the host assembly to the refered assemblies in the compiler parameters:
compilerParams.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
So no need for any special callback or INotifier.
Here's the full code that strictly answers my question and nothing more:
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 Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace MamaProgram
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string source =
#"
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 System.Net;
using MyMama = MamaProgram;
namespace Baby
{
public class Program
{
public WebBrowser wb = new WebBrowser();
public void navigateTo(string url)
{
wb.Navigated += wb_navigated;
wb.Navigate(url);
}
public void wb_navigated(object sender, WebBrowserNavigatedEventArgs e)
{
MyMama.Form1.getResult(wb.DocumentText);
}
}
}
";
Dictionary<string, string> providerOptions = new Dictionary<string, string>
{
{"CompilerVersion", "v3.5"}
};
CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions);
CompilerParameters compilerParams = new CompilerParameters
{
GenerateInMemory = true,
GenerateExecutable = false,
TreatWarningsAsErrors = false
};
compilerParams.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
compilerParams.ReferencedAssemblies.Add("System.Data.dll");
compilerParams.ReferencedAssemblies.Add(typeof(System.Linq.Enumerable).Assembly.Location); // Trick to add assembly without knowing their name
compilerParams.ReferencedAssemblies.Add(typeof(System.ComponentModel.Component).Assembly.Location); // Trick to add assembly without knowing their name
compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
CompilerResults results = provider.CompileAssemblyFromSource(compilerParams, source);
if (results.Errors.Count != 0)
throw new Exception("Compilation failed");
object o = results.CompiledAssembly.CreateInstance("Baby.Program");
MethodInfo mi2 = o.GetType().GetMethod("navigateTo");
mi2.Invoke(o, new object[] { "http://www.google.com" });
}
public static void getResult(string result)
{
MessageBox.Show(result);
}
}
}