1
- // Copyright © 2010-2015 The CefSharp Authors. All rights reserved.
1
+ // Copyright © 2010-2021 The CefSharp Authors. All rights reserved.
2
2
//
3
3
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4
4
11
11
12
12
namespace CefSharp . MinimalExample . OffScreen
13
13
{
14
+ /// <summary>
15
+ /// CefSharp.OffScreen Minimal Example
16
+ /// </summary>
14
17
public class Program
15
18
{
16
- private static ChromiumWebBrowser browser ;
17
-
19
+ /// <summary>
20
+ /// Asynchronous demo using CefSharp.OffScreen
21
+ /// Loads google.com, uses javascript to fill out the search box then takes a screenshot which is opened
22
+ /// in the default image viewer.
23
+ /// For a synchronous demo see <see cref="MainSync(string[])"/> below.
24
+ /// </summary>
25
+ /// <param name="args">args</param>
26
+ /// <returns>exit code</returns>
18
27
public static int Main ( string [ ] args )
19
28
{
20
29
#if ANYCPU
@@ -28,6 +37,108 @@ public static int Main(string[] args)
28
37
Console . WriteLine ( "You may see Chromium debugging output, please wait..." ) ;
29
38
Console . WriteLine ( ) ;
30
39
40
+ //Console apps don't have a SynchronizationContext, so to ensure our await calls continue on the main thread we use a super simple implementation from
41
+ //https://devblogs.microsoft.com/pfxteam/await-synchronizationcontext-and-console-apps/
42
+ //Continuations will happen on the main thread. Cef.Initialize/Cef.Shutdown must be called on the same Thread.
43
+ //The Nito.AsyncEx.Context Nuget package has a more advanced implementation
44
+ //should you wish to use a pre-build implementation.
45
+ //https://github.com/StephenCleary/AsyncEx/blob/8a73d0467d40ca41f9f9cf827c7a35702243abb8/doc/AsyncContext.md#console-example-using-asynccontext
46
+ //NOTE: This is only required if you use await
47
+
48
+ AsyncContext . Run ( async delegate
49
+ {
50
+ var settings = new CefSettings ( )
51
+ {
52
+ //By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
53
+ CachePath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . LocalApplicationData ) , "CefSharp\\ Cache" )
54
+ } ;
55
+
56
+ //Perform dependency check to make sure all relevant resources are in our output directory.
57
+ var success = await Cef . InitializeAsync ( settings , performDependencyCheck : true , browserProcessHandler : null ) ;
58
+
59
+ if ( ! success )
60
+ {
61
+ throw new Exception ( "Unable to initialize CEF, check the log file." ) ;
62
+ }
63
+
64
+ // Create the CefSharp.OffScreen.ChromiumWebBrowser instance
65
+ using ( var browser = new ChromiumWebBrowser ( testUrl ) )
66
+ {
67
+ var initialLoadResponse = await browser . WaitForInitialLoadAsync ( ) ;
68
+
69
+ if ( ! initialLoadResponse . Success )
70
+ {
71
+ throw new Exception ( string . Format ( "Page load failed with ErrorCode:{0}, HttpStatusCode:{1}" , initialLoadResponse . ErrorCode , initialLoadResponse . HttpStatusCode ) ) ;
72
+ }
73
+
74
+ browser . ShowDevTools ( ) ;
75
+
76
+ var response = await browser . EvaluateScriptAsync ( "document.querySelector('[name=q]').value = 'CefSharp Was Here!'" ) ;
77
+
78
+ //Give the browser a little time to render
79
+ await Task . Delay ( 500 ) ;
80
+ // Wait for the screenshot to be taken.
81
+ var bitmap = await browser . ScreenshotAsync ( ) ;
82
+
83
+ // File path to save our screenshot e.g. C:\Users\{username}\Desktop\CefSharp screenshot.png
84
+ var screenshotPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . Desktop ) , "CefSharp screenshot.png" ) ;
85
+
86
+ Console . WriteLine ( ) ;
87
+ Console . WriteLine ( "Screenshot ready. Saving to {0}" , screenshotPath ) ;
88
+
89
+ // Save the Bitmap to the path.
90
+ // The image type is auto-detected via the ".png" extension.
91
+ bitmap . Save ( screenshotPath ) ;
92
+
93
+ // We no longer need the Bitmap.
94
+ // Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications.
95
+ bitmap . Dispose ( ) ;
96
+
97
+ Console . WriteLine ( "Screenshot saved. Launching your default image viewer..." ) ;
98
+
99
+ // Tell Windows to launch the saved image.
100
+ Process . Start ( new ProcessStartInfo ( screenshotPath )
101
+ {
102
+ // UseShellExecute is false by default on .NET Core.
103
+ UseShellExecute = true
104
+ } ) ;
105
+
106
+ Console . WriteLine ( "Image viewer launched. Press any key to exit." ) ;
107
+ }
108
+
109
+ // Wait for user to press a key before exit
110
+ Console . ReadKey ( ) ;
111
+
112
+ // Clean up Chromium objects. You need to call this in your application otherwise
113
+ // you will get a crash when closing.
114
+ Cef . Shutdown ( ) ;
115
+ } ) ;
116
+
117
+ return 0 ;
118
+ }
119
+
120
+ /// <summary>
121
+ /// Synchronous demo using CefSharp.OffScreen
122
+ /// Loads google.com, uses javascript to fill out the search box then takes a screenshot which is opened
123
+ /// in the default image viewer.
124
+ /// For a asynchronous demo see <see cref="Main(string[])"/> above.
125
+ /// To use this demo simply delete the <see cref="Main(string[])"/> method and rename this method to Main.
126
+ /// </summary>
127
+ /// <param name="args">args</param>
128
+ /// <returns>exit code</returns>
129
+ public static int MainSync ( string [ ] args )
130
+ {
131
+ #if ANYCPU
132
+ //Only required for PlatformTarget of AnyCPU
133
+ CefRuntime . SubscribeAnyCpuAssemblyResolver ( ) ;
134
+ #endif
135
+
136
+ const string testUrl = "https://www.google.com/" ;
137
+
138
+ Console . WriteLine ( "This example application will load {0}, take a screenshot, and save it to your desktop." , testUrl ) ;
139
+ Console . WriteLine ( "You may see Chromium debugging output, please wait..." ) ;
140
+ Console . WriteLine ( ) ;
141
+
31
142
var settings = new CefSettings ( )
32
143
{
33
144
//By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
@@ -38,69 +149,76 @@ public static int Main(string[] args)
38
149
Cef . Initialize ( settings , performDependencyCheck : true , browserProcessHandler : null ) ;
39
150
40
151
// Create the offscreen Chromium browser.
41
- browser = new ChromiumWebBrowser ( testUrl ) ;
152
+ var browser = new ChromiumWebBrowser ( testUrl ) ;
42
153
43
- // An event that is fired when the first page is finished loading.
44
- // This returns to us from another thread.
45
- browser . LoadingStateChanged += BrowserLoadingStateChanged ;
154
+ EventHandler < LoadingStateChangedEventArgs > handler = null ;
46
155
47
- // We have to wait for something, otherwise the process will exit too soon.
48
- Console . ReadKey ( ) ;
156
+ handler = ( s , e ) =>
157
+ {
158
+ // Check to see if loading is complete - this event is called twice, one when loading starts
159
+ // second time when it's finished
160
+ if ( ! e . IsLoading )
161
+ {
162
+ // Remove the load event handler, because we only want one snapshot of the page.
163
+ browser . LoadingStateChanged -= handler ;
49
164
50
- // Clean up Chromium objects. You need to call this in your application otherwise
51
- // you will get a crash when closing.
52
- Cef . Shutdown ( ) ;
165
+ var scriptTask = browser . EvaluateScriptAsync ( "document.querySelector('[name=q]').value = 'CefSharp Was Here!'" ) ;
53
166
54
- return 0 ;
55
- }
167
+ scriptTask . ContinueWith ( t =>
168
+ {
169
+ if ( ! t . Result . Success )
170
+ {
171
+ throw new Exception ( "EvaluateScriptAsync failed:" + t . Result . Message ) ;
172
+ }
173
+
174
+ //Give the browser a little time to render
175
+ Thread . Sleep ( 500 ) ;
176
+ // Wait for the screenshot to be taken.
177
+ var task = browser . ScreenshotAsync ( ) ;
178
+ task . ContinueWith ( x =>
179
+ {
180
+ // File path to save our screenshot e.g. C:\Users\{username}\Desktop\CefSharp screenshot.png
181
+ var screenshotPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . Desktop ) , "CefSharp screenshot.png" ) ;
56
182
57
- private static void BrowserLoadingStateChanged ( object sender , LoadingStateChangedEventArgs e )
58
- {
59
- // Check to see if loading is complete - this event is called twice, one when loading starts
60
- // second time when it's finished
61
- // (rather than an iframe within the main frame).
62
- if ( ! e . IsLoading )
63
- {
64
- // Remove the load event handler, because we only want one snapshot of the initial page.
65
- browser . LoadingStateChanged -= BrowserLoadingStateChanged ;
183
+ Console . WriteLine ( ) ;
184
+ Console . WriteLine ( "Screenshot ready. Saving to {0}" , screenshotPath ) ;
66
185
67
- var scriptTask = browser . EvaluateScriptAsync ( "document.querySelector('[name=q]').value = 'CefSharp Was Here!'" ) ;
186
+ // Save the Bitmap to the path.
187
+ // The image type is auto-detected via the ".png" extension.
188
+ task . Result . Save ( screenshotPath ) ;
68
189
69
- scriptTask . ContinueWith ( t =>
70
- {
71
- //Give the browser a little time to render
72
- Thread . Sleep ( 500 ) ;
73
- // Wait for the screenshot to be taken.
74
- var task = browser . ScreenshotAsync ( ) ;
75
- task . ContinueWith ( x =>
76
- {
77
- // Make a file to save it to (e.g. C:\Users\jan\Desktop\CefSharp screenshot.png)
78
- var screenshotPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . Desktop ) , "CefSharp screenshot.png" ) ;
190
+ // We no longer need the Bitmap.
191
+ // Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications.
192
+ task . Result . Dispose ( ) ;
193
+
194
+ Console . WriteLine ( "Screenshot saved. Launching your default image viewer..." ) ;
195
+
196
+ // Tell Windows to launch the saved image.
197
+ Process . Start ( new ProcessStartInfo ( screenshotPath )
198
+ {
199
+ // UseShellExecute is false by default on .NET Core.
200
+ UseShellExecute = true
201
+ } ) ;
79
202
80
- Console . WriteLine ( ) ;
81
- Console . WriteLine ( "Screenshot ready. Saving to {0}" , screenshotPath ) ;
203
+ Console . WriteLine ( "Image viewer launched. Press any key to exit." ) ;
204
+ } , TaskScheduler . Default ) ;
205
+ } ) ;
206
+ }
207
+ } ;
82
208
83
- // Save the Bitmap to the path .
84
- // The image type is auto-detected via the ".png" extension .
85
- task . Result . Save ( screenshotPath ) ;
209
+ // An event that is fired when the first page is finished loading .
210
+ // This returns to us from another thread .
211
+ browser . LoadingStateChanged += handler ;
86
212
87
- // We no longer need the Bitmap.
88
- // Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications.
89
- task . Result . Dispose ( ) ;
213
+ // We have to wait for something, otherwise the process will exit too soon.
214
+ Console . ReadKey ( ) ;
90
215
91
- Console . WriteLine ( "Screenshot saved. Launching your default image viewer..." ) ;
216
+ // Clean up Chromium objects. You need to call this in your application otherwise
217
+ // you will get a crash when closing.
218
+ //The ChromiumWebBrowser instance will be disposed
219
+ Cef . Shutdown ( ) ;
92
220
93
- // Tell Windows to launch the saved image.
94
- Process . Start ( new ProcessStartInfo ( screenshotPath )
95
- {
96
- // UseShellExecute is false by default on .NET Core.
97
- UseShellExecute = true
98
- } ) ;
99
-
100
- Console . WriteLine ( "Image viewer launched. Press any key to exit." ) ;
101
- } , TaskScheduler . Default ) ;
102
- } ) ;
103
- }
221
+ return 0 ;
104
222
}
105
223
}
106
224
}
0 commit comments