wvwinstreamclone.cc

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

Generated on Thu Jan 24 16:50:57 2008 for WvStreams by  doxygen 1.5.4