1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
#define CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
#include <deque>
#include "base/lock.h"
#include "ipc/ipc_channel_proxy.h"
// Base class used to allow synchronous IPC messages to be sent and
// received in an asynchronous manner. To use this class add it as a filter to
// your IPC channel using ChannelProxy::AddFilter(). From then on, before
// sending a synchronous message, call SyncMessageReplyDispatcher::Push() with
// a callback and a key. This class will then handle the message response and
// will call the callback when it is received.
//
// This class is intended to be extended by classes implementing
// HandleMessageType with delegation for the messages they expect to receive in
// cases where you care about the return values of synchronous messages.
//
// Sample usage pattern:
//
// // Add handling for desired message types.
// class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher {
// virtual bool HandleMessageType(const IPC::Message& msg,
// const MessageSent& origin) {
// switch (origin.type) {
// case AutomationMsg_CreateExternalTab::ID:
// InvokeCallback<Tuple3<HWND, HWND, int> >(msg, origin);
// break;
// [HANDLING FOR OTHER EXPECTED MESSAGE TYPES]
// }
// }
//
// // Add the filter
// IPC::SyncChannel channel_;
// channel_.AddFilter(new SyncMessageReplyDispatcherImpl());
//
// sync_->Push(msg, NewCallback(this, CallbackMethod, this);
// channel_->ChannelProxy::Send(msg);
//
class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter {
public:
SyncMessageReplyDispatcher() {}
void Push(IPC::SyncMessage* msg, void* callback, void* key);
void Cancel(void* key);
protected:
struct MessageSent {
MessageSent() {}
MessageSent(int id, uint32 type, void* callback, void* key)
: id(id), callback(callback), type(type), key(key) {}
int id;
void* callback;
void* key;
uint32 type;
};
typedef std::deque<MessageSent> PendingSyncMessageQueue;
bool Pop(const IPC::Message& msg, MessageSent* t);
virtual bool OnMessageReceived(const IPC::Message& msg);
// Child classes must implement a handler for the message types they are
// interested in handling responses for. If you don't care about the replies
// to any of the sync messages you are handling, then you don't have to
// implement this.
virtual bool HandleMessageType(const IPC::Message& msg,
const MessageSent& origin);
template <typename T>
void InvokeCallback(const IPC::Message& msg, const MessageSent& origin) {
// Ensure we delete the callback
scoped_ptr<CallbackRunner<T> > c(
reinterpret_cast<CallbackRunner<T>*>(origin.callback));
if (origin.key == NULL) { // Canceled
return;
}
T tmp; // Acts as "initializer" for output parameters.
IPC::ParamDeserializer<T> deserializer(tmp);
if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) {
c->RunWithParams(deserializer.out_);
} else {
// TODO(stoyan): How to handle errors?
}
}
PendingSyncMessageQueue message_queue_;
Lock message_queue_lock_;
};
#endif // CHROME_FRAME_SYNC_MSG_REPLY_DISPATCHER_H_
|