1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Implementation for the asynchronous interface to the Windows shell
6 // SHOpenWithDialog function. The call is made on a dedicated UI thread in a
7 // single-threaded apartment.
9 #include "win8/test/open_with_dialog_async.h"
13 #include "base/bind.h"
14 #include "base/callback.h"
15 #include "base/location.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/threading/platform_thread.h"
20 #include "base/threading/thread.h"
21 #include "base/win/windows_version.h"
27 struct OpenWithContext
{
29 HWND parent_window_in
,
30 const base::string16
& file_name_in
,
31 const base::string16
& file_type_class_in
,
32 int open_as_info_flags_in
,
33 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_runner_in
,
34 const OpenWithDialogCallback
& callback_in
);
39 base::string16 file_name
;
40 base::string16 file_type_class
;
41 int open_as_info_flags
;
42 scoped_refptr
<base::SingleThreadTaskRunner
> client_runner
;
43 OpenWithDialogCallback callback
;
46 OpenWithContext::OpenWithContext(
47 HWND parent_window_in
,
48 const base::string16
& file_name_in
,
49 const base::string16
& file_type_class_in
,
50 int open_as_info_flags_in
,
51 const scoped_refptr
<base::SingleThreadTaskRunner
>& client_runner_in
,
52 const OpenWithDialogCallback
& callback_in
)
53 : thread("OpenWithDialog"),
54 parent_window(parent_window_in
),
55 file_name(file_name_in
),
56 file_type_class(file_type_class_in
),
57 open_as_info_flags(open_as_info_flags_in
),
58 client_runner(client_runner_in
),
59 callback(callback_in
) {
60 thread
.init_com_with_mta(false);
64 OpenWithContext::~OpenWithContext() {}
66 // Runs the caller-provided |callback| with the result of the call to
67 // SHOpenWithDialog on the caller's initial thread.
68 void OnOpenWithDialogDone(OpenWithContext
* context
, HRESULT result
) {
69 DCHECK(context
->client_runner
->BelongsToCurrentThread());
70 OpenWithDialogCallback
callback(context
->callback
);
72 // Join with the thread.
75 // Run the client's callback.
79 // Calls SHOpenWithDialog (blocking), and returns the result back to the client
81 void OpenWithDialogTask(OpenWithContext
* context
) {
82 DCHECK_EQ(context
->thread
.thread_id(), base::PlatformThread::CurrentId());
83 OPENASINFO open_as_info
= {
84 context
->file_name
.c_str(),
85 context
->file_type_class
.c_str(),
86 context
->open_as_info_flags
89 HRESULT result
= ::SHOpenWithDialog(context
->parent_window
, &open_as_info
);
91 // Bounce back to the calling thread to release resources and deliver the
93 if (!context
->client_runner
->PostTask(
95 base::Bind(&OnOpenWithDialogDone
, context
, result
))) {
96 // The calling thread has gone away. There's nothing to be done but leak.
97 // In practice this is only likely to happen at shutdown, so there isn't
98 // much of a concern that it'll happen in the real world.
99 DLOG(ERROR
) << "leaking OpenWith thread; result = " << std::hex
<< result
;
105 void OpenWithDialogAsync(
107 const base::string16
& file_name
,
108 const base::string16
& file_type_class
,
109 int open_as_info_flags
,
110 const OpenWithDialogCallback
& callback
) {
111 DCHECK_GE(base::win::GetVersion(), base::win::VERSION_VISTA
);
112 OpenWithContext
* context
=
113 new OpenWithContext(parent_window
, file_name
, file_type_class
,
115 base::ThreadTaskRunnerHandle::Get(), callback
);
116 context
->thread
.message_loop()->PostTask(
118 base::Bind(&OpenWithDialogTask
, context
));