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,106 @@ 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
+ var response = await browser . EvaluateScriptAsync ( "document.querySelector('[name=q]').value = 'CefSharp Was Here!'" ) ;
75
+
76
+ //Give the browser a little time to render
77
+ await Task . Delay ( 500 ) ;
78
+ // Wait for the screenshot to be taken.
79
+ var bitmap = await browser . ScreenshotAsync ( ) ;
80
+
81
+ // File path to save our screenshot e.g. C:\Users\{username}\Desktop\CefSharp screenshot.png
82
+ var screenshotPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . Desktop ) , "CefSharp screenshot.png" ) ;
83
+
84
+ Console . WriteLine ( ) ;
85
+ Console . WriteLine ( "Screenshot ready. Saving to {0}" , screenshotPath ) ;
86
+
87
+ // Save the Bitmap to the path.
88
+ // The image type is auto-detected via the ".png" extension.
89
+ bitmap . Save ( screenshotPath ) ;
90
+
91
+ // We no longer need the Bitmap.
92
+ // Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications.
93
+ bitmap . Dispose ( ) ;
94
+
95
+ Console . WriteLine ( "Screenshot saved. Launching your default image viewer..." ) ;
96
+
97
+ // Tell Windows to launch the saved image.
98
+ Process . Start ( new ProcessStartInfo ( screenshotPath )
99
+ {
100
+ // UseShellExecute is false by default on .NET Core.
101
+ UseShellExecute = true
102
+ } ) ;
103
+
104
+ Console . WriteLine ( "Image viewer launched. Press any key to exit." ) ;
105
+ }
106
+
107
+ // Wait for user to press a key before exit
108
+ Console . ReadKey ( ) ;
109
+
110
+ // Clean up Chromium objects. You need to call this in your application otherwise
111
+ // you will get a crash when closing.
112
+ Cef . Shutdown ( ) ;
113
+ } ) ;
114
+
115
+ return 0 ;
116
+ }
117
+
118
+ /// <summary>
119
+ /// Synchronous demo using CefSharp.OffScreen
120
+ /// Loads google.com, uses javascript to fill out the search box then takes a screenshot which is opened
121
+ /// in the default image viewer.
122
+ /// For a asynchronous demo see <see cref="Main(string[])"/> above.
123
+ /// To use this demo simply delete the <see cref="Main(string[])"/> method and rename this method to Main.
124
+ /// </summary>
125
+ /// <param name="args">args</param>
126
+ /// <returns>exit code</returns>
127
+ public static int MainSync ( string [ ] args )
128
+ {
129
+ #if ANYCPU
130
+ //Only required for PlatformTarget of AnyCPU
131
+ CefRuntime . SubscribeAnyCpuAssemblyResolver ( ) ;
132
+ #endif
133
+
134
+ const string testUrl = "https://www.google.com/" ;
135
+
136
+ Console . WriteLine ( "This example application will load {0}, take a screenshot, and save it to your desktop." , testUrl ) ;
137
+ Console . WriteLine ( "You may see Chromium debugging output, please wait..." ) ;
138
+ Console . WriteLine ( ) ;
139
+
31
140
var settings = new CefSettings ( )
32
141
{
33
142
//By default CefSharp will use an in-memory cache, you need to specify a Cache Folder to persist data
@@ -38,69 +147,76 @@ public static int Main(string[] args)
38
147
Cef . Initialize ( settings , performDependencyCheck : true , browserProcessHandler : null ) ;
39
148
40
149
// Create the offscreen Chromium browser.
41
- browser = new ChromiumWebBrowser ( testUrl ) ;
150
+ var browser = new ChromiumWebBrowser ( testUrl ) ;
42
151
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 ;
152
+ EventHandler < LoadingStateChangedEventArgs > handler = null ;
46
153
47
- // We have to wait for something, otherwise the process will exit too soon.
48
- Console . ReadKey ( ) ;
154
+ handler = ( s , e ) =>
155
+ {
156
+ // Check to see if loading is complete - this event is called twice, one when loading starts
157
+ // second time when it's finished
158
+ if ( ! e . IsLoading )
159
+ {
160
+ // Remove the load event handler, because we only want one snapshot of the page.
161
+ browser . LoadingStateChanged -= handler ;
49
162
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 ( ) ;
163
+ var scriptTask = browser . EvaluateScriptAsync ( "document.querySelector('[name=q]').value = 'CefSharp Was Here!'" ) ;
53
164
54
- return 0 ;
55
- }
165
+ scriptTask . ContinueWith ( t =>
166
+ {
167
+ if ( ! t . Result . Success )
168
+ {
169
+ throw new Exception ( "EvaluateScriptAsync failed:" + t . Result . Message ) ;
170
+ }
171
+
172
+ //Give the browser a little time to render
173
+ Thread . Sleep ( 500 ) ;
174
+ // Wait for the screenshot to be taken.
175
+ var task = browser . ScreenshotAsync ( ) ;
176
+ task . ContinueWith ( x =>
177
+ {
178
+ // File path to save our screenshot e.g. C:\Users\{username}\Desktop\CefSharp screenshot.png
179
+ var screenshotPath = Path . Combine ( Environment . GetFolderPath ( Environment . SpecialFolder . Desktop ) , "CefSharp screenshot.png" ) ;
56
180
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 ;
181
+ Console . WriteLine ( ) ;
182
+ Console . WriteLine ( "Screenshot ready. Saving to {0}" , screenshotPath ) ;
66
183
67
- var scriptTask = browser . EvaluateScriptAsync ( "document.querySelector('[name=q]').value = 'CefSharp Was Here!'" ) ;
184
+ // Save the Bitmap to the path.
185
+ // The image type is auto-detected via the ".png" extension.
186
+ task . Result . Save ( screenshotPath ) ;
68
187
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" ) ;
188
+ // We no longer need the Bitmap.
189
+ // Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications.
190
+ task . Result . Dispose ( ) ;
79
191
80
- Console . WriteLine ( ) ;
81
- Console . WriteLine ( "Screenshot ready. Saving to {0}" , screenshotPath ) ;
192
+ Console . WriteLine ( "Screenshot saved. Launching your default image viewer..." ) ;
82
193
83
- // Save the Bitmap to the path.
84
- // The image type is auto-detected via the ".png" extension.
85
- task . Result . Save ( screenshotPath ) ;
194
+ // Tell Windows to launch the saved image.
195
+ Process . Start ( new ProcessStartInfo ( screenshotPath )
196
+ {
197
+ // UseShellExecute is false by default on .NET Core.
198
+ UseShellExecute = true
199
+ } ) ;
86
200
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 ( ) ;
201
+ Console . WriteLine ( "Image viewer launched. Press any key to exit." ) ;
202
+ } , TaskScheduler . Default ) ;
203
+ } ) ;
204
+ }
205
+ } ;
90
206
91
- Console . WriteLine ( "Screenshot saved. Launching your default image viewer..." ) ;
207
+ // An event that is fired when the first page is finished loading.
208
+ // This returns to us from another thread.
209
+ browser . LoadingStateChanged += handler ;
92
210
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
- }
211
+ // We have to wait for something, otherwise the process will exit too soon.
212
+ Console . ReadKey ( ) ;
213
+
214
+ // Clean up Chromium objects. You need to call this in your application otherwise
215
+ // you will get a crash when closing.
216
+ //The ChromiumWebBrowser instance will be disposed
217
+ Cef . Shutdown ( ) ;
218
+
219
+ return 0 ;
104
220
}
105
221
}
106
222
}
0 commit comments