# 六、附录 C：`CDocSource`类代码列表

以下代码来自微软提供的“[direct 2 DAP 打印示例(Windows 8.1)](http://code.msdn.microsoft.com/windowsapps/Direct2Dapp-printing-sample-9869f99C# content) ”。我已经修改了格式，以更好地适应这本书的页面；这导致了更难阅读的代码。为了方便起见，此处包含了这段代码，原始代码(可以与微软 Windows 8 示例一起下载)可读性更强。所有评论都是微软的。我只修改了上面提到的格式。它们指的是从中下载代码的示例。

微软提供的示例代码中的类名是 D2DPageRenderer。对于我们的打印应用程序，这应该改为“简单文本渲染器”。我在后面的代码中用绿色突出显示了这一行。我们代码中的主渲染器类被称为 SimpleTextRenderer，因此您还必须将对 PageRenderer 类的所有引用都更改为 SimpleTextRenderer。我用红色突出了这些线条。

DocSource.h 列表

```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
    #pragma once
    #include <windows.graphics.printing.h>
    #include <printpreview.h>
    #include <documentsource.h>

      #include "D2DPageRenderer.h"

```

类 CDocumentSource:public Microsoft::WRL::RuntimeClass<:wrl::runtimeclassflags>，

ABI::Windows::Graphics::Printing::IPrintDocumentSource，

IPrintDocumentPageSource，

IPrintPreviewPageCollection >

{

私人:

可检查类(L”窗口。图形. Printing.IPrintDocumentSource "，

baseTrust)；

公共:

HRESULT RuntimeClassInitialize(

_ In _ Iunknown * page renderer){ 0

HRESULT hr = (pageRenderer！=空值？S_OK : E_INVALIDARG：

if(SUCCESS(HR)){ 0

m _ paginateCalled = false

m_totalPages = 1：

m _ height = 0.f

m _ width = 0.f

//将 d2dRender 强制转换回 PageRenderer 对象。

m _ renderer = re interpret _ cast<pagerenderer>(page renderer)；</pagerenderer>

}

返回 HR；

}

//

//经典的 COM 接口 IDocumentPageSource 方法

//

IFACEMETHODIMP

GetPreviewPageCollection(

_ in _ iprindocumentpackage target * docpackage target，

_ out _ ipprintpreviewpagecollection * * docpagecollection

);

IFACEMETHODIMP

MakeDocument(

_ In _ IInspectable *文档选项，

_ in _ ipprintdocumentpacktarget * docpackage target

);

//

//经典的 COM 接口 IPrintPreviewPageCollection 方法

//

IFACEMETHODIMP

分页(

_ In _ uint32 currentJobPage，

_ In _ iinspective * docOptions)；

IFACEMETHODIMP

MakePage(

S7-1200 可编程控制器，

_In_ float 宽度，

_In_ float 高度)；

私人:

浮点转换页面大小(

_In_ float desiredWidth，

_In_ float desiredHeight，

_ Out _ Windows::Foundation::Size * previewSize)；

uint32 m_totalPages：

bool m _ paginateCalled

float m _ height

float m _ width

D2D1_RECT_F m_imageableRect;

pagerenderer^ m _ renderer；

Microsoft::wrl::comptr<iprintpreviewdxgipackagetarget>m _ dxgipreviewtarget；</iprintpreviewdxgipackagetarget>

};

DocSource.cpp 列表

```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
    #include "pch.h"
    #include "docsource.h"
    using namespace Microsoft::WRL;
    using namespace Windows::Graphics::Printing;
    #pragma region IDocumentPageSource Methods
    IFACEMETHODIMP
    CDocumentSource::GetPreviewPageCollection(
        _In_  IPrintDocumentPackageTarget*  docPackageTarget,
        _Out_ IPrintPreviewPageCollection** docPageCollection
        )
    {
        HRESULT hr = (docPackageTarget != nullptr) ? S_OK : E_INVALIDARG;
        // Get for IPrintPreviewDxgiPackageTarget interface.
        if (SUCCEEDED(hr)){
            hr = docPackageTarget->GetPackageTarget(
                ID_PREVIEWPACKAGETARGET_DXGI,
                IID_PPV_ARGS(&m_dxgiPreviewTarget));
        }
        ComPtr<IPrintPreviewPageCollection> pageCollection;
        if (SUCCEEDED(hr)){
            ComPtr<CDocumentSource> docSource(this);
            hr = docSource.As<IPrintPreviewPageCollection>(&pageCollection);
        }

        if (SUCCEEDED(hr)){
            hr = pageCollection.CopyTo(docPageCollection);
        }

        return hr;
    }
    IFACEMETHODIMP
    CDocumentSource::MakeDocument(
        _In_ IInspectable*                docOptions,
        _In_ IPrintDocumentPackageTarget* docPackageTarget)
    {
        if (docOptions == nullptr || docPackageTarget == nullptr){
            return E_INVALIDARG;
        }
        // Get print settings from PrintTaskOptions for printing,
        // such as page description,
        // which contains page size, imageable area, DPI.
        // User can obtain other print settings in the same way, such as ColorMode,
        // NumberOfCopies, etc., which are not shown in this sample.
        PrintTaskOptions^ option = reinterpret_cast<PrintTaskOptions^>(docOptions);
        // Get the description of the first page.
        PrintPageDescription pageDesc = option->GetPageDescription(1);
        // Create a print control properties and set DPI from PrintPageDescription.
        D2D1_PRINT_CONTROL_PROPERTIES printControlProperties;   
        // DPI for rasterization of all unsupported D2D commands or options
        printControlProperties.rasterDPI  = (float)(min(pageDesc.DpiX,
               pageDesc.DpiY));                
        // Color space for vector graphics in D2D print control.
        printControlProperties.colorSpace = D2D1_COLOR_SPACE_SRGB;
        // Subset for used glyphs, send and discard font resource after every
        // five pages
        printControlProperties.fontSubset = D2D1_PRINT_FONT_SUBSET_MODE_DEFAULT;
        HRESULT hr = S_OK;
        try {
            // Create a new print control linked to the package target.
            m_renderer->CreatePrintControl(docPackageTarget,&printControlProperties);

            // Calculate imageable area and page size from PrintPageDescription.
            D2D1_RECT_F imageableRect = D2D1::RectF(
                pageDesc.ImageableRect.X, pageDesc.ImageableRect.Y,
                pageDesc.ImageableRect.X + pageDesc.ImageableRect.Width,
                pageDesc.ImageableRect.Y + pageDesc.ImageableRect.Height
                );
            D2D1_SIZE_F pageSize = D2D1::SizeF(pageDesc.PageSize.Width,
          pageDesc.PageSize.Height);
            // Loop to add page command list to d2d print control.
            for (uint32 pageNum = 1; pageNum <= m_totalPages; ++pageNum){
                m_renderer->PrintPage(pageNum, imageableRect, pageSize,
                    nullptr // If a page-level print ticket is not specified here, the
                            //package print ticket is applied for each page.
                    );
            }
        }
        catch (Platform::Exception^ e){
            hr = e->HResult;
            if (hr == D2DERR_RECREATE_TARGET){
            // In case of device lost, the whole print job will be aborted,
         // and we should recover
            // so that the device is ready when used again. At the same time,
         // we should propagate this error to the Modern Print Dialog.
            m_renderer->HandleDeviceLost();
            }
        }
        // Make sure to close d2d print control even if AddPage fails.
        HRESULT hrClose = m_renderer->ClosePrintControl();
        if (SUCCEEDED(hr)){
            hr = hrClose;
        }
        return hr;
    }

    #pragma endregion IDocumentPageSource Methods
    #pragma region IPrintPreviewPageCollection Methods
    IFACEMETHODIMP CDocumentSource::Paginate(
        _In_   uint32           currentJobPage,
        _In_   IInspectable*    docOptions
        )
    {
        HRESULT hr = (docOptions != nullptr) ? S_OK : E_INVALIDARG;
        if (SUCCEEDED(hr)) {
            // Get print settings from PrintTaskOptions for preview, such as page
    // description, which contains page size, imageable area, DPI.
            // User can obtain other print settings in the same way, such
         // as ColorMode,
    // NumberOfCopies, etc., which are not shown in this sample.
            PrintTaskOptions^ option =
              reinterpret_cast<PrintTaskOptions^>(docOptions);
            PrintPageDescription pageDesc =
              option->GetPageDescription(currentJobPage);
            hr = m_dxgiPreviewTarget->InvalidatePreview();
            // Set the total page number.
            if (SUCCEEDED(hr)){
                hr = m_dxgiPreviewTarget->SetJobPageCount(
                    PageCountType::FinalPageCount, m_totalPages);
            }
            if (SUCCEEDED(hr)) {
                m_width = pageDesc.PageSize.Width;
                m_height = pageDesc.PageSize.Height;
                m_imageableRect = D2D1::RectF(
                    pageDesc.ImageableRect.X,
                    pageDesc.ImageableRect.Y,
                    pageDesc.ImageableRect.X + pageDesc.ImageableRect.Width,
                    pageDesc.ImageableRect.Y + pageDesc.ImageableRect.Height
                    );
                // Now we are ready to let MakePage to be called.
                m_paginateCalled = true;
            }
        }
        return hr;
    }

    // Here, desiredWidth/desiredHeight is the desired size of preview surface
    // by print mananger in system. The final size of the preview surface must
    // have the same proportion as that of the desired width/height.
    // In this sample, we just use it as preview size and return the scale variant
    // for surface drawing.
    // The size here is in DIPs.
    Float CDocumentSource::TransformedPageSize(
        _In_  float                         desiredWidth,
        _In_  float                         desiredHeight,
        _Out_ Windows::Foundation::Size*    previewSize
        ){
        float scale = 1.0f;
        if (desiredWidth > 0 && desiredHeight > 0) {
            previewSize->Width  = desiredWidth;
            previewSize->Height = desiredHeight;
            scale = m_width / desiredWidth;
        }
        else {
            previewSize->Width = 0;
            previewSize->Height = 0;
        }
        return scale;
    }

    // This sample only acts upon orientation setting for an example.
    // The orientation is read from the user selection in the Print Experience
    // and is then used to reflow the content in a different way.
    IFACEMETHODIMP CDocumentSource::MakePage(
        _In_ uint32 desiredJobPage,
        _In_ float  width,
        _In_ float  height){
        HRESULT hr = (width > 0 && height > 0) ? S_OK : E_INVALIDARG;
        // When desiredJobPage is JOB_PAGE_APPLICATION_DEFINED, it means a new
        // preview begins. If the implementation here is by an async way,
        // for example, queue MakePage calls for preview, app needs to clean
        // resources for previous preview before next.
        // In this sample, we will reset page number if Paginate() has been called.
        if (desiredJobPage == JOB_PAGE_APPLICATION_DEFINED && m_paginateCalled){
            desiredJobPage = 1;
        }
        if (SUCCEEDED(hr) && m_paginateCalled){
            // Calculate the size of preview surface, according to desired width and
    // height.
            Windows::Foundation::Size previewSize;
            float scale = TransformedPageSize(width, height, &previewSize);
            try {
                m_renderer->DrawPreviewSurface(
                    previewSize.Width, previewSize.Height, scale, m_imageableRect,
                    desiredJobPage,m_dxgiPreviewTarget.Get());
            }
            catch (Platform::Exception^ e) {
                hr = e->HResult;
                if (hr == D2DERR_RECREATE_TARGET){
    // In case of device lost, we should recover so that the device is
         // ready to render the next preview page when requested. At the same time,
         // we should propagate this error to the Modern Print Dialog.
                m_renderer->HandleDeviceLost();
                }
            }
        }
        return hr;
    }

    #pragma region IPrintPreviewPageCollection Methods

```