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