├── LICENSE
├── OpenSource.png
├── README.md
├── images
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── error1.png
├── error2.png
├── logo3.png
└── search.png
└── src
├── App.config
├── Data
└── JSON.cs
├── Handlers
├── ContextMenuHandler.cs
├── DownloadHandler.cs
├── HostHandler.cs
├── KeyboardHandler.cs
├── LifeSpanHandler.cs
├── RequestHandler.cs
├── SchemeHandler.cs
└── SchemeHandlerFactory.cs
├── MainForm.Designer.cs
├── MainForm.cs
├── MainForm.resx
├── Program.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── Resources
├── blankpage.png
└── sharpbrowser.ico
├── SharpBrowser.csproj
├── SharpBrowser.sln
├── SharpBrowser.zip
├── Utils
├── FileIconUtils.cs
├── MiscUtils.cs
└── URLUtils.cs
├── obj
└── Debug
│ ├── DesignTimeResolveAssemblyReferencesInput.cache
│ ├── SharpBrowser.MainForm.resources
│ ├── SharpBrowser.Properties.Resources.resources
│ ├── SharpBrowser.csproj.FileListAbsolute.txt
│ ├── SharpBrowser.csproj.GenerateResource.Cache
│ ├── SharpBrowser.csprojResolveAssemblyReference.cache
│ ├── TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
│ ├── TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
│ └── TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
└── packages.config
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 sharpbrowser
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/OpenSource.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/OpenSource.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/sharpbrowser/SharpBrowser)
2 |
3 | ## ***``Windows OS Desktop PC``*** [](https://github.com/sharpbrowser/SharpBrowser)
4 | ***
5 | ## The Prerequisites are Required: Loading Preview
6 | ## **`Microsoft .NET Framework 4.7`**
7 | [](https://github.com/CreateBrowser/SharpBrowser/releases/tag/v1.0)
8 |
9 |
10 | ***
11 | ## **`NOT Microsoft .NET Framework 4.5.2`**
12 |
13 | ***
14 |
15 | 
16 |
17 | SharpBrowser is the fastest open source C# web browser there is! Slightly faster than Google Chrome when rendering web pages due to lightweight CEF renderer. We compared every available .NET browsing browsing engine and finally settled on the high-performance [CefSharp](https://github.com/cefsharp/CefSharp/). Released under the permissive MIT license.
18 |
19 | ## Features
20 |
21 | - HTML5, CSS3, JS, HTML5 Video, WebGL 3D, etc
22 | - Tabbed browsing
23 | - Address bar (also opens Google)
24 | - Back, Forward, Stop, Refresh
25 | - Developer tools
26 | - Search bar (also highlights all instances)
27 | - Download manager
28 | - Custom error pages
29 | - Custom context menu
30 | - Easily add vendor-specific branding, buttons or hotkeys
31 | - View online & offline webpages
32 |
33 | ## Hotkeys
34 |
35 | Hotkeys | Function
36 | ------------ | -------------
37 | Ctrl+T | Add a new tab
38 | Ctrl+N | Add a new window
39 | Ctrl+W | Close active tab
40 | F5 | Refresh active tab
41 | F12 | Open developer tools
42 | Ctrl+Tab | Switch to the next tab
43 | Ctrl+Shift+Tab | Switch to the previous tab
44 | Ctrl+F | Open search bar (Enter to find next, Esc to close)
45 |
46 | ## Code
47 |
48 | - SharpBrowser uses CefSharp 51, NET Framework 4.5.2
49 | - `MainForm.cs` - main web browser UI and related functionality
50 | - `Handlers` - various handlers that we have registered with CefSharp that enable deeper integration between us and CefSharp
51 | - `Data/JSON.cs` - fast JSON serializer/deserializer
52 | - `bin` - Binaries are included in the `bin` folder due to the complex CefSharp setup required. Don't empty this folder.
53 | - `bin/storage` - HTML and JS required for downloads manager and custom error pages
54 |
55 | ## Credits
56 | - [Mohammed Osama Mohamed Sayed Ahmed](https://github.com/mohamedosama914) - **`Microsoft .NET Framework 4.7`** SharpBrowser project.
57 |
58 | - [Robin Rodricks](https://github.com/robinrodricks) - SharpBrowser project.
59 | - [Alex Maitland](https://github.com/amaitland) - CefSharp project, wrapper for CEF embeddable browser.
60 | - [Ahmet Uzun](https://github.com/postacik) - Original browser project.
61 |
62 | ## Screenshots
63 |
64 |
65 | ### Apple Homepage
66 |
67 | 
68 |
69 | ### Google Maps
70 |
71 | 
72 |
73 | ### Search Bar
74 |
75 | 
76 |
77 | ### Downloads Tab
78 |
79 | 
80 |
81 | ### Developer Tools
82 |
83 | 
84 |
85 | ### Custom Error Pages
86 |
87 | 
88 |
89 | 
90 |
91 |
--------------------------------------------------------------------------------
/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/1.png
--------------------------------------------------------------------------------
/images/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/2.png
--------------------------------------------------------------------------------
/images/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/3.png
--------------------------------------------------------------------------------
/images/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/4.png
--------------------------------------------------------------------------------
/images/error1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/error1.png
--------------------------------------------------------------------------------
/images/error2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/error2.png
--------------------------------------------------------------------------------
/images/logo3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/logo3.png
--------------------------------------------------------------------------------
/images/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/images/search.png
--------------------------------------------------------------------------------
/src/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/Data/JSON.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Data;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.Text;
8 | using System.Reflection.Emit;
9 | using System.Reflection;
10 | using System.Data;
11 | using System.Xml;
12 |
13 |
14 | #region JSON
15 |
16 | public delegate string Serialize(object data);
17 | public delegate object Deserialize(string data);
18 |
19 | public class JSONParameters
20 | {
21 | ///
22 | /// Use the optimized fast Dataset Schema format (dfault = True)
23 | ///
24 | public bool UseOptimizedDatasetSchema = true;
25 | ///
26 | /// Use the fast GUID format (default = True)
27 | ///
28 | public bool UseFastGuid = true;
29 | ///
30 | /// Serialize null values to the output (default = True)
31 | ///
32 | public bool SerializeNullValues = true;
33 | ///
34 | /// Use the UTC date format (default = True)
35 | ///
36 | public bool UseUTCDateTime = true;
37 | ///
38 | /// Show the readonly properties of types in the output (default = False)
39 | ///
40 | public bool ShowReadOnlyProperties = false;
41 | ///
42 | /// Use the $types extension to optimise the output json (default = True)
43 | ///
44 | public bool UsingGlobalTypes = true;
45 | ///
46 | ///
47 | ///
48 | public bool IgnoreCaseOnDeserialize = false;
49 | ///
50 | /// Anonymous types have read only properties
51 | ///
52 | public bool EnableAnonymousTypes = false;
53 | ///
54 | /// Enable fastJSON extensions $types, $type, $map (default = True)
55 | ///
56 | public bool UseExtensions = true;
57 | }
58 |
59 | public class JSON
60 | {
61 | public readonly static JSON Instance = new JSON();
62 |
63 | private JSON()
64 | {
65 | }
66 | ///
67 | /// You can set these paramters globally for all calls
68 | ///
69 | public JSONParameters Parameters = new JSONParameters();
70 | private JSONParameters _params;
71 | // FIX : extensions off should not output $types
72 | public string ToJSON(object obj)
73 | {
74 | _params = Parameters;
75 | Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
76 | return ToJSON(obj, Parameters);
77 | }
78 |
79 | public string ToJSON(object obj, JSONParameters param)
80 | {
81 | _params = param;
82 | Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
83 | // FEATURE : enable extensions when you can deserialize anon types
84 | if (_params.EnableAnonymousTypes) { _params.UseExtensions = false; _params.UsingGlobalTypes = false; }
85 | return new JSONSerializer(param).ConvertToJSON(obj);
86 | }
87 |
88 | public object Parse(string json)
89 | {
90 | _params = Parameters;
91 | Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
92 | return new JsonParser(json, Parameters.IgnoreCaseOnDeserialize).Decode();
93 | }
94 |
95 | public T ToObject(string json)
96 | {
97 | return (T)ToObject(json, typeof(T));
98 | }
99 |
100 | public object ToObject(string json)
101 | {
102 | return ToObject(json, null);
103 | }
104 |
105 | public object ToObject(string json, Type type)
106 | {
107 | _params = Parameters;
108 | Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
109 | Dictionary ht = new JsonParser(json, Parameters.IgnoreCaseOnDeserialize).Decode() as Dictionary;
110 | if (ht == null) return null;
111 | return ParseDictionary(ht, null, type, null);
112 | }
113 |
114 | public string Beautify(string input)
115 | {
116 | return Formatter.PrettyPrint(input);
117 | }
118 |
119 | public object FillObject(object input, string json)
120 | {
121 | _params = Parameters;
122 | Reflection.Instance.ShowReadOnlyProperties = _params.ShowReadOnlyProperties;
123 | Dictionary ht = new JsonParser(json, Parameters.IgnoreCaseOnDeserialize).Decode() as Dictionary;
124 | if (ht == null) return null;
125 | return ParseDictionary(ht, null, input.GetType(), input);
126 | }
127 |
128 | public object DeepCopy(object obj)
129 | {
130 | return ToObject(ToJSON(obj));
131 | }
132 |
133 | public T DeepCopy(T obj)
134 | {
135 | return ToObject(ToJSON(obj));
136 | }
137 |
138 | #region [ JSON specific reflection ]
139 |
140 | private struct myPropInfo
141 | {
142 | public bool filled;
143 | public Type pt;
144 | public Type bt;
145 | public Type changeType;
146 | public bool isDictionary;
147 | public bool isValueType;
148 | public bool isGenericType;
149 | public bool isArray;
150 | public bool isByteArray;
151 | public bool isGuid;
152 | public bool isDataSet;
153 | public bool isDataTable;
154 | public bool isHashtable;
155 | public Reflection.GenericSetter setter;
156 | public bool isEnum;
157 | public bool isDateTime;
158 | public Type[] GenericTypes;
159 | public bool isInt;
160 | public bool isLong;
161 | public bool isString;
162 | public bool isBool;
163 | public bool isClass;
164 | public Reflection.GenericGetter getter;
165 | public bool isStringDictionary;
166 | public string Name;
167 | public bool CanWrite;
168 | }
169 |
170 | SafeDictionary> _propertycache = new SafeDictionary>();
171 | private SafeDictionary Getproperties(Type type, string typename)
172 | {
173 | SafeDictionary sd = null;
174 | if (_propertycache.TryGetValue(typename, out sd))
175 | {
176 | return sd;
177 | }
178 | else
179 | {
180 | sd = new SafeDictionary();
181 | PropertyInfo[] pr = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
182 | foreach (PropertyInfo p in pr)
183 | {
184 | myPropInfo d = CreateMyProp(p.PropertyType, p.Name);
185 | d.CanWrite = p.CanWrite;
186 | d.setter = Reflection.CreateSetMethod(type, p);
187 | d.getter = Reflection.CreateGetMethod(type, p);
188 | sd.Add(p.Name, d);
189 | }
190 | FieldInfo[] fi = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
191 | foreach (FieldInfo f in fi)
192 | {
193 | myPropInfo d = CreateMyProp(f.FieldType, f.Name);
194 | d.setter = Reflection.CreateSetField(type, f);
195 | d.getter = Reflection.CreateGetField(type, f);
196 | sd.Add(f.Name, d);
197 | }
198 |
199 | _propertycache.Add(typename, sd);
200 | return sd;
201 | }
202 | }
203 |
204 | private myPropInfo CreateMyProp(Type t, string name)
205 | {
206 | myPropInfo d = new myPropInfo();
207 | d.filled = true;
208 | d.CanWrite = true;
209 | d.pt = t;
210 | d.Name = name;
211 | d.isDictionary = t.Name.Contains("Dictionary");
212 | if (d.isDictionary)
213 | d.GenericTypes = t.GetGenericArguments();
214 | d.isValueType = t.IsValueType;
215 | d.isGenericType = t.IsGenericType;
216 | d.isArray = t.IsArray;
217 | if (d.isArray)
218 | d.bt = t.GetElementType();
219 | if (d.isGenericType)
220 | d.bt = t.GetGenericArguments()[0];
221 | d.isByteArray = t == typeof(byte[]);
222 | d.isGuid = (t == typeof(Guid) || t == typeof(Guid?));
223 | d.isHashtable = t == typeof(Hashtable);
224 | d.isDataSet = t == typeof(DataSet);
225 | d.isDataTable = t == typeof(DataTable);
226 |
227 | d.changeType = GetChangeType(t);
228 | d.isEnum = t.IsEnum;
229 | d.isDateTime = t == typeof(DateTime) || t == typeof(DateTime?);
230 | d.isInt = t == typeof(int) || t == typeof(int?);
231 | d.isLong = t == typeof(long) || t == typeof(long?);
232 | d.isString = t == typeof(string);
233 | d.isBool = t == typeof(bool) || t == typeof(bool?);
234 | d.isClass = t.IsClass;
235 |
236 | if (d.isDictionary && d.GenericTypes.Length > 0 && d.GenericTypes[0] == typeof(string))
237 | d.isStringDictionary = true;
238 |
239 | return d;
240 | }
241 |
242 | private object ChangeType(object value, Type conversionType)
243 | {
244 | if (conversionType == typeof(int))
245 | return (int)CreateLong((string)value);
246 |
247 | else if (conversionType == typeof(long))
248 | return CreateLong((string)value);
249 |
250 | else if (conversionType == typeof(string))
251 | return (string)value;
252 |
253 | else if (conversionType == typeof(Guid))
254 | return CreateGuid((string)value);
255 |
256 | else if (conversionType.IsEnum)
257 | return CreateEnum(conversionType, (string)value);
258 |
259 | return Convert.ChangeType(value, conversionType, CultureInfo.InvariantCulture);
260 | }
261 | #endregion
262 |
263 | #region [ p r i v a t e m e t h o d s ]
264 | bool usingglobals = false;
265 | private object ParseDictionary(Dictionary d, Dictionary globaltypes, Type type, object input)
266 | {
267 | object tn = "";
268 |
269 | if (d.TryGetValue("$types", out tn))
270 | {
271 | usingglobals = true;
272 | globaltypes = new Dictionary();
273 | foreach (var kv in (Dictionary)tn)
274 | {
275 | globaltypes.Add((string)kv.Value, kv.Key);
276 | }
277 | }
278 |
279 | bool found = d.TryGetValue("$type", out tn);
280 | if (found == false && type == typeof(System.Object))
281 | {
282 | return CreateDataset(d, globaltypes);
283 | }
284 |
285 | if (found)
286 | {
287 | if (usingglobals)
288 | {
289 | object tname = "";
290 | if (globaltypes.TryGetValue((string)tn, out tname))
291 | tn = tname;
292 | }
293 | type = Reflection.Instance.GetTypeFromCache((string)tn);
294 | }
295 |
296 | if (type == null)
297 | throw new Exception("Cannot determine type");
298 |
299 | string typename = type.FullName;
300 | object o = input;
301 | if (o == null)
302 | o = Reflection.Instance.FastCreateInstance(type);
303 | SafeDictionary props = Getproperties(type, typename);
304 | foreach (string n in d.Keys)
305 | {
306 | string name = n;
307 | if (_params.IgnoreCaseOnDeserialize) name = name.ToLower();
308 | if (name == "$map")
309 | {
310 | ProcessMap(o, props, (Dictionary)d[name]);
311 | continue;
312 | }
313 | myPropInfo pi;
314 | if (props.TryGetValue(name, out pi) == false)
315 | continue;
316 | if (pi.filled == true)
317 | {
318 | object v = d[name];
319 |
320 | if (v != null)
321 | {
322 | object oset = null;
323 |
324 | if (pi.isInt)
325 | oset = (int)CreateLong((string)v);
326 |
327 | else if (pi.isLong)
328 | oset = CreateLong((string)v);
329 |
330 | else if (pi.isString)
331 | oset = (string)v;
332 |
333 | else if (pi.isBool)
334 | oset = (bool)v;
335 |
336 | else if (pi.isGenericType && pi.isValueType == false && pi.isDictionary == false)
337 | oset = CreateGenericList((ArrayList)v, pi.pt, pi.bt, globaltypes);
338 |
339 | else if (pi.isByteArray)
340 | oset = Convert.FromBase64String((string)v);
341 |
342 | else if (pi.isArray && pi.isValueType == false)
343 | oset = CreateArray((ArrayList)v, pi.pt, pi.bt, globaltypes);
344 |
345 | else if (pi.isGuid)
346 | oset = CreateGuid((string)v);
347 |
348 | else if (pi.isDataSet)
349 | oset = CreateDataset((Dictionary)v, globaltypes);
350 |
351 | else if (pi.isDataTable)
352 | oset = this.CreateDataTable((Dictionary)v, globaltypes);
353 |
354 | else if (pi.isStringDictionary)
355 | oset = CreateStringKeyDictionary((Dictionary)v, pi.pt, pi.GenericTypes, globaltypes);
356 |
357 | else if (pi.isDictionary || pi.isHashtable)
358 | oset = CreateDictionary((ArrayList)v, pi.pt, pi.GenericTypes, globaltypes);
359 |
360 | else if (pi.isEnum)
361 | oset = CreateEnum(pi.pt, (string)v);
362 |
363 | else if (pi.isDateTime)
364 | oset = CreateDateTime((string)v);
365 |
366 | else if (pi.isClass && v is Dictionary)
367 | oset = ParseDictionary((Dictionary)v, globaltypes, pi.pt, null);
368 |
369 | else if (pi.isValueType)
370 | oset = ChangeType(v, pi.changeType);
371 |
372 | else if (v is ArrayList)
373 | oset = CreateArray((ArrayList)v, pi.pt, typeof(object), globaltypes);
374 | else
375 | oset = v;
376 |
377 | if (pi.CanWrite)
378 | o = pi.setter(o, oset);
379 | }
380 | }
381 | }
382 | return o;
383 | }
384 |
385 | private void ProcessMap(object obj, SafeDictionary props, Dictionary dic)
386 | {
387 | foreach (KeyValuePair kv in dic)
388 | {
389 | myPropInfo p = props[kv.Key];
390 | object o = p.getter(obj);
391 | Type t = Type.GetType((string)kv.Value);
392 | if (t == typeof(Guid))
393 | p.setter(obj, CreateGuid((string)o));
394 | }
395 | }
396 |
397 | private long CreateLong(string s)
398 | {
399 | long num = 0;
400 | bool neg = false;
401 | foreach (char cc in s)
402 | {
403 | if (cc == '-')
404 | neg = true;
405 | else if (cc == '+')
406 | neg = false;
407 | else
408 | {
409 | num *= 10;
410 | num += (int)(cc - '0');
411 | }
412 | }
413 |
414 | return neg ? -num : num;
415 | }
416 |
417 | private object CreateEnum(Type pt, string v)
418 | {
419 | // TODO : optimize create enum
420 | return Enum.Parse(pt, v);
421 | }
422 |
423 | private Guid CreateGuid(string s)
424 | {
425 | if (s.Length > 30)
426 | return new Guid(s);
427 | else
428 | return new Guid(Convert.FromBase64String(s));
429 | }
430 |
431 | private DateTime CreateDateTime(string value)
432 | {
433 | bool utc = false;
434 | // 0123456789012345678
435 | // datetime format = yyyy-MM-dd HH:mm:ss
436 | int year = (int)CreateLong(value.Substring(0, 4));
437 | int month = (int)CreateLong(value.Substring(5, 2));
438 | int day = (int)CreateLong(value.Substring(8, 2));
439 | int hour = (int)CreateLong(value.Substring(11, 2));
440 | int min = (int)CreateLong(value.Substring(14, 2));
441 | int sec = (int)CreateLong(value.Substring(17, 2));
442 |
443 | if (value.EndsWith("Z"))
444 | utc = true;
445 |
446 | if (_params.UseUTCDateTime == false && utc == false)
447 | return new DateTime(year, month, day, hour, min, sec);
448 | else
449 | return new DateTime(year, month, day, hour, min, sec, DateTimeKind.Utc).ToLocalTime();
450 | }
451 |
452 | private object CreateArray(ArrayList data, Type pt, Type bt, Dictionary globalTypes)
453 | {
454 | ArrayList col = new ArrayList();
455 | // create an array of objects
456 | foreach (object ob in data)
457 | {
458 | if (ob is IDictionary)
459 | col.Add(ParseDictionary((Dictionary)ob, globalTypes, bt, null));
460 | else
461 | col.Add(ChangeType(ob, bt));
462 | }
463 | return col.ToArray(bt);
464 | }
465 |
466 |
467 | private object CreateGenericList(ArrayList data, Type pt, Type bt, Dictionary globalTypes)
468 | {
469 | IList col = (IList)Reflection.Instance.FastCreateInstance(pt);
470 | // create an array of objects
471 | foreach (object ob in data)
472 | {
473 | if (ob is IDictionary)
474 | col.Add(ParseDictionary((Dictionary)ob, globalTypes, bt, null));
475 | else if (ob is ArrayList)
476 | col.Add(((ArrayList)ob).ToArray());
477 | else
478 | col.Add(ChangeType(ob, bt));
479 | }
480 | return col;
481 | }
482 |
483 | private object CreateStringKeyDictionary(Dictionary reader, Type pt, Type[] types, Dictionary globalTypes)
484 | {
485 | var col = (IDictionary)Reflection.Instance.FastCreateInstance(pt);
486 | Type t1 = null;
487 | Type t2 = null;
488 | if (types != null)
489 | {
490 | t1 = types[0];
491 | t2 = types[1];
492 | }
493 |
494 | foreach (KeyValuePair values in reader)
495 | {
496 | var key = values.Key;//ChangeType(values.Key, t1);
497 | object val = null;
498 | if (values.Value is Dictionary)
499 | val = ParseDictionary((Dictionary)values.Value, globalTypes, t2, null);
500 | else
501 | val = ChangeType(values.Value, t2);
502 | col.Add(key, val);
503 | }
504 |
505 | return col;
506 | }
507 |
508 | private object CreateDictionary(ArrayList reader, Type pt, Type[] types, Dictionary globalTypes)
509 | {
510 | IDictionary col = (IDictionary)Reflection.Instance.FastCreateInstance(pt);
511 | Type t1 = null;
512 | Type t2 = null;
513 | if (types != null)
514 | {
515 | t1 = types[0];
516 | t2 = types[1];
517 | }
518 |
519 | foreach (Dictionary values in reader)
520 | {
521 | object key = values["k"];
522 | object val = values["v"];
523 |
524 | if (key is Dictionary)
525 | key = ParseDictionary((Dictionary)key, globalTypes, t1, null);
526 | else
527 | key = ChangeType(key, t1);
528 |
529 | if (val is Dictionary)
530 | val = ParseDictionary((Dictionary)val, globalTypes, t2, null);
531 | else
532 | val = ChangeType(val, t2);
533 |
534 | col.Add(key, val);
535 | }
536 |
537 | return col;
538 | }
539 |
540 | private Type GetChangeType(Type conversionType)
541 | {
542 | if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
543 | return conversionType.GetGenericArguments()[0];
544 |
545 | return conversionType;
546 | }
547 |
548 | private DataSet CreateDataset(Dictionary reader, Dictionary globalTypes)
549 | {
550 | DataSet ds = new DataSet();
551 | ds.EnforceConstraints = false;
552 | ds.BeginInit();
553 |
554 | // read dataset schema here
555 | ReadSchema(reader, ds, globalTypes);
556 |
557 | foreach (KeyValuePair pair in reader)
558 | {
559 | if (pair.Key == "$type" || pair.Key == "$schema") continue;
560 |
561 | ArrayList rows = (ArrayList)pair.Value;
562 | if (rows == null) continue;
563 |
564 | DataTable dt = ds.Tables[pair.Key];
565 | ReadDataTable(rows, dt);
566 | }
567 |
568 | ds.EndInit();
569 |
570 | return ds;
571 | }
572 |
573 | private void ReadSchema(Dictionary reader, DataSet ds, Dictionary globalTypes)
574 | {
575 | var schema = reader["$schema"];
576 |
577 | if (schema is string)
578 | {
579 | TextReader tr = new StringReader((string)schema);
580 | ds.ReadXmlSchema(tr);
581 | }
582 | else
583 | {
584 | DatasetSchema ms = (DatasetSchema)ParseDictionary((Dictionary)schema, globalTypes, typeof(DatasetSchema), null);
585 | ds.DataSetName = ms.Name;
586 | for (int i = 0; i < ms.Info.Count; i += 3)
587 | {
588 | if (ds.Tables.Contains(ms.Info[i]) == false)
589 | ds.Tables.Add(ms.Info[i]);
590 | ds.Tables[ms.Info[i]].Columns.Add(ms.Info[i + 1], Type.GetType(ms.Info[i + 2]));
591 | }
592 | }
593 | }
594 |
595 | private void ReadDataTable(ArrayList rows, DataTable dt)
596 | {
597 | dt.BeginInit();
598 | dt.BeginLoadData();
599 | List guidcols = new List();
600 | List datecol = new List();
601 |
602 | foreach (DataColumn c in dt.Columns)
603 | {
604 | if (c.DataType == typeof(Guid) || c.DataType == typeof(Guid?))
605 | guidcols.Add(c.Ordinal);
606 | if (_params.UseUTCDateTime && (c.DataType == typeof(DateTime) || c.DataType == typeof(DateTime?)))
607 | datecol.Add(c.Ordinal);
608 | }
609 |
610 | foreach (ArrayList row in rows)
611 | {
612 | object[] v = new object[row.Count];
613 | row.CopyTo(v, 0);
614 | foreach (int i in guidcols)
615 | {
616 | string s = (string)v[i];
617 | if (s != null && s.Length < 36)
618 | v[i] = new Guid(Convert.FromBase64String(s));
619 | }
620 | if (_params.UseUTCDateTime)
621 | {
622 | foreach (int i in datecol)
623 | {
624 | string s = (string)v[i];
625 | if (s != null)
626 | v[i] = CreateDateTime(s);
627 | }
628 | }
629 | dt.Rows.Add(v);
630 | }
631 |
632 | dt.EndLoadData();
633 | dt.EndInit();
634 | }
635 |
636 | DataTable CreateDataTable(Dictionary reader, Dictionary globalTypes)
637 | {
638 | var dt = new DataTable();
639 |
640 | // read dataset schema here
641 | var schema = reader["$schema"];
642 |
643 | if (schema is string)
644 | {
645 | TextReader tr = new StringReader((string)schema);
646 | dt.ReadXmlSchema(tr);
647 | }
648 | else
649 | {
650 | var ms = (DatasetSchema)this.ParseDictionary((Dictionary)schema, globalTypes, typeof(DatasetSchema), null);
651 | dt.TableName = ms.Info[0];
652 | for (int i = 0; i < ms.Info.Count; i += 3)
653 | {
654 | dt.Columns.Add(ms.Info[i + 1], Type.GetType(ms.Info[i + 2]));
655 | }
656 | }
657 |
658 | foreach (var pair in reader)
659 | {
660 | if (pair.Key == "$type" || pair.Key == "$schema")
661 | continue;
662 |
663 | var rows = (ArrayList)pair.Value;
664 | if (rows == null)
665 | continue;
666 |
667 | if (!dt.TableName.Equals(pair.Key, StringComparison.InvariantCultureIgnoreCase))
668 | continue;
669 |
670 | ReadDataTable(rows, dt);
671 | }
672 |
673 | return dt;
674 | }
675 |
676 | #endregion
677 | }
678 |
679 | #endregion
680 |
681 |
682 |
683 |
684 |
685 | #region Serializer
686 | internal class JSONSerializer
687 | {
688 | private readonly StringBuilder _output = new StringBuilder();
689 | readonly int _MAX_DEPTH = 10;
690 | int _current_depth = 0;
691 | private Dictionary _globalTypes = new Dictionary();
692 | private JSONParameters _params;
693 |
694 | internal JSONSerializer(JSONParameters param)
695 | {
696 | _params = param;
697 | }
698 |
699 | internal string ConvertToJSON(object obj)
700 | {
701 | WriteValue(obj);
702 |
703 | string str = "";
704 | if (_params.UsingGlobalTypes)
705 | {
706 | StringBuilder sb = new StringBuilder();
707 | sb.Append("\"$types\":{");
708 | bool pendingSeparator = false;
709 | foreach (var kv in _globalTypes)
710 | {
711 | if (pendingSeparator) sb.Append(',');
712 | pendingSeparator = true;
713 | sb.Append("\"");
714 | sb.Append(kv.Key);
715 | sb.Append("\":\"");
716 | sb.Append(kv.Value);
717 | sb.Append("\"");
718 | }
719 | sb.Append("},");
720 | str = _output.Replace("$types$", sb.ToString()).ToString();
721 | }
722 | else
723 | str = _output.ToString();
724 |
725 | return str;
726 | }
727 |
728 | private void WriteValue(object obj)
729 | {
730 | if (obj == null || obj is DBNull)
731 | _output.Append("null");
732 |
733 | else if (obj is string || obj is char)
734 | WriteString(obj.ToString());
735 |
736 | else if (obj is Guid)
737 | WriteGuid((Guid)obj);
738 |
739 | else if (obj is bool)
740 | _output.Append(((bool)obj) ? "true" : "false"); // conform to standard
741 |
742 | else if (
743 | obj is int || obj is long || obj is double ||
744 | obj is decimal || obj is float ||
745 | obj is byte || obj is short ||
746 | obj is sbyte || obj is ushort ||
747 | obj is uint || obj is ulong
748 | )
749 | _output.Append(((IConvertible)obj).ToString(NumberFormatInfo.InvariantInfo));
750 |
751 | else if (obj is DateTime)
752 | WriteDateTime((DateTime)obj);
753 |
754 | else if (obj is IDictionary && obj.GetType().IsGenericType && obj.GetType().GetGenericArguments()[0] == typeof(string))
755 | WriteStringDictionary((IDictionary)obj);
756 |
757 | else if (obj is IDictionary)
758 | WriteDictionary((IDictionary)obj);
759 |
760 | else if (obj is DataSet)
761 | WriteDataset((DataSet)obj);
762 |
763 | else if (obj is DataTable)
764 | this.WriteDataTable((DataTable)obj);
765 |
766 | else if (obj is byte[])
767 | WriteBytes((byte[])obj);
768 |
769 | else if (obj is Array || obj is IList || obj is ICollection)
770 | WriteArray((IEnumerable)obj);
771 |
772 | else if (obj is Enum)
773 | WriteEnum((Enum)obj);
774 |
775 | else
776 | WriteObject(obj);
777 | }
778 |
779 | private void WriteEnum(Enum e)
780 | {
781 | // TODO : optimize enum write
782 | WriteStringFast(e.ToString());
783 | }
784 |
785 | private void WriteGuid(Guid g)
786 | {
787 | if (_params.UseFastGuid == false)
788 | WriteStringFast(g.ToString());
789 | else
790 | WriteBytes(g.ToByteArray());
791 | }
792 |
793 | private void WriteBytes(byte[] bytes)
794 | {
795 | WriteStringFast(Convert.ToBase64String(bytes, 0, bytes.Length, Base64FormattingOptions.None));
796 | }
797 |
798 | private void WriteDateTime(DateTime dateTime)
799 | {
800 | // datetime format standard : yyyy-MM-dd HH:mm:ss
801 | DateTime dt = dateTime;
802 | if (_params.UseUTCDateTime)
803 | dt = dateTime.ToUniversalTime();
804 |
805 | _output.Append("\"");
806 | _output.Append(dt.Year.ToString("0000", NumberFormatInfo.InvariantInfo));
807 | _output.Append("-");
808 | _output.Append(dt.Month.ToString("00", NumberFormatInfo.InvariantInfo));
809 | _output.Append("-");
810 | _output.Append(dt.Day.ToString("00", NumberFormatInfo.InvariantInfo));
811 | _output.Append(" ");
812 | _output.Append(dt.Hour.ToString("00", NumberFormatInfo.InvariantInfo));
813 | _output.Append(":");
814 | _output.Append(dt.Minute.ToString("00", NumberFormatInfo.InvariantInfo));
815 | _output.Append(":");
816 | _output.Append(dt.Second.ToString("00", NumberFormatInfo.InvariantInfo));
817 |
818 | if (_params.UseUTCDateTime)
819 | _output.Append("Z");
820 |
821 | _output.Append("\"");
822 | }
823 | private DatasetSchema GetSchema(DataTable ds)
824 | {
825 | if (ds == null) return null;
826 |
827 | DatasetSchema m = new DatasetSchema();
828 | m.Info = new List();
829 | m.Name = ds.TableName;
830 |
831 | foreach (DataColumn c in ds.Columns)
832 | {
833 | m.Info.Add(ds.TableName);
834 | m.Info.Add(c.ColumnName);
835 | m.Info.Add(c.DataType.ToString());
836 | }
837 | // FEATURE : serialize relations and constraints here
838 |
839 | return m;
840 | }
841 |
842 | private DatasetSchema GetSchema(DataSet ds)
843 | {
844 | if (ds == null) return null;
845 |
846 | DatasetSchema m = new DatasetSchema();
847 | m.Info = new List();
848 | m.Name = ds.DataSetName;
849 |
850 | foreach (DataTable t in ds.Tables)
851 | {
852 | foreach (DataColumn c in t.Columns)
853 | {
854 | m.Info.Add(t.TableName);
855 | m.Info.Add(c.ColumnName);
856 | m.Info.Add(c.DataType.ToString());
857 | }
858 | }
859 | // FEATURE : serialize relations and constraints here
860 |
861 | return m;
862 | }
863 |
864 | private string GetXmlSchema(DataTable dt)
865 | {
866 | using (var writer = new StringWriter())
867 | {
868 | dt.WriteXmlSchema(writer);
869 | return dt.ToString();
870 | }
871 | }
872 |
873 | private void WriteDataset(DataSet ds)
874 | {
875 | _output.Append('{');
876 | if ( _params.UseExtensions)
877 | {
878 | WritePair("$schema", _params.UseOptimizedDatasetSchema ? (object)GetSchema(ds) : ds.GetXmlSchema());
879 | _output.Append(',');
880 | }
881 | bool tablesep = false;
882 | foreach (DataTable table in ds.Tables)
883 | {
884 | if (tablesep) _output.Append(",");
885 | tablesep = true;
886 | WriteDataTableData(table);
887 | }
888 | // end dataset
889 | _output.Append('}');
890 | }
891 |
892 | private void WriteDataTableData(DataTable table)
893 | {
894 | _output.Append('\"');
895 | _output.Append(table.TableName);
896 | _output.Append("\":[");
897 | DataColumnCollection cols = table.Columns;
898 | bool rowseparator = false;
899 | foreach (DataRow row in table.Rows)
900 | {
901 | if (rowseparator) _output.Append(",");
902 | rowseparator = true;
903 | _output.Append('[');
904 |
905 | bool pendingSeperator = false;
906 | foreach (DataColumn column in cols)
907 | {
908 | if (pendingSeperator) _output.Append(',');
909 | WriteValue(row[column]);
910 | pendingSeperator = true;
911 | }
912 | _output.Append(']');
913 | }
914 |
915 | _output.Append(']');
916 | }
917 |
918 | void WriteDataTable(DataTable dt)
919 | {
920 | this._output.Append('{');
921 | if (_params.UseExtensions)
922 | {
923 | this.WritePair("$schema", _params.UseOptimizedDatasetSchema ? (object)this.GetSchema(dt) : this.GetXmlSchema(dt));
924 | this._output.Append(',');
925 | }
926 |
927 | WriteDataTableData(dt);
928 |
929 | // end datatable
930 | this._output.Append('}');
931 | }
932 | bool _TypesWritten = false;
933 | private void WriteObject(object obj)
934 | {
935 | if (_params.UsingGlobalTypes == false)
936 | _output.Append('{');
937 | else
938 | {
939 | if (_TypesWritten== false)
940 | _output.Append("{$types$");
941 | else
942 | _output.Append("{");
943 | }
944 | _TypesWritten = true;
945 | _current_depth++;
946 | if (_current_depth > _MAX_DEPTH)
947 | throw new Exception("Serializer encountered maximum depth of " + _MAX_DEPTH);
948 |
949 |
950 | Dictionary map = new Dictionary();
951 | Type t = obj.GetType();
952 | bool append = false;
953 | if (_params.UseExtensions)
954 | {
955 | if (_params.UsingGlobalTypes == false)
956 | WritePairFast("$type", Reflection.Instance.GetTypeAssemblyName(t));
957 | else
958 | {
959 | int dt = 0;
960 | string ct = Reflection.Instance.GetTypeAssemblyName(t);
961 | if (_globalTypes.TryGetValue(ct, out dt) == false)
962 | {
963 | dt = _globalTypes.Count + 1;
964 | _globalTypes.Add(ct, dt);
965 | }
966 | WritePairFast("$type", dt.ToString());
967 | }
968 | append = true;
969 | }
970 |
971 | List g = Reflection.Instance.GetGetters(t);
972 | foreach (var p in g)
973 | {
974 | if (append)
975 | _output.Append(',');
976 | object o = p.Getter(obj);
977 | if ((o == null || o is DBNull) && _params.SerializeNullValues == false)
978 | append = false;
979 | else
980 | {
981 | WritePair(p.Name, o);
982 | if (o != null && _params.UseExtensions)
983 | {
984 | Type tt = o.GetType();
985 | if (tt == typeof(System.Object))
986 | map.Add(p.Name, tt.ToString());
987 | }
988 | append = true;
989 | }
990 | }
991 | if (map.Count > 0 && _params.UseExtensions)
992 | {
993 | _output.Append(",\"$map\":");
994 | WriteStringDictionary(map);
995 | }
996 | _current_depth--;
997 | _output.Append('}');
998 | _current_depth--;
999 |
1000 | }
1001 |
1002 | private void WritePairFast(string name, string value)
1003 | {
1004 | if ((value == null) && _params.SerializeNullValues == false)
1005 | return;
1006 | WriteStringFast(name);
1007 |
1008 | _output.Append(':');
1009 |
1010 | WriteStringFast(value);
1011 | }
1012 |
1013 | private void WritePair(string name, object value)
1014 | {
1015 | if ((value == null || value is DBNull) && _params.SerializeNullValues == false)
1016 | return;
1017 | WriteStringFast(name);
1018 |
1019 | _output.Append(':');
1020 |
1021 | WriteValue(value);
1022 | }
1023 |
1024 | private void WriteArray(IEnumerable array)
1025 | {
1026 | _output.Append('[');
1027 |
1028 | bool pendingSeperator = false;
1029 |
1030 | foreach (object obj in array)
1031 | {
1032 | if (pendingSeperator) _output.Append(',');
1033 |
1034 | WriteValue(obj);
1035 |
1036 | pendingSeperator = true;
1037 | }
1038 | _output.Append(']');
1039 | }
1040 |
1041 | private void WriteStringDictionary(IDictionary dic)
1042 | {
1043 | _output.Append('{');
1044 |
1045 | bool pendingSeparator = false;
1046 |
1047 | foreach (DictionaryEntry entry in dic)
1048 | {
1049 | if (pendingSeparator) _output.Append(',');
1050 |
1051 | WritePair((string)entry.Key, entry.Value);
1052 |
1053 | pendingSeparator = true;
1054 | }
1055 | _output.Append('}');
1056 | }
1057 |
1058 | private void WriteDictionary(IDictionary dic)
1059 | {
1060 | _output.Append('[');
1061 |
1062 | bool pendingSeparator = false;
1063 |
1064 | foreach (DictionaryEntry entry in dic)
1065 | {
1066 | if (pendingSeparator) _output.Append(',');
1067 | _output.Append('{');
1068 | WritePair("k", entry.Key);
1069 | _output.Append(",");
1070 | WritePair("v", entry.Value);
1071 | _output.Append('}');
1072 |
1073 | pendingSeparator = true;
1074 | }
1075 | _output.Append(']');
1076 | }
1077 |
1078 | private void WriteStringFast(string s)
1079 | {
1080 | _output.Append('\"');
1081 | _output.Append(s);
1082 | _output.Append('\"');
1083 | }
1084 |
1085 | private void WriteString(string s)
1086 | {
1087 | _output.Append('\"');
1088 |
1089 | int runIndex = -1;
1090 |
1091 | for (var index = 0; index < s.Length; ++index)
1092 | {
1093 | var c = s[index];
1094 |
1095 | if (c >= ' ' && c < 128 && c != '\"' && c != '\\')
1096 | {
1097 | if (runIndex == -1)
1098 | {
1099 | runIndex = index;
1100 | }
1101 |
1102 | continue;
1103 | }
1104 |
1105 | if (runIndex != -1)
1106 | {
1107 | _output.Append(s, runIndex, index - runIndex);
1108 | runIndex = -1;
1109 | }
1110 |
1111 | switch (c)
1112 | {
1113 | case '\t': _output.Append("\\t"); break;
1114 | case '\r': _output.Append("\\r"); break;
1115 | case '\n': _output.Append("\\n"); break;
1116 | case '"':
1117 | case '\\': _output.Append('\\'); _output.Append(c); break;
1118 | default:
1119 | _output.Append("\\u");
1120 | _output.Append(((int)c).ToString("X4", NumberFormatInfo.InvariantInfo));
1121 | break;
1122 | }
1123 | }
1124 |
1125 | if (runIndex != -1)
1126 | {
1127 | _output.Append(s, runIndex, s.Length - runIndex);
1128 | }
1129 |
1130 | _output.Append('\"');
1131 | }
1132 | }
1133 |
1134 |
1135 | #endregion
1136 |
1137 |
1138 |
1139 |
1140 |
1141 | #region Reflection
1142 | internal class Getters
1143 | {
1144 | public string Name;
1145 | public Reflection.GenericGetter Getter;
1146 | public Type propertyType;
1147 | }
1148 |
1149 | internal class Reflection
1150 | {
1151 | public readonly static Reflection Instance = new Reflection();
1152 | private Reflection()
1153 | {
1154 | }
1155 |
1156 | public bool ShowReadOnlyProperties = false;
1157 | internal delegate object GenericSetter(object target, object value);
1158 | internal delegate object GenericGetter(object obj);
1159 | private delegate object CreateObject();
1160 |
1161 | private SafeDictionary _tyname = new SafeDictionary();
1162 | private SafeDictionary _typecache = new SafeDictionary();
1163 | private SafeDictionary _constrcache = new SafeDictionary();
1164 | private SafeDictionary> _getterscache = new SafeDictionary>();
1165 |
1166 | #region [ PROPERTY GET SET ]
1167 | internal string GetTypeAssemblyName(Type t)
1168 | {
1169 | string val = "";
1170 | if (_tyname.TryGetValue(t, out val))
1171 | return val;
1172 | else
1173 | {
1174 | string s = t.AssemblyQualifiedName;
1175 | _tyname.Add(t, s);
1176 | return s;
1177 | }
1178 | }
1179 |
1180 | internal Type GetTypeFromCache(string typename)
1181 | {
1182 | Type val = null;
1183 | if (_typecache.TryGetValue(typename, out val))
1184 | return val;
1185 | else
1186 | {
1187 | Type t = Type.GetType(typename);
1188 | _typecache.Add(typename, t);
1189 | return t;
1190 | }
1191 | }
1192 |
1193 | internal object FastCreateInstance(Type objtype)
1194 | {
1195 | try
1196 | {
1197 | CreateObject c = null;
1198 | if (_constrcache.TryGetValue(objtype, out c))
1199 | {
1200 | return c();
1201 | }
1202 | else
1203 | {
1204 | DynamicMethod dynMethod = new DynamicMethod("_",
1205 | MethodAttributes.Public | MethodAttributes.Static,
1206 | CallingConventions.Standard,
1207 | typeof(object),
1208 | null,
1209 | objtype, false);
1210 | ILGenerator ilGen = dynMethod.GetILGenerator();
1211 |
1212 | if (objtype.IsClass)
1213 | {
1214 | ilGen.Emit(OpCodes.Newobj, objtype.GetConstructor(Type.EmptyTypes));
1215 | ilGen.Emit(OpCodes.Ret);
1216 | c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject));
1217 | _constrcache.Add(objtype, c);
1218 | }
1219 | else // structs
1220 | {
1221 | var lv = ilGen.DeclareLocal(objtype);
1222 | ilGen.Emit(OpCodes.Ldloca_S, lv);
1223 | ilGen.Emit(OpCodes.Initobj, objtype);
1224 | ilGen.Emit(OpCodes.Ldloc_0);
1225 | ilGen.Emit(OpCodes.Box, objtype);
1226 | ilGen.Emit(OpCodes.Ret);
1227 | c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject));
1228 | _constrcache.Add(objtype, c);
1229 | }
1230 | return c();
1231 | }
1232 | }
1233 | catch (Exception exc)
1234 | {
1235 | throw new Exception(string.Format("Failed to fast create instance for type '{0}' from assemebly '{1}'",
1236 | objtype.FullName, objtype.AssemblyQualifiedName), exc);
1237 | }
1238 | }
1239 |
1240 | internal static GenericSetter CreateSetField(Type type, FieldInfo fieldInfo)
1241 | {
1242 | Type[] arguments = new Type[2];
1243 | arguments[0] = arguments[1] = typeof(object);
1244 |
1245 | DynamicMethod dynamicSet = new DynamicMethod("_", typeof(object), arguments, type, true);
1246 | ILGenerator il = dynamicSet.GetILGenerator();
1247 |
1248 | if (!type.IsClass) // structs
1249 | {
1250 | var lv = il.DeclareLocal(type);
1251 | il.Emit(OpCodes.Ldarg_0);
1252 | il.Emit(OpCodes.Unbox_Any, type);
1253 | il.Emit(OpCodes.Stloc_0);
1254 | il.Emit(OpCodes.Ldloca_S, lv);
1255 | il.Emit(OpCodes.Ldarg_1);
1256 | if (fieldInfo.FieldType.IsClass)
1257 | il.Emit(OpCodes.Castclass, fieldInfo.FieldType);
1258 | else
1259 | il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
1260 | il.Emit(OpCodes.Stfld, fieldInfo);
1261 | il.Emit(OpCodes.Ldloc_0);
1262 | il.Emit(OpCodes.Box, type);
1263 | il.Emit(OpCodes.Ret);
1264 | }
1265 | else
1266 | {
1267 | il.Emit(OpCodes.Ldarg_0);
1268 | il.Emit(OpCodes.Ldarg_1);
1269 | if (fieldInfo.FieldType.IsValueType)
1270 | il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
1271 | il.Emit(OpCodes.Stfld, fieldInfo);
1272 | il.Emit(OpCodes.Ldarg_0);
1273 | il.Emit(OpCodes.Ret);
1274 | }
1275 | return (GenericSetter)dynamicSet.CreateDelegate(typeof(GenericSetter));
1276 | }
1277 |
1278 | internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo)
1279 | {
1280 | MethodInfo setMethod = propertyInfo.GetSetMethod();
1281 | if (setMethod == null)
1282 | return null;
1283 |
1284 | Type[] arguments = new Type[2];
1285 | arguments[0] = arguments[1] = typeof(object);
1286 |
1287 | DynamicMethod setter = new DynamicMethod("_", typeof(object), arguments, type);
1288 | ILGenerator il = setter.GetILGenerator();
1289 |
1290 | if (!type.IsClass) // structs
1291 | {
1292 | var lv = il.DeclareLocal(type);
1293 | il.Emit(OpCodes.Ldarg_0);
1294 | il.Emit(OpCodes.Unbox_Any, type);
1295 | il.Emit(OpCodes.Stloc_0);
1296 | il.Emit(OpCodes.Ldloca_S, lv);
1297 | il.Emit(OpCodes.Ldarg_1);
1298 | if (propertyInfo.PropertyType.IsClass)
1299 | il.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
1300 | else
1301 | il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
1302 | il.EmitCall(OpCodes.Call, setMethod, null);
1303 | il.Emit(OpCodes.Ldloc_0);
1304 | il.Emit(OpCodes.Box, type);
1305 | }
1306 | else
1307 | {
1308 | il.Emit(OpCodes.Ldarg_0);
1309 | il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
1310 | il.Emit(OpCodes.Ldarg_1);
1311 | if (propertyInfo.PropertyType.IsClass)
1312 | il.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
1313 | else
1314 | il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
1315 | il.EmitCall(OpCodes.Callvirt, setMethod, null);
1316 | il.Emit(OpCodes.Ldarg_0);
1317 | }
1318 |
1319 | il.Emit(OpCodes.Ret);
1320 |
1321 | return (GenericSetter)setter.CreateDelegate(typeof(GenericSetter));
1322 | }
1323 |
1324 | internal static GenericGetter CreateGetField(Type type, FieldInfo fieldInfo)
1325 | {
1326 | DynamicMethod dynamicGet = new DynamicMethod("_", typeof(object), new Type[] { typeof(object) }, type, true);
1327 | ILGenerator il = dynamicGet.GetILGenerator();
1328 |
1329 | if (!type.IsClass) // structs
1330 | {
1331 | var lv = il.DeclareLocal(type);
1332 | il.Emit(OpCodes.Ldarg_0);
1333 | il.Emit(OpCodes.Unbox_Any, type);
1334 | il.Emit(OpCodes.Stloc_0);
1335 | il.Emit(OpCodes.Ldloca_S, lv);
1336 | il.Emit(OpCodes.Ldfld, fieldInfo);
1337 | if (fieldInfo.FieldType.IsValueType)
1338 | il.Emit(OpCodes.Box, fieldInfo.FieldType);
1339 | }
1340 | else
1341 | {
1342 | il.Emit(OpCodes.Ldarg_0);
1343 | il.Emit(OpCodes.Ldfld, fieldInfo);
1344 | if (fieldInfo.FieldType.IsValueType)
1345 | il.Emit(OpCodes.Box, fieldInfo.FieldType);
1346 | }
1347 |
1348 | il.Emit(OpCodes.Ret);
1349 |
1350 | return (GenericGetter)dynamicGet.CreateDelegate(typeof(GenericGetter));
1351 | }
1352 |
1353 | internal static GenericGetter CreateGetMethod(Type type, PropertyInfo propertyInfo)
1354 | {
1355 | MethodInfo getMethod = propertyInfo.GetGetMethod();
1356 | if (getMethod == null)
1357 | return null;
1358 |
1359 | Type[] arguments = new Type[1];
1360 | arguments[0] = typeof(object);
1361 |
1362 | DynamicMethod getter = new DynamicMethod("_", typeof(object), arguments, type);
1363 | ILGenerator il = getter.GetILGenerator();
1364 |
1365 | if (!type.IsClass) // structs
1366 | {
1367 | var lv = il.DeclareLocal(type);
1368 | il.Emit(OpCodes.Ldarg_0);
1369 | il.Emit(OpCodes.Unbox_Any, type);
1370 | il.Emit(OpCodes.Stloc_0);
1371 | il.Emit(OpCodes.Ldloca_S, lv);
1372 | il.EmitCall(OpCodes.Call, getMethod, null);
1373 | if (propertyInfo.PropertyType.IsValueType)
1374 | il.Emit(OpCodes.Box, propertyInfo.PropertyType);
1375 | }
1376 | else
1377 | {
1378 | il.Emit(OpCodes.Ldarg_0);
1379 | il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
1380 | il.EmitCall(OpCodes.Callvirt, getMethod, null);
1381 | if (propertyInfo.PropertyType.IsValueType)
1382 | il.Emit(OpCodes.Box, propertyInfo.PropertyType);
1383 | }
1384 |
1385 | il.Emit(OpCodes.Ret);
1386 |
1387 | return (GenericGetter)getter.CreateDelegate(typeof(GenericGetter));
1388 | }
1389 |
1390 | internal List GetGetters(Type type)
1391 | {
1392 | List val = null;
1393 | if (_getterscache.TryGetValue(type, out val))
1394 | return val;
1395 |
1396 | PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
1397 | List getters = new List();
1398 | foreach (PropertyInfo p in props)
1399 | {
1400 | if (!p.CanWrite && ShowReadOnlyProperties == false) continue;
1401 |
1402 | object[] att = p.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false);
1403 | if (att != null && att.Length > 0)
1404 | continue;
1405 |
1406 | GenericGetter g = CreateGetMethod(type, p);
1407 | if (g != null)
1408 | {
1409 | Getters gg = new Getters();
1410 | gg.Name = p.Name;
1411 | gg.Getter = g;
1412 | gg.propertyType = p.PropertyType;
1413 | getters.Add(gg);
1414 | }
1415 | }
1416 |
1417 | FieldInfo[] fi = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
1418 | foreach (var f in fi)
1419 | {
1420 | object[] att = f.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false);
1421 | if (att != null && att.Length > 0)
1422 | continue;
1423 |
1424 | GenericGetter g = CreateGetField(type, f);
1425 | if (g != null)
1426 | {
1427 | Getters gg = new Getters();
1428 | gg.Name = f.Name;
1429 | gg.Getter = g;
1430 | gg.propertyType = f.FieldType;
1431 | getters.Add(gg);
1432 | }
1433 | }
1434 |
1435 | _getterscache.Add(type, getters);
1436 | return getters;
1437 | }
1438 |
1439 | #endregion
1440 | }
1441 | #endregion
1442 |
1443 |
1444 |
1445 |
1446 |
1447 | #region SafeDictionary
1448 | internal class SafeDictionary
1449 | {
1450 | private readonly object _Padlock = new object();
1451 | private readonly Dictionary _Dictionary;
1452 |
1453 | public SafeDictionary(int capacity)
1454 | {
1455 | _Dictionary = new Dictionary(capacity);
1456 | }
1457 |
1458 | public SafeDictionary()
1459 | {
1460 | _Dictionary = new Dictionary();
1461 | }
1462 |
1463 | public bool TryGetValue(TKey key, out TValue value)
1464 | {
1465 | lock (_Padlock)
1466 | return _Dictionary.TryGetValue(key, out value);
1467 | }
1468 |
1469 | public TValue this[TKey key]
1470 | {
1471 | get
1472 | {
1473 | lock (_Padlock)
1474 | return _Dictionary[key];
1475 | }
1476 | set
1477 | {
1478 | lock (_Padlock)
1479 | _Dictionary[key] = value;
1480 | }
1481 | }
1482 |
1483 | public void Add(TKey key, TValue value)
1484 | {
1485 | lock (_Padlock)
1486 | {
1487 | if (_Dictionary.ContainsKey(key) == false)
1488 | _Dictionary.Add(key, value);
1489 | }
1490 | }
1491 | }
1492 | #endregion
1493 |
1494 |
1495 |
1496 |
1497 | #region Formatter
1498 | internal static class Formatter
1499 | {
1500 | public static string Indent = " ";
1501 |
1502 | public static void AppendIndent(StringBuilder sb, int count)
1503 | {
1504 | for (; count > 0; --count) sb.Append(Indent);
1505 | }
1506 |
1507 | public static bool IsEscaped(StringBuilder sb, int index)
1508 | {
1509 | bool escaped = false;
1510 | while (index > 0 && sb[--index] == '\\') escaped = !escaped;
1511 | return escaped;
1512 | }
1513 |
1514 | public static string PrettyPrint(string input)
1515 | {
1516 | var output = new StringBuilder(input.Length * 2);
1517 | char? quote = null;
1518 | int depth = 0;
1519 |
1520 | for (int i = 0; i < input.Length; ++i)
1521 | {
1522 | char ch = input[i];
1523 |
1524 | switch (ch)
1525 | {
1526 | case '{':
1527 | case '[':
1528 | output.Append(ch);
1529 | if (!quote.HasValue)
1530 | {
1531 | output.AppendLine();
1532 | AppendIndent(output, ++depth);
1533 | }
1534 | break;
1535 | case '}':
1536 | case ']':
1537 | if (quote.HasValue)
1538 | output.Append(ch);
1539 | else
1540 | {
1541 | output.AppendLine();
1542 | AppendIndent(output, --depth);
1543 | output.Append(ch);
1544 | }
1545 | break;
1546 | case '"':
1547 | case '\'':
1548 | output.Append(ch);
1549 | if (quote.HasValue)
1550 | {
1551 | if (!IsEscaped(output, i))
1552 | quote = null;
1553 | }
1554 | else quote = ch;
1555 | break;
1556 | case ',':
1557 | output.Append(ch);
1558 | if (!quote.HasValue)
1559 | {
1560 | output.AppendLine();
1561 | AppendIndent(output, depth);
1562 | }
1563 | break;
1564 | case ':':
1565 | if (quote.HasValue) output.Append(ch);
1566 | else output.Append(" : ");
1567 | break;
1568 | default:
1569 | if (quote.HasValue || !char.IsWhiteSpace(ch))
1570 | output.Append(ch);
1571 | break;
1572 | }
1573 | }
1574 |
1575 | return output.ToString();
1576 | }
1577 | }
1578 | #endregion
1579 |
1580 |
1581 |
1582 |
1583 | #region Getters
1584 | public class DatasetSchema
1585 | {
1586 | public List Info { get; set; }
1587 | public string Name { get; set; }
1588 | }
1589 | #endregion
1590 |
1591 |
1592 |
1593 |
1594 |
1595 |
1596 | #region Parser
1597 |
1598 | ///
1599 | /// This class encodes and decodes JSON strings.
1600 | /// Spec. details, see http://www.json.org/
1601 | ///
1602 | /// JSON uses Arrays and Objects. These correspond here to the datatypes ArrayList and Hashtable.
1603 | /// All numbers are parsed to doubles.
1604 | ///
1605 | internal class JsonParser
1606 | {
1607 | enum Token
1608 | {
1609 | None = -1, // Used to denote no Lookahead available
1610 | Curly_Open,
1611 | Curly_Close,
1612 | Squared_Open,
1613 | Squared_Close,
1614 | Colon,
1615 | Comma,
1616 | String,
1617 | Number,
1618 | True,
1619 | False,
1620 | Null
1621 | }
1622 |
1623 | readonly char[] json;
1624 | readonly StringBuilder s = new StringBuilder();
1625 | Token lookAheadToken = Token.None;
1626 | int index;
1627 | bool _ignorecase = false;
1628 |
1629 |
1630 | internal JsonParser(string json, bool ignorecase)
1631 | {
1632 | this.json = json.ToCharArray();
1633 | _ignorecase = ignorecase;
1634 | }
1635 |
1636 | public object Decode()
1637 | {
1638 | return ParseValue();
1639 | }
1640 |
1641 | private Dictionary ParseObject()
1642 | {
1643 | Dictionary table = new Dictionary();
1644 |
1645 | ConsumeToken(); // {
1646 |
1647 | while (true)
1648 | {
1649 | switch (LookAhead())
1650 | {
1651 |
1652 | case Token.Comma:
1653 | ConsumeToken();
1654 | break;
1655 |
1656 | case Token.Curly_Close:
1657 | ConsumeToken();
1658 | return table;
1659 |
1660 | default:
1661 | {
1662 |
1663 | // name
1664 | string name = ParseString();
1665 | if (_ignorecase)
1666 | name = name.ToLower();
1667 |
1668 | // :
1669 | if (NextToken() != Token.Colon)
1670 | {
1671 | throw new Exception("Expected colon at index " + index);
1672 | }
1673 |
1674 | // value
1675 | object value = ParseValue();
1676 |
1677 | table[name] = value;
1678 | }
1679 | break;
1680 | }
1681 | }
1682 | }
1683 |
1684 | private ArrayList ParseArray()
1685 | {
1686 | ArrayList array = new ArrayList();
1687 |
1688 | ConsumeToken(); // [
1689 |
1690 | while (true)
1691 | {
1692 | switch (LookAhead())
1693 | {
1694 |
1695 | case Token.Comma:
1696 | ConsumeToken();
1697 | break;
1698 |
1699 | case Token.Squared_Close:
1700 | ConsumeToken();
1701 | return array;
1702 |
1703 | default:
1704 | {
1705 | array.Add(ParseValue());
1706 | }
1707 | break;
1708 | }
1709 | }
1710 | }
1711 |
1712 | private object ParseValue()
1713 | {
1714 | switch (LookAhead())
1715 | {
1716 | case Token.Number:
1717 | return ParseNumber();
1718 |
1719 | case Token.String:
1720 | return ParseString();
1721 |
1722 | case Token.Curly_Open:
1723 | return ParseObject();
1724 |
1725 | case Token.Squared_Open:
1726 | return ParseArray();
1727 |
1728 | case Token.True:
1729 | ConsumeToken();
1730 | return true;
1731 |
1732 | case Token.False:
1733 | ConsumeToken();
1734 | return false;
1735 |
1736 | case Token.Null:
1737 | ConsumeToken();
1738 | return null;
1739 | }
1740 |
1741 | throw new Exception("Unrecognized token at index" + index);
1742 | }
1743 |
1744 | private string ParseString()
1745 | {
1746 | ConsumeToken(); // "
1747 |
1748 | s.Length = 0;
1749 |
1750 | int runIndex = -1;
1751 |
1752 | while (index < json.Length)
1753 | {
1754 | var c = json[index++];
1755 |
1756 | if (c == '"')
1757 | {
1758 | if (runIndex != -1)
1759 | {
1760 | if (s.Length == 0)
1761 | return new string(json, runIndex, index - runIndex - 1);
1762 |
1763 | s.Append(json, runIndex, index - runIndex - 1);
1764 | }
1765 | return s.ToString();
1766 | }
1767 |
1768 | if (c != '\\')
1769 | {
1770 | if (runIndex == -1)
1771 | runIndex = index - 1;
1772 |
1773 | continue;
1774 | }
1775 |
1776 | if (index == json.Length) break;
1777 |
1778 | if (runIndex != -1)
1779 | {
1780 | s.Append(json, runIndex, index - runIndex - 1);
1781 | runIndex = -1;
1782 | }
1783 |
1784 | switch (json[index++])
1785 | {
1786 | case '"':
1787 | s.Append('"');
1788 | break;
1789 |
1790 | case '\\':
1791 | s.Append('\\');
1792 | break;
1793 |
1794 | case '/':
1795 | s.Append('/');
1796 | break;
1797 |
1798 | case 'b':
1799 | s.Append('\b');
1800 | break;
1801 |
1802 | case 'f':
1803 | s.Append('\f');
1804 | break;
1805 |
1806 | case 'n':
1807 | s.Append('\n');
1808 | break;
1809 |
1810 | case 'r':
1811 | s.Append('\r');
1812 | break;
1813 |
1814 | case 't':
1815 | s.Append('\t');
1816 | break;
1817 |
1818 | case 'u':
1819 | {
1820 | int remainingLength = json.Length - index;
1821 | if (remainingLength < 4) break;
1822 |
1823 | // parse the 32 bit hex into an integer codepoint
1824 | uint codePoint = ParseUnicode(json[index], json[index + 1], json[index + 2], json[index + 3]);
1825 | s.Append((char)codePoint);
1826 |
1827 | // skip 4 chars
1828 | index += 4;
1829 | }
1830 | break;
1831 | }
1832 | }
1833 |
1834 | throw new Exception("Unexpectedly reached end of string");
1835 | }
1836 |
1837 | private uint ParseSingleChar(char c1, uint multipliyer)
1838 | {
1839 | uint p1 = 0;
1840 | if (c1 >= '0' && c1 <= '9')
1841 | p1 = (uint)(c1 - '0') * multipliyer;
1842 | else if (c1 >= 'A' && c1 <= 'F')
1843 | p1 = (uint)((c1 - 'A') + 10) * multipliyer;
1844 | else if (c1 >= 'a' && c1 <= 'f')
1845 | p1 = (uint)((c1 - 'a') + 10) * multipliyer;
1846 | return p1;
1847 | }
1848 |
1849 | private uint ParseUnicode(char c1, char c2, char c3, char c4)
1850 | {
1851 | uint p1 = ParseSingleChar(c1, 0x1000);
1852 | uint p2 = ParseSingleChar(c2, 0x100);
1853 | uint p3 = ParseSingleChar(c3, 0x10);
1854 | uint p4 = ParseSingleChar(c4, 1);
1855 |
1856 | return p1 + p2 + p3 + p4;
1857 | }
1858 |
1859 | private string ParseNumber()
1860 | {
1861 | ConsumeToken();
1862 |
1863 | // Need to start back one place because the first digit is also a token and would have been consumed
1864 | var startIndex = index - 1;
1865 |
1866 | do
1867 | {
1868 | var c = json[index];
1869 |
1870 | if ((c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+' || c == 'e' || c == 'E')
1871 | {
1872 | if (++index == json.Length) throw new Exception("Unexpected end of string whilst parsing number");
1873 | continue;
1874 | }
1875 |
1876 | break;
1877 | } while (true);
1878 |
1879 | return new string(json, startIndex, index - startIndex);
1880 | }
1881 |
1882 | private Token LookAhead()
1883 | {
1884 | if (lookAheadToken != Token.None) return lookAheadToken;
1885 |
1886 | return lookAheadToken = NextTokenCore();
1887 | }
1888 |
1889 | private void ConsumeToken()
1890 | {
1891 | lookAheadToken = Token.None;
1892 | }
1893 |
1894 | private Token NextToken()
1895 | {
1896 | var result = lookAheadToken != Token.None ? lookAheadToken : NextTokenCore();
1897 |
1898 | lookAheadToken = Token.None;
1899 |
1900 | return result;
1901 | }
1902 |
1903 | private Token NextTokenCore()
1904 | {
1905 | char c;
1906 |
1907 | // Skip past whitespace
1908 | do
1909 | {
1910 | c = json[index];
1911 |
1912 | if (c > ' ') break;
1913 | if (c != ' ' && c != '\t' && c != '\n' && c != '\r') break;
1914 |
1915 | } while (++index < json.Length);
1916 |
1917 | if (index == json.Length)
1918 | {
1919 | throw new Exception("Reached end of string unexpectedly");
1920 | }
1921 |
1922 | c = json[index];
1923 |
1924 | index++;
1925 |
1926 | //if (c >= '0' && c <= '9')
1927 | // return Token.Number;
1928 |
1929 | switch (c)
1930 | {
1931 | case '{':
1932 | return Token.Curly_Open;
1933 |
1934 | case '}':
1935 | return Token.Curly_Close;
1936 |
1937 | case '[':
1938 | return Token.Squared_Open;
1939 |
1940 | case ']':
1941 | return Token.Squared_Close;
1942 |
1943 | case ',':
1944 | return Token.Comma;
1945 |
1946 | case '"':
1947 | return Token.String;
1948 |
1949 | case '0': case '1': case '2': case '3': case '4':
1950 | case '5': case '6': case '7': case '8': case '9':
1951 | case '-': case '+': case '.':
1952 | return Token.Number;
1953 |
1954 | case ':':
1955 | return Token.Colon;
1956 |
1957 | case 'f':
1958 | if (json.Length - index >= 4 &&
1959 | json[index + 0] == 'a' &&
1960 | json[index + 1] == 'l' &&
1961 | json[index + 2] == 's' &&
1962 | json[index + 3] == 'e')
1963 | {
1964 | index += 4;
1965 | return Token.False;
1966 | }
1967 | break;
1968 |
1969 | case 't':
1970 | if (json.Length - index >= 3 &&
1971 | json[index + 0] == 'r' &&
1972 | json[index + 1] == 'u' &&
1973 | json[index + 2] == 'e')
1974 | {
1975 | index += 3;
1976 | return Token.True;
1977 | }
1978 | break;
1979 |
1980 | case 'n':
1981 | if (json.Length - index >= 3 &&
1982 | json[index + 0] == 'u' &&
1983 | json[index + 1] == 'l' &&
1984 | json[index + 2] == 'l')
1985 | {
1986 | index += 3;
1987 | return Token.Null;
1988 | }
1989 | break;
1990 |
1991 | }
1992 |
1993 | throw new Exception("Could not find token at index " + --index);
1994 | }
1995 | }
1996 | #endregion
1997 |
1998 |
--------------------------------------------------------------------------------
/src/Handlers/ContextMenuHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using CefSharp;
6 | using System.Windows.Forms;
7 | using CefSharp.WinForms;
8 |
9 | namespace SharpBrowser {
10 | internal class ContextMenuHandler : IContextMenuHandler {
11 |
12 | private const int ShowDevTools = 26501;
13 | private const int CloseDevTools = 26502;
14 | private const int SaveImageAs = 26503;
15 | private const int SaveAsPdf = 26504;
16 | private const int SaveLinkAs = 26505;
17 | private const int CopyLinkAddress = 26506;
18 | private const int OpenLinkInNewTab = 26507;
19 | private const int CloseTab = 40007;
20 | private const int RefreshTab = 40008;
21 | MainForm myForm;
22 |
23 | private string lastSelText = "";
24 |
25 | public ContextMenuHandler(MainForm form) {
26 | myForm = form;
27 | }
28 |
29 | public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model) {
30 |
31 | // clear the menu
32 | model.Clear();
33 |
34 | // save text
35 | lastSelText = parameters.SelectionText;
36 |
37 | // to copy text
38 | if (parameters.SelectionText.CheckIfValid()) {
39 | model.AddItem(CefMenuCommand.Copy, "Copy");
40 | model.AddSeparator();
41 | }
42 |
43 | //Removing existing menu item
44 | //bool removed = model.Remove(CefMenuCommand.ViewSource); // Remove "View Source" option
45 | if (parameters.LinkUrl != "") {
46 | model.AddItem((CefMenuCommand)OpenLinkInNewTab, "Open link in new tab");
47 | model.AddItem((CefMenuCommand)CopyLinkAddress, "Copy link");
48 | model.AddSeparator();
49 | }
50 |
51 | if (parameters.HasImageContents && parameters.SourceUrl.CheckIfValid()) {
52 |
53 | // RIGHT CLICKED ON IMAGE
54 |
55 | }
56 |
57 | if (parameters.SelectionText != null) {
58 |
59 | // TEXT IS SELECTED
60 |
61 | }
62 |
63 | //Add new custom menu items
64 | //#if DEBUG
65 | model.AddItem((CefMenuCommand)ShowDevTools, "Developer tools");
66 | model.AddItem(CefMenuCommand.ViewSource, "View source");
67 | model.AddSeparator();
68 | //#endif
69 |
70 | model.AddItem((CefMenuCommand)RefreshTab, "Refresh tab");
71 | model.AddItem((CefMenuCommand)CloseTab, "Close tab");
72 |
73 | }
74 |
75 | public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags) {
76 |
77 | int id = (int)commandId;
78 |
79 | if (id == ShowDevTools) {
80 | browser.ShowDevTools();
81 | }
82 | if (id == CloseDevTools) {
83 | browser.CloseDevTools();
84 | }
85 | if (id == SaveImageAs) {
86 | browser.GetHost().StartDownload(parameters.SourceUrl);
87 | }
88 | if (id == SaveLinkAs) {
89 | browser.GetHost().StartDownload(parameters.LinkUrl);
90 | }
91 | if (id == OpenLinkInNewTab) {
92 | ChromiumWebBrowser newBrowser = myForm.AddNewBrowserTab(parameters.LinkUrl, false, browser.MainFrame.Url);
93 | }
94 | if (id == CopyLinkAddress) {
95 | Clipboard.SetText(parameters.LinkUrl);
96 | }
97 | if (id == CloseTab) {
98 | myForm.InvokeOnParent(delegate() {
99 | myForm.CloseActiveTab();
100 | });
101 | }
102 | if (id == RefreshTab) {
103 | myForm.InvokeOnParent(delegate() {
104 | myForm.RefreshActiveTab();
105 | });
106 | }
107 |
108 | return false;
109 | }
110 |
111 | public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame) {
112 |
113 | }
114 |
115 | public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback) {
116 |
117 | // show default menu
118 | return false;
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/Handlers/DownloadHandler.cs:
--------------------------------------------------------------------------------
1 | using CefSharp;
2 |
3 | namespace SharpBrowser {
4 | internal class DownloadHandler : IDownloadHandler
5 | {
6 | MainForm myForm;
7 |
8 | public DownloadHandler(MainForm form)
9 | {
10 | myForm = form;
11 | }
12 |
13 | public void OnBeforeDownload(IBrowser browser, DownloadItem item, IBeforeDownloadCallback callback)
14 | {
15 | if (!callback.IsDisposed)
16 | {
17 | using (callback)
18 | {
19 |
20 | myForm.UpdateDownloadItem(item);
21 |
22 | // ask browser what path it wants to save the file into
23 | string path = myForm.CalcDownloadPath(item);
24 |
25 | // if file should not be saved, path will be null, so skip file
26 | if (path != null) {
27 |
28 | // skip file
29 | callback.Continue(path, false);
30 |
31 | } else {
32 |
33 | // download file
34 | callback.Dispose();
35 |
36 | // open the downloads tab
37 | myForm.OpenDownloadsTab();
38 |
39 | }
40 |
41 | }
42 | }
43 | }
44 |
45 | public void OnDownloadUpdated(IBrowser browser, DownloadItem downloadItem, IDownloadItemCallback callback)
46 | {
47 | myForm.UpdateDownloadItem(downloadItem);
48 | if (downloadItem.IsInProgress && myForm.CancelRequests.Contains(downloadItem.Id)) {
49 | callback.Cancel();
50 | }
51 | //Console.WriteLine(downloadItem.Url + " %" + downloadItem.PercentComplete + " complete");
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Handlers/HostHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Windows.Forms;
6 |
7 | namespace SharpBrowser {
8 |
9 | ///
10 | /// functions in this class are accessible by JS using the code `host.X()`
11 | ///
12 | internal class HostHandler {
13 | MainForm myForm;
14 |
15 | public HostHandler(MainForm form) {
16 | myForm = form;
17 | }
18 | public void addNewBrowserTab(string url, bool focusNewTab = true) {
19 | myForm.AddNewBrowserTab(url, focusNewTab);
20 | }
21 | public string getDownloads() {
22 | lock (myForm.downloads) {
23 | string x = JSON.Instance.ToJSON(myForm.downloads);
24 | //MessageBox.Show(x);
25 | return x;
26 | }
27 | }
28 |
29 | public bool cancelDownload(int downloadId) {
30 | lock (myForm.downloadCancelRequests) {
31 | if (!myForm.downloadCancelRequests.Contains(downloadId)) {
32 | myForm.downloadCancelRequests.Add(downloadId);
33 | }
34 | }
35 | return true;
36 | }
37 | public void refreshActiveTab() {
38 | myForm.RefreshActiveTab();
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/Handlers/KeyboardHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 | using CefSharp;
5 |
6 |
7 | namespace SharpBrowser {
8 | internal class KeyboardHandler : IKeyboardHandler
9 | {
10 | MainForm myForm;
11 |
12 | public static List Hotkeys = new List();
13 | public static void AddHotKey(Form form, Action function, Keys key, bool ctrl = false, bool shift = false, bool alt = false) {
14 | Utils.AddHotKey(form, function, key, ctrl, shift, alt);
15 | Hotkeys.Add(new SharpHotKey(function, key, ctrl, shift, alt));
16 | }
17 |
18 | public KeyboardHandler(MainForm form)
19 | {
20 | myForm = form;
21 | }
22 | public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
23 | {
24 | return false;
25 | }
26 |
27 | ///
28 | public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey) {
29 |
30 | if (type == KeyType.RawKeyDown) {
31 |
32 |
33 | // check if my hotkey
34 | int mod = ((int)modifiers);
35 | bool ctrlDown = mod.IsBitmaskOn((int)CefEventFlags.ControlDown);
36 | bool shiftDown = mod.IsBitmaskOn((int)CefEventFlags.ShiftDown);
37 | bool altDown = mod.IsBitmaskOn((int)CefEventFlags.AltDown);
38 |
39 | // per registered hotkey
40 | foreach (SharpHotKey key in Hotkeys) {
41 | if (key.KeyCode == windowsKeyCode){
42 | if (key.Ctrl == ctrlDown && key.Shift == shiftDown && key.Alt == altDown) {
43 | myForm.InvokeOnParent(delegate() {
44 | key.Callback();
45 | });
46 | }
47 | }
48 | }
49 |
50 | //Debug.WriteLine(String.Format("OnKeyEvent: KeyType: {0} 0x{1:X} Modifiers: {2}", type, windowsKeyCode, modifiers));
51 |
52 | }
53 |
54 | return false;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Handlers/LifeSpanHandler.cs:
--------------------------------------------------------------------------------
1 | using CefSharp;
2 |
3 | namespace SharpBrowser {
4 | internal class LifeSpanHandler : ILifeSpanHandler
5 | {
6 | MainForm myForm;
7 |
8 | public LifeSpanHandler(MainForm form)
9 | {
10 | myForm = form;
11 | }
12 |
13 |
14 | // Summary:
15 | // Called when a browser has recieved a request to close. This may result directly
16 | // from a call to CefBrowserHost::CloseBrowser() or indirectly if the browser
17 | // is a top-level OS window created by CEF and the user attempts to close the
18 | // window. This method will be called after the JavaScript 'onunload' event
19 | // has been fired. It will not be called for browsers after the associated OS
20 | // window has been destroyed (for those browsers it is no longer possible to
21 | // cancel the close). If CEF created an OS window for the browser returning
22 | // false will send an OS close notification to the browser window's top-level
23 | // owner (e.g. WM_CLOSE on Windows, performClose: on OS-X and "delete_event"
24 | // on Linux). If no OS window exists (window rendering disabled) returning false
25 | // will cause the browser object to be destroyed immediately. Return true if
26 | // the browser is parented to another window and that other window needs to
27 | // receive close notification via some non-standard technique. If an application
28 | // provides its own top-level window it should handle OS close notifications
29 | // by calling CefBrowserHost::CloseBrowser(false) instead of immediately closing
30 | // (see the example below). This gives CEF an opportunity to process the 'onbeforeunload'
31 | // event and optionally cancel the close before DoClose() is called. The CefLifeSpanHandler::OnBeforeClose()
32 | // method will be called immediately before the browser object is destroyed.
33 | // The application should only exit after OnBeforeClose() has been called for
34 | // all existing browsers. If the browser represents a modal window and a custom
35 | // modal loop implementation was provided in CefLifeSpanHandler::RunModal()
36 | // this callback should be used to restore the opener window to a usable state.
37 | // By way of example consider what should happen during window close when the
38 | // browser is parented to an application-provided top-level OS window. 1. User
39 | // clicks the window close button which sends an OS close notification (e.g.
40 | // WM_CLOSE on Windows, performClose: on OS-X and "delete_event" on Linux).
41 | // 2. Application's top-level window receives the close notification and: A.
42 | // Calls CefBrowserHost::CloseBrowser(false). B. Cancels the window close.
43 | // 3. JavaScript 'onbeforeunload' handler executes and shows the close confirmation
44 | // dialog (which can be overridden via CefJSDialogHandler::OnBeforeUnloadDialog()).
45 | // 4. User approves the close. 5. JavaScript 'onunload' handler executes.
46 | // 6. Application's DoClose() handler is called. Application will: A. Set a
47 | // flag to indicate that the next close attempt will be allowed. B. Return
48 | // false. 7. CEF sends an OS close notification. 8. Application's top-level
49 | // window receives the OS close notification and allows the window to close
50 | // based on the flag from #6B. 9. Browser OS window is destroyed. 10. Application's
51 | // CefLifeSpanHandler::OnBeforeClose() handler is called and the browser object
52 | // is destroyed. 11. Application exits by calling CefQuitMessageLoop() if no
53 | // other browsers exist.
54 | //
55 | // Parameters:
56 | // browserControl:
57 | // The CefSharp.IWebBrowser control that is realted to the window is closing.
58 | //
59 | // browser:
60 | // The browser instance
61 | //
62 | // Returns:
63 | // For default behaviour return false
64 | public bool DoClose(IWebBrowser browserControl, IBrowser browser) {
65 | return false;
66 | }
67 | //
68 | // Summary:
69 | // Called after a new browser is created.
70 | //
71 | // Parameters:
72 | // browserControl:
73 | // The CefSharp.IWebBrowser control that is realted to the window is closing.
74 | //
75 | // browser:
76 | // The browser instance
77 | public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser) {
78 | }
79 | //
80 | // Summary:
81 | // Called before a CefBrowser window (either the main browser for CefSharp.IWebBrowser,
82 | // or one of its children)
83 | //
84 | // Parameters:
85 | // browserControl:
86 | // The CefSharp.IWebBrowser control that is realted to the window is closing.
87 | //
88 | // browser:
89 | // The browser instance
90 | public void OnBeforeClose(IWebBrowser browserControl, IBrowser browser) {
91 | }
92 | //
93 | // Summary:
94 | // Called before a popup window is created.
95 | //
96 | // Parameters:
97 | // browserControl:
98 | // The CefSharp.IWebBrowser control this request is for.
99 | //
100 | // browser:
101 | // The browser instance that launched this popup.
102 | //
103 | // frame:
104 | // The HTML frame that launched this popup.
105 | //
106 | // targetUrl:
107 | // The URL of the popup content. (This may be empty/null)
108 | //
109 | // targetFrameName:
110 | // The name of the popup. (This may be empty/null)
111 | //
112 | // targetDisposition:
113 | // The value indicates where the user intended to open the popup (e.g. current
114 | // tab, new tab, etc)
115 | //
116 | // userGesture:
117 | // The value will be true if the popup was opened via explicit user gesture
118 | // (e.g. clicking a link) or false if the popup opened automatically (e.g. via
119 | // the DomContentLoaded event).
120 | //
121 | // popupFeatures:
122 | // structure contains additional information about the requested popup window
123 | //
124 | // windowInfo:
125 | // window information
126 | //
127 | // browserSettings:
128 | // browser settings, defaults to source browsers
129 | //
130 | // noJavascriptAccess:
131 | // value indicates whether the new browser window should be scriptable and in
132 | // the same process as the source browser.
133 | //
134 | // newBrowser:
135 | // EXPERIMENTAL - A newly created browser that will host the popup
136 | //
137 | // Returns:
138 | // To cancel creation of the popup window return true otherwise return false.
139 | //
140 | // Remarks:
141 | // CEF documentation: Called on the IO thread before a new popup window is created.
142 | // The |browser| and |frame| parameters represent the source of the popup request.
143 | // The |target_url| and |target_frame_name| values may be empty if none were
144 | // specified with the request. The |popupFeatures| structure contains information
145 | // about the requested popup window. To allow creation of the popup window optionally
146 | // modify |windowInfo|, |client|, |settings| and |no_javascript_access| and
147 | // return false. To cancel creation of the popup window return true. The |client|
148 | // and |settings| values will default to the source browser's values. The |no_javascript_access|
149 | // value indicates whether the new browser window should be scriptable and in
150 | // the same process as the source browser.
151 | public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser) {
152 |
153 | // open popup in new tab!
154 | newBrowser = myForm.AddNewBrowserTab(targetUrl);
155 |
156 | return true;
157 |
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/Handlers/RequestHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Specialized;
2 | using CefSharp;
3 |
4 | namespace SharpBrowser {
5 | internal class RequestHandler : IRequestHandler {
6 | MainForm myForm;
7 |
8 | public RequestHandler(MainForm form) {
9 | myForm = form;
10 | }
11 |
12 | // Summary:
13 | // Called when the browser needs credentials from the user.
14 | //
15 | // Parameters:
16 | // frame:
17 | // The frame object that needs credentials (This will contain the URL that is
18 | // being requested.)
19 | //
20 | // isProxy:
21 | // indicates whether the host is a proxy server
22 | //
23 | // callback:
24 | // Callback interface used for asynchronous continuation of authentication requests.
25 | //
26 | // Returns:
27 | // Return true to continue the request and call CefAuthCallback::Continue()
28 | // when the authentication information is available. Return false to cancel
29 | // the request.
30 | public bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback) {
31 |
32 | return false;
33 | }
34 | //
35 | // Summary:
36 | // Called on the CEF IO thread to optionally filter resource response content.
37 | //
38 | // Parameters:
39 | // frame:
40 | // The frame that is being redirected.
41 | //
42 | // request:
43 | // the request object - cannot be modified in this callback
44 | //
45 | // response:
46 | // the response object - cannot be modified in this callback
47 | //
48 | // Returns:
49 | // Return an IResponseFilter to intercept this response, otherwise return null
50 | public IResponseFilter GetResourceResponseFilter(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response) {
51 | return null;
52 | }
53 | //
54 | // Summary:
55 | // Called before browser navigation. If the navigation is allowed CefSharp.IWebBrowser.FrameLoadStart
56 | // and CefSharp.IWebBrowser.FrameLoadEnd will be called. If the navigation is
57 | // canceled CefSharp.IWebBrowser.LoadError will be called with an ErrorCode
58 | // value of CefSharp.CefErrorCode.Aborted.
59 | //
60 | // Parameters:
61 | // frame:
62 | // The frame the request is coming from
63 | //
64 | // request:
65 | // the request object - cannot be modified in this callback
66 | //
67 | // isRedirect:
68 | // has the request been redirected
69 | //
70 | // Returns:
71 | // Return true to cancel the navigation or false to allow the navigation to
72 | // proceed.
73 | public bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, bool isRedirect) {
74 | return false;
75 | }
76 | //
77 | // Summary:
78 | // Called before a resource request is loaded. For async processing return CefSharp.CefReturnValue.ContinueAsync
79 | // and execute CefSharp.IRequestCallback.Continue(System.Boolean) or CefSharp.IRequestCallback.Cancel()
80 | //
81 | // Parameters:
82 | // frame:
83 | // The frame object
84 | //
85 | // request:
86 | // the request object - can be modified in this callback.
87 | //
88 | // callback:
89 | // Callback interface used for asynchronous continuation of url requests.
90 | //
91 | // Returns:
92 | // To cancel loading of the resource return CefSharp.CefReturnValue.Cancel or
93 | // CefSharp.CefReturnValue.Continue to allow the resource to load normally.
94 | // For async return CefSharp.CefReturnValue.ContinueAsync
95 | public CefReturnValue OnBeforeResourceLoad(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IRequestCallback callback) {
96 |
97 | // if referer given
98 | var tab = myForm.GetTabByBrowser(browserControl);
99 | if (tab != null && tab.RefererURL != null) {
100 |
101 | // Set referer
102 | request.SetReferrer(tab.RefererURL, ReferrerPolicy.Always);
103 |
104 | }
105 |
106 | return CefSharp.CefReturnValue.Continue;
107 | }
108 | //
109 | // Summary:
110 | // Called to handle requests for URLs with an invalid SSL certificate. Return
111 | // true and call CefSharp.IRequestCallback.Continue(System.Boolean) either in
112 | // this method or at a later time to continue or cancel the request. If CefSettings.IgnoreCertificateErrors
113 | // is set all invalid certificates will be accepted without calling this method.
114 | //
115 | // Parameters:
116 | // errorCode:
117 | // the error code for this invalid certificate
118 | //
119 | // requestUrl:
120 | // the url of the request for the invalid certificate
121 | //
122 | // sslInfo:
123 | // ssl certificate information
124 | //
125 | // callback:
126 | // Callback interface used for asynchronous continuation of url requests. If
127 | // empty the error cannot be recovered from and the request will be canceled
128 | // automatically.
129 | //
130 | // Returns:
131 | // Return false to cancel the request immediately. Return true and use CefSharp.IRequestCallback
132 | // to execute in an async fashion.
133 | public bool OnCertificateError(IWebBrowser browserControl, IBrowser browser, CefErrorCode errorCode, string requestUrl, ISslInfo sslInfo, IRequestCallback callback) {
134 | return true;
135 | }
136 | //
137 | // Summary:
138 | // Called on the UI thread before OnBeforeBrowse in certain limited cases where
139 | // navigating a new or different browser might be desirable. This includes user-initiated
140 | // navigation that might open in a special way (e.g. links clicked via middle-click
141 | // or ctrl + left-click) and certain types of cross-origin navigation initiated
142 | // from the renderer process (e.g. navigating the top-level frame to/from a
143 | // file URL).
144 | //
145 | // Parameters:
146 | // frame:
147 | // The frame object
148 | //
149 | // targetDisposition:
150 | // The value indicates where the user intended to navigate the browser based
151 | // on standard Chromium behaviors (e.g. current tab, new tab, etc).
152 | //
153 | // userGesture:
154 | // The value will be true if the browser navigated via explicit user gesture
155 | // (e.g. clicking a link) or false if it navigated automatically (e.g. via the
156 | // DomContentLoaded event).
157 | //
158 | // Returns:
159 | // Return true to cancel the navigation or false to allow the navigation to
160 | // proceed in the source browser's top-level frame.
161 | public bool OnOpenUrlFromTab(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, WindowOpenDisposition targetDisposition, bool userGesture) {
162 | return false;
163 | }
164 | //
165 | // Summary:
166 | // Called when a plugin has crashed
167 | //
168 | // Parameters:
169 | // pluginPath:
170 | // path of the plugin that crashed
171 | public void OnPluginCrashed(IWebBrowser browserControl, IBrowser browser, string pluginPath) {
172 | }
173 | //
174 | // Summary:
175 | // Called on the UI thread to handle requests for URLs with an unknown protocol
176 | // component. SECURITY WARNING: YOU SHOULD USE THIS METHOD TO ENFORCE RESTRICTIONS
177 | // BASED ON SCHEME, HOST OR OTHER URL ANALYSIS BEFORE ALLOWING OS EXECUTION.
178 | //
179 | // Parameters:
180 | // url:
181 | // the request url
182 | //
183 | // Returns:
184 | // return to true to attempt execution via the registered OS protocol handler,
185 | // if any. Otherwise return false.
186 | public bool OnProtocolExecution(IWebBrowser browserControl, IBrowser browser, string url) {
187 | return true;
188 | }
189 | //
190 | // Summary:
191 | // Called when JavaScript requests a specific storage quota size via the webkitStorageInfo.requestQuota
192 | // function. For async processing return true and execute CefSharp.IRequestCallback.Continue(System.Boolean)
193 | // at a later time to grant or deny the request or CefSharp.IRequestCallback.Cancel()
194 | // to cancel.
195 | //
196 | // Parameters:
197 | // originUrl:
198 | // the origin of the page making the request
199 | //
200 | // newSize:
201 | // is the requested quota size in bytes
202 | //
203 | // callback:
204 | // Callback interface used for asynchronous continuation of url requests.
205 | //
206 | // Returns:
207 | // Return false to cancel the request immediately. Return true to continue the
208 | // request and call CefSharp.IRequestCallback.Continue(System.Boolean) either
209 | // in this method or at a later time to grant or deny the request.
210 | public bool OnQuotaRequest(IWebBrowser browserControl, IBrowser browser, string originUrl, long newSize, IRequestCallback callback) {
211 | callback.Continue(true);
212 | return true;
213 | }
214 | //
215 | // Summary:
216 | // Called when the render process terminates unexpectedly.
217 | //
218 | // Parameters:
219 | // status:
220 | // indicates how the process terminated.
221 | public void OnRenderProcessTerminated(IWebBrowser browserControl, IBrowser browser, CefTerminationStatus status) {
222 | }
223 | //
224 | // Summary:
225 | // Called on the CEF UI thread when the render view associated with browser
226 | // is ready to receive/handle IPC messages in the render process.
227 | public void OnRenderViewReady(IWebBrowser browserControl, IBrowser browser) {
228 | }
229 | //
230 | // Summary:
231 | // Called on the CEF IO thread when a resource load has completed.
232 | //
233 | // Parameters:
234 | // frame:
235 | // The frame that is being redirected.
236 | //
237 | // request:
238 | // the request object - cannot be modified in this callback
239 | //
240 | // response:
241 | // the response object - cannot be modified in this callback
242 | //
243 | // status:
244 | // indicates the load completion status
245 | //
246 | // receivedContentLength:
247 | // is the number of response bytes actually read.
248 | public void OnResourceLoadComplete(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response, UrlRequestStatus status, long receivedContentLength) {
249 | }
250 | //
251 | // Summary:
252 | // Called on the IO thread when a resource load is redirected. The CefSharp.IRequest.Url
253 | // parameter will contain the old URL and other request-related information.
254 | //
255 | // Parameters:
256 | // frame:
257 | // The frame that is being redirected.
258 | //
259 | // request:
260 | // the request object - cannot be modified in this callback
261 | //
262 | // newUrl:
263 | // the new URL and can be changed if desired
264 | public void OnResourceRedirect(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, ref string newUrl) {
265 | }
266 | //
267 | // Summary:
268 | // Called on the CEF IO thread when a resource response is received. To allow
269 | // the resource to load normally return false. To redirect or retry the resource
270 | // modify request (url, headers or post body) and return true. The response
271 | // object cannot be modified in this callback.
272 | //
273 | // Parameters:
274 | // frame:
275 | // The frame that is being redirected.
276 | //
277 | // request:
278 | // the request object
279 | //
280 | // response:
281 | // the response object - cannot be modified in this callback
282 | //
283 | // Returns:
284 | // To allow the resource to load normally return false. To redirect or retry
285 | // the resource modify request (url, headers or post body) and return true.
286 | public bool OnResourceResponse(IWebBrowser browserControl, IBrowser browser, IFrame frame, IRequest request, IResponse response) {
287 |
288 |
289 | int code = response.StatusCode;
290 |
291 |
292 | // if NOT FOUND
293 | if (code == 404) {
294 |
295 | if (!request.Url.IsURLLocalhost()) {
296 |
297 | // redirect to web archive to try and find older version
298 | request.Url = "http://web.archive.org/web/*/" + request.Url;
299 |
300 | } else {
301 |
302 | // show offline "file not found" page
303 | request.Url = MainForm.FileNotFoundURL + "?path=" + request.Url.EncodeURL();
304 | }
305 |
306 | return true;
307 | }
308 |
309 |
310 | // if FILE NOT FOUND
311 | if (code == 0 && request.Url.IsURLOfflineFile()) {
312 | string path = request.Url.FileURLToPath();
313 | if (path.FileNotExists()) {
314 |
315 | // show offline "file not found" page
316 | request.Url = MainForm.FileNotFoundURL + "?path=" + path.EncodeURL();
317 | return true;
318 |
319 | }
320 | } else {
321 |
322 | // if CANNOT CONNECT
323 | if (code == 0 || code == 444 || (code >= 500 && code <= 599)) {
324 |
325 | // show offline "cannot connect to server" page
326 | request.Url = MainForm.CannotConnectURL;
327 | return true;
328 | }
329 |
330 | }
331 |
332 | return false;
333 | }
334 |
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/src/Handlers/SchemeHandler.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Net;
6 | using System.Threading.Tasks;
7 | using CefSharp;
8 | using System.Windows.Forms;
9 | using System.Drawing;
10 |
11 | namespace SharpBrowser {
12 | internal class SchemeHandler : IResourceHandler, IDisposable
13 | {
14 | private static string appPath = Path.GetDirectoryName(Application.ExecutablePath) + @"\";
15 |
16 | private string mimeType;
17 | private Stream stream;
18 | MainForm myForm;
19 | private Uri uri;
20 | private string fileName;
21 |
22 | public SchemeHandler(MainForm form) {
23 | myForm = form;
24 | }
25 |
26 | public void Dispose() {
27 |
28 | }
29 |
30 |
31 | //
32 | // Summary:
33 | // Begin processing the request.
34 | //
35 | // Parameters:
36 | // request:
37 | // The request object.
38 | //
39 | // callback:
40 | // The callback used to Continue or Cancel the request (async).
41 | //
42 | // Returns:
43 | // To handle the request return true and call CefSharp.ICallback.Continue()
44 | // once the response header information is available CefSharp.ICallback.Continue()
45 | // can also be called from inside this method if header information is available
46 | // immediately). To cancel the request return false.
47 | public bool ProcessRequest(IRequest request, ICallback callback) {
48 | uri = new Uri(request.Url);
49 | fileName = uri.AbsolutePath;
50 |
51 | // if url is blocked
52 | /*if (!myForm.IsURLOk(request.Url)) {
53 |
54 | // return true so it does not open up
55 | return true;
56 | }*/
57 |
58 | // if url is browser file
59 | if (uri.Host == "storage") {
60 | fileName = appPath + uri.Host + fileName;
61 | if (File.Exists(fileName)) {
62 | Task.Factory.StartNew(() => {
63 | using (callback) {
64 | //var bytes = Encoding.UTF8.GetBytes(resource);
65 | //stream = new MemoryStream(bytes);
66 | FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
67 | mimeType = ResourceHandler.GetMimeType(Path.GetExtension(fileName));
68 | stream = fStream;
69 | callback.Continue();
70 | }
71 | });
72 |
73 | return true;
74 | }
75 | }
76 |
77 | // if url is request for icon of another file
78 | if (uri.Host == "fileicon") {
79 | Task.Factory.StartNew(() => {
80 | using (callback) {
81 | stream = FileIconUtils.GetFileIcon(fileName, FileIconSize.Large);
82 | mimeType = ResourceHandler.GetMimeType(".png");
83 | callback.Continue();
84 | }
85 | });
86 | return true;
87 | }
88 |
89 |
90 | // by default reject
91 | callback.Dispose();
92 | return false;
93 | }
94 | //
95 | // Summary:
96 | // Retrieve response header information. If the response length is not known
97 | // set responseLength to -1 and ReadResponse() will be called until it returns
98 | // false. If the response length is known set responseLength to a positive value
99 | // and ReadResponse() will be called until it returns false or the specified
100 | // number of bytes have been read. If an error occured while setting up the
101 | // request you can set CefSharp.IResponse.ErrorCode to indicate the error condition.
102 | //
103 | // Parameters:
104 | // response:
105 | // Use the response object to set the mime type, http status code and other
106 | // optional header values.
107 | //
108 | // responseLength:
109 | // If the response length is not known set responseLength to -1
110 | //
111 | // redirectUrl:
112 | // To redirect the request to a new URL set redirectUrl to the new Url.
113 | public void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl) {
114 |
115 | responseLength = stream.Length;
116 | redirectUrl = null;
117 |
118 | response.StatusCode = (int)HttpStatusCode.OK;
119 | response.StatusText = "OK";
120 | response.MimeType = mimeType;
121 |
122 | //return stream;
123 | }
124 | //
125 | // Summary:
126 | // Read response data. If data is available immediately copy to dataOut, set
127 | // bytesRead to the number of bytes copied, and return true. To read the data
128 | // at a later time set bytesRead to 0, return true and call ICallback.Continue()
129 | // when the data is available. To indicate response completion return false.
130 | //
131 | // Parameters:
132 | // dataOut:
133 | // Stream to write to
134 | //
135 | // bytesRead:
136 | // Number of bytes copied to the stream
137 | //
138 | // callback:
139 | // The callback used to Continue or Cancel the request (async).
140 | //
141 | // Returns:
142 | // If data is available immediately copy to dataOut, set bytesRead to the number
143 | // of bytes copied, and return true.To indicate response completion return false.
144 | //
145 | // Remarks:
146 | // Depending on this size of your response this method may be called multiple
147 | // times
148 | public bool ReadResponse(Stream dataOut, out int bytesRead, ICallback callback) {
149 |
150 | //Dispose the callback as it's an unmanaged resource, we don't need it in this case
151 | callback.Dispose();
152 |
153 | if (stream == null) {
154 | bytesRead = 0;
155 | return false;
156 | }
157 |
158 | //Data out represents an underlying buffer (typically 32kb in size).
159 | var buffer = new byte[dataOut.Length];
160 | bytesRead = stream.Read(buffer, 0, buffer.Length);
161 |
162 | dataOut.Write(buffer, 0, buffer.Length);
163 |
164 | return bytesRead > 0;
165 |
166 | }
167 | // Summary:
168 | // Request processing has been canceled.
169 | public void Cancel() {
170 | }
171 | //
172 | // Summary:
173 | // Return true if the specified cookie can be sent with the request or false
174 | // otherwise. If false is returned for any cookie then no cookies will be sent
175 | // with the request.
176 | public bool CanGetCookie(CefSharp.Cookie cookie) {
177 | return true;
178 | }
179 | //
180 | // Summary:
181 | // Return true if the specified cookie returned with the response can be set
182 | // or false otherwise.
183 | public bool CanSetCookie(CefSharp.Cookie cookie) {
184 | return true;
185 | }
186 |
187 | }
188 | }
--------------------------------------------------------------------------------
/src/Handlers/SchemeHandlerFactory.cs:
--------------------------------------------------------------------------------
1 | using CefSharp;
2 |
3 | namespace SharpBrowser {
4 | internal class SchemeHandlerFactory : ISchemeHandlerFactory
5 | {
6 |
7 | public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
8 | {
9 | return new SchemeHandler(MainForm.Instance);
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/MainForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace SharpBrowser
2 | {
3 | partial class MainForm
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.components = new System.ComponentModel.Container();
32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
33 | this.menuStripTab = new System.Windows.Forms.ContextMenuStrip(this.components);
34 | this.menuCloseTab = new System.Windows.Forms.ToolStripMenuItem();
35 | this.menuCloseOtherTabs = new System.Windows.Forms.ToolStripMenuItem();
36 | this.BtnRefresh = new System.Windows.Forms.Button();
37 | this.BtnStop = new System.Windows.Forms.Button();
38 | this.BtnForward = new System.Windows.Forms.Button();
39 | this.BtnBack = new System.Windows.Forms.Button();
40 | this.timer1 = new System.Windows.Forms.Timer(this.components);
41 | this.BtnDownloads = new System.Windows.Forms.Button();
42 | this.TxtURL = new System.Windows.Forms.TextBox();
43 | this.PanelToolbar = new System.Windows.Forms.Panel();
44 | this.TabPages = new FarsiLibrary.Win.FATabStrip();
45 | this.tabStrip1 = new FarsiLibrary.Win.FATabStripItem();
46 | this.tabStripAdd = new FarsiLibrary.Win.FATabStripItem();
47 | this.PanelStatus = new System.Windows.Forms.Panel();
48 | this.PanelSearch = new System.Windows.Forms.Panel();
49 | this.BtnNextSearch = new System.Windows.Forms.Button();
50 | this.BtnPrevSearch = new System.Windows.Forms.Button();
51 | this.BtnCloseSearch = new System.Windows.Forms.Button();
52 | this.TxtSearch = new System.Windows.Forms.TextBox();
53 | this.menuStripTab.SuspendLayout();
54 | this.PanelToolbar.SuspendLayout();
55 | ((System.ComponentModel.ISupportInitialize)(this.TabPages)).BeginInit();
56 | this.TabPages.SuspendLayout();
57 | this.PanelSearch.SuspendLayout();
58 | this.SuspendLayout();
59 | //
60 | // menuStripTab
61 | //
62 | this.menuStripTab.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
63 | this.menuCloseTab,
64 | this.menuCloseOtherTabs});
65 | this.menuStripTab.Name = "menuStripTab";
66 | this.menuStripTab.Size = new System.Drawing.Size(198, 52);
67 | //
68 | // menuCloseTab
69 | //
70 | this.menuCloseTab.Name = "menuCloseTab";
71 | this.menuCloseTab.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F4)));
72 | this.menuCloseTab.Size = new System.Drawing.Size(197, 24);
73 | this.menuCloseTab.Text = "Close tab";
74 | this.menuCloseTab.Click += new System.EventHandler(this.menuCloseTab_Click);
75 | //
76 | // menuCloseOtherTabs
77 | //
78 | this.menuCloseOtherTabs.Name = "menuCloseOtherTabs";
79 | this.menuCloseOtherTabs.Size = new System.Drawing.Size(197, 24);
80 | this.menuCloseOtherTabs.Text = "Close other tabs";
81 | this.menuCloseOtherTabs.Click += new System.EventHandler(this.menuCloseOtherTabs_Click);
82 | //
83 | // BtnRefresh
84 | //
85 | this.BtnRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
86 | this.BtnRefresh.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
87 | this.BtnRefresh.ForeColor = System.Drawing.Color.White;
88 | this.BtnRefresh.Image = ((System.Drawing.Image)(resources.GetObject("BtnRefresh.Image")));
89 | this.BtnRefresh.Location = new System.Drawing.Point(878, 0);
90 | this.BtnRefresh.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
91 | this.BtnRefresh.Name = "BtnRefresh";
92 | this.BtnRefresh.Size = new System.Drawing.Size(25, 30);
93 | this.BtnRefresh.TabIndex = 3;
94 | this.BtnRefresh.UseVisualStyleBackColor = true;
95 | this.BtnRefresh.Click += new System.EventHandler(this.bRefresh_Click);
96 | //
97 | // BtnStop
98 | //
99 | this.BtnStop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
100 | this.BtnStop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
101 | this.BtnStop.ForeColor = System.Drawing.Color.White;
102 | this.BtnStop.Image = ((System.Drawing.Image)(resources.GetObject("BtnStop.Image")));
103 | this.BtnStop.Location = new System.Drawing.Point(878, -2);
104 | this.BtnStop.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
105 | this.BtnStop.Name = "BtnStop";
106 | this.BtnStop.Size = new System.Drawing.Size(25, 30);
107 | this.BtnStop.TabIndex = 2;
108 | this.BtnStop.UseVisualStyleBackColor = true;
109 | this.BtnStop.Click += new System.EventHandler(this.bStop_Click);
110 | //
111 | // BtnForward
112 | //
113 | this.BtnForward.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
114 | this.BtnForward.ForeColor = System.Drawing.Color.White;
115 | this.BtnForward.Image = ((System.Drawing.Image)(resources.GetObject("BtnForward.Image")));
116 | this.BtnForward.Location = new System.Drawing.Point(29, 0);
117 | this.BtnForward.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
118 | this.BtnForward.Name = "BtnForward";
119 | this.BtnForward.Size = new System.Drawing.Size(25, 30);
120 | this.BtnForward.TabIndex = 1;
121 | this.BtnForward.UseVisualStyleBackColor = true;
122 | this.BtnForward.Click += new System.EventHandler(this.bForward_Click);
123 | //
124 | // BtnBack
125 | //
126 | this.BtnBack.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
127 | this.BtnBack.ForeColor = System.Drawing.Color.White;
128 | this.BtnBack.Image = ((System.Drawing.Image)(resources.GetObject("BtnBack.Image")));
129 | this.BtnBack.Location = new System.Drawing.Point(2, 0);
130 | this.BtnBack.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
131 | this.BtnBack.Name = "BtnBack";
132 | this.BtnBack.Size = new System.Drawing.Size(25, 30);
133 | this.BtnBack.TabIndex = 0;
134 | this.BtnBack.UseVisualStyleBackColor = true;
135 | this.BtnBack.Click += new System.EventHandler(this.bBack_Click);
136 | //
137 | // timer1
138 | //
139 | this.timer1.Interval = 50;
140 | this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
141 | //
142 | // BtnDownloads
143 | //
144 | this.BtnDownloads.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
145 | this.BtnDownloads.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
146 | this.BtnDownloads.ForeColor = System.Drawing.Color.White;
147 | this.BtnDownloads.Image = ((System.Drawing.Image)(resources.GetObject("BtnDownloads.Image")));
148 | this.BtnDownloads.Location = new System.Drawing.Point(906, 0);
149 | this.BtnDownloads.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
150 | this.BtnDownloads.Name = "BtnDownloads";
151 | this.BtnDownloads.Size = new System.Drawing.Size(25, 30);
152 | this.BtnDownloads.TabIndex = 4;
153 | this.BtnDownloads.Tag = "Downloads";
154 | this.BtnDownloads.UseVisualStyleBackColor = true;
155 | this.BtnDownloads.Click += new System.EventHandler(this.bDownloads_Click);
156 | //
157 | // TxtURL
158 | //
159 | this.TxtURL.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
160 | | System.Windows.Forms.AnchorStyles.Right)));
161 | this.TxtURL.BorderStyle = System.Windows.Forms.BorderStyle.None;
162 | this.TxtURL.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
163 | this.TxtURL.Location = new System.Drawing.Point(60, 5);
164 | this.TxtURL.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
165 | this.TxtURL.Name = "TxtURL";
166 | this.TxtURL.Size = new System.Drawing.Size(812, 27);
167 | this.TxtURL.TabIndex = 5;
168 | this.TxtURL.Click += new System.EventHandler(this.txtUrl_Click);
169 | this.TxtURL.TextChanged += new System.EventHandler(this.txtUrl_TextChanged);
170 | this.TxtURL.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TxtURL_KeyDown);
171 | //
172 | // PanelToolbar
173 | //
174 | this.PanelToolbar.BackColor = System.Drawing.Color.White;
175 | this.PanelToolbar.Controls.Add(this.TxtURL);
176 | this.PanelToolbar.Controls.Add(this.BtnDownloads);
177 | this.PanelToolbar.Controls.Add(this.BtnForward);
178 | this.PanelToolbar.Controls.Add(this.BtnBack);
179 | this.PanelToolbar.Controls.Add(this.BtnRefresh);
180 | this.PanelToolbar.Controls.Add(this.BtnStop);
181 | this.PanelToolbar.Dock = System.Windows.Forms.DockStyle.Top;
182 | this.PanelToolbar.Location = new System.Drawing.Point(0, 0);
183 | this.PanelToolbar.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
184 | this.PanelToolbar.Name = "PanelToolbar";
185 | this.PanelToolbar.Size = new System.Drawing.Size(934, 30);
186 | this.PanelToolbar.TabIndex = 6;
187 | //
188 | // TabPages
189 | //
190 | this.TabPages.ContextMenuStrip = this.menuStripTab;
191 | this.TabPages.Dock = System.Windows.Forms.DockStyle.Fill;
192 | this.TabPages.Font = new System.Drawing.Font("Segoe UI", 10.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
193 | this.TabPages.Items.AddRange(new FarsiLibrary.Win.FATabStripItem[] {
194 | this.tabStrip1,
195 | this.tabStripAdd});
196 | this.TabPages.Location = new System.Drawing.Point(0, 30);
197 | this.TabPages.Name = "TabPages";
198 | this.TabPages.SelectedItem = this.tabStrip1;
199 | this.TabPages.Size = new System.Drawing.Size(934, 621);
200 | this.TabPages.TabIndex = 4;
201 | this.TabPages.Text = "faTabStrip1";
202 | this.TabPages.TabStripItemSelectionChanged += new FarsiLibrary.Win.TabStripItemChangedHandler(this.OnTabsChanged);
203 | this.TabPages.TabStripItemClosed += new System.EventHandler(this.OnTabClosed);
204 | this.TabPages.MouseClick += new System.Windows.Forms.MouseEventHandler(this.tabPages_MouseClick);
205 | //
206 | // tabStrip1
207 | //
208 | this.tabStrip1.IsDrawn = true;
209 | this.tabStrip1.Name = "tabStrip1";
210 | this.tabStrip1.Selected = true;
211 | this.tabStrip1.Size = new System.Drawing.Size(932, 591);
212 | this.tabStrip1.TabIndex = 0;
213 | this.tabStrip1.Title = "Loading...";
214 | //
215 | // tabStripAdd
216 | //
217 | this.tabStripAdd.CanClose = false;
218 | this.tabStripAdd.IsDrawn = true;
219 | this.tabStripAdd.Name = "tabStripAdd";
220 | this.tabStripAdd.Size = new System.Drawing.Size(931, 601);
221 | this.tabStripAdd.TabIndex = 1;
222 | this.tabStripAdd.Title = "+";
223 | //
224 | // PanelStatus
225 | //
226 | this.PanelStatus.Dock = System.Windows.Forms.DockStyle.Bottom;
227 | this.PanelStatus.Location = new System.Drawing.Point(0, 651);
228 | this.PanelStatus.Name = "PanelStatus";
229 | this.PanelStatus.Size = new System.Drawing.Size(934, 20);
230 | this.PanelStatus.TabIndex = 8;
231 | //
232 | // PanelSearch
233 | //
234 | this.PanelSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
235 | this.PanelSearch.BackColor = System.Drawing.Color.White;
236 | this.PanelSearch.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
237 | this.PanelSearch.Controls.Add(this.BtnNextSearch);
238 | this.PanelSearch.Controls.Add(this.BtnPrevSearch);
239 | this.PanelSearch.Controls.Add(this.BtnCloseSearch);
240 | this.PanelSearch.Controls.Add(this.TxtSearch);
241 | this.PanelSearch.Location = new System.Drawing.Point(625, 41);
242 | this.PanelSearch.Name = "PanelSearch";
243 | this.PanelSearch.Size = new System.Drawing.Size(307, 40);
244 | this.PanelSearch.TabIndex = 9;
245 | this.PanelSearch.Visible = false;
246 | //
247 | // BtnNextSearch
248 | //
249 | this.BtnNextSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
250 | this.BtnNextSearch.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
251 | this.BtnNextSearch.ForeColor = System.Drawing.Color.White;
252 | this.BtnNextSearch.Image = ((System.Drawing.Image)(resources.GetObject("BtnNextSearch.Image")));
253 | this.BtnNextSearch.Location = new System.Drawing.Point(239, 4);
254 | this.BtnNextSearch.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
255 | this.BtnNextSearch.Name = "BtnNextSearch";
256 | this.BtnNextSearch.Size = new System.Drawing.Size(25, 30);
257 | this.BtnNextSearch.TabIndex = 9;
258 | this.BtnNextSearch.Tag = "Find next (Enter)";
259 | this.BtnNextSearch.UseVisualStyleBackColor = true;
260 | this.BtnNextSearch.Click += new System.EventHandler(this.BtnNextSearch_Click);
261 | //
262 | // BtnPrevSearch
263 | //
264 | this.BtnPrevSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
265 | this.BtnPrevSearch.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
266 | this.BtnPrevSearch.ForeColor = System.Drawing.Color.White;
267 | this.BtnPrevSearch.Image = ((System.Drawing.Image)(resources.GetObject("BtnPrevSearch.Image")));
268 | this.BtnPrevSearch.Location = new System.Drawing.Point(206, 4);
269 | this.BtnPrevSearch.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
270 | this.BtnPrevSearch.Name = "BtnPrevSearch";
271 | this.BtnPrevSearch.Size = new System.Drawing.Size(25, 30);
272 | this.BtnPrevSearch.TabIndex = 8;
273 | this.BtnPrevSearch.Tag = "Find previous (Shift+Enter)";
274 | this.BtnPrevSearch.UseVisualStyleBackColor = true;
275 | this.BtnPrevSearch.Click += new System.EventHandler(this.BtnPrevSearch_Click);
276 | //
277 | // BtnCloseSearch
278 | //
279 | this.BtnCloseSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
280 | this.BtnCloseSearch.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
281 | this.BtnCloseSearch.ForeColor = System.Drawing.Color.White;
282 | this.BtnCloseSearch.Image = ((System.Drawing.Image)(resources.GetObject("BtnCloseSearch.Image")));
283 | this.BtnCloseSearch.Location = new System.Drawing.Point(272, 4);
284 | this.BtnCloseSearch.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
285 | this.BtnCloseSearch.Name = "BtnCloseSearch";
286 | this.BtnCloseSearch.Size = new System.Drawing.Size(25, 30);
287 | this.BtnCloseSearch.TabIndex = 7;
288 | this.BtnCloseSearch.Tag = "Close (Esc)";
289 | this.BtnCloseSearch.UseVisualStyleBackColor = true;
290 | this.BtnCloseSearch.Click += new System.EventHandler(this.BtnClearSearch_Click);
291 | //
292 | // TxtSearch
293 | //
294 | this.TxtSearch.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
295 | | System.Windows.Forms.AnchorStyles.Right)));
296 | this.TxtSearch.BorderStyle = System.Windows.Forms.BorderStyle.None;
297 | this.TxtSearch.Font = new System.Drawing.Font("Segoe UI", 13.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
298 | this.TxtSearch.Location = new System.Drawing.Point(10, 6);
299 | this.TxtSearch.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4);
300 | this.TxtSearch.Name = "TxtSearch";
301 | this.TxtSearch.Size = new System.Drawing.Size(181, 31);
302 | this.TxtSearch.TabIndex = 6;
303 | this.TxtSearch.TextChanged += new System.EventHandler(this.TxtSearch_TextChanged);
304 | this.TxtSearch.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TxtSearch_KeyDown);
305 | //
306 | // MainForm
307 | //
308 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
309 | this.ClientSize = new System.Drawing.Size(934, 671);
310 | this.Controls.Add(this.PanelSearch);
311 | this.Controls.Add(this.TabPages);
312 | this.Controls.Add(this.PanelToolbar);
313 | this.Controls.Add(this.PanelStatus);
314 | this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
315 | this.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5);
316 | this.Name = "MainForm";
317 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
318 | this.Text = "Title";
319 | this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
320 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
321 | this.Load += new System.EventHandler(this.MainForm_Load);
322 | this.menuStripTab.ResumeLayout(false);
323 | this.PanelToolbar.ResumeLayout(false);
324 | this.PanelToolbar.PerformLayout();
325 | ((System.ComponentModel.ISupportInitialize)(this.TabPages)).EndInit();
326 | this.TabPages.ResumeLayout(false);
327 | this.PanelSearch.ResumeLayout(false);
328 | this.PanelSearch.PerformLayout();
329 | this.ResumeLayout(false);
330 |
331 | }
332 |
333 | #endregion
334 |
335 | private FarsiLibrary.Win.FATabStrip TabPages;
336 | private FarsiLibrary.Win.FATabStripItem tabStrip1;
337 | private FarsiLibrary.Win.FATabStripItem tabStripAdd;
338 | private System.Windows.Forms.Timer timer1;
339 | private System.Windows.Forms.ContextMenuStrip menuStripTab;
340 | private System.Windows.Forms.ToolStripMenuItem menuCloseTab;
341 | private System.Windows.Forms.ToolStripMenuItem menuCloseOtherTabs;
342 | private System.Windows.Forms.Button BtnForward;
343 | private System.Windows.Forms.Button BtnBack;
344 | private System.Windows.Forms.Button BtnStop;
345 | private System.Windows.Forms.Button BtnRefresh;
346 | private System.Windows.Forms.Button BtnDownloads;
347 | private System.Windows.Forms.TextBox TxtURL;
348 | private System.Windows.Forms.Panel PanelToolbar;
349 | private System.Windows.Forms.Panel PanelStatus;
350 | private System.Windows.Forms.Panel PanelSearch;
351 | private System.Windows.Forms.TextBox TxtSearch;
352 | private System.Windows.Forms.Button BtnCloseSearch;
353 | private System.Windows.Forms.Button BtnPrevSearch;
354 | private System.Windows.Forms.Button BtnNextSearch;
355 | }
356 | }
357 |
358 |
--------------------------------------------------------------------------------
/src/MainForm.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 | using System.Threading;
4 | using System.Diagnostics;
5 | using System.Configuration;
6 | using System.Collections.Generic;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Web;
10 | using CefSharp;
11 | using CefSharp.WinForms;
12 | using FarsiLibrary.Win;
13 | using Timer = System.Windows.Forms.Timer;
14 | using System.Drawing;
15 | using System.Reflection;
16 |
17 | namespace SharpBrowser {
18 |
19 | ///
20 | /// The main SharpBrowser form, supporting multiple tabs.
21 | /// We used the x86 version of CefSharp V51, so the app works on 32-bit and 64-bit machines.
22 | /// If you would only like to support 64-bit machines, simply change the DLL references.
23 | ///
24 | internal partial class MainForm : Form {
25 |
26 | private string appPath = Path.GetDirectoryName(Application.ExecutablePath) + @"\";
27 |
28 | public static MainForm Instance;
29 |
30 | public static string Branding = "SharpBrowser";
31 | public static string UserAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36";
32 | public static string HomepageURL = "https://www.google.com";
33 | public static string NewTabURL = "about:blank";
34 | public static string DownloadsURL = "sharpbrowser://storage/downloads.html";
35 | public static string FileNotFoundURL = "sharpbrowser://storage/errors/notFound.html";
36 | public static string CannotConnectURL = "sharpbrowser://storage/errors/cannotConnect.html";
37 | public static string SearchURL = "https://www.google.com/#q=";
38 |
39 | public bool WebSecurity = true;
40 | public bool CrossDomainSecurity = true;
41 | public bool WebGL = true;
42 |
43 |
44 |
45 | public MainForm() {
46 |
47 | Instance = this;
48 |
49 | InitializeComponent();
50 |
51 | InitBrowser();
52 |
53 | SetFormTitle(null);
54 |
55 | }
56 |
57 | private void MainForm_Load(object sender, EventArgs e) {
58 |
59 | InitAppIcon();
60 | InitTooltips(this.Controls);
61 | InitHotkeys();
62 |
63 | }
64 |
65 | #region App Icon
66 |
67 | ///
68 | /// embedding the resource using the Visual Studio designer results in a blurry icon.
69 | /// the best way to get a non-blurry icon for Windows 7 apps.
70 | ///
71 | private void InitAppIcon() {
72 | assembly = Assembly.GetAssembly(typeof(MainForm));
73 | Icon = new Icon(GetResourceStream("sharpbrowser.ico"), new Size(64, 64));
74 | }
75 |
76 | public static Assembly assembly = null;
77 | public Stream GetResourceStream(string filename, bool withNamespace = true) {
78 | try {
79 | return assembly.GetManifestResourceStream("SharpBrowser.Resources." + filename);
80 | } catch (System.Exception ex) { }
81 | return null;
82 | }
83 |
84 | #endregion
85 |
86 | #region Tooltips & Hotkeys
87 |
88 | ///
89 | /// these hotkeys work when the user is focussed on the .NET form and its controls,
90 | /// AND when the user is focussed on the browser (CefSharp portion)
91 | ///
92 | private void InitHotkeys() {
93 |
94 | // browser hotkeys
95 | KeyboardHandler.AddHotKey(this, CloseActiveTab, Keys.W, true);
96 | KeyboardHandler.AddHotKey(this, CloseActiveTab, Keys.Escape, true);
97 | KeyboardHandler.AddHotKey(this, AddBlankWindow, Keys.N, true);
98 | KeyboardHandler.AddHotKey(this, AddBlankTab, Keys.T, true);
99 | KeyboardHandler.AddHotKey(this, RefreshActiveTab, Keys.F5);
100 | KeyboardHandler.AddHotKey(this, OpenDeveloperTools, Keys.F12);
101 | KeyboardHandler.AddHotKey(this, NextTab, Keys.Tab, true);
102 | KeyboardHandler.AddHotKey(this, PrevTab, Keys.Tab, true, true);
103 |
104 | // search hotkeys
105 | KeyboardHandler.AddHotKey(this, OpenSearch, Keys.F, true);
106 | KeyboardHandler.AddHotKey(this, CloseSearch, Keys.Escape);
107 | KeyboardHandler.AddHotKey(this, StopActiveTab, Keys.Escape);
108 |
109 |
110 | }
111 |
112 | ///
113 | /// we activate all the tooltips stored in the Tag property of the buttons
114 | ///
115 | public void InitTooltips(System.Windows.Forms.Control.ControlCollection parent) {
116 | foreach (Control ui in parent) {
117 | Button btn = ui as Button;
118 | if (btn != null) {
119 | if (btn.Tag != null) {
120 | ToolTip tip = new ToolTip();
121 | tip.ReshowDelay = tip.InitialDelay = 200;
122 | tip.ShowAlways = true;
123 | tip.SetToolTip(btn, btn.Tag.ToString());
124 | }
125 | }
126 | Panel panel = ui as Panel;
127 | if (panel != null) {
128 | InitTooltips(panel.Controls);
129 | }
130 | }
131 | }
132 |
133 | #endregion
134 |
135 | #region Web Browser & Tabs
136 |
137 | private FATabStripItem newStrip;
138 | private FATabStripItem downloadsStrip;
139 |
140 | private string currentFullURL;
141 | private string currentCleanURL;
142 | private string currentTitle;
143 |
144 | public HostHandler host;
145 | private DownloadHandler dHandler;
146 | private ContextMenuHandler mHandler;
147 | private LifeSpanHandler lHandler;
148 | private KeyboardHandler kHandler;
149 | private RequestHandler rHandler;
150 |
151 | ///
152 | /// this is done just once, to globally initialize CefSharp/CEF
153 | ///
154 | private void InitBrowser() {
155 |
156 | CefSettings settings = new CefSettings();
157 |
158 | settings.RegisterScheme(new CefCustomScheme {
159 | SchemeName = "sharpbrowser",
160 | SchemeHandlerFactory = new SchemeHandlerFactory()
161 | });
162 |
163 | settings.UserAgent = UserAgent;
164 |
165 | settings.IgnoreCertificateErrors = true;
166 |
167 | settings.CachePath = GetAppDir("Cache");
168 |
169 | Cef.Initialize(settings);
170 |
171 | dHandler = new DownloadHandler(this);
172 | lHandler = new LifeSpanHandler(this);
173 | mHandler = new ContextMenuHandler(this);
174 | kHandler = new KeyboardHandler(this);
175 | rHandler = new RequestHandler(this);
176 |
177 | InitDownloads();
178 |
179 | host = new HostHandler(this);
180 |
181 | AddNewBrowser(tabStrip1, HomepageURL);
182 |
183 | }
184 |
185 | ///
186 | /// this is done every time a new tab is openede
187 | ///
188 | private void ConfigureBrowser(ChromiumWebBrowser browser) {
189 |
190 | BrowserSettings config = new BrowserSettings();
191 |
192 | config.FileAccessFromFileUrls = (!CrossDomainSecurity).ToCefState();
193 | config.UniversalAccessFromFileUrls = (!CrossDomainSecurity).ToCefState();
194 | config.WebSecurity = WebSecurity.ToCefState();
195 | config.WebGl = WebGL.ToCefState();
196 |
197 | browser.BrowserSettings = config;
198 |
199 | }
200 |
201 |
202 | private static string GetAppDir(string name) {
203 | string winXPDir = @"C:\Documents and Settings\All Users\Application Data\";
204 | if (Directory.Exists(winXPDir)) {
205 | return winXPDir + Branding + @"\" + name + @"\";
206 | }
207 | return @"C:\ProgramData\" + Branding + @"\" + name + @"\";
208 |
209 | }
210 |
211 | private void LoadURL(string url) {
212 | Uri outUri;
213 | string newUrl = url;
214 | string urlLower = url.Trim().ToLower();
215 |
216 | // UI
217 | SetTabTitle(CurBrowser, "Loading...");
218 |
219 | // load page
220 | if (urlLower == "localhost") {
221 |
222 | newUrl = "http://localhost/";
223 |
224 | } else if (url.CheckIfFilePath() || url.CheckIfFilePath2()) {
225 |
226 | newUrl = url.PathToURL();
227 |
228 | } else {
229 |
230 | Uri.TryCreate(url, UriKind.Absolute, out outUri);
231 |
232 | if (!(urlLower.StartsWith("http") || urlLower.StartsWith("sharpbrowser"))) {
233 | if (outUri == null || outUri.Scheme != Uri.UriSchemeFile) newUrl = "http://" + url;
234 | }
235 |
236 | if (urlLower.StartsWith("sharpbrowser:") ||
237 |
238 | // load URL if it seems valid
239 | (Uri.TryCreate(newUrl, UriKind.Absolute, out outUri)
240 | && ((outUri.Scheme == Uri.UriSchemeHttp || outUri.Scheme == Uri.UriSchemeHttps) && newUrl.Contains(".") || outUri.Scheme == Uri.UriSchemeFile))) {
241 |
242 | } else {
243 |
244 | // run search if unknown URL
245 | newUrl = SearchURL + HttpUtility.UrlEncode(url);
246 |
247 | }
248 |
249 | }
250 |
251 | // load URL
252 | CurBrowser.Load(newUrl);
253 |
254 | // set URL in UI
255 | SetFormURL(newUrl);
256 |
257 | // always enable back btn
258 | EnableBackButton(true);
259 | EnableForwardButton(false);
260 |
261 | }
262 |
263 | private void SetFormTitle(string tabName) {
264 |
265 | if (tabName.CheckIfValid()) {
266 |
267 | this.Text = tabName + " - " + Branding;
268 | currentTitle = tabName;
269 |
270 | } else {
271 |
272 | this.Text = Branding;
273 | currentTitle = "New Tab";
274 | }
275 |
276 | }
277 |
278 | private void SetFormURL(string URL) {
279 |
280 | currentFullURL = URL;
281 | currentCleanURL = CleanURL(URL);
282 |
283 | TxtURL.Text = currentCleanURL;
284 |
285 | CurTab.CurURL = currentFullURL;
286 |
287 | CloseSearch();
288 |
289 | }
290 |
291 | private string CleanURL(string url) {
292 | if (url.BeginsWith("about:")) {
293 | return "";
294 | }
295 | url = url.RemovePrefix("http://");
296 | url = url.RemovePrefix("https://");
297 | url = url.RemovePrefix("file://");
298 | url = url.RemovePrefix("/");
299 | return url.DecodeURL();
300 | }
301 | private bool IsBlank(string url) {
302 | return (url == "" || url == "about:blank");
303 | }
304 | private bool IsBlankOrSystem(string url) {
305 | return (url == "" || url.BeginsWith("about:") || url.BeginsWith("chrome:") || url.BeginsWith("sharpbrowser:"));
306 | }
307 |
308 | public void AddBlankWindow() {
309 |
310 | // open a new instance of the browser
311 |
312 | ProcessStartInfo info = new ProcessStartInfo(Application.ExecutablePath, "");
313 | //info.WorkingDirectory = workingDir ?? exePath.GetPathDir(true);
314 | info.LoadUserProfile = true;
315 |
316 | info.UseShellExecute = false;
317 | info.RedirectStandardError = true;
318 | info.RedirectStandardOutput = true;
319 | info.RedirectStandardInput = true;
320 |
321 | Process.Start(info);
322 | }
323 | public void AddBlankTab() {
324 | AddNewBrowserTab("");
325 | this.InvokeOnParent(delegate() {
326 | TxtURL.Focus();
327 | });
328 | }
329 |
330 | public ChromiumWebBrowser AddNewBrowserTab(string url, bool focusNewTab = true, string refererUrl = null) {
331 | return (ChromiumWebBrowser)this.Invoke((Func)delegate {
332 |
333 | // check if already exists
334 | foreach (FATabStripItem tab in TabPages.Items) {
335 | SharpTab tab2 = (SharpTab)tab.Tag;
336 | if (tab2 != null && (tab2.CurURL == url)) {
337 | TabPages.SelectedItem = tab;
338 | return tab2.Browser;
339 | }
340 | }
341 |
342 | FATabStripItem tabStrip = new FATabStripItem();
343 | tabStrip.Title = "New Tab";
344 | TabPages.Items.Insert(TabPages.Items.Count - 1, tabStrip);
345 | newStrip = tabStrip;
346 |
347 | SharpTab newTab = AddNewBrowser(newStrip, url);
348 | newTab.RefererURL = refererUrl;
349 | if (focusNewTab) timer1.Enabled = true;
350 | return newTab.Browser;
351 | });
352 | }
353 | private SharpTab AddNewBrowser(FATabStripItem tabStrip, String url) {
354 | if (url == "") url = NewTabURL;
355 | ChromiumWebBrowser browser = new ChromiumWebBrowser(url);
356 |
357 | // set config
358 | ConfigureBrowser(browser);
359 |
360 | // set layout
361 | browser.Dock = DockStyle.Fill;
362 | tabStrip.Controls.Add(browser);
363 | browser.BringToFront();
364 |
365 | // add events
366 | browser.StatusMessage += Browser_StatusMessage;
367 | browser.LoadingStateChanged += Browser_LoadingStateChanged;
368 | browser.TitleChanged += Browser_TitleChanged;
369 | browser.LoadError += Browser_LoadError;
370 | browser.AddressChanged += Browser_URLChanged;
371 | browser.DownloadHandler = dHandler;
372 | browser.MenuHandler = mHandler;
373 | browser.LifeSpanHandler = lHandler;
374 | browser.KeyboardHandler = kHandler;
375 | browser.RequestHandler = rHandler;
376 |
377 | // new tab obj
378 | SharpTab tab = new SharpTab {
379 | IsOpen = true,
380 | Browser = browser,
381 | Tab = tabStrip,
382 | OrigURL = url,
383 | CurURL = url,
384 | Title = "New Tab",
385 | DateCreated = DateTime.Now
386 | };
387 |
388 | // save tab obj in tabstrip
389 | tabStrip.Tag = tab;
390 |
391 | if (url.StartsWith("sharpbrowser:")) {
392 | browser.RegisterAsyncJsObject("host", host, true);
393 | }
394 | return tab;
395 | }
396 |
397 | public SharpTab GetTabByBrowser(IWebBrowser browser) {
398 | foreach (FATabStripItem tab2 in TabPages.Items) {
399 | SharpTab tab = (SharpTab)(tab2.Tag);
400 | if (tab != null && tab.Browser == browser) {
401 | return tab;
402 | }
403 | }
404 | return null;
405 | }
406 |
407 | public void RefreshActiveTab() {
408 | CurBrowser.Load(CurBrowser.Address);
409 | }
410 |
411 | public void CloseActiveTab() {
412 | if (CurTab != null/* && TabPages.Items.Count > 2*/) {
413 |
414 | // remove tab and save its index
415 | int index = TabPages.Items.IndexOf(TabPages.SelectedItem);
416 | TabPages.RemoveTab(TabPages.SelectedItem);
417 |
418 | // keep tab at same index focussed
419 | if ((TabPages.Items.Count - 1) > index) {
420 | TabPages.SelectedItem = TabPages.Items[index];
421 | }
422 | }
423 | }
424 |
425 | private void OnTabClosed(object sender, EventArgs e) {
426 |
427 | }
428 |
429 | private void OnTabClosing(FarsiLibrary.Win.TabStripItemClosingEventArgs e) {
430 |
431 | // exit if invalid tab
432 | if (CurTab == null){
433 | e.Cancel = true;
434 | return;
435 | }
436 |
437 | // add a blank tab if the very last tab is closed!
438 | if (TabPages.Items.Count <= 2) {
439 | AddBlankTab();
440 | //e.Cancel = true;
441 | }
442 |
443 | }
444 |
445 | private void StopActiveTab() {
446 | CurBrowser.Stop();
447 | }
448 |
449 | private bool IsOnFirstTab() {
450 | return TabPages.SelectedItem == TabPages.Items[0];
451 | }
452 | private bool IsOnLastTab() {
453 | return TabPages.SelectedItem == TabPages.Items[TabPages.Items.Count - 2];
454 | }
455 |
456 | private int CurIndex {
457 | get {
458 | return TabPages.Items.IndexOf(TabPages.SelectedItem);
459 | }
460 | set {
461 | TabPages.SelectedItem = TabPages.Items[value];
462 | }
463 | }
464 | private int LastIndex {
465 | get {
466 | return TabPages.Items.Count - 2;
467 | }
468 | }
469 |
470 | private void NextTab() {
471 | if (IsOnLastTab()) {
472 | CurIndex = 0;
473 | } else {
474 | CurIndex++;
475 | }
476 | }
477 | private void PrevTab() {
478 | if (IsOnFirstTab()) {
479 | CurIndex = LastIndex;
480 | } else {
481 | CurIndex--;
482 | }
483 | }
484 |
485 | public ChromiumWebBrowser CurBrowser {
486 | get {
487 | if (TabPages.SelectedItem != null && TabPages.SelectedItem.Tag != null) {
488 | return ((SharpTab)TabPages.SelectedItem.Tag).Browser;
489 | } else {
490 | return null;
491 | }
492 | }
493 | }
494 |
495 | public SharpTab CurTab {
496 | get {
497 | if (TabPages.SelectedItem != null && TabPages.SelectedItem.Tag != null) {
498 | return ((SharpTab)TabPages.SelectedItem.Tag);
499 | } else {
500 | return null;
501 | }
502 | }
503 | }
504 |
505 | public int CurTabLoadingDur {
506 | get {
507 | if (TabPages.SelectedItem != null && TabPages.SelectedItem.Tag != null) {
508 | int loadTime = (int)(DateTime.Now - CurTab.DateCreated).TotalMilliseconds;
509 | return loadTime;
510 | } else {
511 | return 0;
512 | }
513 | }
514 | }
515 |
516 | private void Browser_URLChanged(object sender, AddressChangedEventArgs e) {
517 | InvokeIfNeeded(() => {
518 |
519 | // if current tab
520 | if (sender == CurBrowser) {
521 |
522 | if (!Utils.IsFocussed(TxtURL)) {
523 | SetFormURL(e.Address);
524 | }
525 |
526 | EnableBackButton(CurBrowser.CanGoBack);
527 | EnableForwardButton(CurBrowser.CanGoForward);
528 |
529 | SetTabTitle((ChromiumWebBrowser)sender, "Loading...");
530 |
531 | BtnRefresh.Visible = false;
532 | BtnStop.Visible = true;
533 |
534 | CurTab.DateCreated = DateTime.Now;
535 |
536 | }
537 |
538 | });
539 | }
540 |
541 | private void Browser_LoadError(object sender, LoadErrorEventArgs e) {
542 | // ("Load Error:" + e.ErrorCode + ";" + e.ErrorText);
543 | }
544 |
545 | private void Browser_TitleChanged(object sender, TitleChangedEventArgs e) {
546 | InvokeIfNeeded(() => {
547 |
548 | ChromiumWebBrowser browser = (ChromiumWebBrowser)sender;
549 |
550 | SetTabTitle(browser, e.Title);
551 |
552 | });
553 | }
554 |
555 | private void SetTabTitle(ChromiumWebBrowser browser, string text) {
556 |
557 | text = text.Trim();
558 | if (IsBlank(text)) {
559 | text = "New Tab";
560 | }
561 |
562 | // save text
563 | browser.Tag = text;
564 |
565 | // get tab of given browser
566 | FATabStripItem tabStrip = (FATabStripItem)browser.Parent;
567 | tabStrip.Title = text;
568 |
569 |
570 | // if current tab
571 | if (browser == CurBrowser) {
572 |
573 | SetFormTitle(text);
574 |
575 | }
576 | }
577 |
578 | private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e) {
579 | if (sender == CurBrowser) {
580 |
581 | EnableBackButton(e.CanGoBack);
582 | EnableForwardButton(e.CanGoForward);
583 |
584 | if (e.IsLoading) {
585 |
586 | // set title
587 | //SetTabTitle();
588 |
589 | } else {
590 |
591 | // after loaded / stopped
592 | InvokeIfNeeded(() => {
593 | BtnRefresh.Visible = true;
594 | BtnStop.Visible = false;
595 | });
596 | }
597 | }
598 | }
599 |
600 | public void InvokeIfNeeded(Action action) {
601 | if (this.InvokeRequired) {
602 | this.BeginInvoke(action);
603 | } else {
604 | action.Invoke();
605 | }
606 | }
607 |
608 | private void Browser_StatusMessage(object sender, StatusMessageEventArgs e) {
609 | }
610 |
611 | public void WaitForBrowserToInitialize(ChromiumWebBrowser browser) {
612 | while (!browser.IsBrowserInitialized) {
613 | Thread.Sleep(100);
614 | }
615 | }
616 |
617 | private void EnableBackButton(bool canGoBack) {
618 | InvokeIfNeeded(() => BtnBack.Enabled = canGoBack);
619 | }
620 | private void EnableForwardButton(bool canGoForward) {
621 | InvokeIfNeeded(() => BtnForward.Enabled = canGoForward);
622 | }
623 |
624 | private void OnTabsChanged(TabStripItemChangedEventArgs e) {
625 |
626 |
627 | ChromiumWebBrowser browser = null;
628 | try {
629 | browser = ((ChromiumWebBrowser)e.Item.Controls[0]);
630 | } catch (System.Exception ex) { }
631 |
632 |
633 | if (e.ChangeType == FATabStripItemChangeTypes.SelectionChanged) {
634 | if (TabPages.SelectedItem == tabStripAdd) {
635 | AddBlankTab();
636 | } else {
637 |
638 | browser = CurBrowser;
639 |
640 | SetFormURL(browser.Address);
641 | SetFormTitle(browser.Tag.ConvertToString() ?? "New Tab");
642 |
643 |
644 | EnableBackButton(browser.CanGoBack);
645 | EnableForwardButton(browser.CanGoForward);
646 |
647 | }
648 | }
649 |
650 | if (e.ChangeType == FATabStripItemChangeTypes.Removed) {
651 | if (e.Item == downloadsStrip) downloadsStrip = null;
652 | if (browser != null) {
653 | browser.Dispose();
654 | }
655 | }
656 |
657 | if (e.ChangeType == FATabStripItemChangeTypes.Changed) {
658 | if (browser != null) {
659 | if (currentFullURL != "about:blank") {
660 | browser.Focus();
661 | }
662 | }
663 | }
664 |
665 | }
666 |
667 | private void timer1_Tick(object sender, EventArgs e) {
668 | TabPages.SelectedItem = newStrip;
669 | timer1.Enabled = false;
670 | }
671 |
672 | private void menuCloseTab_Click(object sender, EventArgs e) {
673 | CloseActiveTab();
674 | }
675 |
676 | private void menuCloseOtherTabs_Click(object sender, EventArgs e) {
677 | List listToClose = new List();
678 | foreach (FATabStripItem tab in TabPages.Items) {
679 | if (tab != tabStripAdd && tab != TabPages.SelectedItem) listToClose.Add(tab);
680 | }
681 | foreach (FATabStripItem tab in listToClose) {
682 | TabPages.RemoveTab(tab);
683 | }
684 |
685 | }
686 |
687 | public List CancelRequests {
688 | get {
689 | return downloadCancelRequests;
690 | }
691 | }
692 |
693 | private void bBack_Click(object sender, EventArgs e) {
694 | CurBrowser.Back();
695 | }
696 |
697 | private void bForward_Click(object sender, EventArgs e) {
698 | CurBrowser.Forward();
699 | }
700 |
701 | private void txtUrl_TextChanged(object sender, EventArgs e) {
702 |
703 | }
704 |
705 | private void bDownloads_Click(object sender, EventArgs e) {
706 | AddNewBrowserTab(DownloadsURL);
707 | }
708 |
709 | private void bRefresh_Click(object sender, EventArgs e) {
710 | RefreshActiveTab();
711 | }
712 |
713 | private void bStop_Click(object sender, EventArgs e) {
714 | StopActiveTab();
715 | }
716 | private void TxtURL_KeyDown(object sender, KeyEventArgs e) {
717 |
718 | // if ENTER or CTRL+ENTER pressed
719 | if (e.IsHotkey(Keys.Enter) || e.IsHotkey(Keys.Enter, true)) {
720 | LoadURL(TxtURL.Text);
721 |
722 | // im handling this
723 | e.Handled = true;
724 | e.SuppressKeyPress = true;
725 |
726 | // defocus from url textbox
727 | this.Focus();
728 | }
729 |
730 | // if full URL copied
731 | if (e.IsHotkey(Keys.C, true) && Utils.IsFullySelected(TxtURL)) {
732 |
733 | // copy the real URL, not the pretty one
734 | Clipboard.SetText(CurBrowser.Address, TextDataFormat.UnicodeText);
735 |
736 | // im handling this
737 | e.Handled = true;
738 | e.SuppressKeyPress = true;
739 | }
740 | }
741 |
742 | private void txtUrl_Click(object sender, EventArgs e) {
743 | if (!Utils.HasSelection(TxtURL)) {
744 | TxtURL.SelectAll();
745 | }
746 | }
747 |
748 | private void OpenDeveloperTools() {
749 | CurBrowser.ShowDevTools();
750 | }
751 |
752 | private void tabPages_MouseClick(object sender, MouseEventArgs e) {
753 | /*if (e.Button == System.Windows.Forms.MouseButtons.Right) {
754 | tabPages.GetTabItemByPoint(this.mouse
755 | }*/
756 | }
757 |
758 | #endregion
759 |
760 | #region Download Queue
761 |
762 | private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
763 |
764 | // ask user if they are sure
765 | if (DownloadsInProgress()) {
766 | if (MessageBox.Show("Downloads are in progress. Cancel those and exit?", "Confirm exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes) {
767 | e.Cancel = true;
768 | return;
769 | }
770 | }
771 |
772 | // dispose all browsers
773 | try {
774 | foreach (TabPage tab in TabPages.Items) {
775 | ChromiumWebBrowser browser = (ChromiumWebBrowser)tab.Controls[0];
776 | browser.Dispose();
777 | }
778 | } catch (System.Exception ex) { }
779 |
780 | }
781 |
782 | public Dictionary downloads;
783 | public Dictionary downloadNames;
784 | public List downloadCancelRequests;
785 |
786 | ///
787 | /// we must store download metadata in a list, since CefSharp does not
788 | ///
789 | private void InitDownloads() {
790 |
791 | downloads = new Dictionary();
792 | downloadNames = new Dictionary();
793 | downloadCancelRequests = new List();
794 |
795 | }
796 |
797 | public Dictionary Downloads {
798 | get {
799 | return downloads;
800 | }
801 | }
802 |
803 | public void UpdateDownloadItem(DownloadItem item) {
804 | lock (downloads) {
805 |
806 | // SuggestedFileName comes full only in the first attempt so keep it somewhere
807 | if (item.SuggestedFileName != "") {
808 | downloadNames[item.Id] = item.SuggestedFileName;
809 | }
810 |
811 | // Set it back if it is empty
812 | if (item.SuggestedFileName == "" && downloadNames.ContainsKey(item.Id)) {
813 | item.SuggestedFileName = downloadNames[item.Id];
814 | }
815 |
816 | downloads[item.Id] = item;
817 |
818 | //UpdateSnipProgress();
819 | }
820 | }
821 |
822 | public string CalcDownloadPath(DownloadItem item) {
823 |
824 | string itemName = item.SuggestedFileName != null ? item.SuggestedFileName.GetAfterLast(".") + " file" : "downloads";
825 |
826 | string path = null;
827 | if (path != null) {
828 | return path;
829 | }
830 |
831 | return null;
832 | }
833 |
834 | public bool DownloadsInProgress() {
835 | foreach (DownloadItem item in downloads.Values) {
836 | if (item.IsInProgress) {
837 | return true;
838 | }
839 | }
840 | return false;
841 | }
842 |
843 | ///
844 | /// open a new tab with the downloads URL
845 | ///
846 | private void btnDownloads_Click(object sender, EventArgs e) {
847 | OpenDownloadsTab();
848 | }
849 |
850 | public void OpenDownloadsTab() {
851 | if (downloadsStrip != null && ((ChromiumWebBrowser)downloadsStrip.Controls[0]).Address == DownloadsURL) {
852 | TabPages.SelectedItem = downloadsStrip;
853 | } else {
854 | ChromiumWebBrowser brw = AddNewBrowserTab(DownloadsURL);
855 | downloadsStrip = (FATabStripItem)brw.Parent;
856 | }
857 | }
858 |
859 | #endregion
860 |
861 | #region Search Bar
862 |
863 | bool searchOpen = false;
864 | string lastSearch = "";
865 |
866 | private void OpenSearch() {
867 | if (!searchOpen) {
868 | searchOpen = true;
869 | InvokeIfNeeded(delegate() {
870 | PanelSearch.Visible = true;
871 | TxtSearch.Text = lastSearch;
872 | TxtSearch.Focus();
873 | TxtSearch.SelectAll();
874 | });
875 | } else {
876 | InvokeIfNeeded(delegate() {
877 | TxtSearch.Focus();
878 | TxtSearch.SelectAll();
879 | });
880 | }
881 | }
882 | private void CloseSearch() {
883 | if (searchOpen) {
884 | searchOpen = false;
885 | InvokeIfNeeded(delegate() {
886 | PanelSearch.Visible = false;
887 | CurBrowser.GetBrowser().StopFinding(true);
888 | });
889 | }
890 | }
891 |
892 | private void BtnClearSearch_Click(object sender, EventArgs e) {
893 | CloseSearch();
894 | }
895 |
896 | private void BtnPrevSearch_Click(object sender, EventArgs e) {
897 | FindTextOnPage(false);
898 | }
899 | private void BtnNextSearch_Click(object sender, EventArgs e) {
900 | FindTextOnPage(true);
901 | }
902 |
903 | private void FindTextOnPage(bool next = true) {
904 | bool first = lastSearch != TxtSearch.Text;
905 | lastSearch = TxtSearch.Text;
906 | if (lastSearch.CheckIfValid()) {
907 | CurBrowser.GetBrowser().Find(0, lastSearch, true, false, !first);
908 | } else {
909 | CurBrowser.GetBrowser().StopFinding(true);
910 | }
911 | TxtSearch.Focus();
912 | }
913 |
914 | private void TxtSearch_TextChanged(object sender, EventArgs e) {
915 | FindTextOnPage(true);
916 | }
917 |
918 | private void TxtSearch_KeyDown(object sender, KeyEventArgs e) {
919 | if (e.IsHotkey(Keys.Enter)) {
920 | FindTextOnPage(true);
921 | }
922 | if (e.IsHotkey(Keys.Enter, true) || e.IsHotkey(Keys.Enter, false, true)) {
923 | FindTextOnPage(false);
924 | }
925 | }
926 |
927 | #endregion
928 |
929 |
930 |
931 | }
932 | }
933 |
934 | ///
935 | /// POCO created for holding data per tab
936 | ///
937 | internal class SharpTab {
938 |
939 | public bool IsOpen;
940 |
941 | public string OrigURL;
942 | public string CurURL;
943 | public string Title;
944 |
945 | public string RefererURL;
946 |
947 | public DateTime DateCreated;
948 |
949 | public FATabStripItem Tab;
950 | public ChromiumWebBrowser Browser;
951 |
952 | }
953 |
954 | ///
955 | /// POCO for holding hotkey data
956 | ///
957 | internal class SharpHotKey {
958 |
959 | public Keys Key;
960 | public int KeyCode;
961 | public bool Ctrl;
962 | public bool Shift;
963 | public bool Alt;
964 |
965 | public Action Callback;
966 |
967 | public SharpHotKey(Action callback, Keys key, bool ctrl = false, bool shift = false, bool alt = false) {
968 | Callback = callback;
969 | Key = key;
970 | KeyCode = (int)key;
971 | Ctrl = ctrl;
972 | Shift = shift;
973 | Alt = alt;
974 | }
975 |
976 | }
--------------------------------------------------------------------------------
/src/MainForm.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 325, 17
122 |
123 |
124 |
125 |
126 | iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
127 | YQUAAAEZSURBVDhPxVRbEQIxDKwDJCABCfzwxXBXCUhAAlJOAgJoDwlIQMJJgGw7LUlf9AfITKcznXST
128 | TbJR6mc2zFppOyltbtkZ5m1/Hod5QwB3Anu2DwWCL8wFJv/MdtdVHxgPZi4xsAAsgY32rECPH7xpuxSz
129 | F4DekdOcqnVywe0jA40fvAOPWgfDp9Gc2hmO5vh2oIa0rAYmmoIagXKoWQuQ+4Y/4e6fpb977u06UuY0
130 | ehSBmro/1Idomg2nHJ3lQ4NYM0ktDJD0mkltidIqoaZCEGzcAkgAQaNlglU6aiVAH2ByskM2MNx+DqVK
131 | wpIoUIZayjqtbR/RjIDo0/c1Q8frGTOtE03szKIBBIcbnP3CSJfAw72HMnx75l9XQGc65ZPKTwAAAABJ
132 | RU5ErkJggg==
133 |
134 |
135 |
136 |
137 | iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
138 | YQUAAAEtSURBVDhPvZTbDcIwDEW9ASMwAiMwAiMwAiMwAr+8pI7ACB2BETpCRii+lZ06r8ZfVIpUqHN8
139 | r+OY6F/Pg2j3Ijrxuj6Jxmwd3ToA4nVjwLy1OOZzJzpsggFjyLcHM99DEyrKJg3m35PYTewBAHUWyu9l
140 | CaRGanNoWQGQY4N1geRJvAQtMGT3wgBSMA4w7uMPZ2P1XANWlA1Sc1W7upJaLQrfRPscWINpDO8ZxNlq
141 | W4tc1IJ3bcEAtWKiEHMgo1XXgyHW9mzcq1msQg8MABWTuOM/L3ooqKEXJodStpptG8lo+6zZk7Z+SduI
142 | 9NqVa8KyVksbG8CKzVBk5TiUJLt6cy1uOSC5p7H7pa5QbseXnUIBSj0TB4De+Jq648tmwgSRHksGAW5G
143 | V5V7+joCf9RfGvLkc7XEAAAAAElFTkSuQmCC
144 |
145 |
146 |
147 |
148 | iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
149 | YQUAAAEWSURBVDhPvZRNEcIwEIXjAAlIQAIXTgxNJCABCUhAAhIQQFIkIAEJlVB22ybk522bXtiZXDrJ
150 | 1/dedqPUX+rotsrYhzKuo9WXy76Utpc6LU1rZFAOp58enhsZrO0ZK2Kl9i2qhcSm3YuwU7sbzhh3h3u0
151 | u5ZMQ7mgvPLNGNql1lkBDJ8zI6t5TgiaXBKrEIHDRXTK2/beCig5DBXb1e5W1w4gUwjky1lTxn2CO6yQ
152 | Wqe2xux/zR/Osc35DHuajPRHOYwvL9Q4HWDEpm+LMNpXZB9nEcPzPiyUTT/l+U9KnBSaV18SDE7K3Gjx
153 | yzP2Knh9QOMnSmsuKESyBPPk0T5+CAYYgarfw1guB80H2a5faxu/tqelfV9C2Z1KUaQMeQAAAABJRU5E
154 | rkJggg==
155 |
156 |
157 |
158 |
159 | iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
160 | YQUAAAEHSURBVDhPvVTbDcIwEMsGjMAIjMAPX4gmIzACIzACI3QEBiApI3QERmCEckfaKJf6+vjpSZEq
161 | wTm2a9eYTeYc9sb5p3HhS6cbH/821t+WcakapwOV4HTp6bXTga2/YkbhQ4xblS1ErJqjstAmFo6kIgts
162 | uI8x4Z+JVS6Jn6Gn5LWQfmkOwHgJxhRcqBXATr4kpixuRswUuWmPfk8j5BZgU9kolUFAzuCayZVBwMWB
163 | 7bchoA0P4SHnMZ8oTWnNEHayKk1sh6zYWlAmJcZxGxaBgm7T3sh7rSk5U62asClTwWU5MavAx7mYlS8I
164 | V62XPQc2mBrl6zXjL8/aeP2x2WheZLnD4cu2nB+yNJ4saRMhYwAAAABJRU5ErkJggg==
165 |
166 |
167 |
168 | 238, 17
169 |
170 |
171 |
172 | iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
173 | YQUAAADWSURBVDhPY2AY8sDIyOi+sbHxfxAGsSn2EMwwGD1qIOEQAIYVPxCvB+L9UAyOECQME19vaGio
174 | T9BEkIHA2HyPHhnY+EQZCLIRpJAIQ+MJug5ZAQFDSTMMZjC6oSBXE+VNoCJ5YBjlAzXUI2OQZpihMMOg
175 | fBR1IL0gM+A+BCqejy3QodmOH6QYaikowuBZEVkPyAy4gTiSBzz/GhgY+IMwLsOgBu8nykAcyQeUFkFp
176 | FVRgzIdaRL6BQAP6QWENtSweSJ8H+ZJgGBKTuJGKNkQYkpRA6a0YAGJH+ATjKEoQAAAAAElFTkSuQmCC
177 |
178 |
179 |
180 |
181 | iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
182 | YQUAAACfSURBVEhLY2AYBaMhMExDwHefP4PfnnyifAdSB1JPEvDbE8/gv/c/FM/Hq9d/73y4Wp99+sTZ
183 | 47VXHskC/BYhWwBx1HsGl938xFnkv+c8QYswLQBZgt/XKLaDXIPPIootgNmG26L7BH1JXHhBVeG2CBZX
184 | JAYRLtvxWgSMO6IjmpD3sFpETQuwxhEtLECxCJhMqRZEhIJwVH40BAZFCAAAcuCqYT80zm4AAAAASUVO
185 | RK5CYII=
186 |
187 |
188 |
189 |
190 | iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
191 | YQUAAACXSURBVEhLY2AYBaMhMHhCwG9PPG0d4793PoP/3v9APJ82FiEsAFlCA4swLaCyRaA4gLgcF6Yw
192 | 6AhbQKGPsFqw5zyD1155Bn8gjekzEn2EywKX3fzgVAWiKbII7FL08Ae6HGYBLO3issh3nz1xydtvTz7C
193 | IiwW4LaI1CDb2w8MkvUYPkB3JsRH6xn8gOpHwWgIjIYA2SEAAOtGqKV2Jt9uAAAAAElFTkSuQmCC
194 |
195 |
196 |
197 |
198 | iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
199 | YQUAAADTSURBVEhL7ZTBDYMwDEW9QUfoCIzQS09VCyN0lI7CICWs0FEyAs0nJBTsNDJCnGIpQjgJz/62
200 | ISpWFDhegev7RE33ocZYuveVGAD82Me5TeYBw7Q4KALimVbHuZnzD4CDOABnLCF7ldXdUwR5v5MoZuAB
201 | KUmzUBkUMpufmwEhghwI+7tYbV6CdAPBv4vJRU53nRr6HzCD1F0VIkkDWi6dmyk1aJx21qauBlORxWbQ
202 | gjjE0qO/LOTG+yIQLQRfG6de8e9SyxVCxsXcoCEYrGJFgbUCX35H/c2nacnTAAAAAElFTkSuQmCC
203 |
204 |
205 |
--------------------------------------------------------------------------------
/src/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Windows.Forms;
5 |
6 | namespace SharpBrowser
7 | {
8 | static class Program
9 | {
10 | ///
11 | /// The main entry point for the application.
12 | ///
13 | [STAThread]
14 | static void Main()
15 | {
16 | Application.EnableVisualStyles();
17 | Application.SetCompatibleTextRenderingDefault(false);
18 | Application.Run(new MainForm());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SharpBrowser")]
9 | [assembly: AssemblyDescription("Sharp Browser Project")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Sharp Browser Project")]
12 | [assembly: AssemblyProduct("SharpBrowser")]
13 | [assembly: AssemblyCopyright("Copyright © 2016 Sharp Browser Project")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("ef19e884-45b7-4cde-8b5a-4d2bcede2e0c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("2.0.0.0")]
36 | [assembly: AssemblyFileVersion("2.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.17929
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SharpBrowser.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SharpBrowser.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.17929
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace SharpBrowser.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Resources/blankpage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/Resources/blankpage.png
--------------------------------------------------------------------------------
/src/Resources/sharpbrowser.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/Resources/sharpbrowser.ico
--------------------------------------------------------------------------------
/src/SharpBrowser.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Debug
11 | AnyCPU
12 | {703472B8-B275-4F3F-95B6-426036F8462E}
13 | WinExe
14 | Properties
15 | SharpBrowser
16 | SharpBrowser
17 | v4.5.2
18 | 512
19 |
20 |
21 | true
22 |
23 |
24 |
25 |
26 | x86
27 | true
28 | pdbonly
29 | false
30 | bin\
31 | DEBUG;TRACE
32 | prompt
33 | 4
34 | false
35 |
36 |
37 | x86
38 | pdbonly
39 | true
40 | bin\
41 | TRACE
42 | prompt
43 | 4
44 | false
45 |
46 |
47 | true
48 | bin\
49 | DEBUG;TRACE
50 | full
51 | x86
52 | prompt
53 | MinimumRecommendedRules.ruleset
54 |
55 |
56 | bin\
57 | TRACE
58 | true
59 | pdbonly
60 | x86
61 | prompt
62 | MinimumRecommendedRules.ruleset
63 |
64 |
65 | Resources\sharpbrowser.ico
66 |
67 |
68 | SharpBrowser.Program
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | Form
82 |
83 |
84 | MainForm.cs
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | MainForm.cs
93 |
94 |
95 | ResXFileCodeGenerator
96 | Resources.Designer.cs
97 | Designer
98 |
99 |
100 | True
101 | Resources.resx
102 | True
103 |
104 |
105 | Designer
106 |
107 |
108 |
109 | SettingsSingleFileGenerator
110 | Settings.Designer.cs
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | bin\CefSharp.dll
119 |
120 |
121 | bin\CefSharp.Core.dll
122 |
123 |
124 | bin\CefSharp.WinForms.dll
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | bin\TabStrip.dll
135 |
136 |
137 |
138 |
139 |
140 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
157 |
--------------------------------------------------------------------------------
/src/SharpBrowser.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.23107.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpBrowser", "SharpBrowser.csproj", "{703472B8-B275-4F3F-95B6-426036F8462E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|x86 = Debug|x86
12 | Release|Any CPU = Release|Any CPU
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {703472B8-B275-4F3F-95B6-426036F8462E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {703472B8-B275-4F3F-95B6-426036F8462E}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {703472B8-B275-4F3F-95B6-426036F8462E}.Debug|x86.ActiveCfg = Debug|x86
19 | {703472B8-B275-4F3F-95B6-426036F8462E}.Debug|x86.Build.0 = Debug|x86
20 | {703472B8-B275-4F3F-95B6-426036F8462E}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {703472B8-B275-4F3F-95B6-426036F8462E}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {703472B8-B275-4F3F-95B6-426036F8462E}.Release|x86.ActiveCfg = Release|x86
23 | {703472B8-B275-4F3F-95B6-426036F8462E}.Release|x86.Build.0 = Release|x86
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/src/SharpBrowser.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/SharpBrowser.zip
--------------------------------------------------------------------------------
/src/Utils/FileIconUtils.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | using System;
4 | using System.Drawing;
5 | using System.Runtime.InteropServices;
6 | using Microsoft.Win32;
7 | using System.Reflection;
8 | using System.Collections.Generic;
9 | using System.IO;
10 |
11 | namespace SharpBrowser {
12 |
13 | ///
14 | /// Two constants extracted from the FileInfoFlags, the only that are
15 | /// meaningfull for the user of this class.
16 | ///
17 | public enum FileIconSize : int {
18 | Large = 0x000000000,
19 | Small = 0x000000001
20 | }
21 |
22 | public static class FileIconUtils {
23 |
24 |
25 | // TOP LEVEL API
26 |
27 | public static MemoryStream GetFileIcon(string name, FileIconSize size) {
28 | Icon icon = FileIconUtils.IconFromExtension(name.GetAfter("."), size);
29 | using (icon) {
30 | using (var bmp = icon.ToBitmap()) {
31 | MemoryStream ms = new MemoryStream();
32 | bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
33 | ms.Seek(0, SeekOrigin.Begin);
34 | return ms;
35 | }
36 | }
37 | }
38 |
39 |
40 | #region Custom exceptions class
41 |
42 | public class IconNotFoundException : Exception {
43 | public IconNotFoundException(string fileName, int index)
44 | : base(string.Format("Icon with Id = {0} wasn't found in file {1}", index, fileName)) {
45 | }
46 | }
47 |
48 | public class UnableToExtractIconsException : Exception {
49 | public UnableToExtractIconsException(string fileName, int firstIconIndex, int iconCount)
50 | : base(string.Format("Tryed to extract {2} icons starting from the one with id {1} from the \"{0}\" file but failed", fileName, firstIconIndex, iconCount)) {
51 | }
52 | }
53 |
54 | #endregion
55 |
56 | #region DllImports
57 |
58 | ///
59 | /// Contains information about a file object.
60 | ///
61 | struct SHFILEINFO {
62 | ///
63 | /// Handle to the icon that represents the file. You are responsible for
64 | /// destroying this handle with DestroyIcon when you no longer need it.
65 | ///
66 | public IntPtr hIcon;
67 |
68 | ///
69 | /// Index of the icon image within the system image list.
70 | ///
71 | public IntPtr iIcon;
72 |
73 | ///
74 | /// Array of values that indicates the attributes of the file object.
75 | /// For information about these values, see the IShellFolder::GetAttributesOf
76 | /// method.
77 | ///
78 | public uint dwAttributes;
79 |
80 | ///
81 | /// String that contains the name of the file as it appears in the Microsoft
82 | /// Windows Shell, or the path and file name of the file that contains the
83 | /// icon representing the file.
84 | ///
85 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
86 | public string szDisplayName;
87 |
88 | ///
89 | /// String that describes the type of file.
90 | ///
91 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
92 | public string szTypeName;
93 | };
94 |
95 | [Flags]
96 | enum FileInfoFlags : int {
97 | ///
98 | /// Retrieve the handle to the icon that represents the file and the index
99 | /// of the icon within the system image list. The handle is copied to the
100 | /// hIcon member of the structure specified by psfi, and the index is copied
101 | /// to the iIcon member.
102 | ///
103 | SHGFI_ICON = 0x000000100,
104 | ///
105 | /// Indicates that the function should not attempt to access the file
106 | /// specified by pszPath. Rather, it should act as if the file specified by
107 | /// pszPath exists with the file attributes passed in dwFileAttributes.
108 | ///
109 | SHGFI_USEFILEATTRIBUTES = 0x000000010
110 | }
111 |
112 | ///
113 | /// Creates an array of handles to large or small icons extracted from
114 | /// the specified executable file, dynamic-link library (DLL), or icon
115 | /// file.
116 | ///
117 | ///
118 | /// Name of an executable file, DLL, or icon file from which icons will
119 | /// be extracted.
120 | ///
121 | ///
122 | ///
123 | /// Specifies the zero-based index of the first icon to extract. For
124 | /// example, if this value is zero, the function extracts the first
125 | /// icon in the specified file.
126 | ///
127 | ///
128 | /// If this value is �1 and and
129 | /// are both NULL, the function returns
130 | /// the total number of icons in the specified file. If the file is an
131 | /// executable file or DLL, the return value is the number of
132 | /// RT_GROUP_ICON resources. If the file is an .ico file, the return
133 | /// value is 1.
134 | ///
135 | ///
136 | /// Windows 95/98/Me, Windows NT 4.0 and later: If this value is a
137 | /// negative number and either or
138 | /// is not NULL, the function begins by
139 | /// extracting the icon whose resource identifier is equal to the
140 | /// absolute value of . For example, use -3
141 | /// to extract the icon whose resource identifier is 3.
142 | ///
143 | ///
144 | ///
145 | /// An array of icon handles that receives handles to the large icons
146 | /// extracted from the file. If this parameter is NULL, no large icons
147 | /// are extracted from the file.
148 | ///
149 | ///
150 | /// An array of icon handles that receives handles to the small icons
151 | /// extracted from the file. If this parameter is NULL, no small icons
152 | /// are extracted from the file.
153 | ///
154 | ///
155 | /// Specifies the number of icons to extract from the file.
156 | ///
157 | ///
158 | /// If the parameter is -1, the
159 | /// parameter is NULL, and the
160 | /// parameter is NULL, then the return
161 | /// value is the number of icons contained in the specified file.
162 | /// Otherwise, the return value is the number of icons successfully
163 | /// extracted from the file.
164 | ///
165 | [DllImport("Shell32", CharSet = CharSet.Auto)]
166 | extern static int ExtractIconEx(
167 | [MarshalAs(UnmanagedType.LPTStr)]
168 | string lpszFile,
169 | int nIconIndex,
170 | IntPtr[] phIconLarge,
171 | IntPtr[] phIconSmall,
172 | int nIcons);
173 |
174 | [DllImport("Shell32", CharSet = CharSet.Auto)]
175 | extern static IntPtr SHGetFileInfo(
176 | string pszPath,
177 | int dwFileAttributes,
178 | out SHFILEINFO psfi,
179 | int cbFileInfo,
180 | FileInfoFlags uFlags);
181 |
182 | #endregion
183 |
184 | #region ExtractIcon-like functions
185 |
186 | public static void ExtractEx(string fileName, List largeIcons,
187 | List smallIcons, int firstIconIndex, int iconCount) {
188 | /*
189 | * Memory allocations
190 | */
191 |
192 | IntPtr[] smallIconsPtrs = null;
193 | IntPtr[] largeIconsPtrs = null;
194 |
195 | if (smallIcons != null) {
196 | smallIconsPtrs = new IntPtr[iconCount];
197 | }
198 | if (largeIcons != null) {
199 | largeIconsPtrs = new IntPtr[iconCount];
200 | }
201 |
202 | /*
203 | * Call to native Win32 API
204 | */
205 |
206 | int apiResult = ExtractIconEx(fileName, firstIconIndex, largeIconsPtrs, smallIconsPtrs, iconCount);
207 | if (apiResult != iconCount) {
208 | throw new UnableToExtractIconsException(fileName, firstIconIndex, iconCount);
209 | }
210 |
211 | /*
212 | * Fill lists
213 | */
214 |
215 | if (smallIcons != null) {
216 | smallIcons.Clear();
217 | foreach (IntPtr actualIconPtr in smallIconsPtrs) {
218 | smallIcons.Add(Icon.FromHandle(actualIconPtr));
219 | }
220 | }
221 | if (largeIcons != null) {
222 | largeIcons.Clear();
223 | foreach (IntPtr actualIconPtr in largeIconsPtrs) {
224 | largeIcons.Add(Icon.FromHandle(actualIconPtr));
225 | }
226 | }
227 | }
228 |
229 | public static List ExtractEx(string fileName, FileIconSize size,
230 | int firstIconIndex, int iconCount) {
231 | List iconList = new List();
232 |
233 | switch (size) {
234 | case FileIconSize.Large:
235 | ExtractEx(fileName, iconList, null, firstIconIndex, iconCount);
236 | break;
237 |
238 | case FileIconSize.Small:
239 | ExtractEx(fileName, null, iconList, firstIconIndex, iconCount);
240 | break;
241 |
242 | default:
243 | throw new ArgumentOutOfRangeException("size");
244 | }
245 |
246 | return iconList;
247 | }
248 |
249 | public static void Extract(string fileName, List largeIcons, List smallIcons) {
250 | int iconCount = GetIconsCountInFile(fileName);
251 | ExtractEx(fileName, largeIcons, smallIcons, 0, iconCount);
252 | }
253 |
254 | public static List Extract(string fileName, FileIconSize size) {
255 | int iconCount = GetIconsCountInFile(fileName);
256 | return ExtractEx(fileName, size, 0, iconCount);
257 | }
258 |
259 | public static Icon ExtractOne(string fileName, int index, FileIconSize size) {
260 | try {
261 | List iconList = ExtractEx(fileName, size, index, 1);
262 | return iconList[0];
263 | } catch (UnableToExtractIconsException) {
264 | throw new IconNotFoundException(fileName, index);
265 | }
266 | }
267 |
268 | public static void ExtractOne(string fileName, int index,
269 | out Icon largeIcon, out Icon smallIcon) {
270 | List smallIconList = new List();
271 | List largeIconList = new List();
272 | try {
273 | ExtractEx(fileName, largeIconList, smallIconList, index, 1);
274 | largeIcon = largeIconList[0];
275 | smallIcon = smallIconList[0];
276 | } catch (UnableToExtractIconsException) {
277 | throw new IconNotFoundException(fileName, index);
278 | }
279 | }
280 |
281 | #endregion
282 |
283 |
284 |
285 | ///
286 | /// Get the number of icons in the specified file.
287 | ///
288 | /// Full path of the file to look for.
289 | ///
290 | static int GetIconsCountInFile(string fileName) {
291 | return ExtractIconEx(fileName, -1, null, null, 0);
292 | }
293 |
294 | //this will look throw the registry
295 | //to find if the Extension have an icon.
296 | public static Icon IconFromExtension(string extension,
297 | FileIconSize size) {
298 | // Add the '.' to the extension if needed
299 | if (extension[0] != '.') extension = '.' + extension;
300 | extension = extension.ToLower();
301 |
302 | //opens the registry for the wanted key.
303 | RegistryKey Root = Registry.ClassesRoot;
304 | RegistryKey ExtensionKey = Root.OpenSubKey(extension);
305 | ExtensionKey.GetValueNames();
306 | RegistryKey ApplicationKey =
307 | Root.OpenSubKey(ExtensionKey.GetValue("").ToString());
308 |
309 | //gets the name of the file that have the icon.
310 | string IconLocation =
311 | ApplicationKey.OpenSubKey("DefaultIcon").GetValue("").ToString();
312 | string[] IconPath = IconLocation.Split(',');
313 |
314 | if (IconPath[1] == null) IconPath[1] = "0";
315 | IntPtr[] Large = new IntPtr[1], Small = new IntPtr[1];
316 |
317 | //extracts the icon from the file.
318 | ExtractIconEx(IconPath[0],
319 | Convert.ToInt16(IconPath[1]), Large, Small, 1);
320 | return size == FileIconSize.Large ?
321 | Icon.FromHandle(Large[0]) : Icon.FromHandle(Small[0]);
322 | }
323 |
324 | ///
325 | /// Parse strings in registry who contains the name of the icon and
326 | /// the index of the icon an return both parts.
327 | ///
328 | /// The full string in the form "path,index" as found in registry.
329 | /// The "path" part of the string.
330 | /// The "index" part of the string.
331 | public static void ExtractInformationsFromRegistryString(
332 | string regString, out string fileName, out int index) {
333 | if (regString == null) {
334 | throw new ArgumentNullException("regString");
335 | }
336 | if (regString.Length == 0) {
337 | throw new ArgumentException("The string should not be empty.", "regString");
338 | }
339 |
340 | index = 0;
341 | string[] strArr = regString.Replace("\"", "").Split(',');
342 | fileName = strArr[0].Trim();
343 | if (strArr.Length > 1) {
344 | int.TryParse(strArr[1].Trim(), out index);
345 | }
346 | }
347 |
348 | }
349 |
350 | }
--------------------------------------------------------------------------------
/src/Utils/MiscUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows.Forms;
9 | using CefSharp;
10 |
11 | namespace SharpBrowser {
12 | internal static class Utils {
13 |
14 | public static bool IsFocussed(TextBox tb) {
15 | return tb.Focused;
16 | }
17 |
18 | public static void AddHotKey(Form form, Action function, Keys key, bool ctrl = false, bool shift = false, bool alt = false) {
19 | form.KeyPreview = true;
20 | form.KeyDown += delegate(object sender, KeyEventArgs e) {
21 | if (e.IsHotkey(key, ctrl, shift, alt)) {
22 | function();
23 | }
24 | };
25 | }
26 |
27 | public static bool IsFullySelected(TextBox tb) {
28 | return tb.SelectionLength == tb.TextLength;
29 | }
30 | public static bool HasSelection(TextBox tb) {
31 | return tb.SelectionLength > 0;
32 | }
33 |
34 |
35 | public static bool CheckIfFilePath(this string path) {
36 |
37 | if (path[1] == ':') {
38 | if (path[2] == '\\') {
39 | if (Char.IsLetter(path[0])) {
40 | return true;
41 | }
42 | }
43 | }
44 | return false;
45 | }
46 |
47 | public static bool CheckIfFilePath2(this string path) {
48 |
49 | if (path[1] == ':') {
50 | if (path[2] == '/') {
51 | if (Char.IsLetter(path[0])) {
52 | return true;
53 | }
54 | }
55 | }
56 | return false;
57 | }
58 |
59 | public static string GetAfter(this string text, string find, int startAt = 0, bool returnAll = false, bool forward = true) {
60 | if (text == null) { return returnAll ? text : ""; }
61 | int idx;
62 | if (!forward) {
63 | idx = text.LastIndexOf(find, text.Length - startAt, StringComparison.Ordinal);
64 | } else {
65 | idx = text.IndexOf(find, startAt, StringComparison.Ordinal);
66 | }
67 | if (idx == -1) { return returnAll ? text : ""; }
68 | idx += find.Length;
69 | return text.Substring(idx);
70 | }
71 |
72 | public static string GetAfterLast(this string text, string find, bool returnAll = false) {
73 | int idx = text.LastIndexOf(find, StringComparison.Ordinal);
74 | if (idx == -1) {
75 | return returnAll ? text : "";
76 | }
77 | idx += find.Length;
78 | return text.Substring(idx);
79 | }
80 |
81 | public static bool SupportedInFilePath(this char c) {
82 | return !(c == '?' || c == '\'' || c == '\"' || c == '/' || c == '\\' || c == ';' || c == ':' || c == '&' || c == '*' || c == '<' || c == '>' || c == '|' || c == '{' || c == '}' || c == '[' || c == ']' || c == '(' || c == ')');
83 | }
84 |
85 | public static string ChangePathSlash(this string filePath, string slash) {
86 | if (slash == "\\") {
87 | if (filePath.Contains('/')) {
88 | return filePath.Replace("/", "\\");
89 | }
90 | }
91 | if (slash == "/") {
92 | if (filePath.Contains('\\')) {
93 | return filePath.Replace("\\", "/");
94 | }
95 | }
96 | return filePath;
97 | }
98 | public static string FileURLToPath(this string url) {
99 | return url.RemovePrefix("file:///").ChangePathSlash(@"\").DecodeURLForFilepath();
100 | }
101 |
102 | public static bool FileNotExists(this string path) {
103 | return !File.Exists(path);
104 | }
105 |
106 |
107 | public static string ConvertToString(this object o) {
108 | if (o is string) {
109 | return o as string;
110 | }
111 | return null;
112 | }
113 | public static bool CheckIfValid(this string text, bool trimAndCheck = false) {
114 | return text != null && text.Length > 0;
115 | }
116 |
117 | public static void InvokeOnParent(this Control control, MethodInvoker method) {
118 | Control parent = control.Parent == null ? control : control.Parent;
119 | if (parent.IsHandleCreated) {
120 | parent.Invoke(method);
121 | return;
122 | }
123 | }
124 |
125 | public static bool IsHotkey(this KeyEventArgs eventData, Keys key, bool ctrl = false, bool shift = false, bool alt = false) {
126 | return eventData.KeyCode == key && eventData.Control == ctrl && eventData.Shift == shift && eventData.Alt == alt;
127 | }
128 |
129 | public static CefState ToCefState(this bool value) {
130 | return value ? CefState.Enabled : CefState.Disabled;
131 | }
132 | public static bool IsBitmaskOn(this int num, int bitmask) {
133 | return (num & bitmask) != 0;
134 | }
135 |
136 | public static bool BeginsWith(this string str, string beginsWith, bool caseSensitive = true) {
137 | if (beginsWith.Length > str.Length) {
138 | return false;
139 | }
140 | if (beginsWith.Length == str.Length) {
141 | return String.Equals(beginsWith, str, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
142 | }
143 | return str.LastIndexOf(beginsWith, beginsWith.Length - 1, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase) == 0;
144 | }
145 | public static string RemovePrefix(this string str, string prefix, bool caseSensitive = true) {
146 | if (str.Length >= prefix.Length && str.BeginsWith(prefix, caseSensitive)) {
147 | return str.Substring(prefix.Length);
148 | }
149 | return str;
150 | }
151 |
152 |
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/src/Utils/URLUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace SharpBrowser {
8 | internal static class URLUtils {
9 |
10 | public static string PathToURL(this string filePath, string removeBaseDir = null) {
11 |
12 | if (!filePath.CheckIfValid()) {
13 | return "";
14 | }
15 |
16 | return @"file:///" + filePath.Replace(@"\", "/");
17 | }
18 |
19 | ///
20 | /// checks if URL starts with file:
21 | ///
22 | public static bool IsURLOfflineFile(this string url) {
23 | return url.StartsWith("file://", StringComparison.Ordinal);
24 | }
25 | ///
26 | /// checks if URL is localhost
27 | ///
28 | public static bool IsURLLocalhost(this string url) {
29 | return url.BeginsWith("http://localhost") || url.BeginsWith("localhost");
30 | }
31 |
32 | ///
33 | /// UrlDecodes a string
34 | ///
35 | public static string DecodeURL(this string url) {
36 | if (url == null) {
37 | return null;
38 | }
39 | int length = url.Length;
40 | UrlDecoder decoder = new UrlDecoder(length, Encoding.UTF8);
41 |
42 | // per char
43 | for (int i = 0; i < length; i++) {
44 | char ch = url[i];
45 |
46 |
47 | // PLUS char converts to SPACE
48 | if (ch == '+') {
49 | ch = ' ';
50 |
51 | // SPECIAL chars encoded in "%20" format
52 | } else if ((ch == '%') && (i < (length - 2))) {
53 |
54 | // unicode char (4 digit hex)
55 | if ((url[i + 1] == 'u') && (i < (length - 5))) {
56 | int num3 = HexToInt(url[i + 2]);
57 | int num4 = HexToInt(url[i + 3]);
58 | int num5 = HexToInt(url[i + 4]);
59 | int num6 = HexToInt(url[i + 5]);
60 | if (((num3 < 0) || (num4 < 0)) || ((num5 < 0) || (num6 < 0))) {
61 | goto Label_010B;
62 | }
63 | ch = (char)((((num3 << 12) | (num4 << 8)) | (num5 << 4)) | num6);
64 | i += 5;
65 | decoder.AddChar(ch);
66 | continue;
67 | }
68 |
69 | // ascii char (2 digit hex)
70 | int num7 = HexToInt(url[i + 1]);
71 | int num8 = HexToInt(url[i + 2]);
72 | if ((num7 >= 0) && (num8 >= 0)) {
73 | byte b = (byte)((num7 << 4) | num8);
74 | i += 2;
75 | decoder.AddByte(b);
76 | continue;
77 | }
78 |
79 | }
80 | Label_010B:
81 | if ((ch & 0xff80) == 0) {
82 | decoder.AddByte((byte)ch);
83 | } else {
84 | decoder.AddChar(ch);
85 | }
86 | }
87 | return decoder.GetString();
88 | }
89 |
90 | public static int HexToInt(this char hex) {
91 | if ((hex >= '0') && (hex <= '9')) {
92 | return (hex - '0');
93 | }
94 | if ((hex >= 'a') && (hex <= 'f')) {
95 | return ((hex - 'a') + 10);
96 | }
97 | if ((hex >= 'A') && (hex <= 'F')) {
98 | return ((hex - 'A') + 10);
99 | }
100 | return -1;
101 | }
102 |
103 | private class UrlDecoder {
104 | private int _bufferSize;
105 | private byte[] _byteBuffer;
106 | private char[] _charBuffer;
107 | private Encoding _encoding;
108 | private int _numBytes;
109 | private int _numChars;
110 |
111 | public bool forFilePaths = false;
112 |
113 | internal UrlDecoder(int bufferSize, Encoding encoding) {
114 | this._bufferSize = bufferSize;
115 | this._encoding = encoding;
116 | this._charBuffer = new char[bufferSize];
117 | }
118 |
119 | internal void AddByte(byte b) {
120 | if (this._byteBuffer == null) {
121 | this._byteBuffer = new byte[this._bufferSize];
122 | }
123 | this._byteBuffer[this._numBytes++] = b;
124 | }
125 |
126 | internal void AddChar(char ch, bool checkChar = false) {
127 | if (this._numBytes > 0) {
128 | this.FlushBytes();
129 | }
130 |
131 | // ADD CHAR AS HEX .. IF NOT SUPPORTED IN FILEPATHS
132 | if (checkChar && forFilePaths) {
133 | if (!ch.SupportedInFilePath()) {
134 | AddChar('_');
135 | AddString("0x" + ((int)ch).ToString("X"));
136 | AddChar('_');
137 | return;
138 | }
139 | }
140 |
141 | this._charBuffer[this._numChars++] = ch;
142 | }
143 | internal void AddString(string str) {
144 | if (this._numBytes > 0) {
145 | this.FlushBytes();
146 | }
147 | foreach (char ch in str) {
148 | this._charBuffer[this._numChars++] = ch;
149 | }
150 | }
151 |
152 | public void FlushBytes(bool checkChar = false) {
153 | if (this._numBytes > 0) {
154 |
155 | if (checkChar && forFilePaths) {
156 |
157 | char[] newChars = this._encoding.GetChars(this._byteBuffer, 0, this._numBytes);
158 | this._numBytes = 0;
159 |
160 | foreach (char ch in newChars) {
161 | AddChar(ch);
162 | }
163 |
164 | } else {
165 |
166 | this._numChars += this._encoding.GetChars(this._byteBuffer, 0, this._numBytes, this._charBuffer, this._numChars);
167 | this._numBytes = 0;
168 |
169 | }
170 | }
171 | }
172 |
173 | internal string GetString() {
174 | if (this._numBytes > 0) {
175 | this.FlushBytes();
176 | }
177 | if (this._numChars > 0) {
178 | return new string(this._charBuffer, 0, this._numChars);
179 | }
180 | return string.Empty;
181 | }
182 | }
183 |
184 | ///
185 | /// UrlDecodes a string except chars forbidden in Windows filepaths
186 | ///
187 | public static string DecodeURLForFilepath(this string url) {
188 |
189 |
190 | if (url == null) {
191 | return null;
192 | }
193 |
194 | int length = url.Length;
195 | UrlDecoder decoder = new UrlDecoder(length * 10, Encoding.UTF8);
196 | decoder.forFilePaths = true;
197 |
198 |
199 | // per char
200 | for (int i = 0; i < length; i++) {
201 | char ch = url[i];
202 |
203 |
204 | // PLUS char converts to SPACE
205 | if (ch == '+') {
206 | ch = ' ';
207 |
208 | // SPECIAL chars encoded in "%20" format
209 | } else if ((ch == '%') && (i < (length - 2))) {
210 |
211 | // unicode char (4 digit hex)
212 | if ((url[i + 1] == 'u') && (i < (length - 5))) {
213 | int num3 = HexToInt(url[i + 2]);
214 | int num4 = HexToInt(url[i + 3]);
215 | int num5 = HexToInt(url[i + 4]);
216 | int num6 = HexToInt(url[i + 5]);
217 | if (((num3 < 0) || (num4 < 0)) || ((num5 < 0) || (num6 < 0))) {
218 | goto Label_010B;
219 | }
220 | ch = (char)((((num3 << 12) | (num4 << 8)) | (num5 << 4)) | num6);
221 | i += 5;
222 | decoder.FlushBytes(false); // dont check previous stuff
223 | decoder.AddChar(ch, true); // CHECK IF CHAR OK WITH FILEPATH
224 | continue;
225 | }
226 |
227 | // ascii char (2 digit hex)
228 | int num7 = HexToInt(url[i + 1]);
229 | int num8 = HexToInt(url[i + 2]);
230 | if ((num7 >= 0) && (num8 >= 0)) {
231 | byte b = (byte)((num7 << 4) | num8);
232 | i += 2;
233 | decoder.FlushBytes(false); // dont check previous stuff
234 | decoder.AddByte(b);
235 |
236 | // check if unicode char ("%11%11")
237 | if (((i + 1) < (length - 2)) && (url[i + 1] == '%')) {
238 |
239 | // YES, unicode char
240 | num7 = HexToInt(url[i + 1]);
241 | num8 = HexToInt(url[i + 2]);
242 | if ((num7 >= 0) && (num8 >= 0)) {
243 | b = (byte)((num7 << 4) | num8);
244 | i += 2;
245 | decoder.AddByte(b);
246 | decoder.FlushBytes(true); // CHECK IF CHARS OK WITH FILEPATHS
247 | }
248 | } else {
249 |
250 | // NO, not unicode char
251 | decoder.FlushBytes(true); // CHECK IF CHARS OK WITH FILEPATHS
252 |
253 | }
254 |
255 | continue;
256 | }
257 |
258 | }
259 |
260 | Label_010B:
261 | if ((ch & 0xff80) == 0) {
262 | decoder.AddByte((byte)ch);
263 | } else {
264 | decoder.AddChar(ch, false);
265 | }
266 | }
267 |
268 | return decoder.GetString();
269 | }
270 |
271 | ///
272 | /// UrlEncodes a string without the requirement for System.Web
273 | ///
274 | public static string EncodeURL(this string text) {
275 | return System.Uri.EscapeDataString(text);
276 | }
277 |
278 |
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/src/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/DesignTimeResolveAssemblyReferencesInput.cache
--------------------------------------------------------------------------------
/src/obj/Debug/SharpBrowser.MainForm.resources:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/SharpBrowser.MainForm.resources
--------------------------------------------------------------------------------
/src/obj/Debug/SharpBrowser.Properties.Resources.resources:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/SharpBrowser.Properties.Resources.resources
--------------------------------------------------------------------------------
/src/obj/Debug/SharpBrowser.csproj.FileListAbsolute.txt:
--------------------------------------------------------------------------------
1 | E:\Program Files\Git\@\SharpBrowser\src\obj\Debug\SharpBrowser.csprojResolveAssemblyReference.cache
2 | E:\Program Files\Git\@\SharpBrowser\src\obj\Debug\SharpBrowser.MainForm.resources
3 | E:\Program Files\Git\@\SharpBrowser\src\obj\Debug\SharpBrowser.Properties.Resources.resources
4 | E:\Program Files\Git\@\SharpBrowser\src\obj\Debug\SharpBrowser.csproj.GenerateResource.Cache
5 |
--------------------------------------------------------------------------------
/src/obj/Debug/SharpBrowser.csproj.GenerateResource.Cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/SharpBrowser.csproj.GenerateResource.Cache
--------------------------------------------------------------------------------
/src/obj/Debug/SharpBrowser.csprojResolveAssemblyReference.cache:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/SharpBrowser.csprojResolveAssemblyReference.cache
--------------------------------------------------------------------------------
/src/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
--------------------------------------------------------------------------------
/src/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
--------------------------------------------------------------------------------
/src/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CreateBrowser/SharpBrowser/bf64cb1976e39d33c8b3d5792e42197da95d459e/src/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
--------------------------------------------------------------------------------
/src/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------