如何以動畫顯示分層子視窗的點陣圖
注意
針對Windows 10上的應用程式,我們建議使用 Windows.UI.Composition API,而不是 DirectComposition。 如需詳細資訊,請參閱 使用視覺層將傳統型應用程式現代化。
本主題描述如何建立及建立視覺效果的動畫,該視覺效果會使用分層子視窗的點陣圖做為視覺效果的內容。 本主題所述的範例會使用動畫縮放轉換,將子視窗的點陣圖從指紋大小「成長」到完整大小。 如需分層視窗的詳細資訊,請參閱 視窗點陣圖。
您所需了解的事情
技術
必要條件
- C/C++
- Microsoft Win32
- 元件物件模型 (COM)
指示
步驟 1:建立分層子視窗
使用下列步驟來建立分層子視窗。
- 註冊子視窗類別,並建立具有 WS_EX_LAYERED 樣式的子視窗。 在下列範例中,
m_dpiX
並以m_dpiY
每個邏輯英吋的圖元指定螢幕解析度,而且m_hwndMain
是主應用程式視窗的控制碼。
HWND m_hwndLayeredChild;
HRESULT hr = S_OK;
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(wcex);
wcex.style = 0;
wcex.lpfnWndProc = DemoApp::ChildWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"DCompLayeredChildWindow";
wcex.hIconSm = NULL;
if (!RegisterClassExW(&wcex))
{
return FALSE;
}
m_hwndLayeredChild = CreateWindowEx(WS_EX_LAYERED,
L"DCompLayeredChildWindow",
NULL,
WS_CHILD | WS_CLIPSIBLINGS,
0,
0,
static_cast<UINT>(ceil(640.0f * m_dpiX / 96.0f)),
static_cast<UINT>(ceil(480.0f * m_dpiY / 96.0f)),
m_hwndMain,
NULL,
HINST_THISCOMPONENT,
this);
- 呼叫 SetLayeredWindowAttributes 函式,以設定分層子視窗的透明度色彩索引鍵和不透明度。 下列程式碼會將透明度色彩索引鍵設定為零,並將不透明度設定為 255 (不透明) 。
if (!SetLayeredWindowAttributes(m_hwndLayeredChild, 0, 255, LWA_ALPHA))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
- 將某些內容轉譯至子視窗。
步驟 2:初始化 DirectComposition 物件
建立裝置物件和組合目標物件。 如需詳細資訊,請參閱 如何初始化 DirectComposition。
步驟 3:建立視覺物件,並將分層子視窗的點陣圖設定為 content 屬性
使用下列步驟來建立視覺效果、設定其內容屬性以使用分層子視窗的點陣圖,然後將視覺效果新增至視覺化樹狀結構。
- 呼叫 IDCompositionDevice::CreateVisual 以建立視覺物件。
- 將子視窗的控制碼傳遞至 CreateSurfaceFromHwnd 函式,為分層子視窗建立 Microsoft DirectComposition 介面。
- 呼叫視覺物件的 IDCompositionVisual::SetContent 方法,將新表面設定為分層子視窗的視覺內容。
- 將視覺化物件新增至視覺化樹狀結構。 若要將視覺效果新增至樹狀結構的根目錄,請呼叫 IDCompositionTarget::SetRoot 方法。 若要將視覺效果新增為另一個視覺效果的子系,請使用父視覺效果的 IDCompositionVisual::AddVisual 方法。
下列範例會建立視覺化物件、設定其 Content 屬性以使用分層子視窗的點陣圖,並將視覺效果新增至視覺化樹狀結構的根目錄。
IDCompositionVisual *pVisual = nullptr;
IUnknown* pSurface = nullptr;
hr = m_pDevice->CreateVisual(&pVisual);
if (SUCCEEDED(hr))
{
hr = m_pDevice->CreateSurfaceFromHwnd(m_hwndLayeredChild, &pSurface);
}
if (SUCCEEDED(hr))
{
hr = pVisual->SetContent(pSurface);
}
if (SUCCEEDED(hr))
{
hr = m_pCompTarget->SetRoot(pVisual);
}
步驟 4:建立動畫物件和縮放轉換物件
使用 IDCompositionDevice::CreateAnimation 方法來建立動畫物件,並使用 IDCompositionDevice::CreateScaleTransform 方法來建立縮放轉換物件。
IDCompositionAnimation *pAnimateScale = NULL;
IDCompositionScaleTransform *pScale = NULL;
if (SUCCEEDED(hr))
{
hr = m_pDevice->CreateAnimation(&pAnimateScale);
}
if (SUCCEEDED(hr))
{
// Create the scale transform object.
hr = m_pDevice->CreateScaleTransform(&pScale);
}
步驟 5:建置動畫函式
使用動畫物件的 IDCompositionAnimation 介面方法來建置動畫函式。
下列範例會建置一個簡單的動畫函式,其中包含一個立方多項式區段和一個結束線段。
pAnimateScale->AddCubic(
0.0f, // offset from beginning of animation function, in seconds
0.0f, // constant coefficient
1.0f, // linear coefficient
0.0f, // quadratic coefficient
0.0f); // cubic coefficient
pAnimateScale->End(1.0f, 1.0f);
步驟 6:將動畫物件套用至縮放轉換物件的屬性
使用 IDCompositionScale::SetScaleX 和 SetScaleY 方法,將動畫物件套用至縮放轉換物件的 ScaleX 和 ScaleY 屬性。
// Find the center of the child window.
RECT rcChild = { };
GetClientRect(m_hwndLayeredChild, &rcChild);
float centerX = rcChild.right / 2.0f;
float centerY = rcChild.bottom / 2.0f;
// Scale from the center point of the child window's bitmap.
pScale->SetCenterX(centerX);
pScale->SetCenterY(centerY);
// Use the same animation object to animate the X and Y scale
// factors.
pScale->SetScaleX(pAnimateScale);
pScale->SetScaleY(pAnimateScale);
步驟 7:將縮放轉換物件套用至視覺效果的轉換屬性
使用 IDCompositionVisual::SetTransform 方法,將縮放轉換物件套用至視覺效果的 Transform 屬性。
hr = pVisual->SetTransform(pScale);
步驟 8:遮蔽分層子視窗
認可動畫之前,請使用 DwmSetWindowAttribute 函式搭配 DWMWA_CLOAK 旗標來「遮蔽」分層子視窗。 Cloaking 會從檢視中移除分層子視窗,而視窗的點陣圖檢視的動畫版本會轉譯至畫面。
BOOL fCloak = TRUE;
DwmSetWindowAttribute(pDemoApp->m_hwndLayeredChild,
DWMWA_CLOAK,
&fCloak,
sizeof(fCloak));
步驟 9:認可組合
使用 IDCompositionDevice::Commit 方法,將命令批次認可至 Microsoft DirectComposition 進行處理。 動畫會出現在目標視窗中。
步驟 10:取消遮蔽分層子視窗
動畫完成之後,請使用 DwmSetWindowAttribute 函式搭配 DWMWA_CLOAK 旗標來取消遮蔽分層子視窗。
步驟 11:釋放 DirectComposition 物件
當您不再需要 DirectComposition 物件時,請務必釋放所有 DirectComposition 物件。 下列範例會呼叫應用程式定義的 SafeRelease 宏,以釋放 DirectComposition 物件。
SafeRelease(&pVisual);
SafeRelease(&pAnimateScale);
SafeRelease(&pScale);
SafeRelease(&m_pDevice);
SafeRelease(&m_pCompTarget);
完整範例
//
// AnimateLayeredChildWindow.h
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
#pragma once
// Modify the following definitions if you need to target a platform prior to the ones specified below.
#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
#ifndef UNICODE
#define UNICODE
#endif
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used items from Windows headers
// Windows Header Files:
#include <windows.h>
#include <wincodec.h>
// C RunTime Header Files
#include <math.h>
// DirectComposition Header File
#include <dcomp.h>
// Direct2D Header Files
#include <d2d1.h>
#include <d2d1helper.h>
// Desktop Window Manager (DWM) Header File
#include <dwmapi.h>
/******************************************************************
* *
* Macros *
* *
******************************************************************/
template<class Interface>
inline void
SafeRelease(
Interface **ppInterfaceToRelease
)
{
if (*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
#ifndef HINST_THISCOMPONENT
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
#endif
/******************************************************************
* *
* DemoApp *
* *
******************************************************************/
class DemoApp
{
public:
DemoApp();
~DemoApp();
HRESULT InitializeMainWindow();
HRESULT InitializeLayeredChildWindow();
void RunMessageLoop();
private:
HRESULT InitializeDirectCompositionObjects();
HRESULT CreateDeviceIndependentResources();
HRESULT CreateDeviceResources();
void DiscardDeviceResources();
HRESULT OnChildClick();
HRESULT OnChildRender();
HRESULT LoadResourceD2DBitmap(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR resourceName,
PCWSTR resourceType,
ID2D1Bitmap **ppBitmap
);
static LRESULT CALLBACK MainWndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam
);
static LRESULT CALLBACK ChildWndProc(
HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam
);
private:
int m_dpiX;
int m_dpiY;
int m_childOffsetX;
int m_childOffsetY;
HWND m_hwndMain;
HWND m_hwndLayeredChild;
IDCompositionDevice *m_pDevice;
IDCompositionTarget *m_pCompTarget;
ID2D1HwndRenderTarget *m_pRenderTarget;
ID2D1Factory *m_pD2DFactory;
ID2D1Bitmap *m_pBitmap;
IWICImagingFactory *m_pWICFactory;
};
//
// AnimateLayeredChildWindow.cpp
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
// Instructions: Click the thumnail image to animate the transition
// of the child window from thumbsize to fullsize. Click the child
// window again to reset.
#include "AnimateLayeredChildWindow.h"
#define TIMER_ID 100
/******************************************************************
* *
* The application entry point. *
* *
******************************************************************/
int WINAPI WinMain(
HINSTANCE /* hInstance */,
HINSTANCE /* hPrevInstance */,
LPSTR /* lpCmdLine */,
int /* nCmdShow */
)
{
// Ignore the return value because we want to run the program even in the
// unlikely event that HeapSetInformation fails.
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
if (SUCCEEDED(CoInitialize(NULL)))
{
{
DemoApp app;
if (SUCCEEDED(app.InitializeMainWindow()) && SUCCEEDED(app.InitializeLayeredChildWindow()))
{
app.RunMessageLoop();
}
}
CoUninitialize();
}
return 0;
}
/******************************************************************
* *
* DemoApp::DemoApp constructor *
* *
* Initialize member data. *
* *
******************************************************************/
DemoApp::DemoApp() :
m_dpiX(0),
m_dpiY(0),
m_childOffsetX(20),
m_childOffsetY(40),
m_hwndMain(NULL),
m_hwndLayeredChild(NULL),
m_pDevice(NULL),
m_pCompTarget(NULL),
m_pRenderTarget(NULL),
m_pBitmap(NULL),
m_pD2DFactory(NULL),
m_pWICFactory(NULL)
{
}
/******************************************************************
* *
* Release resources. *
* *
******************************************************************/
DemoApp::~DemoApp()
{
SafeRelease(&m_pDevice);
SafeRelease(&m_pCompTarget);
SafeRelease(&m_pRenderTarget);
SafeRelease(&m_pBitmap),
SafeRelease(&m_pD2DFactory);
SafeRelease(&m_pWICFactory);
}
/*******************************************************************
* *
* Create the application window. *
* *
*******************************************************************/
HRESULT DemoApp::InitializeMainWindow()
{
HRESULT hr = S_OK;
// Initialize device-independent resources, such
// as the Direct2D factory.
hr = CreateDeviceIndependentResources();
if (SUCCEEDED(hr))
{
// Register the main window class.
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
wcex.style = 0;
wcex.lpfnWndProc = DemoApp::MainWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = sizeof(LONG_PTR);
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.lpszClassName = L"DirectCompDemoApp";
RegisterClassEx(&wcex);
RECT rect = { };
SetRect(&rect, 0, 0, 640, 480);
AdjustWindowRect(&rect, WS_OVERLAPPED | WS_SYSMENU, FALSE);
// Create the main application window.
//
// Because the CreateWindow function takes its size in pixels, we
// obtain the system DPI and use it to scale the window size.
HDC hdc = GetDC(NULL);
if (hdc)
{
m_dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
m_dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
ReleaseDC(NULL, hdc);
}
float width = static_cast<float>(rect.right - rect.left);
float height = static_cast<float>(rect.bottom - rect.top);
m_hwndMain = CreateWindow(
L"DirectCompDemoApp",
L"DirectComposition Demo Application",
WS_OVERLAPPED | WS_SYSMENU,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<UINT>(ceil(width * m_dpiX / 96.f)),
static_cast<UINT>(ceil(height * m_dpiY / 96.f)),
NULL,
NULL,
HINST_THISCOMPONENT,
this
);
}
hr = m_hwndMain ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// Create and initialize the DirectCompositoin objects.
hr = InitializeDirectCompositionObjects();
}
if (SUCCEEDED(hr))
{
ShowWindow(m_hwndMain, SW_SHOWNORMAL);
UpdateWindow(m_hwndMain);
}
return hr;
}
/*******************************************************************
* *
* Create the layered child window. *
* *
/******************************************************************/
HRESULT DemoApp::InitializeLayeredChildWindow()
{
int thumbWidth = 48;
int thumbHeight = 32;
HRESULT hr = S_OK;
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(wcex);
wcex.style = 0;
wcex.lpfnWndProc = DemoApp::ChildWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = HINST_THISCOMPONENT;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH) GetStockObject (GRAY_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"DCompLayeredChildWindow";
wcex.hIconSm = NULL;
if (!RegisterClassExW(&wcex))
{
return FALSE;
}
m_hwndLayeredChild = CreateWindowEx(WS_EX_LAYERED,
L"DCompLayeredChildWindow",
NULL,
WS_CHILD | WS_CLIPSIBLINGS,
0,
0,
static_cast<UINT>(ceil(640.0f * m_dpiX / 96.0f)),
static_cast<UINT>(ceil(480.0f * m_dpiY / 96.0f)),
m_hwndMain,
NULL,
HINST_THISCOMPONENT,
this);
hr = m_hwndLayeredChild ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// Set the opacity and transparency color key of the layered
// child window.
if (!SetLayeredWindowAttributes(m_hwndLayeredChild, 0, 255, LWA_ALPHA))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
if (SUCCEEDED(hr))
{
// While the child window is fullsize, load the bitmap resource and
// render it to the child window.
hr = CreateDeviceResources();
}
if (SUCCEEDED(hr))
{
// Reduce the window to thumbsize.
MoveWindow(m_hwndLayeredChild, m_childOffsetX, m_childOffsetY,
thumbWidth, thumbHeight, TRUE);
ShowWindow(m_hwndLayeredChild, SW_SHOWNORMAL);
UpdateWindow(m_hwndLayeredChild);
}
return hr;
}
/******************************************************************
* *
* This method creates the DirectComposition device object and *
* and the composition target object. These objects endure for *
* the lifetime of the application. *
* *
******************************************************************/
HRESULT DemoApp::InitializeDirectCompositionObjects()
{
HRESULT hr = S_OK;
// Create a DirectComposition device object.
hr = DCompositionCreateDevice(nullptr, __uuidof(IDCompositionDevice),
reinterpret_cast<void**>(&m_pDevice));
if (SUCCEEDED(hr))
{
// Create the composition target object.
hr = m_pDevice->CreateTargetForHwnd(m_hwndMain, TRUE, &m_pCompTarget);
}
return hr;
}
/******************************************************************
* *
* This method is used to create resources which are not bound *
* to any device. Their lifetime effectively extends for the *
* duration of the app. *
* *
******************************************************************/
HRESULT DemoApp::CreateDeviceIndependentResources()
{
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_pWICFactory)
);
if (SUCCEEDED(hr))
{
// Create a Direct2D factory.
hr = D2D1CreateFactory(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&m_pD2DFactory
);
}
return hr;
}
/******************************************************************
* *
* This method creates the D2D bitmap that the application gives *
* to DirectComposition to be composed. *
* *
******************************************************************/
HRESULT DemoApp::CreateDeviceResources()
{
HRESULT hr = S_OK;
RECT rc;
GetClientRect(m_hwndLayeredChild, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top
);
// Create a Direct2D render target.
hr = m_pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(m_hwndLayeredChild, size),
&m_pRenderTarget
);
if (SUCCEEDED(hr))
{
hr = LoadResourceD2DBitmap(
m_pRenderTarget,
m_pWICFactory,
L"WhiteFlowers",
L"Image",
&m_pBitmap
);
}
return hr;
}
/******************************************************************
* *
* Discard device-specific resources. *
* *
******************************************************************/
void DemoApp::DiscardDeviceResources()
{
SafeRelease(&m_pRenderTarget);
SafeRelease(&m_pBitmap);
}
/******************************************************************
* *
* The main window's message loop. *
* *
******************************************************************/
void DemoApp::RunMessageLoop()
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
/******************************************************************
* *
* The main window's message handler. *
* *
******************************************************************/
LRESULT CALLBACK DemoApp::MainWndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
DemoApp *pDemoApp = (DemoApp *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(pDemoApp)
);
result = 1;
}
else
{
DemoApp *pDemoApp = reinterpret_cast<DemoApp *>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(
hwnd,
GWLP_USERDATA
)));
bool wasHandled = false;
if (pDemoApp)
{
switch (message)
{
case WM_DISPLAYCHANGE:
{
InvalidateRect(hwnd, NULL, FALSE);
}
wasHandled = true;
result = 0;
break;
case WM_DESTROY:
{
PostQuitMessage(0);
pDemoApp->DiscardDeviceResources();
}
wasHandled = true;
result = 1;
break;
}
}
if (!wasHandled)
{
result = DefWindowProc(hwnd, message, wParam, lParam);
}
}
return result;
}
/******************************************************************
* *
* The layered child window's message handler. *
* *
******************************************************************/
LRESULT CALLBACK DemoApp::ChildWndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
LRESULT result = 0;
if (message == WM_CREATE)
{
LPCREATESTRUCT pcs = (LPCREATESTRUCT)lParam;
DemoApp *pDemoApp = (DemoApp *)pcs->lpCreateParams;
::SetWindowLongPtrW(
hwnd,
GWLP_USERDATA,
PtrToUlong(pDemoApp)
);
result = 1;
}
else
{
DemoApp *pDemoApp = reinterpret_cast<DemoApp *>(static_cast<LONG_PTR>(
::GetWindowLongPtrW(
hwnd,
GWLP_USERDATA
)));
bool wasHandled = false;
if (pDemoApp)
{
switch (message)
{
case WM_PAINT:
{
pDemoApp->OnChildRender();
ValidateRect(hwnd, NULL);
}
wasHandled = true;
result = 0;
break;
case WM_LBUTTONDOWN:
{
HRESULT hr = S_OK;
static BOOL fThumbsize = TRUE;
// If the child window is already fullsize, reset
// the visual tree and return the child window
// to thumbsize and move it to its initial location.
if (!fThumbsize)
{
pDemoApp->m_pCompTarget->SetRoot(NULL);
hr = pDemoApp->m_pDevice->Commit();
MoveWindow(pDemoApp->m_hwndLayeredChild,
pDemoApp->m_childOffsetX,
pDemoApp->m_childOffsetY, 48, 32, TRUE);
pDemoApp->OnChildRender();
}
else
{
// Cloak the child window.
BOOL fCloak = TRUE;
DwmSetWindowAttribute(pDemoApp->m_hwndLayeredChild,
DWMWA_CLOAK,
&fCloak,
sizeof(fCloak));
pDemoApp->OnChildClick();
}
fThumbsize = !fThumbsize;
}
wasHandled = true;
result = 0;
break;
case WM_TIMER:
{
// Uncloak the child window.
BOOL fCloak = FALSE;
DwmSetWindowAttribute(pDemoApp->m_hwndLayeredChild,
DWMWA_CLOAK,
&fCloak,
sizeof(fCloak));
KillTimer(pDemoApp->m_hwndLayeredChild, TIMER_ID);
}
wasHandled = true;
result = 0;
break;
}
}
if (!wasHandled)
{
result = DefWindowProc(hwnd, message, wParam, lParam);
}
}
return result;
}
/******************************************************************
* *
* Draws a bitmap in the layered child window. *
* *
******************************************************************/
HRESULT DemoApp::OnChildRender()
{
HRESULT hr = S_OK;
// Retrieve the size of the render target.
D2D1_SIZE_F size = m_pRenderTarget->GetSize();
m_pRenderTarget->BeginDraw();
// Draw a bitmap scaled to fill the window.
m_pRenderTarget->DrawBitmap(
m_pBitmap,
D2D1::RectF(0.0f, 0.0f, size.width, size.height)
);
hr = m_pRenderTarget->EndDraw();
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
return hr;
}
/******************************************************************
* *
* Handles a mouse click in the layered child window by animating *
* the transition from a thumbsize window to a fullsize window. *
* *
******************************************************************/
HRESULT DemoApp::OnChildClick()
{
int fullWidth = 640;
int fullHeight = 480;
HRESULT hr = S_OK;
IDCompositionVisual *pVisual = nullptr;
IUnknown* pSurface = nullptr;
hr = m_pDevice->CreateVisual(&pVisual);
if (SUCCEEDED(hr))
{
hr = m_pDevice->CreateSurfaceFromHwnd(m_hwndLayeredChild, &pSurface);
}
if (SUCCEEDED(hr))
{
hr = pVisual->SetContent(pSurface);
}
if (SUCCEEDED(hr))
{
hr = m_pCompTarget->SetRoot(pVisual);
}
if (SUCCEEDED(hr))
{
// Position the visual at the same location as the
// the child window.
hr = pVisual->SetOffsetX(static_cast<float>(m_childOffsetX));
if (SUCCEEDED(hr))
{
hr = pVisual->SetOffsetY(static_cast<float>(m_childOffsetY));
}
}
IDCompositionAnimation *pAnimateX = NULL;
IDCompositionAnimation *pAnimateY = NULL;
if (SUCCEEDED(hr))
{
// Create the animation objects.
hr = m_pDevice->CreateAnimation(&pAnimateX);
if (SUCCEEDED(hr))
{
hr = m_pDevice->CreateAnimation(&pAnimateY);
}
}
IDCompositionAnimation *pAnimateScale = NULL;
IDCompositionScaleTransform *pScale = NULL;
if (SUCCEEDED(hr))
{
hr = m_pDevice->CreateAnimation(&pAnimateScale);
}
if (SUCCEEDED(hr))
{
// Create the scale transform object.
hr = m_pDevice->CreateScaleTransform(&pScale);
}
if (SUCCEEDED(hr))
{
// Calculate the X and Y offsets that will position the child window
// in the center of the main window's client area.
RECT rcParent = { };
RECT rcChild = { };
GetClientRect(m_hwndMain, &rcParent);
GetClientRect(m_hwndLayeredChild, &rcChild);
float endValX = rcParent.right / 2.0f - rcChild.right / 2.0f;
float endValY = rcParent.bottom / 2.0f - rcChild.bottom / 2.0f;
// Build the animation functions that will move the visual to the
// center of the main window's client area.
pAnimateX->AddCubic(0.0f, static_cast<float>(m_childOffsetX),
endValX - m_childOffsetX, 0.0f, 0.0f);
pAnimateX->End(0.9f, endValX);
pAnimateY->AddCubic(0.0f, static_cast<float>(m_childOffsetY),
endValY - m_childOffsetY, 0.0f, 0.0f);
pAnimateY->End(0.9f, endValY);
// Associate the animation objects with the offset properties of
// the visual.
hr = pVisual->SetOffsetX(pAnimateX);
if (SUCCEEDED(hr))
{
hr = pVisual->SetOffsetY(pAnimateY);
}
}
if (SUCCEEDED(hr))
{
// Commit the visual tree.
hr = m_pDevice->Commit();
// Give the animation a chance to run.
Sleep(900);
}
if (SUCCEEDED(hr))
{
// Align the visual with the upper-left corner of the
// parent window's client area.
pVisual->SetOffsetX(0.0);
pVisual->SetOffsetY(0.0);
// Enlarge the child window to fill the main window.
if (!MoveWindow(m_hwndLayeredChild, 0, 0, fullWidth, fullHeight, TRUE))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
if (SUCCEEDED(hr))
{
// Add animation primitives that define the animation object function
// used to scale up the child window's bitmap.
pAnimateScale->AddCubic(
0.0f, // offset from beginning of animation function, in seconds
0.0f, // constant coefficient
1.0f, // linear coefficient
0.0f, // quadratic coefficient
0.0f); // cubic coefficient
pAnimateScale->End(1.0f, 1.0f);
// Find the center of the child window.
RECT rcChild = { };
GetClientRect(m_hwndLayeredChild, &rcChild);
float centerX = rcChild.right / 2.0f;
float centerY = rcChild.bottom / 2.0f;
// Scale from the center point of the child window's bitmap.
pScale->SetCenterX(centerX);
pScale->SetCenterY(centerY);
// Use the same animation object to animate the X and Y scale
// factors.
pScale->SetScaleX(pAnimateScale);
pScale->SetScaleY(pAnimateScale);
// Set the Transform property of the visual to use the scale
// transform.
hr = pVisual->SetTransform(pScale);
}
if (SUCCEEDED(hr))
{ // Commit the visual tree.
hr = m_pDevice->Commit();
// Use a WM_TIMER message in the child window procedure
// to uncloak the child window.
SetTimer(m_hwndLayeredChild, TIMER_ID, 1000, NULL);
}
SafeRelease(&pAnimateX);
SafeRelease(&pAnimateY);
SafeRelease(&pVisual);
SafeRelease(&pAnimateScale);
SafeRelease(&pScale);
return hr;
}
/******************************************************************
* *
* This method will create a Direct2D bitmap from an application *
* resource. *
* *
******************************************************************/
HRESULT DemoApp::LoadResourceD2DBitmap(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR resourceName,
PCWSTR resourceType,
ID2D1Bitmap **ppBitmap
)
{
HRESULT hr = S_OK;
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
HRSRC imageResHandle = NULL;
HGLOBAL imageResDataHandle = NULL;
void *pImageFile = NULL;
DWORD imageFileSize = 0;
// Locate the resource.
imageResHandle = FindResourceW(HINST_THISCOMPONENT, resourceName, resourceType);
hr = imageResHandle ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
// Load the resource.
imageResDataHandle = LoadResource(HINST_THISCOMPONENT, imageResHandle);
hr = imageResDataHandle ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Lock it to get a system memory pointer.
pImageFile = LockResource(imageResDataHandle);
hr = pImageFile ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Calculate the size.
imageFileSize = SizeofResource(HINST_THISCOMPONENT, imageResHandle);
hr = imageFileSize ? S_OK : E_FAIL;
}
if (SUCCEEDED(hr))
{
// Create a WIC stream to map onto the memory.
hr = pIWICFactory->CreateStream(&pStream);
}
if (SUCCEEDED(hr))
{
// Initialize the stream with the memory pointer and size.
hr = pStream->InitializeFromMemory(
reinterpret_cast<BYTE*>(pImageFile),
imageFileSize
);
}
if (SUCCEEDED(hr))
{
// Create a decoder for the stream.
hr = pIWICFactory->CreateDecoderFromStream(
pStream,
NULL,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
}
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = pIWICFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(
pSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
if (SUCCEEDED(hr))
{
// Create a Direct2D bitmap from the WIC bitmap.
hr = pRenderTarget->CreateBitmapFromWicBitmap(
pConverter,
NULL,
ppBitmap
);
}
SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
return hr;
}
相關主題