Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 17 additions & 10 deletions CefSharp.OutOfProcess.BrowserProcess/BrowserProcessHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Diagnostics;
using CefSharp.OutOfProcess.Interface;
using System.Threading.Tasks;
using CefSharp.OutOfProcess.BrowserProcess.CallbackProxies;
using CefSharp.OutOfProcess.Interface.Callbacks;

namespace CefSharp.OutOfProcess.BrowserProcess
{
Expand Down Expand Up @@ -38,6 +40,7 @@ protected override void OnContextInitialized()
var threadId = Kernel32.GetCurrentThreadId();

_outOfProcessServer.NotifyContextInitialized(threadId, Cef.CefSharpVersion, Cef.CefVersion, Cef.ChromiumVersion);
_outOfProcessServer.FileDialogCallback += _outOfProcessServer_FileDialogCallback;
}

protected override void Dispose(bool disposing)
Expand Down Expand Up @@ -65,14 +68,22 @@ Task IOutOfProcessClientRpc.CloseBrowser(int browserId)
});
}

private OutOfProcessChromiumWebBrowser GetBrowser(int id) => _browsers.FirstOrDefault(x => x.Id == id);

private void _outOfProcessServer_FileDialogCallback(object sender, FileDialogCallbackDetails e)
{
_ = CefThread.ExecuteOnUiThread(() =>
{
((DialogHandlerProxy)GetBrowser(e.BrowserId).DialogHandler)?.Callback(e);
return true;
});
}

Task IOutOfProcessClientRpc.SendDevToolsMessage(int browserId, string message)
{
return CefThread.ExecuteOnUiThread(() =>
{
var browser = _browsers.FirstOrDefault(x => x.Id == browserId);

browser?.GetBrowserHost().SendDevToolsMessage(message);

GetBrowser(browserId).GetBrowserHost()?.SendDevToolsMessage(message);
return true;
});
}
Expand Down Expand Up @@ -113,16 +124,12 @@ Task IOutOfProcessClientRpc.CreateBrowser(IntPtr parentHwnd, string url, int id)

void IOutOfProcessClientRpc.NotifyMoveOrResizeStarted(int browserId)
{
var browser = _browsers.FirstOrDefault(x => x.Id == browserId);

browser?.GetBrowserHost().NotifyMoveOrResizeStarted();
GetBrowser(browserId).GetBrowserHost()?.NotifyMoveOrResizeStarted();
}

