WvStreams
|
00001 00002 #define WINVER 0x0500 00003 #include "wvwinstreamclone.h" 00004 00005 ATOM WvWinStreamClone::s_aClass = 0; 00006 WvWinStreamClone::WndVector WvWinStreamClone::s_wndpool; 00007 WvWinStreamClone::WndStreamMap WvWinStreamClone::s_wndmap; 00008 00009 HWND WvWinStreamClone::alloc_wnd() 00010 { 00011 if (s_wndpool.empty()) 00012 { 00013 HWND hWnd = CreateWindow( 00014 "WvWinStreamClone", 00015 "WvWinStreamWindowName", 00016 WS_POPUP | WS_DISABLED, 00017 CW_USEDEFAULT, // initial x position 00018 CW_USEDEFAULT, // initial y position 00019 CW_USEDEFAULT, // initial x extent 00020 CW_USEDEFAULT, // initial y extent 00021 HWND_MESSAGE, 00022 NULL, 00023 NULL, 00024 NULL 00025 ); 00026 assert(hWnd); 00027 s_wndpool.push_back(hWnd); 00028 } 00029 00030 HWND hWnd = s_wndpool.back(); 00031 s_wndpool.pop_back(); 00032 00033 // associate window with this instance 00034 s_wndmap[hWnd] = this; 00035 00036 return hWnd; 00037 } 00038 00039 void WvWinStreamClone::free_wnd(HWND w) 00040 { 00041 s_wndpool.push_back(w); 00042 } 00043 00044 DWORD WvWinStreamClone::Initialize() 00045 { 00046 WNDCLASS wc; 00047 wc.style = CS_HREDRAW | CS_VREDRAW; 00048 wc.lpfnWndProc = WvWinStreamClone::WndProc; 00049 wc.cbClsExtra = 0; 00050 wc.cbWndExtra = 0; 00051 wc.hInstance = GetModuleHandle(NULL); 00052 wc.hIcon = NULL; 00053 wc.hCursor = NULL; 00054 wc.hbrBackground = NULL; 00055 wc.lpszMenuName = NULL; 00056 wc.lpszClassName = "WvWinStreamClone"; 00057 00058 s_aClass = RegisterClass(&wc); 00059 if (!s_aClass) 00060 { 00061 DWORD error = GetLastError(); 00062 return error; 00063 } 00064 return 0; 00065 } 00066 00067 WvWinStreamClone::WvWinStreamClone(WvStream * _cloned) : 00068 WvStreamClone(_cloned), m_pending_callback(false), m_select_in_progress(false), 00069 m_msec_timeout(500) 00070 { 00071 memset(&m_si, 0, sizeof(m_si)); 00072 m_hWnd = alloc_wnd(); 00073 pre_poll(); 00074 } 00075 00076 WvWinStreamClone::~WvWinStreamClone() 00077 { 00078 free_wnd(m_hWnd); 00079 } 00080 00081 // for each socket in "set", add the "event" to the its associated mask in sockmap 00082 void WvWinStreamClone::select_set(SocketEventsMap &sockmap, fd_set *set, long event ) 00083 { 00084 for (unsigned i=0; i<set->fd_count; i++) 00085 { 00086 SOCKET &socket = set->fd_array[i]; 00087 sockmap[socket] |= event; 00088 } 00089 00090 FD_ZERO(set); 00091 } 00092 00093 void WvWinStreamClone::pre_poll() 00094 { 00095 this->_build_selectinfo(m_si, m_msec_timeout, 00096 false, false, false, true); 00097 00098 // We must only call WSAAsyncSelect once per socket, so we need 00099 // to collect all the events from each set first, grouping them by 00100 // socket rather than by event 00101 SocketEventsMap sockmap; 00102 this->select_set(sockmap, &m_si.read, FD_READ); 00103 this->select_set(sockmap, &m_si.write, FD_WRITE); 00104 this->select_set(sockmap, &m_si.except, FD_OOB); 00105 00106 // Call WSAAsyncSelect, asking the OS to send us a message when the socket 00107 // becomes readable | writable | exceptional 00108 for (SocketEventsMap::iterator i = sockmap.begin(); i!=sockmap.end(); ++i) 00109 { 00110 SOCKET socket = (*i).first; 00111 long events = (*i).second; 00112 00113 int result = ::WSAAsyncSelect(socket, m_hWnd, WM_SELECT, 00114 events | FD_CONNECT | FD_CLOSE | FD_ACCEPT); 00115 assert(result == 0); 00116 } 00117 00118 // alarm 00119 ::KillTimer(m_hWnd, TIMER_ID); 00120 if (m_si.msec_timeout >= 0) 00121 { 00122 ::SetTimer(m_hWnd, TIMER_ID, m_si.msec_timeout, NULL); 00123 } 00124 00125 m_select_in_progress = true; 00126 } 00127 00128 void WvWinStreamClone::post_poll() 00129 { 00130 bool sure = this->_process_selectinfo(m_si, true); 00131 00132 if (sure || m_pending_callback) 00133 { 00134 m_pending_callback = false; 00135 callback(); 00136 if (globalstream) globalstream->callback(); 00137 } 00138 } 00139 00140 void WvWinStreamClone::select_callback(SOCKET socket, int events, int error) 00141 { 00142 if (events | FD_READ) FD_SET(socket, &m_si.read); 00143 if (events | FD_WRITE) FD_SET(socket, &m_si.write); 00144 if (events | FD_OOB) FD_SET(socket, &m_si.except); 00145 m_pending_callback = true; 00146 00147 if (m_select_in_progress) 00148 { 00149 ::PostMessage(m_hWnd, WM_DONESELECT, 0, 0); 00150 m_select_in_progress = false; 00151 } 00152 } 00153 00154 LRESULT CALLBACK WvWinStreamClone::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 00155 { 00156 switch (uMsg) 00157 { 00158 case WM_DONESELECT: 00159 { 00160 WvWinStreamClone *_this = s_wndmap[hwnd]; 00161 assert(_this); 00162 _this->post_poll(); 00163 _this->pre_poll(); 00164 00165 break; 00166 } 00167 00168 case WM_SELECT: 00169 { 00170 WvWinStreamClone *_this = s_wndmap[hwnd]; 00171 assert(_this); 00172 SOCKET socket = wParam; 00173 int events = WSAGETSELECTEVENT(lParam); 00174 int error = WSAGETSELECTERROR(lParam); 00175 _this->select_callback( socket, events, error ); 00176 00177 break; 00178 } 00179 00180 case WM_TIMER: 00181 { 00182 ::PostMessage(hwnd, WM_DONESELECT, 0, 0); 00183 00184 break; 00185 } 00186 00187 default: 00188 return DefWindowProc(hwnd, uMsg, wParam, lParam); 00189 } 00190 return 0; 00191 } 00192 00193 00194 00195 void WvWinStreamClone::setclone(IWvStream *newclone) 00196 { 00197 WvStreamClone::setclone(newclone); 00198 00199 if (newclone != NULL) 00200 my_type = WvString("WvWinStreamClone:%s", newclone->wstype()); 00201 else 00202 my_type = "WvWinStreamClone:(none)"; 00203 }