2004-05-16 editboxstream C++ 何かと便利なエディットボックスストリーム。 // // editbox_stream.hpp // #ifndef KN_EDITBOX_STRAEM_HPP__ #define KN_EDITBOX_STRAEM_HPP__ #include #include #include #include namespace kn { struct editbox_wrapper { static std::map wndproctbl_; HWND handle_; WNDPROC prev_wndproc_; bool is_modified_; // コールバック static LRESULT editbox_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); // ctor & dtor editbox_wrapper(HWND handle) : handle_(handle) , prev_wndproc_(NULL) , is_modified_(true) { } ~editbox_wrapper() { stop_hook(); } // 更新チェック bool is_modified() { return is_modified_; } // フック開始 void start_hook(); // フック停止 void stop_hook(); // リロード template DWORD reload_text(Container& buf) { DWORD len = (DWORD)::SendMessage(handle_, WM_GETTEXTLENGTH, (WPARAM)0, (LPARAM)0); buf.resize(len); len = (DWORD)::SendMessage(handle_, WM_GETTEXT, (WPARAM)len, (LPARAM)&buf[0]); is_modified_ = false; return len; } }; // // class basic_editbox_streambuf // // stream buffer for the EditBox stream // template< typename charT, typename Traits = std::char_traits > class basic_editbox_streambuf : public std::basic_streambuf , public editbox_wrapper { private: typedef basic_editbox_streambuf this_type; public: typedef Traits traits_type; typedef typename std::basic_streambuf::char_type char_type; typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::off_type off_type; typedef typename std::basic_streambuf::pos_type pos_type; typedef int_type streamsize; private: std::vector pbuf_; std::vector gbuf_; public: // sync // バッファのフラッシュ用らしい virtual int sync() { overflow(traits_type::eof()); return 0; } // overflow // オーバーフローの発生時に呼ばれる(つまり書き込みバッファが埋まったとき) virtual int_type overflow(int_type c) { char_type* p = pbase(); *(p + (pptr() - pbase())) = traits_type::to_char_type(0); ::SendMessage(handle_, EM_SETSEL, (WPARAM)-1, (LPARAM)-1); ::SendMessage(handle_, EM_REPLACESEL, (WPARAM)TRUE, (LPARAM)p); pbump(pbase() - pptr()); if (c != traits_type::eof()) { *pbase() = c; pbump(1); } return traits_type::not_eof(c); } // underflow // アンダーフロー発生時に呼ばれる(つまり読み込みバッファが空になったとき) virtual int_type underflow() { // 更新チェック if (is_modified()) { // テキストを読み込み直す DWORD len = reload_text(gbuf_); // バッファの再登録 setg(&gbuf_[0], &gbuf_[0] + (gptr() - eback()), &gbuf_[0] + len); if (gptr() < egptr()) { int_type c = *gptr(); return traits_type::not_eof(c); } else { return traits_type::eof(); } } else { if (gptr() < egptr()) { int_type c = *gptr(); gbump(1); return traits_type::not_eof(c); } else { return traits_type::eof(); } } } // xsputn virtual streamsize xsputn(const char_type* s, streamsize n) { streamsize total_put_size = 0; do { streamsize bufmax = epptr() - pptr(); streamsize putsize = (bufmax < n) ? bufmax : n; char_type* p = pptr(); memcpy(p, s, putsize); total_put_size += putsize; pbump(putsize); n -= putsize; } while (n > 0 && overflow(*s++) != traits_type::eof()); return total_put_size; } public: basic_editbox_streambuf(HWND handle = NULL) : editbox_wrapper(handle) { pbuf_.resize(1024); gbuf_.resize(1); setp(&pbuf_[0], &*pbuf_.end()); setg(&gbuf_[0], &gbuf_[0], &gbuf_[0]); } ~basic_editbox_streambuf() { sync(); stop_hook(); } void attach(HWND handle) { stop_hook(); handle_ = handle; setp(&pbuf_[0], &*pbuf_.end()); setg(&gbuf_[0], &gbuf_[0], &gbuf_[0]); } HWND get_handle() const { return handle_; } }; typedef basic_editbox_streambuf editbox_streambuf; typedef basic_editbox_streambuf weditbox_streambuf; template struct editbox_stream_implement_helper : public BaseT { protected: typedef editbox_stream_implement_helper helper_type; private: basic_editbox_streambuf sb; protected: basic_editbox_streambuf* rdbuf() { return &sb; } public: explicit editbox_stream_implement_helper(HWND handle) : BaseT(&sb) , sb(handle) { } void attach(HWND handle) { rdbuf()->attach(handle); } }; template< typename charT, typename Traits = std::char_traits > class basic_ieditbox_stream : public editbox_stream_implement_helper< charT, Traits, std::basic_istream > { public: explicit basic_ieditbox_stream(HWND handle = NULL) : helper_type(handle) { } }; template< typename charT, typename Traits = std::char_traits > class basic_oeditbox_stream : public editbox_stream_implement_helper< charT, Traits, std::basic_ostream > { public: explicit basic_oeditbox_stream(HWND handle = NULL) : helper_type(handle) { } }; template< typename charT, typename Traits = std::char_traits > class basic_editbox_stream : public editbox_stream_implement_helper< charT, Traits, std::basic_iostream > { public: explicit basic_editbox_stream(HWND handle = NULL) : helper_type(handle) { } }; typedef basic_ieditbox_stream ieditbox_stream; typedef basic_ieditbox_stream wieditbox_stream; typedef basic_oeditbox_stream oeditbox_stream; typedef basic_oeditbox_stream woeditbox_stream; typedef basic_editbox_stream editbox_stream; typedef basic_editbox_stream weditbox_stream; } // end of namespace kn #ifdef KN_EDITBOX_STRAEM_IMPLEMENT #include "./editbox_stream.cpp" #endif #endif /* KN_EDITBOX_STRAEM_HPP__ */ // // editbox_stream.cpp // #undef KN_EDITBOX_STRAEM_IMPLEMENT #include "./editbox_stream.hpp" namespace kn { std::map editbox_wrapper::wndproctbl_; // コールバック LRESULT editbox_wrapper::editbox_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { std::map::const_iterator itr = wndproctbl_.find*1 { editbox_wrapper* self = itr->second; switch (msg) { case WM_COMMAND: switch (HIWORD(wparam)) { case EN_CHANGE: self->is_modified_ = true; break; } break; } return CallWindowProc(self->prev_wndproc_, hwnd, msg, wparam, lparam); } // must not pass through here ASSERT(0); return 0; } // フック開始 void editbox_wrapper::start_hook() { if (prev_wndproc_ == NULL) { wndproctbl_[handle_] = this; prev_wndproc_ = (WNDPROC)SetWindowLong(handle_, GWL_WNDPROC, (LONG)&editbox_wndproc); } } // フック停止 void editbox_wrapper::stop_hook() { if (prev_wndproc_ != NULL) { SetWindowLong(handle_, GWL_WNDPROC, (LONG)prev_wndproc_); wndproctbl_.erase(handle_); prev_wndproc_ = NULL; } } } // end of namespace kn *1:HWND)hwnd); if (itr != wndproctbl_.end(