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

Side by Side Diff: media/midi/midi_manager_winrt.cc

Issue 2301513002: Remove RuntimeObject.lib dependency in Windows 10 Web MIDI backend (Closed)
Patch Set: rebase Created 4 years, 3 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
« no previous file with comments | « media/midi/BUILD.gn ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 #include "media/midi/midi_manager_winrt.h" 5 #include "media/midi/midi_manager_winrt.h"
6 6
7 #include <comdef.h> 7 #include <comdef.h>
8 #include <robuffer.h> 8 #include <robuffer.h>
9 #include <windows.devices.enumeration.h> 9 #include <windows.devices.enumeration.h>
10 #include <windows.devices.midi.h> 10 #include <windows.devices.midi.h>
11 #include <wrl/event.h> 11 #include <wrl/event.h>
12 12
13 #include <iomanip> 13 #include <iomanip>
14 #include <unordered_map> 14 #include <unordered_map>
15 #include <unordered_set> 15 #include <unordered_set>
16 16
17 #include "base/bind.h" 17 #include "base/bind.h"
18 #include "base/lazy_instance.h"
19 #include "base/scoped_generic.h"
18 #include "base/strings/utf_string_conversions.h" 20 #include "base/strings/utf_string_conversions.h"
19 #include "base/threading/thread_checker.h" 21 #include "base/threading/thread_checker.h"
20 #include "base/threading/thread_task_runner_handle.h" 22 #include "base/threading/thread_task_runner_handle.h"
21 #include "base/timer/timer.h" 23 #include "base/timer/timer.h"
22 #include "base/win/scoped_comptr.h" 24 #include "base/win/scoped_comptr.h"
23 #include "base/win/windows_version.h" 25 #include "base/win/windows_version.h"
24 #include "media/midi/midi_scheduler.h" 26 #include "media/midi/midi_scheduler.h"
25 27
26 namespace media { 28 namespace media {
27 namespace midi { 29 namespace midi {
(...skipping 15 matching lines...) Expand all
43 }; 45 };
44 46
45 std::ostream& operator<<(std::ostream& os, const PrintHr& phr) { 47 std::ostream& operator<<(std::ostream& os, const PrintHr& phr) {
46 std::ios_base::fmtflags ff = os.flags(); 48 std::ios_base::fmtflags ff = os.flags();
47 os << _com_error(phr.hr).ErrorMessage() << " (0x" << std::hex 49 os << _com_error(phr.hr).ErrorMessage() << " (0x" << std::hex
48 << std::uppercase << std::setfill('0') << std::setw(8) << phr.hr << ")"; 50 << std::uppercase << std::setfill('0') << std::setw(8) << phr.hr << ")";
49 os.flags(ff); 51 os.flags(ff);
50 return os; 52 return os;
51 } 53 }
52 54
55 // Provides access to functions in combase.dll which may not be available on
56 // Windows 7. Loads functions dynamically at runtime to prevent library
57 // dependencies. Use this class through the global LazyInstance
58 // |g_combase_functions|.
59 class CombaseFunctions {
60 public:
61 CombaseFunctions() = default;
62
63 ~CombaseFunctions() {
64 if (combase_dll_)
65 ::FreeLibrary(combase_dll_);
66 }
67
68 bool LoadFunctions() {
69 combase_dll_ = ::LoadLibrary(L"combase.dll");
70 if (!combase_dll_)
71 return false;
72
73 get_factory_func_ = reinterpret_cast<decltype(&::RoGetActivationFactory)>(
74 ::GetProcAddress(combase_dll_, "RoGetActivationFactory"));
75 if (!get_factory_func_)
76 return false;
77
78 create_string_func_ = reinterpret_cast<decltype(&::WindowsCreateString)>(
79 ::GetProcAddress(combase_dll_, "WindowsCreateString"));
80 if (!create_string_func_)
81 return false;
82
83 delete_string_func_ = reinterpret_cast<decltype(&::WindowsDeleteString)>(
84 ::GetProcAddress(combase_dll_, "WindowsDeleteString"));
85 if (!delete_string_func_)
86 return false;
87
88 get_string_raw_buffer_func_ =
89 reinterpret_cast<decltype(&::WindowsGetStringRawBuffer)>(
90 ::GetProcAddress(combase_dll_, "WindowsGetStringRawBuffer"));
91 if (!get_string_raw_buffer_func_)
92 return false;
93
94 return true;
95 }
96
97 HRESULT RoGetActivationFactory(HSTRING class_id,
98 const IID& iid,
99 void** out_factory) {
100 DCHECK(get_factory_func_);
101 return get_factory_func_(class_id, iid, out_factory);
102 }
103
104 HRESULT WindowsCreateString(const base::char16* src,
105 uint32_t len,
106 HSTRING* out_hstr) {
107 DCHECK(create_string_func_);
108 return create_string_func_(src, len, out_hstr);
109 }
110
111 HRESULT WindowsDeleteString(HSTRING hstr) {
112 DCHECK(delete_string_func_);
113 return delete_string_func_(hstr);
114 }
115
116 const base::char16* WindowsGetStringRawBuffer(HSTRING hstr,
117 uint32_t* out_len) {
118 DCHECK(get_string_raw_buffer_func_);
119 return get_string_raw_buffer_func_(hstr, out_len);
120 }
121
122 private:
123 HMODULE combase_dll_ = nullptr;
124
125 decltype(&::RoGetActivationFactory) get_factory_func_ = nullptr;
126 decltype(&::WindowsCreateString) create_string_func_ = nullptr;
127 decltype(&::WindowsDeleteString) delete_string_func_ = nullptr;
128 decltype(&::WindowsGetStringRawBuffer) get_string_raw_buffer_func_ = nullptr;
129 };
130
131 base::LazyInstance<CombaseFunctions> g_combase_functions =
132 LAZY_INSTANCE_INITIALIZER;
133
134 // Scoped HSTRING class to maintain lifetime of HSTRINGs allocated with
135 // WindowsCreateString().
136 class ScopedHStringTraits {
137 public:
138 static HSTRING InvalidValue() { return nullptr; }
Takashi Toyoshima 2016/09/01 05:57:04 I'm not sure, but could this be INVALID_HANDLE_VAL
Shao-Chuan Lee 2016/09/01 06:11:35 MSDN: "string [out]: A pointer to the newly create
Takashi Toyoshima 2016/09/01 07:07:25 Generally speaking, H* types of Windows use INVALI
139
140 static void Free(HSTRING hstr) {
141 g_combase_functions.Get().WindowsDeleteString(hstr);
142 }
143 };
144
145 class ScopedHString : public base::ScopedGeneric<HSTRING, ScopedHStringTraits> {
146 public:
147 explicit ScopedHString(const base::char16* str) : ScopedGeneric(nullptr) {
148 HSTRING hstr;
149 HRESULT hr = g_combase_functions.Get().WindowsCreateString(
150 str, static_cast<uint32_t>(wcslen(str)), &hstr);
151 if (FAILED(hr))
152 VLOG(1) << "WindowsCreateString failed: " << PrintHr(hr);
153 else
154 reset(hstr);
155 }
156 };
157
53 // Factory functions that activate and create WinRT components. The caller takes 158 // Factory functions that activate and create WinRT components. The caller takes
54 // ownership of the returning ComPtr. 159 // ownership of the returning ComPtr.
55 template <typename InterfaceType, base::char16 const* runtime_class_id> 160 template <typename InterfaceType, base::char16 const* runtime_class_id>
56 ScopedComPtr<InterfaceType> WrlStaticsFactory() { 161 ScopedComPtr<InterfaceType> WrlStaticsFactory() {
57 ScopedComPtr<InterfaceType> com_ptr; 162 ScopedComPtr<InterfaceType> com_ptr;
58 163
59 HRESULT hr = GetActivationFactory( 164 ScopedHString class_id_hstring(runtime_class_id);
60 WRL::Wrappers::HStringReference(runtime_class_id).Get(), 165 if (!class_id_hstring.is_valid()) {
61 com_ptr.Receive()); 166 com_ptr = nullptr;
167 return com_ptr;
168 }
169
170 HRESULT hr = g_combase_functions.Get().RoGetActivationFactory(
171 class_id_hstring.get(), __uuidof(InterfaceType), com_ptr.ReceiveVoid());
62 if (FAILED(hr)) { 172 if (FAILED(hr)) {
63 VLOG(1) << "GetActivationFactory failed: " << PrintHr(hr); 173 VLOG(1) << "RoGetActivationFactory failed: " << PrintHr(hr);
64 com_ptr = nullptr; 174 com_ptr = nullptr;
65 } 175 }
66 176
67 return com_ptr; 177 return com_ptr;
68 } 178 }
69 179
70 template <typename T, HRESULT (T::*method)(HSTRING*)> 180 template <typename T, HRESULT (T::*method)(HSTRING*)>
71 std::string GetStringFromObjectMethod(T* obj) { 181 std::string GetStringFromObjectMethod(T* obj) {
72 HSTRING result; 182 HSTRING result;
73 HRESULT hr = (obj->*method)(&result); 183 HRESULT hr = (obj->*method)(&result);
74 if (FAILED(hr)) { 184 if (FAILED(hr)) {
75 VLOG(1) << "GetStringFromObjectMethod failed: " << PrintHr(hr); 185 VLOG(1) << "GetStringFromObjectMethod failed: " << PrintHr(hr);
76 return std::string(); 186 return std::string();
77 } 187 }
78 188
79 // Note: empty HSTRINGs are represent as nullptr, and instantiating 189 // Note: empty HSTRINGs are represent as nullptr, and instantiating
80 // std::string with nullptr (in base::WideToUTF8) is undefined behavior. 190 // std::string with nullptr (in base::WideToUTF8) is undefined behavior.
81 const base::char16* buffer = WindowsGetStringRawBuffer(result, nullptr); 191 const base::char16* buffer =
192 g_combase_functions.Get().WindowsGetStringRawBuffer(result, nullptr);
82 if (buffer) 193 if (buffer)
83 return base::WideToUTF8(buffer); 194 return base::WideToUTF8(buffer);
84 return std::string(); 195 return std::string();
85 } 196 }
86 197
87 template <typename T> 198 template <typename T>
88 std::string GetIdString(T* obj) { 199 std::string GetIdString(T* obj) {
89 return GetStringFromObjectMethod<T, &T::get_Id>(obj); 200 return GetStringFromObjectMethod<T, &T::get_Id>(obj);
90 } 201 }
91 202
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
368 base::ThreadChecker thread_checker_; 479 base::ThreadChecker thread_checker_;
369 480
370 private: 481 private:
371 // DeviceWatcher callbacks: 482 // DeviceWatcher callbacks:
372 void OnAdded(std::string dev_id, std::string dev_name) { 483 void OnAdded(std::string dev_id, std::string dev_name) {
373 DCHECK(thread_checker_.CalledOnValidThread()); 484 DCHECK(thread_checker_.CalledOnValidThread());
374 CHECK(is_initialized_); 485 CHECK(is_initialized_);
375 486
376 port_names_[dev_id] = dev_name; 487 port_names_[dev_id] = dev_name;
377 488
378 WRL::Wrappers::HString dev_id_hstring; 489 ScopedHString dev_id_hstring(base::UTF8ToWide(dev_id).c_str());
379 HRESULT hr = dev_id_hstring.Set(base::UTF8ToWide(dev_id).c_str()); 490 if (!dev_id_hstring.is_valid())
380 if (FAILED(hr)) {
381 VLOG(1) << "Set failed: " << PrintHr(hr);
382 return; 491 return;
383 }
384 492
385 IAsyncOperation<RuntimeType*>* async_op; 493 IAsyncOperation<RuntimeType*>* async_op;
386 494
387 hr = midi_port_statics_->FromIdAsync(dev_id_hstring.Get(), &async_op); 495 HRESULT hr =
496 midi_port_statics_->FromIdAsync(dev_id_hstring.get(), &async_op);
388 if (FAILED(hr)) { 497 if (FAILED(hr)) {
389 VLOG(1) << "FromIdAsync failed: " << PrintHr(hr); 498 VLOG(1) << "FromIdAsync failed: " << PrintHr(hr);
390 return; 499 return;
391 } 500 }
392 501
393 base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory(); 502 base::WeakPtr<MidiPortManager> weak_ptr = GetWeakPtrFromFactory();
394 scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_; 503 scoped_refptr<base::SingleThreadTaskRunner> task_runner = task_runner_;
395 504
396 hr = async_op->put_Completed( 505 hr = async_op->put_Completed(
397 WRL::Callback<IAsyncOperationCompletedHandler<RuntimeType*>>( 506 WRL::Callback<IAsyncOperationCompletedHandler<RuntimeType*>>(
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
700 CHECK(!scheduler_); 809 CHECK(!scheduler_);
701 } 810 }
702 811
703 void MidiManagerWinrt::StartInitialization() { 812 void MidiManagerWinrt::StartInitialization() {
704 if (base::win::GetVersion() < base::win::VERSION_WIN10) { 813 if (base::win::GetVersion() < base::win::VERSION_WIN10) {
705 VLOG(1) << "WinRT MIDI backend is only supported on Windows 10 or later."; 814 VLOG(1) << "WinRT MIDI backend is only supported on Windows 10 or later.";
706 CompleteInitialization(Result::INITIALIZATION_ERROR); 815 CompleteInitialization(Result::INITIALIZATION_ERROR);
707 return; 816 return;
708 } 817 }
709 818
819 if (!g_combase_functions.Get().LoadFunctions()) {
Takashi Toyoshima 2016/09/01 05:57:04 We may want to have this check on the com thread t
Shao-Chuan Lee 2016/09/01 06:11:35 Done.
820 VLOG(1) << "Failed loading functions from combase.dll: "
821 << PrintHr(HRESULT_FROM_WIN32(GetLastError()));
822 CompleteInitialization(Result::INITIALIZATION_ERROR);
823 return;
824 }
825
710 com_thread_.init_com_with_mta(true); 826 com_thread_.init_com_with_mta(true);
711 com_thread_.Start(); 827 com_thread_.Start();
712 828
713 com_thread_.task_runner()->PostTask( 829 com_thread_.task_runner()->PostTask(
714 FROM_HERE, base::Bind(&MidiManagerWinrt::InitializeOnComThread, 830 FROM_HERE, base::Bind(&MidiManagerWinrt::InitializeOnComThread,
715 base::Unretained(this))); 831 base::Unretained(this)));
716 } 832 }
717 833
718 void MidiManagerWinrt::Finalize() { 834 void MidiManagerWinrt::Finalize() {
719 com_thread_.task_runner()->PostTask( 835 com_thread_.task_runner()->PostTask(
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
821 if (++port_manager_ready_count_ == 2) 937 if (++port_manager_ready_count_ == 2)
822 CompleteInitialization(Result::OK); 938 CompleteInitialization(Result::OK);
823 } 939 }
824 940
825 MidiManager* MidiManager::Create() { 941 MidiManager* MidiManager::Create() {
826 return new MidiManagerWinrt(); 942 return new MidiManagerWinrt();
827 } 943 }
828 944
829 } // namespace midi 945 } // namespace midi
830 } // namespace media 946 } // namespace media
OLDNEW
« no previous file with comments | « media/midi/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698