下のMainFrameをDirect2Dで今風(Windows8 Desktop)に作成してみました。Caption右上のボタンは手作りです。




// Win32Project2.cpp : アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"
#include "Win32Project2.h" // VSが作成したデフォルトテンプレート名
#include
#include
#include
#include

#define MAX_LOADSTRING 100

// グローバル変数:
HINSTANCE hInst; // 現在のインターフェイス
TCHAR szTitle[MAX_LOADSTRING]; // タイトル バーのテキスト
TCHAR szWindowClass[MAX_LOADSTRING]; // メイン ウィンドウ クラス名

// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

#define CAPTION_HEIGHT 30

using namespace D2D1;

#pragma comment(lib,"dwrite.lib")
#pragma comment(lib,"d2d1.lib")

#define CLIENT_SPCCX 6
#define CLIENT_SPCCY 6

HWND hChildWnd;

#define D2RGBA(r,g,b,a) ColorF((r/255.0f), (g/255.0f),(b/255.0f),(a/255.0f) )

class FRectF : public D2D1_RECT_F
{
public :
FRectF(){ left=right=bottom=top=0; }
FRectF( const RECT& rc ){ left = (float)rc.left;top=(float)rc.top;bottom=(float)rc.bottom;right=(float)rc.right;}
FRectF(float l,float t, float r, float b ){ SetRect(l,t,r,b); }

void SetRect(float l,float t, float r, float b )
{
left=l;top=t;right=r;bottom=b;
}
void Offset(float cx, float cy )
{
left += cx; right += cx;
top += cy; bottom += cy;
}
bool PtInRect( POINT pt )
{
return ( left <= pt.x && pt.x <= right && top <= pt.y && pt.y <= bottom );
}
};


struct D2DMainFrame
{
CComPtr wrfactory;
CComPtr factory;
CComPtr textformat;
CComPtr cxt;

CComPtr br[3];
CComPtr black, white;

FRectF btn[3];
UINT btnStat;
LPCWSTR title;

enum COLORS{ MOUSE_FLOAT,CLOSEBTN,ACTIVECAPTION };
};

static D2DMainFrame st;

void D2DInitial(HWND hWnd1)
{
HRESULT hr;
D2D1_FACTORY_OPTIONS options;
options.debugLevel = D2D1_DEBUG_LEVEL_NONE;
hr = D2D1CreateFactory( D2D1_FACTORY_TYPE_SINGLE_THREADED,__uuidof(ID2D1Factory),&options,(void**)&st.factory );
_ASSERT(hr==S_OK);

hr = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast(&st.wrfactory));
_ASSERT(hr==S_OK);

hr = st.wrfactory->CreateTextFormat( L"Arial",0,DWRITE_FONT_WEIGHT_NORMAL,DWRITE_FONT_STYLE_NORMAL,DWRITE_FONT_STRETCH_NORMAL,14,L"",&st.textformat);
_ASSERT(hr==S_OK);

hr = st.factory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd1, D2D1::SizeU(1,1), D2D1_PRESENT_OPTIONS_NONE), &st.cxt);
_ASSERT(hr==S_OK);

st.cxt->CreateSolidColorBrush( ColorF(ColorF::Black), &st.black );
st.cxt->CreateSolidColorBrush( ColorF(ColorF::White), &st.white );
st.cxt->CreateSolidColorBrush( D2RGBA(54,101,179,255), &st.br[D2DMainFrame::MOUSE_FLOAT] );
st.cxt->CreateSolidColorBrush( D2RGBA(199,80,80,255), &st.br[D2DMainFrame::CLOSEBTN] );
st.cxt->CreateSolidColorBrush( D2RGBA(144,169,184,255), &st.br[D2DMainFrame::ACTIVECAPTION] );

st.btn[0] = FRectF(0,0,26,20); // MINI BUTTON
st.btn[1] = FRectF(0,0,27,20); // MAX BUTTON
st.btn[2] = FRectF(0,0,45,20); // CLOSE BUTTON

st.btnStat = 0;

st.title = L"D2DMainFrame example";

}


int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

// TODO: ここにコードを挿入してください。
MSG msg;
HACCEL hAccelTable;

