WvStreams
wvwinstreamclone.cc
1
2#define WINVER 0x0500
3#include "wvwinstreamclone.h"
4
5ATOM WvWinStreamClone::s_aClass = 0;
6WvWinStreamClone::WndVector WvWinStreamClone::s_wndpool;
7WvWinStreamClone::WndStreamMap WvWinStreamClone::s_wndmap;
8
9HWND 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
39void WvWinStreamClone::free_wnd(HWND w)
40{
41 s_wndpool.push_back(w);
42}
43
44DWORD 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
67WvWinStreamClone::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
76WvWinStreamClone::~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
82void 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
93void 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
128void 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
140void 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
154LRESULT 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}
WvStreamClone simply forwards all requests to the "cloned" stream.
virtual void setclone(IWvStream *clone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition wvstream.h:25
virtual void callback()
if the stream has a callback function defined, call it now.
Definition wvstream.cc:401
WvString is an implementation of a simple and efficient printable-string class.
Definition wvstring.h:330
void setclone(IWvStream *newclone)
WvStreamClone takes ownership of the given stream; it will WVRELEASE() the stream when you setclone()...