void IOutOfProcessClientRpc.SetFocus(int browserId, bool focus)
{
var browser = _browsers.FirstOrDefault(x => x.Id == browserId);

browser?.GetBrowserHost().SetFocus(focus);
GetBrowser(browserId).GetBrowserHost()?.SetFocus(focus);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using CefSharp.OutOfProcess.Interface;

namespace CefSharp.OutOfProcess.BrowserProcess.CallbackProxies
{
internal class CallbackProxyBase<T> : IDisposable
{
private int id = 0;
private readonly Dictionary<int, T> callbacks = new Dictionary<int, T>();
private protected readonly IOutOfProcessHostRpc host;

public CallbackProxyBase(IOutOfProcessHostRpc host)
{
this.host = host ?? throw new ArgumentNullException(nameof(host));
}

protected int CreateCallback(T callback)
{
int lid = id++;
callbacks.Add(lid, callback);
return lid;
}

protected T GetCallback(int id)
{
T cb = callbacks[id];
callbacks.Remove(id);
return cb;
}

public void Dispose()
{
foreach (var cbs in callbacks)
{
if (cbs.Value is IDisposable d)
{
d.Dispose();
}
}

callbacks.Clear();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.Collections.Generic;
using CefSharp.OutOfProcess.Interface;
using CefSharp.Handler;
using System.Linq;
using CefSharp.OutOfProcess.Interface.Callbacks;
using System;

namespace CefSharp.OutOfProcess.BrowserProcess.CallbackProxies
{

internal sealed class DialogHandlerProxy : CallbackProxyBase<IFileDialogCallback>, IDialogHandler
{
public DialogHandlerProxy(IOutOfProcessHostRpc host)
: base(host)
{

}

public void Callback(FileDialogCallbackDetails details)
{
if (details == null)
{
throw new ArgumentNullException(nameof(details));
}

if (details.Files == null)
{
throw new ArgumentNullException(nameof(details.Files));
}

var cb = GetCallback(details.CallbackId);

if (details.Continue)
{
cb.Continue(details.Files.ToList());
}
else
{
cb.Cancel();
}
}

bool IDialogHandler.OnFileDialog(IWebBrowser chromiumWebBrowser, IBrowser browser, CefFileDialogMode mode, string title, string defaultFilePath, List<string> acceptFilters, IFileDialogCallback callback)
{
var result = host.OnFileDialog(((OutOfProcessChromiumWebBrowser)chromiumWebBrowser).Id, mode.ToString(), title, defaultFilePath, acceptFilters.ToArray(), CreateCallback(callback));
return result.Result;
}
}
}
40 changes: 40 additions & 0 deletions CefSharp.OutOfProcess.Core/CallbackProxies/CallbackProxyBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace CefSharp.OutOfProcess
{
using System;
using CefSharp.OutOfProcess.Internal;

internal class CallbackProxyBase : IDisposable
{
private protected readonly OutOfProcessHost outOfProcessHost;
private protected readonly int callback;
private protected readonly IChromiumWebBrowserInternal chromiumWebBrowser;
private bool disposedValue;

public CallbackProxyBase(OutOfProcessHost outOfProcessHost, int callback, IChromiumWebBrowserInternal chromiumWebBrowser)
{
this.chromiumWebBrowser = chromiumWebBrowser;
this.outOfProcessHost = outOfProcessHost;
this.callback = callback;
}

public bool IsDisposed => disposedValue;

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
}

disposedValue = true;
}
}

void IDisposable.Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace CefSharp.OutOfProcess
{
using System.Collections.Generic;
using CefSharp.OutOfProcess.Interface.Callbacks;
using CefSharp.OutOfProcess.Internal;

internal sealed class FileDialogCallbackProxy : CallbackProxyBase, IFileDialogCallback
{
public FileDialogCallbackProxy(OutOfProcessHost outOfProcessHost, int callback, IChromiumWebBrowserInternal chromiumWebBrowser)
: base(outOfProcessHost, callback, chromiumWebBrowser)
{
}

public void Cancel()
{
outOfProcessHost.InvokeFileDialogCallback(new FileDialogCallbackDetails()
{
CallbackId = callback,
BrowserId = chromiumWebBrowser.Id,
Continue = false,
});
}

public void Continue(List<string> filePaths)
{
outOfProcessHost.InvokeFileDialogCallback(new FileDialogCallbackDetails()
{
CallbackId = callback,
BrowserId = chromiumWebBrowser.Id,
Continue = true,
Files = filePaths.ToArray(),
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageReference Include="PInvoke.User32" Version="0.7.104" />
<PackageReference Include="StreamJsonRpc" Version="2.11.35" />
<ProjectReference Include="..\CefSharp.OutOfProcess.Interface\CefSharp.OutOfProcess.Interface.csproj" />

<ProjectReference Include="..\CefSharp.Dom\lib\PuppeteerSharp\CefSharp.Dom.OutOfProcess.csproj" />
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing line :)

</ItemGroup>

Expand Down
44 changes: 44 additions & 0 deletions CefSharp.OutOfProcess.Core/Handler/IDialogHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace CefSharp.OutOfProcess.Handler
{
using System.Collections.Generic;
using CefSharp.OutOfProcess.Interface.Callbacks;

public interface IDialogHandler
{
//
// Summary:
// Runs a file chooser dialog.
//
// Parameters:
// chromiumWebBrowser:
// the ChromiumWebBrowser control
//
// browser:
// the browser object
//
// mode:
// represents the type of dialog to display
//
// title:
// the title to be used for the dialog. It may be empty to show the default title
// ("Open" or "Save" depending on the mode).
//
// defaultFilePath:
// is the path with optional directory and/or file name component that should be
// initially selected in the dialog.
//
// acceptFilters:
// are used to restrict the selectable file types and may any combination of (a)
// valid lower-cased MIME types (e.g. "text/*" or "image/*"), (b) individual file
// extensions (e.g. ".txt" or ".png"), (c) combined description and file extension
// delimited using "|" and ";" (e.g. "Image Types|.png;.gif;.jpg").
//
// callback:
// Callback interface for asynchronous continuation of file dialog requests.
//
// Returns:
// To display a custom dialog return true. To display the default dialog return
// false.
bool OnFileDialog(IChromiumWebBrowser chromiumWebBrowser, string mode, string title, string defaultFilePath, IEnumerable<string> acceptFilters, IFileDialogCallback callback);
}
}
2 changes: 2 additions & 0 deletions CefSharp.OutOfProcess.Core/IChromiumWebBrowser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,5 +203,7 @@ public interface IChromiumWebBrowser : IDisposable
/// the navigation will resolve with the response of the last redirect. If can not go forward, resolves to null.</returns>
/// <param name="options">Navigation parameters.</param>
Task<Response> GoForwardAsync(NavigationOptions options = null);

Handler.IDialogHandler DialogHandler { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class OutOfProcessConnectionTransport : IConnectionTransport

public event EventHandler<MessageReceivedEventArgs> MessageReceived;
public event EventHandler<MessageErrorEventArgs> MessageError;
public event EventHandler Disconnected;

public OutOfProcessConnectionTransport(int browserId, OutOfProcessHost outOfProcessHost)
{
Expand Down
19 changes: 18 additions & 1 deletion CefSharp.OutOfProcess.Core/OutOfProcessHost.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
using CefSharp.OutOfProcess.Interface;
using CefSharp.OutOfProcess.Interface.Callbacks;
using CefSharp.OutOfProcess.Internal;
using PInvoke;
using StreamJsonRpc;
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace CefSharp.OutOfProcess
Expand Down Expand Up @@ -37,6 +39,8 @@ private OutOfProcessHost(string outOfProcessHostExePath, string cachePath = null
_cachePath = cachePath;
}

public event EventHandler<FileDialogCallbackDetails> FileDialogCallback;

/// <summary>
/// UI Thread assocuated with this <see cref="OutOfProcessHost"/>
/// </summary>
Expand Down Expand Up @@ -253,6 +257,19 @@ public static Task<OutOfProcessHost> CreateAsync(string path = HostExeName, stri
host.Init();

return host.InitializedTask;
}
}

Task<bool> IOutOfProcessHostRpc.OnFileDialog(int browserId, string mode, string title, string defaultFilePath, string[] acceptFilters, int callback)
{
if (_browsers.TryGetValue(browserId, out var chromiumWebBrowser) && chromiumWebBrowser.DialogHandler != null)
{
var result = chromiumWebBrowser.DialogHandler.OnFileDialog(chromiumWebBrowser, mode, title, defaultFilePath, acceptFilters.ToList(), new FileDialogCallbackProxy(this, callback, chromiumWebBrowser));
return Task.FromResult(result);
}

return Task.FromResult(false);
}

internal void InvokeFileDialogCallback(FileDialogCallbackDetails callbackDetails) => FileDialogCallback.Invoke(this, callbackDetails);
}
}
9 changes: 9 additions & 0 deletions CefSharp.OutOfProcess.Interface/Callbacks/CallbackDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace CefSharp.OutOfProcess.Interface.Callbacks
{
public class CallbackDetails
{
public int BrowserId { get; set; }

public int CallbackId { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace CefSharp.OutOfProcess.Interface.Callbacks
{
public class FileDialogCallbackDetails : CallbackDetails
{
public string[] Files { get; set; }

public bool Continue { get; set; }
}
}
11 changes: 11 additions & 0 deletions CefSharp.OutOfProcess.Interface/Callbacks/IFileDialogCallback.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace CefSharp.OutOfProcess.Interface.Callbacks
{
using System.Collections.Generic;

public interface IFileDialogCallback
{
bool IsDisposed { get; }
void Cancel();
void Continue(List<string> filePaths);
}
}
Loading