1- // Copyright © 2010-2015  The CefSharp Authors. All rights reserved. 
1+ // Copyright © 2010-2021  The CefSharp Authors. All rights reserved. 
22// 
33// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. 
44
1111
1212namespace  CefSharp . MinimalExample . OffScreen 
1313{ 
14+     /// <summary> 
15+     /// CefSharp.OffScreen Minimal Example 
16+     /// </summary> 
1417    public  class  Program 
1518    { 
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> 
1827        public  static int  Main ( string [ ]  args ) 
1928        { 
2029#if ANYCPU 
@@ -28,6 +37,108 @@ public static int Main(string[] args)
2837            Console . WriteLine ( "You may see Chromium debugging output, please wait..." ) ; 
2938            Console . WriteLine ( ) ; 
3039
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+ 
31142            var  settings  =  new  CefSettings ( ) 
32143            { 
33144                //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)
38149            Cef . Initialize ( settings ,  performDependencyCheck :  true ,  browserProcessHandler :  null ) ; 
39150
40151            // Create the offscreen Chromium browser. 
41-             browser  =  new  ChromiumWebBrowser ( testUrl ) ; 
152+             var   browser  =  new  ChromiumWebBrowser ( testUrl ) ; 
42153
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 ; 
46155
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 ; 
49164
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!'" ) ; 
53166
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" ) ; 
56182
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 ) ; 
66185
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 ) ; 
68189
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+                             } ) ; 
79202
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+             } ; 
82208
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 ; 
86212
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 ( ) ; 
90215
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 ( ) ; 
92220
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 ; 
104222        } 
105223    } 
106224} 
0 commit comments