如何使用OLE的API来绘制一个很大的Excel表格?

道政 吴 0 信誉分
2025-06-24T07:24:26.34+00:00
  1. 有一张很大的Excel表格,行数超过了150行(如下图);一张大的Excel表格
  2. 用户全选表格,然后复制(Ctrl+C),我编写了一个应用程序,在其中读取粘贴板的内容,并想通过OLE的API(如OleDraw)来绘制到HDC,最后用CImage保存为图片;
  3. 但是保存后的图片只能显示这个Excel表格的一部分内容(如下图); 只显示了表格的一部分

当把粘贴板的内容粘贴通过选择性粘贴到 Office/Word中,显示正常(如下图);

在Word中完全展现了

  1. 当把粘贴板的内容粘贴通过选择性粘贴到 写字板(WordPad)中,写字板也只能展现一部分;
  2. 所以我想知道的是,是否有什么特殊的API调用来让整个OLE对象得到完整的绘制?

以下是我的程序代码:

#include <iostream>
#include <Windows.h>
#include <ole2.h>
#include <oleidl.h>
#include <comdef.h>
#include <atlimage.h>
#include <atlwin.h>

void DrawExcelFromClipboard()
{
    if (FAILED(OleInitialize(NULL)))
    {
        fprintf(stderr, "Failed to init ole\n");
        return;
    }

    IDataObject *pDataObj = NULL;
    IOleObject *pOleObject = NULL;
    IStorage *pStorage = NULL;
    ILockBytes *pLockBytes = NULL;

    if (SUCCEEDED(OleGetClipboard(&pDataObj)))
    {
        if (SUCCEEDED(CreateILockBytesOnHGlobal(NULL, TRUE, &pLockBytes)) &&
            SUCCEEDED(StgCreateDocfileOnILockBytes(pLockBytes,
                                                    STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
                                                    0, &pStorage)))
        {

            HRESULT hr = OleCreateFromData(pDataObj, IID_IOleObject, OLERENDER_DRAW,
                                            NULL, NULL, pStorage, (void **)&pOleObject);

            if (SUCCEEDED(hr))
            {
                SIZEL sz;
                pOleObject->GetExtent(DVASPECT_CONTENT, &sz);
                HDC hdcDesktop = ::GetDC(NULL);
                int w = MulDiv(sz.cx, GetDeviceCaps(hdcDesktop, LOGPIXELSX), 2540);
                int h = MulDiv(sz.cy, GetDeviceCaps(hdcDesktop, LOGPIXELSY), 2540);
                ::ReleaseDC(NULL, hdcDesktop);

                CImage img;
                img.Create(w, h, 32);
                HDC hdc = img.GetDC();

                RECT rc = {0, 0, w, h};

                // frames
                HBRUSH hBrush = CreateSolidBrush(RGB(240, 240, 240));
                FillRect(hdc, &rc, hBrush);
                DeleteObject(hBrush);
                FrameRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));

                InflateRect(&rc, -10, -10);

                // SetMapMode(hdc, MM_TEXT);
                if (1)
                {
                    IViewObject2 *pView = NULL;
                    pOleObject->QueryInterface(IID_IViewObject2, (void **)&pView);
                    if (pView != NULL)
                    {
                        RECTL rcl;
                        rcl.left = rc.left;
                        rcl.right = rc.right;
                        rcl.top = rc.top;
                        rcl.bottom = rc.bottom;
                        hr = pView->Draw(DVASPECT_CONTENT,
                                            -1,
                                            NULL,
                                            NULL,
                                            NULL,
                                            hdc,
                                            &rcl,
                                            NULL,
                                            NULL,
                                            0);
                        pView->Release();
                    }
                }
                else
                {
                    hr = OleDraw(pOleObject, DVASPECT_CONTENT, hdc, &rc);
                }

                if (FAILED(hr))
                {
                    fprintf(stderr, "Failed to draw ole\n");
                }
                else
                {
                    if (!SUCCEEDED(img.Save(L"./ole.png", Gdiplus::ImageFormatPNG)))
                    {
                        fprintf(stderr, "Failed to save png\n");
                    }
                }
                img.ReleaseDC();
            }
            else
            {
                fprintf(stderr, "Failed to load ole\n");
            }
        }
    }
    else
    {
        fprintf(stderr, "No ole in clipboard\n");
    }

    CloseClipboard();
    if (pDataObj)
        pDataObj->Release();
    if (pOleObject)
        pOleObject->Release();
    if (pStorage)
        pStorage->Release();
    if (pLockBytes)
        pLockBytes->Release();
}

int main()
{
    DrawExcelFromClipboard();
    return 0;
}
开发人员技术 C++
0 个注释 无注释
{count} 票

你的答案

问题作者可以将答案标记为“接受的答案”,这有助于用户了解已解决作者问题的答案。