DirectWriteをいじる(2)

公開:2010-10-31 21:12
更新:2020-02-15 04:36
カテゴリ:directwrite

今日は小幅ないじりで終了。
コードを1本のヘッダ・CPPファイルにまとめたところで終了。

ヘッダ:includes.h


#pragma once
#ifndef UNICODE
#define UNICODE
#endif
// STL
#define WIN32_LEAN_AND_MEAN     // Exclude rarely-used stuff from Windows headers
//
// Modify the following defines if you have to target a platform prior to the ones specified below.
// Refer to MSDN for the latest info on corresponding values for different platforms.
#ifndef WINVER              // Allow use of features specific to Windows 7 or later.
#define WINVER 0x0700       // Change this to the appropriate value to target other versions of Windows.
#endif
#ifndef _WIN32_WINNT        // Allow use of features specific to Windows 7 or later.
#define _WIN32_WINNT 0x0700 // Change this to the appropriate value to target other versions of Windows.
#endif
#define DIRECTINPUT_VERSION 0x0800
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <exception>
#include <memory>
#include <string>
#include <map>
#include <locale>
#include <fstream>
#include <algorithm>
#include <functional>
// Boost
#include <boost/scoped_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/array.hpp>
#include <boost/thread.hpp>
#include <boost/optional.hpp>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/variant.hpp>
#include <boost/any.hpp>
#include <boost/signals2.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/ptr_container/ptr_container.hpp>
#include <boost/thread/condition.hpp>
#include <boost/ptr_container/ptr_array.hpp>
#include <boost/ptr_container/serialize_ptr_container.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/assign.hpp>
#include <boost/assign/ptr_list_of.hpp>
#include <boost/assign/ptr_list_inserter.hpp>
#include <boost/foreach.hpp>
#include <wincodec.h>
#include <windows.h>
#include <windowsx.h>
#include <wincodec.h>
#include <wincodecsdk.h>
#include "objbase.h"
#include <comdef.h>
#include "avrt.h"
#include "mmsystem.h"
#include <d2d1.h>
#include <d2d1helper.h>
#include <dwrite.h>
// 実行時アセンブラ
#include "xbyak.h"
// COM Smart Pointers
_COM_SMARTPTR_TYPEDEF(ID2D1Factory,__uuidof(ID2D1Factory));
_COM_SMARTPTR_TYPEDEF(IWICImagingFactory, __uuidof(IWICImagingFactory));
_COM_SMARTPTR_TYPEDEF(IDWriteFactory , __uuidof(IDWriteFactory));
_COM_SMARTPTR_TYPEDEF(IDWriteGdiInterop , __uuidof(IDWriteGdiInterop));
_COM_SMARTPTR_TYPEDEF(IDWriteFontFace , __uuidof(IDWriteFontFace));
_COM_SMARTPTR_TYPEDEF(IDWriteFont , __uuidof(IDWriteFont));
_COM_SMARTPTR_TYPEDEF(IDWriteFontFamily , __uuidof(IDWriteFontFamily));
_COM_SMARTPTR_TYPEDEF(IDWriteFontCollection , __uuidof(IDWriteFontCollection));
_COM_SMARTPTR_TYPEDEF(IDWriteLocalizedStrings , __uuidof(IDWriteLocalizedStrings));
_COM_SMARTPTR_TYPEDEF(ID2D1HwndRenderTarget , __uuidof(ID2D1HwndRenderTarget));
_COM_SMARTPTR_TYPEDEF(ID2D1GdiInteropRenderTarget , __uuidof(ID2D1GdiInteropRenderTarget));
_COM_SMARTPTR_TYPEDEF(IDWriteTextFormat, __uuidof(IDWriteTextFormat));
_COM_SMARTPTR_TYPEDEF(IDWriteTextLayout, __uuidof(IDWriteTextLayout));
_COM_SMARTPTR_TYPEDEF(ID2D1PathGeometry , __uuidof(ID2D1PathGeometry));
_COM_SMARTPTR_TYPEDEF(ID2D1LinearGradientBrush , __uuidof(ID2D1LinearGradientBrush));
_COM_SMARTPTR_TYPEDEF(ID2D1SolidColorBrush , __uuidof(ID2D1SolidColorBrush));
_COM_SMARTPTR_TYPEDEF(ID2D1BitmapBrush , __uuidof(ID2D1BitmapBrush));
_COM_SMARTPTR_TYPEDEF(ID2D1Bitmap , __uuidof(ID2D1Bitmap));
_COM_SMARTPTR_TYPEDEF(IWICBitmapDecoder,__uuidof(IWICBitmapDecoder));
_COM_SMARTPTR_TYPEDEF(IWICBitmapFrameDecode,__uuidof(IWICBitmapFrameDecode));
_COM_SMARTPTR_TYPEDEF(IWICStream,__uuidof(IWICStream));
_COM_SMARTPTR_TYPEDEF(IWICFormatConverter,__uuidof(IWICFormatConverter));
_COM_SMARTPTR_TYPEDEF(IWICBitmapScaler,__uuidof(IWICBitmapScaler));
namespace sf
{
///Exception
class exception : public std::exception
{
public:
explicit exception(const std::wstring& reason)
{
m_reason = reason;
};
const wchar_t * what() {return m_reason.c_str();};
const std::wstring& what_str() { return m_reason;};
protected:
std::wstring m_reason;
};
class win32_error_exception : std::exception
{
public:
win32_error_exception(boost::uint32_t hr);
win32_error_exception();
virtual ~win32_error_exception() {};
boost::uint32_t hresult() {return hresult_;}
std::wstring& error() {return error_;}
private:
boost::uint32_t hresult_;
std::wstring error_;
};
enum com_init
{
multi_threaded  = 0x0,
apartment_threaded = 0x2,
disable_ole1dde   = 0x4,
speed_over_memory = 0x8
};
struct com_initialize
{
struct impl;
com_initialize(void * reserved = NULL,unsigned int init = multi_threaded);
~com_initialize() {};
private:
boost::shared_ptr<impl> m_impl;
};
template <typename ComClass,typename ComInterface>
boost::intrusive_ptr<ComInterface> create_instance()
{
ComInterface * com_ptr;
CoCreateInstance( __uuidof(ComClass), NULL,
CLSCTX_ALL, __uuidof(ComInterface),
(void**)&com_ptr);
return boost::intrusive_ptr<ComInterface>(com_ptr,false);
};
template <typename COMInterface>
struct IUnknownImpl : public COMInterface
{
IUnknownImpl() : ref_(1) {};
virtual ~IUnknownImpl() {};
ULONG __stdcall AddRef()
{
return InterlockedIncrement(&ref_);
}
ULONG __stdcall Release()
{
ULONG ref = InterlockedDecrement(&ref_);
if (0 == ref)
{
delete this;
}
return ref;
}
HRESULT __stdcall QueryInterface(REFIID riid, VOID **ppObj)
{
if (IID_IUnknown == riid)
{
AddRef();
*ppObj = (IUnknown*)this;
}
else if (__uuidof(COMInterface) == riid)
{
AddRef();
*ppObj = (COMInterface*)this;
}
else
{
*ppObj = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
private:
LONG ref_;
};
struct run_message_loop
{
run_message_loop(){};
inline void operator()()
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
~run_message_loop(void){};
};
struct peek_message_loop
{
typedef boost::function<void ()> func_type;
explicit peek_message_loop(func_type func)  {func_ =  func;};
inline void operator()()
{
MSG msg = {0};
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
func_();  // Do some rendering
}
}
};
private:
func_type func_;
};
// policy class
struct heap_memory_free_policy
{
template< typename T >
void operator()( const T* AMemory ) const
{
if( NULL != AMemory )
::HeapFree( ::GetProcessHeap(), 0, AMemory );
}
};
// policy class
struct local_memory_free_policy
{
template< typename T >
void operator()( const T* AMemory ) const
{
if( NULL != AMemory )
::LocalFree( AMemory );
}
};
// policy class
struct co_task_memory_free_policy
{
template< typename T >
void operator()( const T* AMemory ) const
{
if( NULL != AMemory )
::CoTaskMemFree( AMemory );
}
};
// base guard class
template< typename T,class TFreePolicy >
class base_memory
{
private:
T *FMemory;
public:
base_memory( T* AMemory = NULL )
: FMemory( AMemory ) {}
virtual ~base_memory( void )
{ reset(); }
T* release( void )
{
T *tmp = FMemory;
FMemory = NULL;
return tmp;
}
void reset( T* AMemory = NULL )
{
if( AMemory != FMemory )
{
if( NULL != FMemory )
TFreePolicy( FMemory );
FMemory = AMemory;
}
}
T* get( void )
{ return FMemory; }
T** operator&( void )
{ return &FMemory; }
};
template< typename T >
class heap_memory : public base_memory< T,
heap_memory_free_policy >
{
public:
heap_memory( T* AMemory = NULL )
: base_memory< T, heap_memory_free_policy >( AMemory )
{ }
};
template< typename T >
class local_memory : public base_memory< T,
local_memory_free_policy >
{
public:
local_memory( T* AMemory = NULL )
: base_memory< T, local_memory_free_policy >( AMemory )
{ }
};
template< typename T >
class co_task_memory : public base_memory< T,
co_task_memory_free_policy >
{
public:
co_task_memory( T* AMemory = NULL )
: base_memory< T, co_task_memory_free_policy >( AMemory )
{ }
};
ID2D1BitmapPtr load_bitmap_from_file(
ID2D1HwndRenderTargetPtr render_target,
IWICImagingFactoryPtr wic_factory,
std::wstring uri,
boost::uint32_t destination_width = 0,
boost::uint32_t destination_height = 0
);
/** WNDCLASSEXラッパクラス */
struct window_class_ex
{
window_class_ex(
const wchar_t*  menu_name ,
const std::wstring&  class_name ,
HINSTANCE   hInstance = NULL,
WNDPROC     lpfnWndProc = ::DefWindowProcW,
boost::uint32_t        style = CS_HREDRAW | CS_VREDRAW,
boost::int32_t     cbClsExtra  = 0,
HICON       hIcon = ::LoadIcon(NULL,IDI_APPLICATION),
HCURSOR     hCursor = ::LoadCursor(NULL, IDC_ARROW),
HBRUSH      hbrBackground = NULL,
HICON       hIconSm = NULL
) : is_register_(false)
{
if(::GetClassInfoExW(hInstance,class_name.c_str(),&wndclass_) == 0)
{
if(::GetLastError() == ERROR_CLASS_DOES_NOT_EXIST)
{
::ZeroMemory(&wndclass_,sizeof(wndclass_));
wndclass_.lpszMenuName = menu_name;
wndclass_.lpszClassName = class_name.c_str();
wndclass_.cbSize = sizeof(::WNDCLASSEXW);
wndclass_.cbWndExtra = sizeof(LONG_PTR);
wndclass_.hInstance = hInstance;
wndclass_.lpfnWndProc = lpfnWndProc;
wndclass_.style = style;
wndclass_.cbClsExtra = cbClsExtra;
wndclass_.hIcon = hIcon;
wndclass_.hCursor = hCursor;
wndclass_.hbrBackground = hbrBackground;
wndclass_.hIconSm = hIconSm;
atom_ = ::RegisterClassExW(&wndclass_) ;
BOOST_ASSERT(atom_ != 0);
is_register_ = true;
} else {
throw win32_error_exception();
}
} else {
is_register_ = false;
}
};
~window_class_ex()
{
if(is_register_){
::UnregisterClassW(wndclass_.lpszClassName,wndclass_.hInstance);
}
}
private:
bool is_register_;
ATOM atom_;
::WNDCLASSEXW wndclass_;
};
//------------------------------------------------
// リソースの解放忘れを防ぐ小さなクラスたち
//------------------------------------------------
struct get_dc {
get_dc(HWND hwnd) : hwnd_(hwnd),hdc_(GetDC(hwnd)) {}
HDC get(){return hdc_;}
~get_dc(){::ReleaseDC(hwnd_,hdc_);}
private:
HDC hdc_;
HWND hwnd_;
};
struct compatible_dc {
compatible_dc(HDC hdc) : hdc_(::CreateCompatibleDC(hdc)){};
~compatible_dc(){::DeleteDC(hdc_);};
HDC get() { return hdc_;};
private:
HDC hdc_;
};
struct ref_dc {
ref_dc(HDC& hdc) : hdc_(hdc) {};
~ref_dc(){};
HDC get() { return hdc_;};
private:
HDC& hdc_;
};
template <typename Holder>
struct device_context
{
explicit device_context(Holder* holder) : holder_(holder){};
~device_context() {}
operator HDC(){return holder_->get();}
private:
boost::scoped_ptr<Holder> holder_;
};
struct paint_struct
{
paint_struct(HWND hwnd) : hwnd_(hwnd)
{
::BeginPaint(hwnd,&paintstruct_);
}
~paint_struct() {::EndPaint(hwnd_,&paintstruct_);}
PAINTSTRUCT* operator->(){return &paintstruct_;}
private:
HWND hwnd_;
PAINTSTRUCT paintstruct_;
};
template <typename T>
struct begin_draw
{
begin_draw(T& render_target) : render_target_(render_target) ,is_end_(false) {render_target->BeginDraw();}
HRESULT end_draw()
{
HRESULT hr = S_OK;
if(!is_end_) {
hr = render_target->EndDraw();
is_end_ = true;
}
return hr;
};
~begin_draw(){ if(!is_end_) { render_target_->EndDraw();}}
private:
T& render_target_;
bool is_end_;
};
// ID2D1GdiInteropRenderTargetPtrのGetDC,ReleaseDCラッパ
struct d2d_get_dc {
d2d_get_dc(ID2D1GdiInteropRenderTargetPtr& target,
D2D1_DC_INITIALIZE_MODE mode = D2D1_DC_INITIALIZE_MODE_COPY)
: target_(target)
{
target->GetDC(mode,&dc_);
};
~d2d_get_dc(){target_->ReleaseDC(NULL);}
operator HDC () {return dc_;}
private:
D2D1_DC_INITIALIZE_MODE mode;
ID2D1GdiInteropRenderTargetPtr& target_;
HDC dc_;
};
// GDI SelectObject関数 ラッパ
struct select_object
{
select_object(HDC dc,HGDIOBJ obj)
: dc_(dc),obj_(obj)
{
original_ = ::SelectObject(dc,obj);
}
~select_object()
{
::SelectObject(dc_,original_);
}
private:
HDC dc_;
HGDIOBJ obj_,original_;
};
// GDI HGDIOBJホルダ
struct hgdiobj_holder {
hgdiobj_holder(HGDIOBJ obj) : obj_(obj) {};
~hgdiobj_holder(){::DeleteObject(obj_);};
operator HGDIOBJ () {return obj_;}
private:
HGDIOBJ obj_;
};
struct mouse
{
mouse() : x_(0.0f),y_(0.0f),left_button_(false),middle_button_(false),right_button_(false){}
private:
float x_,y_;
bool left_button_,middle_button_,right_button_;
};
/** window ベースクラス */
struct base_window
{
typedef boost::signals2::signal<LRESULT (HWND,boost::uint32_t,WPARAM, LPARAM) > on_message_type;
on_message_type on_message;
typedef boost::signals2::signal<void ()> on_render_type;
on_render_type on_render;
operator HWND();
protected:
base_window(const std::wstring& title,const std::wstring& name,bool fit_to_display,float width,float height);
~base_window();
void register_class (
wchar_t* menu_name,
boost::uint32_t      style  ,
boost::int32_t     cbClsExtra  = 0,
HICON       hIcon = ::LoadIcon(NULL,IDI_APPLICATION),
HCURSOR     hCursor = ::LoadCursor(NULL, IDC_ARROW),
HBRUSH      hbrBackground = NULL,
HICON       hIconSm = NULL
);
/** デフォルト設定 */
void register_class();
void create_window();
void update();
void show(boost::uint32_t show_flag);
void discard_device();
void create_device();
virtual void create_device_independent_resources();
//ID2D1FactoryPtr factory();
//ID2D1HwndRenderTargetPtr render_target();
//IDWriteFactoryPtr write_factory();
virtual LRESULT window_proc(HWND hwnd,boost::uint32_t message, WPARAM wParam, LPARAM lParam);
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
base_window* ptr = reinterpret_cast<base_window*>(hwnd);
hwnd = ptr->hwnd_;
return ptr->window_proc(hwnd,message,wParam,lParam);
};
struct hwnd_this_thunk : public Xbyak::CodeGenerator {
hwnd_this_thunk(base_window* impl,WNDPROC proc)
{
push(eax);
mov(eax,ptr[esp + 8]);
mov(ptr[&(impl->hwnd_)],eax);
mov(eax,(DWORD)impl);
mov(ptr[esp + 8],eax);
pop(eax);
jmp(proc);
}
};
HWND hwnd_;
ID2D1FactoryPtr factory_;
ID2D1HwndRenderTargetPtr render_target_;
ID2D1GdiInteropRenderTargetPtr gdi_render_target_;
IDWriteFactoryPtr write_factory_;
IWICImagingFactoryPtr wic_imaging_factory_;
ID2D1BitmapPtr bitmap_;
hwnd_this_thunk thunk_;
std::wstring title_;
std::wstring name_;
float width_,height_;
bool fit_to_display_;
boost::shared_ptr<sf::window_class_ex> wnd_class_;
WNDPROC thunk_proc_;
private:
};
struct toplevel_window;
typedef boost::shared_ptr<toplevel_window> toplevel_window_ptr;
/** toplevel_window を生成する関数 */
toplevel_window_ptr create_toplevel_window (
const std::wstring& title,
const std::wstring& name,
const boost::uint32_t show_flag = SW_SHOWNORMAL,
bool fit_to_display = false,
float width = 640,
float height = 480
);
/** toplevel ウィンドウクラス */
/* このクラスは、create_toplevel_window 関数からのみ生成可能 */
struct toplevel_window : public base_window
{
friend   toplevel_window_ptr create_toplevel_window
(
const std::wstring& title,
const std::wstring& name,
const boost::uint32_t show_flag,
bool fit_to_display ,
float width ,
float height
);
void main_loop();
protected:
void render();
toplevel_window(const std::wstring& title,const std::wstring& name,bool fit_to_display,
float width = 640,float height = 480) : base_window(title,name,fit_to_display,width,height)
{
on_render.connect(boost::bind(&toplevel_window::render,this));
};
LRESULT toplevel_window::window_proc(HWND hwnd,boost::uint32_t message, WPARAM wParam, LPARAM lParam);
virtual void create_device_independent_resources();
private:
};
struct av_mm_thread_characteristics
{
av_mm_thread_characteristics(std::wstring& str) : task_name_(str)
{
handle_ = ::AvSetMmThreadCharacteristicsW(str.c_str(),(LPDWORD)&task_index_);
}
bool set_priority(AVRT_PRIORITY p){return (::AvSetMmThreadPriority(handle_,p) == TRUE);}
~av_mm_thread_characteristics()
{
::AvRevertMmThreadCharacteristics(handle_);
}
private:
std::wstring task_name_;
boost::uint32_t task_index_;
HANDLE handle_;
};
struct widget
{
void draw();
float x_,y_;
};
}