CoInitialize(0);
_tsetlocale ( 0, _T("japanese") );
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

// グローバル文字列を初期化しています。
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_WIN32PROJECT2, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);

// アプリケーションの初期化を実行します:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}

hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32PROJECT2));

// メイン メッセージ ループ:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

return (int) msg.wParam;
}
//
// 関数: MyRegisterClass()
//
// 目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);

wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32PROJECT2));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = NULL; // (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

return RegisterClassEx(&wcex);
}

//
// 関数: InitInstance(HINSTANCE, int)
//
// 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します。
//
// コメント:
//
// この関数で、グローバル変数でインスタンス ハンドルを保存し、
// メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;

hInst = hInstance; // グローバル変数にインスタンス処理を格納します。

hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

if (!hWnd)
{
return FALSE;
}

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

return TRUE;
}
//
// 関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: メイン ウィンドウのメッセージを処理します。
//
// WM_COMMAND - アプリケーション メニューの処理
// WM_PAINT - メイン ウィンドウの描画
// WM_DESTROY - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 選択されたメニューの解析:
switch (wmId)
{
case IDM_ABOUT:
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
st.cxt->BeginDraw();
D2D1_MATRIX_3X2_F mat = Matrix3x2F::Identity();
st.cxt->SetTransform(mat);
st.cxt->Clear(D2RGBA(110,129,141,255));// 枠線

RECT rc;
GetClientRect(hWnd,&rc);

const RECT rcClient = rc;

FRectF rcf(rc);
FRectF rcCaption(rcf);


FRectF rcwaku(rcf);
rcwaku.left++; rcwaku.right--;
rcwaku.top++; rcwaku.bottom--;

st.cxt->FillRectangle( &rcwaku, st.br[D2DMainFrame::ACTIVECAPTION] );


rcCaption = rcwaku;

rcCaption.bottom=rcCaption.top+CAPTION_HEIGHT;
st.cxt->FillRectangle( rcCaption, st.br[D2DMainFrame::ACTIVECAPTION] );

FRectF rctext(1,1,rcwaku.right,CAPTION_HEIGHT);

st.cxt->DrawText( st.title, lstrlen(st.title), st.textformat, &rctext, st.black );


mat._31 = (float)( rcClient.right - (26+27+45)); // X ZeroPoint
mat._32 = 1; // Y ZeroPoint

for( int i = 0; i < 3; i++ )
{
FRectF rc;
st.cxt->SetTransform(mat);

if ( i == 0 )
{
// Draw Minimize button.
rc.SetRect(10,12,17,14);
auto br = ( st.btnStat == 0 ? st.black : st.white );
if ( st.btnStat == 1 )
{
st.cxt->FillRectangle( st.btn[i], st.br[D2DMainFrame::MOUSE_FLOAT] );
st.cxt->FillRectangle( rc, st.white );
}
else
st.cxt->FillRectangle( rc, st.black );
}
else if ( i == 1 )
{
// Draw Maxmize button.
// when floatting
if ( st.btnStat == 2 )
{
FRectF rck = st.btn[i];
rck.left++;rck.right--;
st.cxt->FillRectangle( rck, st.br[D2DMainFrame::MOUSE_FLOAT] );
}
auto br = ( st.btnStat == 2 ? st.white : st.black );
rc.SetRect(9,6,10,14); st.cxt->FillRectangle( rc, br );
rc.SetRect(9,13,19,14); st.cxt->FillRectangle( rc, br );
rc.SetRect(18,6,19,14); st.cxt->FillRectangle( rc, br );
rc.SetRect(9,6,19,8); st.cxt->FillRectangle( rc, br );
}
else if ( i == 2 )
{
// Draw close button.
st.cxt->FillRectangle( st.btn[i], st.br[D2DMainFrame::CLOSEBTN]);
FRectF rc1,rc2;
rc1.SetRect(19,6,21,7);
rc2.SetRect(25,6,27,7);
for( int ii = 0; ii < 7; ii++ )
{
st.cxt->FillRectangle( rc1, st.white );
rc1.Offset(1,1);
st.cxt->FillRectangle( rc2, st.white );
rc2.Offset(-1,1);
}
}

mat._31 += st.btn[i].right;
}
st.cxt->EndDraw();
EndPaint(hWnd, &ps);
}
break;
case WM_SIZE :
{
UINT cx = LOWORD(lParam);
UINT cy = HIWORD(lParam);

st.cxt->Resize( D2D1::SizeU(cx,cy));

::MoveWindow(hChildWnd,CLIENT_SPCCX,CAPTION_HEIGHT,cx-CLIENT_SPCCX*2,cy-CAPTION_HEIGHT-CLIENT_SPCCY,TRUE);

return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;

case WM_CREATE:
{
D2DInitial(hWnd);

RECT rc;
GetClientRect(hWnd,&rc);

// 簡単なchild windowを作成
hChildWnd = CreateWindow( L"EDIT", L"SAMPLE",WS_CHILD|WS_VISIBLE|ES_MULTILINE,CLIENT_SPCCX,CAPTION_HEIGHT,rc.right-CLIENT_SPCCX*2,rc.bottom-CAPTION_HEIGHT,hWnd,NULL,hInst,0);

return DefWindowProc(hWnd, message, wParam, lParam);
}
break;

case WM_NCCALCSIZE:
if ( wParam == FALSE )
{
RECT* rc = (RECT*)lParam;
return 0;
}
else
{
NCCALCSIZE_PARAMS* pm = (NCCALCSIZE_PARAMS*)lParam;

WINDOWPLACEMENT info;
info.length = sizeof(info);
GetWindowPlacement(hWnd, &info);

if ( info.showCmd == SW_SHOWMAXIMIZED )
{
RECT r1;
SystemParametersInfo(SPI_GETWORKAREA,0,&r1,0);
pm->rgrc[0] = r1;


pm->lppos->x=pm->rgrc[0].left;
pm->lppos->y=pm->rgrc[0].top;
pm->lppos->cx=pm->rgrc[0].right;
pm->lppos->cy=pm->rgrc[0].bottom;

return WVR_ALIGNTOP|WVR_ALIGNLEFT|WVR_ALIGNBOTTOM|WVR_ALIGNRIGHT;
}
}
return 0;
break;
case WM_NCHITTEST:
{
RECT rc;
GetClientRect(hWnd,&rc);

POINT pt;
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);

ScreenToClient( hWnd, &pt );

POINT ptbtn = pt;

ptbtn.x -= (rc.right - (26+27+45));
ptbtn.y -= 1;
FRectF rcbtn(0,0,(26+27+45),20);
UINT prv = st.btnStat;

UINT nstat = 0;
if ( rcbtn.PtInRect( ptbtn ) )
{
if ( ptbtn.x < 26 )
nstat =1;
else if ( ptbtn.x < (26+27) )
nstat =2;
else
nstat =3;
}

if ( nstat != prv )
{
st.btnStat = nstat;
InvalidateRect(hWnd,NULL,FALSE); // redraw
}

int w = 5;
int width = rc.right;
int height = rc.bottom;
if ( !rcbtn.PtInRect( ptbtn ) )
{
if ( pt.y < w )
{
if ( pt.x < w )
return HTTOPLEFT;
else if ( width - pt.x < w)
return HTTOPRIGHT;
else
return HTTOP;
}
else if ( height-pt.y < w )
{
if ( pt.x < w )
return HTBOTTOMLEFT;
else if ( width - pt.x < w)
return HTBOTTOMRIGHT;
else
return HTBOTTOM;
}
else if ( pt.y < CAPTION_HEIGHT )
return HTCAPTION;
else if ( pt.x < w )
return HTLEFT;
else if ( width - pt.x < w )
return HTRIGHT;
}
return HTCLIENT;
}
break;
case WM_LBUTTONUP:
{
// OnCLicked

if ( st.btnStat == 1 )
ShowWindow( hWnd, SW_MINIMIZE );
else if ( st.btnStat == 2 )
ShowWindow( hWnd, SW_MAXIMIZE );
else if ( st.btnStat == 3 )
DestroyWindow(hWnd);
}
break;
case WM_WINDOWPOSCHANGED:
{
InvalidateRect(hWnd,NULL,FALSE); // redraw
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_ERASEBKGND:
return 1;
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}