WvStreams
wvwinstreamclone.cc
1 
2 #define WINVER 0x0500
3 #include "wvwinstreamclone.h"
4 
5 ATOM WvWinStreamClone::s_aClass = 0;
6 WvWinStreamClone::WndVector WvWinStreamClone::s_wndpool;
7 WvWinStreamClone::WndStreamMap WvWinStreamClone::s_wndmap;
8 
9 HWND WvWinStreamClone::alloc_wnd()
10 {
11  if (s_wndpool.empty())
12  {
13  HWND hWnd = CreateWindow(
14  "WvWinStreamClone",
15  "WvWinStreamWindowName",
16  WS_POPUP | WS_DISABLED,
17  CW_USEDEFAULT, // initial x position
18  CW_USEDEFAULT, // initial y position
19  CW_USEDEFAULT, // initial x extent
20  CW_USEDEFAULT, // initial y extent
21  HWND_MESSAGE,
22  NULL,
23  NULL,
24  NULL
25  );
26  assert(hWnd);
27  s_wndpool.push_back(hWnd);
28  }
29 
30  HWND hWnd = s_wndpool.back();
31  s_wndpool.pop_back();
32 
33  // associate window with this instance
34  s_wndmap[hWnd] = this;
35 
36  return hWnd;
37 }
38 
39 void WvWinStreamClone::free_wnd(HWND w)
40 {
41  s_wndpool.push_back(w);
42 }
43 
44 DWORD WvWinStreamClone::Initialize()
45 {
46  WNDCLASS wc;
47  wc.style = CS_HREDRAW | CS_VREDRAW;
48  wc.lpfnWndProc = WvWinStreamClone::WndProc;
49  wc.cbClsExtra = 0;
50  wc.cbWndExtra = 0;
51  wc.hInstance = GetModuleHandle(NULL);
52  wc.hIcon = NULL;
53  wc.hCursor = NULL;
54  wc.hbrBackground = NULL;
55  wc.lpszMenuName = NULL;
56  wc.lpszClassName = "WvWinStreamClone";
57 
58  s_aClass = RegisterClass(&wc);
59  if (!s_aClass)
60  {
61  DWORD error = GetLastError();
62  return error;
63  }
64  return 0;
65 }
66 
67 WvWinStreamClone::WvWinStreamClone(WvStream * _cloned) :
68  WvStreamClone(_cloned), m_pending_callback(false), m_select_in_progress(false),
69  m_msec_timeout(500)
70 {
71  memset(&m_si, 0, sizeof(m_si));
72  m_hWnd = alloc_wnd();
73  pre_poll();
74 }
75 
76 WvWinStreamClone::~WvWinStreamClone()
77 {
78  free_wnd(m_hWnd);
79 }
80 
81 // for each socket in "set", add the "event" to the its associated mask in sockmap
82 void WvWinStreamClone::select_set(SocketEventsMap &sockmap, fd_set *set, long event )
83 {
84  for (unsigned i=0; i<set->fd_count; i++)
85  {
86  SOCKET &socket = set->fd_array[i];
87  sockmap[socket] |= event;
88  }
89 
90  FD_ZERO(set);
91 }
92 
93 void WvWinStreamClone::pre_poll()
94 {
95  this->_build_selectinfo(m_si, m_msec_timeout,
96  false, false, false, true);
97 
98  // We must only call WSAAsyncSelect once per socket, so we need
99  // to collect all the events from each set first, grouping them by
100  // socket rather than by event
101  SocketEventsMap sockmap;
102  this->select_set(sockmap, &m_si.read, FD_READ);
103  this->select_set(sockmap, &m_si.write, FD_WRITE);
104  this->select_set(sockmap, &m_si.except, FD_OOB);
105 
106  // Call WSAAsyncSelect, asking the OS to send us a message when the socket
107  // becomes readable | writable | exceptional
108  for (SocketEventsMap::iterator i = sockmap.begin(); i!=sockmap.end(); ++i)
109  {
110  SOCKET socket = (*i).first;
111  long events = (*i).second;
112 
113  int result = ::WSAAsyncSelect(socket, m_hWnd, WM_SELECT,
114  events | FD_CONNECT | FD_CLOSE | FD_ACCEPT);
115  assert(result == 0);
116  }
117 
118  // alarm
119  ::KillTimer(m_hWnd, TIMER_ID);
120  if (m_si.msec_timeout >= 0)
121  {
122  ::SetTimer(m_hWnd, TIMER_ID, m_si.msec_timeout, NULL);
123  }
124 
125  m_select_in_progress = true;
126 }
127 
128 void WvWinStreamClone::post_poll()
129 {
130  bool sure = this->_process_selectinfo(m_si, true);
131 
132  if (sure || m_pending_callback)
133  {
134  m_pending_callback = false;
135  callback();
136  if (globalstream) globalstream->callback();
137  }
138 }
139 
140 void WvWinStreamClone::select_callback(SOCKET socket, int events, int error)
141 {
142  if (events | FD_READ) FD_SET(socket, &m_si.read);
143  if (events | FD_WRITE) FD_SET(socket, &m_si.write);
144  if (events | FD_OOB) FD_SET(socket, &m_si.except);
145  m_pending_callback = true;
146 
147  if (m_select_in_progress)
148  {
149  ::PostMessage(m_hWnd, WM_DONESELECT, 0, 0);
150  m_select_in_progress = false;
151  }
152 }
153 
154 LRESULT CALLBACK WvWinStreamClone::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
155 {
156  switch (uMsg)
157  {
158  case WM_DONESELECT:
159  {
160  WvWinStreamClone *_this = s_wndmap[hwnd];
161  assert(_this);
162  _this->post_poll();
163  _this->pre_poll();
164 
165  break;
166  }
167 
168  case WM_SELECT:
169  {
170  WvWinStreamClone *_this = s_wndmap[hwnd];
171  assert(_this);
172  SOCKET socket = wParam;
173  int events = WSAGETSELECTEVENT(lParam);
174  int error = WSAGETSELECTERROR(lParam);
175  _this->select_callback( socket, events, error );
176 
177  break;
178  }
179 
180  case WM_TIMER:
181  {
182  ::PostMessage(hwnd, WM_DONESELECT, 0, 0);
183 
184  break;
185  }
186 
187  default:
188  return DefWindowProc(hwnd, uMsg, wParam, lParam);
189  }
190  return 0;
191 }
192 
193 
194 
196 {
197  WvStreamClone::setclone(newclone);
198 
199  if (newclone != NULL)
200  my_type = WvString("WvWinStreamClone:%s", newclone->wstype());
201  else
202  my_type = "WvWinStreamClone:(none)";
203 }
WvWinStreamClone
Definition: wvwinstreamclone.h:13
IWvStream
Definition: iwvstream.h:24
WvStream::callback
virtual void callback()
if the stream has a callback function defined, call it now.
Definition: wvstream.cc:401
WvString
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:329
WvStreamClone
WvStreamClone simply forwards all requests to the "cloned" stream.
Definition: wvstreamclone.h:23
WvStreamClone::setclone
virtual void setclone(IWvStream *clone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...
Definition: wvstreamclone.cc:181
WvStream
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition: wvstream.h:24
WvWinStreamClone::setclone
void setclone(IWvStream *newclone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...
Definition: wvwinstreamclone.cc:195