.CPPファイル


#include "includes.h"
#define BOOST_ASSIGN_MAX_PARAMS 7
#define EXCEPTION_IF_ERROR(hres) \
if (FAILED(hres)) { throw sf::win32_error_exception(hres); }
#ifndef HINST_THISCOMPONENT
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
#endif
#define SAFE_RELEASE(x) if(x) x.Release();
namespace sf
{
std::map<HRESULT,std::wstring> com_error_  = boost::assign::list_of<std::pair<HRESULT,std::wstring> >
(E_POINTER,L"E_POINTER")
(E_INVALIDARG,L"E_INVALIDARG")
(DWRITE_E_FILEFORMAT,L"DWRITE_E_FILEFORMAT")
(DWRITE_E_UNEXPECTED,L"DWRITE_E_UNEXPECTED")
(DWRITE_E_NOFONT,L"DWRITE_E_NOFONT")
(DWRITE_E_FILENOTFOUND,L"DWRITE_E_FILENOTFOUND")
(DWRITE_E_FILEACCESS,L"DWRITE_E_FILEACCESS")
(DWRITE_E_FONTCOLLECTIONOBSOLETE,L"DWRITE_E_FONTCOLLECTIONOBSOLETE")
(DWRITE_E_ALREADYREGISTERED,L"DWRITE_E_ALREADYREGISTERED")
/*        (AUDCLNT_E_NOT_INITIALIZED,L"AUDCLNT_E_NOT_INITIALIZED")
(AUDCLNT_E_ALREADY_INITIALIZED,L"AUDCLNT_E_ALREADY_INITIALIZED")
(AUDCLNT_E_WRONG_ENDPOINT_TYPE,L"AUDCLNT_E_WRONG_ENDPOINT_TYPE")
(AUDCLNT_E_DEVICE_INVALIDATED,L"AUDCLNT_E_DEVICE_INVALIDATED")
(AUDCLNT_E_NOT_STOPPED,L"AUDCLNT_E_NOT_STOPPED")
(AUDCLNT_E_BUFFER_TOO_LARGE,L"AUDCLNT_E_BUFFER_TOO_LARGE")
(AUDCLNT_E_OUT_OF_ORDER,L"AUDCLNT_E_OUT_OF_ORDER")
(AUDCLNT_E_UNSUPPORTED_FORMAT,L"AUDCLNT_E_UNSUPPORTED_FORMAT")
(AUDCLNT_E_INVALID_SIZE,L"AUDCLNT_E_INVALID_SIZE")
(AUDCLNT_E_DEVICE_IN_USE,L"AUDCLNT_E_DEVICE_IN_USE")
(AUDCLNT_E_BUFFER_OPERATION_PENDING,L"AUDCLNT_E_BUFFER_OPERATION_PENDING")
(AUDCLNT_E_THREAD_NOT_REGISTERED,L"AUDCLNT_E_THREAD_NOT_REGISTERED")
(AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED,L"AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED")
(AUDCLNT_E_ENDPOINT_CREATE_FAILED,L"AUDCLNT_E_ENDPOINT_CREATE_FAILED")
(AUDCLNT_E_SERVICE_NOT_RUNNING,L"AUDCLNT_E_SERVICE_NOT_RUNNING")
(AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED,L"AUDCLNT_E_EVENTHANDLE_NOT_EXPECTED")
(AUDCLNT_E_EXCLUSIVE_MODE_ONLY,L"AUDCLNT_E_EXCLUSIVE_MODE_ONLY")
(AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL,L"AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL")
(AUDCLNT_E_EVENTHANDLE_NOT_SET,L"AUDCLNT_E_EVENTHANDLE_NOT_SET")
(AUDCLNT_E_INCORRECT_BUFFER_SIZE,L"AUDCLNT_E_INCORRECT_BUFFER_SIZE")
(AUDCLNT_E_BUFFER_SIZE_ERROR,L"AUDCLNT_E_BUFFER_SIZE_ERROR")
(AUDCLNT_S_BUFFER_EMPTY,L"AUDCLNT_S_BUFFER_EMPTY")
(AUDCLNT_S_THREAD_ALREADY_REGISTERED,L"AUDCLNT_S_THREAD_ALREADY_REGISTERED")*/;
win32_error_exception::win32_error_exception(boost::uint32_t hr)
: std::exception("HRESULT ERROR"),hresult_(hr)
{
local_memory<wchar_t> mem;
DWORD result = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,0,hr,0,(LPWSTR)&mem,0,0);
if(result != 0){
error_ = mem.get();
} else {
std::map<HRESULT,std::wstring>::iterator it = com_error_.find(hr);
if(it != com_error_.end())
{
error_ = it->second;
} else {
error_ = (boost::wformat(L"0x%x 不明なCOMエラー") % hr).str();
}
}
};
win32_error_exception::win32_error_exception()
{
hresult_ = ::GetLastError();
local_memory<wchar_t> mem;
DWORD rv =  FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,0,hresult_,0,(LPWSTR)&mem,0,0);
error_ = mem.get();
//Logger::outputDebugPrintf(L"Win32 Error %x %s",hresult_,mem.Get() );
};
struct com_initialize::impl
{
impl(void * reserved,unsigned int init) : hr(::CoInitializeEx(reserved,init))
{
}
~impl()
{
if(hr == S_OK){
::CoUninitialize();
}
}
private:
HRESULT hr;
};
com_initialize::com_initialize(void * reserved,unsigned int  init)
: m_impl(new com_initialize::impl(reserved,init))
{
};
LRESULT base_window::window_proc(HWND hwnd,boost::uint32_t message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
switch (message)
{
case WM_CREATE:
{
// TODO:
create_device();
break;
}
case WM_SIZE:
{
if (render_target_)
{
D2D1_SIZE_U size;
size.width = lParam & 0xFFFF;
size.height = (lParam >> 16) & 0xFFFF; ;
render_target_->Resize(size);
}
}
case WM_PAINT:
{
paint_struct begin_paint(hwnd);
return FALSE;
}
case WM_DISPLAYCHANGE:
{
::InvalidateRect(hwnd, NULL, FALSE);
}
case WM_ERASEBKGND:
{
return FALSE;
}
case WM_MOUSEMOVE:
{
//                    on_mouse_move(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),wParam);
}
case WM_LBUTTONDOWN:
{
}
}
return ::DefWindowProcW(hwnd,message,wParam,lParam);
};
void base_window::create_device_independent_resources()
{
//wic_imaging_factory_.CreateInstance(CLSID_WICImagingFactory);
thunk_proc_ = (WNDPROC)thunk_.getCode();
};
void base_window::register_class (
wchar_t* menu_name,
boost::uint32_t        style ,
boost::int32_t     cbClsExtra,
HICON       hIcon ,
HCURSOR     hCursor,
HBRUSH      hbrBackground ,
HICON       hIconSm
)
{
wnd_class_.reset(new sf::window_class_ex(menu_name,name_,HINST_THISCOMPONENT,thunk_proc_,style,cbClsExtra,hIcon,hCursor,hbrBackground,hIconSm));
}
/** デフォルト設定 */
void base_window::register_class()
{
wnd_class_.reset(new sf::window_class_ex(NULL,name_,HINST_THISCOMPONENT,thunk_proc_));
}
void base_window::create_window()
{
// Create the application window.
//
// Because the CreateWindow function takes its size in pixels, we
// obtain the system DPI and use it to scale the window size.
FLOAT dpiX, dpiY;
//factory_->GetDesktopDpi(&dpiX, &dpiY);
// Windowを作成する
CreateWindow(
name_.c_str(),
title_.c_str(),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<boost::uint32_t>(ceil(width_ /** dpiX / 96.f*/)),
static_cast<boost::uint32_t>(ceil(height_ /** dpiY / 96.f*/)),
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
}
void base_window::create_device()
{
//        input_.reset(new input(HINST_THISCOMPONENT,hwnd_));
HRESULT hr = S_OK;
// Direct2DFactory の生成
EXCEPTION_IF_ERROR(D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &factory_));
EXCEPTION_IF_ERROR(::DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&write_factory_)
));
//ウィンドウの現在の幅、高さを求める
RECT rc;
GetClientRect( hwnd_, &rc );
boost::uint32_t width = rc.right - rc.left;
boost::uint32_t height = rc.bottom - rc.top;
{
wic_imaging_factory_.CreateInstance(CLSID_WICImagingFactory);
//            bitmap_ = load_bitmap_from_file(render_target_,wic_imaging_factory_,L"myship.png");
}
if(!render_target_)
{
RECT rc;
GetClientRect(hwnd_, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top
);
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties();
props.usage =  D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
EXCEPTION_IF_ERROR(factory_->CreateHwndRenderTarget(
props,
D2D1::HwndRenderTargetProperties(hwnd_, size),
&render_target_
));
render_target_->QueryInterface<ID2D1GdiInteropRenderTarget>(&gdi_render_target_);
}
}
void base_window::discard_device ()
{
/*        if(render_target_)
{
render_target_.Release();
}*/
}
void base_window::show(boost::uint32_t show_flag) {::ShowWindow(hwnd_,show_flag);}
void base_window::update() {::UpdateWindow(hwnd_);}
base_window::~base_window()
{
}
base_window::base_window(const std::wstring& menu_name,const std::wstring& name,bool fit_to_display,float width,float height)
: title_(menu_name),name_(name),fit_to_display_(fit_to_display),
width_(width),height_(height),thunk_(this,base_window::WndProc),hwnd_(0)
{
create_device_independent_resources();
}
base_window::operator HWND()
{
return hwnd_;
};
//ID2D1FactoryPtr base_window::factory() { return impl_->factory();};
//ID2D1HwndRenderTargetPtr base_window::render_target() { return impl_->render_target();};
//IDWriteFactoryPtr base_window::write_factory() {return impl_->write_factory();};
toplevel_window_ptr create_toplevel_window
(
const std::wstring& title,
const std::wstring& name,
const boost::uint32_t show_flag,
bool fit_to_display,
float width,
float height
)
{
toplevel_window* p = new toplevel_window(title,name,fit_to_display,width,height);
p->register_class();
p->create_window();
p->show(show_flag);
p->update();
return toplevel_window_ptr(p);
}
LRESULT toplevel_window::window_proc(HWND hwnd,boost::uint32_t message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
// TODO:
create_device();
break;
}
case WM_SIZE:
{
if (render_target_)
{
D2D1_SIZE_U size;
size.width = lParam & 0xFFFF;
size.height = (lParam >> 16) & 0xFFFF; ;
render_target_->Resize(size);
}
}
case WM_PAINT:
{
paint_struct begin_paint(hwnd);
render();
return FALSE;
}
case WM_DISPLAYCHANGE:
{
::InvalidateRect(hwnd, NULL, FALSE);
}
case WM_ERASEBKGND:
{
return FALSE;
}
case WM_MOUSEMOVE:
{
//                    on_mouse_move(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam),wParam);
}
case WM_LBUTTONDOWN:
{
}
}
if(message == WM_CLOSE)
{
BOOL ret(::DestroyWindow(hwnd));
BOOST_ASSERT(ret != 0);
}
if(message == WM_DESTROY)
{
::PostQuitMessage(0);
return 0;
}
return ::DefWindowProcW(hwnd,message,wParam,lParam);
}
void toplevel_window::create_device_independent_resources()
{
base_window::create_device_independent_resources();
//
}
void toplevel_window::main_loop()
{
render();
}
void toplevel_window::render()
{
static float t = 0.0f;
if (render_target_)
{
// Retrieve the size of the render target.
D2D1_SIZE_F renderTargetSize = render_target_->GetSize();
try {
sf::begin_draw<ID2D1HwndRenderTargetPtr> begin(render_target_);
render_target_->Clear(D2D1::ColorF(D2D1::ColorF::White));
render_target_->SetTransform(D2D1::Matrix3x2F::Identity());
//render_target_->Clear(D2D1::ColorF(D2D1::ColorF::White));
ID2D1SolidColorBrushPtr brush;
render_target_->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &brush);
ID2D1SolidColorBrushPtr brushr;
render_target_->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Red), &brushr);
D2D1_RECT_F layoutRect = D2D1::RectF(50.f, 50.f, 600.f, 200.f);
IDWriteTextFormatPtr write_text_format;
// Text Formatの作成
//EXCEPTION_IF_ERROR(write_factory_->CreateTextFormat(
//    L"メイリオ",                // Font family name.
//    NULL,                       // Font collection (NULL sets it to use the system font collection).
//    DWRITE_FONT_WEIGHT_REGULAR,
//    DWRITE_FONT_STYLE_NORMAL,
//    DWRITE_FONT_STRETCH_NORMAL,
//    48.0f,
//    L"ja-jp",
//    &write_text_format
//));
//// Actually draw the text at the origin.
//std::wstring t(L"こんにちは、世界!By S.F.");
//render_target_->DrawTextW(
//    t.c_str(),
//    t.size(),
//    write_text_format,
//    layoutRect,
//    brush);
{
LOGFONTW lf;
//std::wstring fname(L"メイリオ");
::ZeroMemory((void *)&lf, sizeof(LOGFONTW));
lf.lfHeight = 32;
lf.lfWidth = 0;
lf.lfWeight = 0;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfCharSet = SHIFTJIS_CHARSET;
lf.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
//std::copy(fname.begin(),fname.end(),lf.lfFaceName);
hgdiobj_holder font(::CreateFontIndirectW(&lf));
// GDC描画
HDC dc;
{
std::wstring tgdi(L"GDI こんにちは、世界!By S.F.");
d2d_get_dc dc(gdi_render_target_,D2D1_DC_INITIALIZE_MODE_COPY);
select_object s(dc,font);
::SetBkMode(dc,TRANSPARENT);
::TextOutW(dc,0,300,tgdi.data(),tgdi.size());
}// font をもとに戻す。
// Direct2Dの論理フォントを描画してみる。
{
//      std::wstring td2d(L"GDI こんにちは、世界!By S.F.");
//IDWriteGdiInteropPtr g;
//IDWriteFontPtr f;
//IDWriteFontFamilyPtr family;
//IDWriteLocalizedStringsPtr family_names;
//      HRESULT hr = E_FAIL;
//EXCEPTION_IF_ERROR(write_factory_->GetGdiInterop(&g));
//      std::wstring font_
//      ::GetTextFaceW(GetDC(hwnd_),
//      GetObject(font, sizeof(LOGFONT), &lf);
//hr = g->CreateFontFromLOGFONT(&lf,&f);
//      if(hr == DWRITE_E_NOFONT)
//      {
//
//
//      }
//      if(f){
//  EXCEPTION_IF_ERROR(f->GetFontFamily(&family));
//  EXCEPTION_IF_ERROR(family->GetFamilyNames(&family_names));
//        boost::uint32_t len(0);
//        EXCEPTION_IF_ERROR(family_names->GetStringLength(0,&len));
//        boost::scoped_array<wchar_t> name(new wchar_t[len + 1]);
//        EXCEPTION_IF_ERROR(family_names->GetString(0,name.get(),len + 1));
//        float font_size =  (float) - MulDiv(lf.lfHeight, 96, GetDeviceCaps(dc, LOGPIXELSY));
//        IDWriteTextFormatPtr format;
//        EXCEPTION_IF_ERROR(
//          write_factory_->CreateTextFormat(
//            name.get(),                // Font family name.
//            NULL,
//            f->GetWeight(),
//            f->GetStyle(),
//            f->GetStretch(),
//            font_size,
//            L"ja-jp",
//            &format));
//    render_target_->DrawTextW(
//     td2d.c_str(),
//     td2d.size(),
//     format,
//     layoutRect,
//     brush);
//      }
}
}
}  catch(...) {
throw;
}
}
};
//
// Creates a Direct2D bitmap from the specified
// file name.
//
ID2D1BitmapPtr load_bitmap_from_file(
ID2D1HwndRenderTargetPtr render_target,
IWICImagingFactoryPtr wic_factory,
std::wstring uri,
boost::uint32_t destination_width,
boost::uint32_t destination_height
)
{
HRESULT hr = S_OK;
IWICBitmapDecoderPtr decoder;
IWICBitmapFrameDecodePtr decoder_source;
IWICStreamPtr stream;
IWICFormatConverterPtr converter;
IWICBitmapScalerPtr scaler;
ID2D1BitmapPtr bitmap;
EXCEPTION_IF_ERROR(wic_factory->CreateDecoderFromFilename(
uri.c_str(),
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&decoder
));
// Create the initial frame.
EXCEPTION_IF_ERROR(decoder->GetFrame(0, &decoder_source));
// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
EXCEPTION_IF_ERROR(hr = wic_factory->CreateFormatConverter(&converter));
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destination_width != 0 || destination_height != 0)
{
boost::uint32_t originalWidth, originalHeight;
EXCEPTION_IF_ERROR(decoder_source->GetSize((UINT*)&originalWidth, (UINT*)&originalHeight));
if (destination_width == 0)
{
FLOAT scalar = static_cast<FLOAT>(destination_height) / static_cast<FLOAT>(originalHeight);
destination_width = static_cast<boost::uint32_t>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destination_height == 0)
{
FLOAT scalar = static_cast<FLOAT>(destination_width) / static_cast<FLOAT>(originalWidth);
destination_height = static_cast<boost::uint32_t>(scalar * static_cast<FLOAT>(originalHeight));
}
EXCEPTION_IF_ERROR(wic_factory->CreateBitmapScaler(&scaler));
EXCEPTION_IF_ERROR(scaler->Initialize(
decoder_source,
destination_width,
destination_height,
WICBitmapInterpolationModeCubic
));
EXCEPTION_IF_ERROR(converter->Initialize(
scaler.GetInterfacePtr(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
));
}
else // Don't scale the image.
{
EXCEPTION_IF_ERROR(converter->Initialize(
decoder_source.GetInterfacePtr(),
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
));
}
// Create a Direct2D bitmap from the WIC bitmap.
EXCEPTION_IF_ERROR(render_target->CreateBitmapFromWicBitmap(
converter.GetInterfacePtr(),
NULL,
&bitmap
));
return bitmap;
}
}
//
// アプリケーションのエントリポイント
//
int WINAPI WinMain(
HINSTANCE /* hInstance */,
HINSTANCE /* hPrevInstance */,
LPSTR /* lpCmdLine */,
int /* nCmdShow */
)
{
// ヒープメモリに関するエラーを検出した場合、Windows Error Reporting Serviceを呼び出し、
// プロセスを終了するようにHeapマネージャに伝える。
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
try {
//COMの初期化
// コンストラクタでCoIntializeExを呼び出し、デストラクタでCoUninitializeを呼び出す。
sf::com_initialize init;
//Windowの作成
sf::toplevel_window_ptr window(sf::create_toplevel_window(std::wstring(L"Test"),std::wstring(L"Test")));
//メッセージループ
//sf::peek_message_loop(boost::bind(&sf::toplevel_window::main_loop,window.get()))();
sf::run_message_loop()();
} catch (sf::exception& e)
{
::MessageBoxW(NULL,e.what(),L"Error",MB_OK | MB_ICONEXCLAMATION);
}
return 0;
}