Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1333)

Side by Side Diff: chrome_frame/chrome_tab.cc

Issue 12521002: Start and stop crash reporting outside of the loader lock. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: revert r70898 Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // chrome_tab.cc : Implementation of DLL Exports. 5 // chrome_tab.cc : Implementation of DLL Exports.
6 6
7 // Need to include this before the ATL headers below. 7 // Need to include this before the ATL headers below.
8 #include "chrome_frame/chrome_tab.h" 8 #include "chrome_frame/chrome_tab.h"
9 9
10 #include <atlsecurity.h> 10 #include <atlsecurity.h>
11 #include <objbase.h> 11 #include <objbase.h>
12 12
13 #include "base/at_exit.h" 13 #include "base/at_exit.h"
14 #include "base/basictypes.h"
14 #include "base/command_line.h" 15 #include "base/command_line.h"
15 #include "base/file_util.h" 16 #include "base/file_util.h"
16 #include "base/file_version_info.h" 17 #include "base/file_version_info.h"
17 #include "base/logging.h" 18 #include "base/logging.h"
18 #include "base/logging_win.h" 19 #include "base/logging_win.h"
19 #include "base/metrics/field_trial.h" 20 #include "base/metrics/field_trial.h"
20 #include "base/path_service.h" 21 #include "base/path_service.h"
21 #include "base/string16.h" 22 #include "base/string16.h"
22 #include "base/string_number_conversions.h" 23 #include "base/string_number_conversions.h"
23 #include "base/string_piece.h" 24 #include "base/string_piece.h"
(...skipping 17 matching lines...) Expand all
41 #include "chrome_frame/exception_barrier.h" 42 #include "chrome_frame/exception_barrier.h"
42 #include "chrome_frame/metrics_service.h" 43 #include "chrome_frame/metrics_service.h"
43 #include "chrome_frame/resource.h" 44 #include "chrome_frame/resource.h"
44 #include "chrome_frame/utils.h" 45 #include "chrome_frame/utils.h"
45 #include "googleurl/src/url_util.h" 46 #include "googleurl/src/url_util.h"
46 #include "grit/chrome_frame_resources.h" 47 #include "grit/chrome_frame_resources.h"
47 48
48 using base::win::RegKey; 49 using base::win::RegKey;
49 50
50 namespace { 51 namespace {
51 // This function has the side effect of initializing an unprotected
52 // vector pointer inside GoogleUrl. If this is called during DLL loading,
53 // it has the effect of avoiding an initialization race on that pointer.
54 // TODO(siggi): fix GoogleUrl.
55 void InitGoogleUrl() {
56 static const char kDummyUrl[] = "http://www.google.com";
57
58 url_util::IsStandard(kDummyUrl,
59 url_parse::MakeRange(0, arraysize(kDummyUrl)));
60 }
61 52
62 const wchar_t kInternetSettings[] = 53 const wchar_t kInternetSettings[] =
63 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings"; 54 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings";
64 55
65 const wchar_t kProtocolHandlers[] = 56 const wchar_t kProtocolHandlers[] =
66 L"Software\\Classes\\Protocols\\Handler"; 57 L"Software\\Classes\\Protocols\\Handler";
67 58
68 const wchar_t kRunOnce[] = 59 const wchar_t kRunOnce[] =
69 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce"; 60 L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce";
70 61
71 const wchar_t kRunKeyName[] = L"ChromeFrameHelper"; 62 const wchar_t kRunKeyName[] = L"ChromeFrameHelper";
72 63
73 const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe"; 64 const wchar_t kChromeFrameHelperExe[] = L"chrome_frame_helper.exe";
74 const wchar_t kChromeFrameHelperStartupArg[] = L"--startup"; 65 const wchar_t kChromeFrameHelperStartupArg[] = L"--startup";
75 66
76 // Window class and window names. 67 // Window class and window names.
77 // TODO(robertshield): These and other constants need to be refactored into 68 // TODO(robertshield): These and other constants need to be refactored into
78 // a common chrome_frame_constants.h|cc and built into a separate lib 69 // a common chrome_frame_constants.h|cc and built into a separate lib
79 // (either chrome_frame_utils or make another one). 70 // (either chrome_frame_utils or make another one).
80 const wchar_t kChromeFrameHelperWindowClassName[] = 71 const wchar_t kChromeFrameHelperWindowClassName[] =
81 L"ChromeFrameHelperWindowClass"; 72 L"ChromeFrameHelperWindowClass";
82 const wchar_t kChromeFrameHelperWindowName[] = 73 const wchar_t kChromeFrameHelperWindowName[] =
83 L"ChromeFrameHelperWindowName"; 74 L"ChromeFrameHelperWindowName";
84 75
85 // {0562BFC3-2550-45b4-BD8E-A310583D3A6F} 76 // {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
86 static const GUID kChromeFrameProvider = 77 const GUID kChromeFrameProvider =
87 { 0x562bfc3, 0x2550, 0x45b4, 78 { 0x562bfc3, 0x2550, 0x45b4,
88 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } }; 79 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
89 80
90 const wchar_t kPostPlatformUAKey[] = 81 const wchar_t kPostPlatformUAKey[] =
91 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\" 82 L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\"
92 L"User Agent\\Post Platform"; 83 L"User Agent\\Post Platform";
93 const wchar_t kChromeFramePrefix[] = L"chromeframe/"; 84 const wchar_t kChromeFramePrefix[] = L"chromeframe/";
94 85
95 // See comments in DllGetClassObject. 86 // See comments in DllGetClassObject.
96 LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL; 87 LPFNGETCLASSOBJECT g_dll_get_class_object_redir_ptr = NULL;
97 88
89 // This function has the side effect of initializing an unprotected
90 // vector pointer inside GoogleUrl. If this is called during DLL loading,
91 // it has the effect of avoiding an initialization race on that pointer.
92 // TODO(siggi): fix GoogleUrl.
93 void InitGoogleUrl() {
94 static const char kDummyUrl[] = "http://www.google.com";
95
96 url_util::IsStandard(kDummyUrl,
97 url_parse::MakeRange(0, arraysize(kDummyUrl)));
98 }
99
98 class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> { 100 class ChromeTabModule : public CAtlDllModuleT<ChromeTabModule> {
99 public: 101 public:
100 typedef CAtlDllModuleT<ChromeTabModule> ParentClass; 102 typedef CAtlDllModuleT<ChromeTabModule> ParentClass;
101 103
102 ChromeTabModule() : do_system_registration_(true) {} 104 ChromeTabModule() : do_system_registration_(true), crash_reporting_(NULL) {}
103 105
104 DECLARE_LIBID(LIBID_ChromeTabLib) 106 DECLARE_LIBID(LIBID_ChromeTabLib)
105 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB, 107 DECLARE_REGISTRY_APPID_RESOURCEID(IDR_CHROMETAB,
106 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}") 108 "{FD9B1B31-F4D8-436A-8F4F-D3C2E36733D3}")
107 109
108 // Override to add our SYSTIME binary value to registry scripts. 110 // Override to add our SYSTIME binary value to registry scripts.
109 // See chrome_frame_activex.rgs for usage. 111 // See chrome_frame_activex.rgs for usage.
110 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() { 112 virtual HRESULT AddCommonRGSReplacements(IRegistrarBase* registrar) throw() {
111 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar); 113 HRESULT hr = ParentClass::AddCommonRGSReplacements(registrar);
112 114
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
182 if (SUCCEEDED(hr)) { 184 if (SUCCEEDED(hr)) {
183 // Add the Chrome Frame CLSID. 185 // Add the Chrome Frame CLSID.
184 wchar_t cf_clsid[64]; 186 wchar_t cf_clsid[64];
185 StringFromGUID2(CLSID_ChromeFrame, &cf_clsid[0], arraysize(cf_clsid)); 187 StringFromGUID2(CLSID_ChromeFrame, &cf_clsid[0], arraysize(cf_clsid));
186 hr = registrar->AddReplacement(L"CHROME_FRAME_CLSID", &cf_clsid[0]); 188 hr = registrar->AddReplacement(L"CHROME_FRAME_CLSID", &cf_clsid[0]);
187 } 189 }
188 190
189 return hr; 191 return hr;
190 } 192 }
191 193
194 // The module is "locked" when an object takes a reference on it. The first
195 // time it is locked, take a reference on crash reporting to bind its lifetime
196 // to the module.
197 virtual LONG Lock() throw() {
198 LONG result = ParentClass::Lock();
199 if (result == 1) {
200 DCHECK_EQ(crash_reporting_,
201 static_cast<chrome_frame::ScopedCrashReporting*>(NULL));
202 crash_reporting_ = new chrome_frame::ScopedCrashReporting();
203 }
204 return result;
205 }
206
207 // The module is "unlocked" when an object that had a reference on it is
208 // destroyed. The last time it is unlocked, release the reference on crash
209 // reporting.
210 virtual LONG Unlock() throw() {
211 LONG result = ParentClass::Unlock();
212 if (!result) {
213 DCHECK_NE(crash_reporting_,
214 static_cast<chrome_frame::ScopedCrashReporting*>(NULL));
215 delete crash_reporting_;
216 crash_reporting_ = NULL;
217 }
218 return result;
219 }
220
192 // See comments in AddCommonRGSReplacements 221 // See comments in AddCommonRGSReplacements
193 bool do_system_registration_; 222 bool do_system_registration_;
223
224 private:
225 // A scoper created when the module is initially locked and destroyed when it
226 // is finally unlocked.
227 chrome_frame::ScopedCrashReporting* crash_reporting_;
robertshield 2013/03/13 17:22:27 Could make this a scoped_ptr?
grt (UTC plus 2) 2013/03/14 14:40:32 No. I explicitly don't want it to be deleted when
194 }; 228 };
195 229
196 ChromeTabModule _AtlModule; 230 ChromeTabModule _AtlModule;
197 231
198 base::AtExitManager* g_exit_manager = NULL; 232 base::AtExitManager* g_exit_manager = NULL;
199 base::FieldTrialList* g_field_trial_list = NULL; 233 base::FieldTrialList* g_field_trial_list = NULL;
200 234
201 HRESULT RefreshElevationPolicy() { 235 HRESULT RefreshElevationPolicy() {
202 const wchar_t kIEFrameDll[] = L"ieframe.dll"; 236 const wchar_t kIEFrameDll[] = L"ieframe.dll";
203 const char kIERefreshPolicy[] = "IERefreshElevationPolicy"; 237 const char kIERefreshPolicy[] = "IERefreshElevationPolicy";
(...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 result2 = key.WriteValue(L"ChromeTab.ChromeActiveDocument.1", 1); 575 result2 = key.WriteValue(L"ChromeTab.ChromeActiveDocument.1", 1);
542 } else { 576 } else {
543 result1 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument"); 577 result1 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument");
544 result2 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1"); 578 result2 = key.DeleteValue(L"ChromeTab.ChromeActiveDocument.1");
545 } 579 }
546 580
547 return result1 != ERROR_SUCCESS ? HRESULT_FROM_WIN32(result1) : 581 return result1 != ERROR_SUCCESS ? HRESULT_FROM_WIN32(result1) :
548 HRESULT_FROM_WIN32(result2); 582 HRESULT_FROM_WIN32(result2);
549 } 583 }
550 584
585 void OnPinModule() {
586 // Pin crash reporting by leaking a reference.
587 ignore_result(new chrome_frame::ScopedCrashReporting());
588 }
589
551 // Chrome Frame registration functions. 590 // Chrome Frame registration functions.
552 //----------------------------------------------------------------------------- 591 //-----------------------------------------------------------------------------
553 HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) { 592 HRESULT RegisterSecuredMimeHandler(bool enable, bool is_system) {
554 if (!is_system) { 593 if (!is_system) {
555 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER); 594 return SetOrDeleteMimeHandlerKey(enable, HKEY_CURRENT_USER);
556 } else if (base::win::GetVersion() < base::win::VERSION_VISTA) { 595 } else if (base::win::GetVersion() < base::win::VERSION_VISTA) {
557 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE); 596 return SetOrDeleteMimeHandlerKey(enable, HKEY_LOCAL_MACHINE);
558 } 597 }
559 598
560 std::wstring mime_key = kInternetSettings; 599 std::wstring mime_key = kInternetSettings;
(...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after
822 if (reason == DLL_PROCESS_ATTACH) { 861 if (reason == DLL_PROCESS_ATTACH) {
823 #ifndef NDEBUG 862 #ifndef NDEBUG
824 // Silence traces from the ATL registrar to reduce the log noise. 863 // Silence traces from the ATL registrar to reduce the log noise.
825 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0, 864 ATL::CTrace::s_trace.ChangeCategory(atlTraceRegistrar, 0,
826 ATLTRACESTATUS_DISABLED); 865 ATLTRACESTATUS_DISABLED);
827 #endif 866 #endif
828 InitGoogleUrl(); 867 InitGoogleUrl();
829 868
830 g_exit_manager = new base::AtExitManager(); 869 g_exit_manager = new base::AtExitManager();
831 CommandLine::Init(0, NULL); 870 CommandLine::Init(0, NULL);
832 InitializeCrashReporting();
833 logging::InitLogging( 871 logging::InitLogging(
834 NULL, 872 NULL,
835 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG, 873 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
836 logging::LOCK_LOG_FILE, 874 logging::LOCK_LOG_FILE,
837 logging::DELETE_OLD_LOG_FILE, 875 logging::DELETE_OLD_LOG_FILE,
838 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); 876 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS);
839 877
840 // Log the same items as Chrome. 878 // Log the same items as Chrome.
841 logging::SetLogItems(true, // enable_process_id 879 logging::SetLogItems(true, // enable_process_id
842 true, // enable_thread_id 880 true, // enable_thread_id
(...skipping 12 matching lines...) Expand all
855 << "Found CF module with no DllGetClassObject export."; 893 << "Found CF module with no DllGetClassObject export.";
856 } 894 }
857 895
858 // Enable trace control and transport through event tracing for Windows. 896 // Enable trace control and transport through event tracing for Windows.
859 logging::LogEventProvider::Initialize(kChromeFrameProvider); 897 logging::LogEventProvider::Initialize(kChromeFrameProvider);
860 898
861 // Initialize the field test infrastructure. Must be done somewhere that 899 // Initialize the field test infrastructure. Must be done somewhere that
862 // can only get called once. For Chrome Frame, that is here. 900 // can only get called once. For Chrome Frame, that is here.
863 g_field_trial_list = new base::FieldTrialList( 901 g_field_trial_list = new base::FieldTrialList(
864 new metrics::SHA1EntropyProvider(MetricsService::GetClientID())); 902 new metrics::SHA1EntropyProvider(MetricsService::GetClientID()));
903
904 // Set a callback so that crash reporting can be pinned when the module is
905 // pinned.
906 SetPinModuleCallback(&OnPinModule);
865 } else if (reason == DLL_PROCESS_DETACH) { 907 } else if (reason == DLL_PROCESS_DETACH) {
866 delete g_field_trial_list; 908 delete g_field_trial_list;
867 g_field_trial_list = NULL; 909 g_field_trial_list = NULL;
868 910
869 DllRedirector* dll_redirector = DllRedirector::GetInstance(); 911 DllRedirector* dll_redirector = DllRedirector::GetInstance();
870 DCHECK(dll_redirector); 912 DCHECK(dll_redirector);
871 dll_redirector->UnregisterAsFirstCFModule(); 913 dll_redirector->UnregisterAsFirstCFModule();
872 914
873 g_patch_helper.UnpatchIfNeeded(); 915 g_patch_helper.UnpatchIfNeeded();
874 916
875 delete g_exit_manager; 917 delete g_exit_manager;
876 g_exit_manager = NULL; 918 g_exit_manager = NULL;
877
878 ShutdownCrashReporting();
879 } 919 }
880 return _AtlModule.DllMain(reason, reserved); 920 return _AtlModule.DllMain(reason, reserved);
881 } 921 }
882 922
883 // Used to determine whether the DLL can be unloaded by OLE 923 // Used to determine whether the DLL can be unloaded by OLE
884 STDAPI DllCanUnloadNow() { 924 STDAPI DllCanUnloadNow() {
885 return _AtlModule.DllCanUnloadNow(); 925 return _AtlModule.DllCanUnloadNow();
886 } 926 }
887 927
888 // Returns a class factory to create an object of the requested type 928 // Returns a class factory to create an object of the requested type
889 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) { 929 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) {
930 chrome_frame::ScopedCrashReporting crash_reporting;
931
890 // If we found another module present when we were loaded, then delegate to 932 // If we found another module present when we were loaded, then delegate to
891 // that: 933 // that:
892 if (g_dll_get_class_object_redir_ptr) { 934 if (g_dll_get_class_object_redir_ptr) {
893 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv); 935 return g_dll_get_class_object_redir_ptr(rclsid, riid, ppv);
894 } 936 }
895 937
896 // Enable sniffing and switching only if asked for BHO 938 // Enable sniffing and switching only if asked for BHO
897 // (we use BHO to get loaded in IE). 939 // (we use BHO to get loaded in IE).
898 if (rclsid == CLSID_ChromeFrameBHO) { 940 if (rclsid == CLSID_ChromeFrameBHO) {
899 g_patch_helper.InitializeAndPatchProtocolsIfNeeded(); 941 g_patch_helper.InitializeAndPatchProtocolsIfNeeded();
900 } 942 }
901 943
902 return _AtlModule.DllGetClassObject(rclsid, riid, ppv); 944 return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
903 } 945 }
904 946
905 // DllRegisterServer - Adds entries to the system registry 947 // DllRegisterServer - Adds entries to the system registry
906 STDAPI DllRegisterServer() { 948 STDAPI DllRegisterServer() {
949 chrome_frame::ScopedCrashReporting crash_reporting;
907 uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL | 950 uint16 flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
908 BHO_CLSID | BHO_REGISTRATION; 951 BHO_CLSID | BHO_REGISTRATION;
909 952
910 HRESULT hr = CustomRegistration(flags, true, true); 953 HRESULT hr = CustomRegistration(flags, true, true);
911 if (SUCCEEDED(hr)) { 954 if (SUCCEEDED(hr)) {
912 SetupRunOnce(); 955 SetupRunOnce();
913 } 956 }
914 957
915 return hr; 958 return hr;
916 } 959 }
917 960
918 // DllUnregisterServer - Removes entries from the system registry 961 // DllUnregisterServer - Removes entries from the system registry
919 STDAPI DllUnregisterServer() { 962 STDAPI DllUnregisterServer() {
963 chrome_frame::ScopedCrashReporting crash_reporting;
920 HRESULT hr = CustomRegistration(ALL, false, true); 964 HRESULT hr = CustomRegistration(ALL, false, true);
921 return hr; 965 return hr;
922 } 966 }
923 967
924 // DllRegisterUserServer - Adds entries to the HKCU hive in the registry. 968 // DllRegisterUserServer - Adds entries to the HKCU hive in the registry.
925 STDAPI DllRegisterUserServer() { 969 STDAPI DllRegisterUserServer() {
970 chrome_frame::ScopedCrashReporting crash_reporting;
926 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL | 971 UINT flags = ACTIVEX | ACTIVEDOC | TYPELIB | GCF_PROTOCOL |
927 BHO_CLSID | BHO_REGISTRATION; 972 BHO_CLSID | BHO_REGISTRATION;
928 973
929 HRESULT hr = CustomRegistration(flags, TRUE, false); 974 HRESULT hr = CustomRegistration(flags, TRUE, false);
930 if (SUCCEEDED(hr)) { 975 if (SUCCEEDED(hr)) {
931 SetupRunOnce(); 976 SetupRunOnce();
932 } 977 }
933 978
934 return hr; 979 return hr;
935 } 980 }
936 981
937 // DllUnregisterUserServer - Removes entries from the HKCU hive in the registry. 982 // DllUnregisterUserServer - Removes entries from the HKCU hive in the registry.
938 STDAPI DllUnregisterUserServer() { 983 STDAPI DllUnregisterUserServer() {
984 chrome_frame::ScopedCrashReporting crash_reporting;
939 HRESULT hr = CustomRegistration(ALL, FALSE, false); 985 HRESULT hr = CustomRegistration(ALL, FALSE, false);
940 return hr; 986 return hr;
941 } 987 }
942 988
943 // Object entries go here instead of with each object, so that we can move 989 // Object entries go here instead of with each object, so that we can move
944 // the objects to a lib. Also reduces magic. 990 // the objects to a lib. Also reduces magic.
945 OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho) 991 OBJECT_ENTRY_AUTO(CLSID_ChromeFrameBHO, Bho)
946 OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument) 992 OBJECT_ENTRY_AUTO(__uuidof(ChromeActiveDocument), ChromeActiveDocument)
947 OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex) 993 OBJECT_ENTRY_AUTO(__uuidof(ChromeFrame), ChromeFrameActivex)
948 OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol) 994 OBJECT_ENTRY_AUTO(__uuidof(ChromeProtocol), ChromeProtocol)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698