如何正确使用和实例化现有预览处理程序

2024-05-13

我正在尝试使用现有的预览处理程序来显示文件的预览。

我编写了一个简单的测试程序,以 1) 查找给定文件的预览处理程序的 CLSID,2) 实例化预览处理程序,3) 通过流或文件初始化它,4) 在基本窗口上渲染预览。

这有效。或多或少。

It works just fine for the pdf preview handler provided by adobe acrobat reader, but doesn't work with the windows provided pdf preview handler (CLSID {3A84F9C2-6164-485C-A7D9-4B27F8AC009E}, provided by edge in PdfPreviewHandler.dll, just for reference). (It doesn't fail anywhere, it just doesnt work and doesn't render a preview, see images). windows provided pdf preview handler acrobat reader pdf handler

Excel (.xlsx) 和 power point (.pptx) 文件的 Microsoft Office 预览处理程序的情况相同。

对于 Word (.docx) 文件,它完全失败。第 106 行中的 IInitializeWithFile 调用失败,并显示“未指定错误”(HRESULT 0x80004005)。

一堆其他预览处理程序工作得很好,一些由流初始化,一些由文件初始化(例如,Windows 为 html 和文本文件提供了处理程序)。

我真的不知道问题可能是什么,或者我什至应该从哪里开始寻找,对此的任何意见将不胜感激。

编译用cl /std:c++20 test.cpp ole32.lib shlwapi.lib user32.lib /EHsc,期望文件路径作为第一个可执行参数。

#include <filesystem>
#include <array>
#include <cassert>
#include <stdexcept>
#include <iostream>

#include "Windows.h"
#include "ShObjIdl.h"
#include "shlwapi.h"
#include "objbase.h"

#define checkHresult(res) (checkHresult_(res, __LINE__, __FILE__))

void checkHresult_(HRESULT res, int line, const char *file){
    if(res != S_OK){
        std::stringstream msg;
        msg << file << ':' << line << ": 0x" << std::hex << res << ' ';
        LPSTR errMsg;
        if(FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 
                          nullptr, 
                          res, 
                          MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), 
                          reinterpret_cast<LPSTR>(&errMsg), 
                          0, 
                          nullptr)){
            msg << errMsg;
            LocalFree(errMsg);
        }
        throw std::runtime_error(msg.str());
    }
}

CLSID getShellExtensionClsidForFileType(const std::wstring& extension, const GUID& interfaceID){
    HRESULT res;
    std::array<wchar_t, 39> ifIdWStr;
    int written;
    written = StringFromGUID2(interfaceID, ifIdWStr.data(), ifIdWStr.size());
    if(written == 0){
        checkHresult(HRESULT_FROM_WIN32(GetLastError())); //StringFromGUID2 should not fail
    }

    std::array<wchar_t, 39> extIdWStr;
    DWORD extIdWStrSize = extIdWStr.size();
    res = AssocQueryStringW(ASSOCF_INIT_DEFAULTTOSTAR, 
                            ASSOCSTR_SHELLEXTENSION,
                            extension.c_str(),
                            ifIdWStr.data(),
                            extIdWStr.data(),
                            &extIdWStrSize);
    checkHresult(res);
    
    CLSID extId;
    res = IIDFromString(extIdWStr.data(), &extId);
    checkHresult(res); //IIDFromString should not fail
    std::wcout << "preview handler clsid: " << extIdWStr.data() << '\n';
    return(extId);
}


IPreviewHandler* getIPreviewHandlerInterfaceForType(const std::wstring& extension){
    HRESULT res;
    //get the CLSID for the preview handler for the specified fily type
    CLSID iPreviewHandlerClsid(getShellExtensionClsidForFileType(extension, IID_IPreviewHandler));
    IPreviewHandler *iPreviewHandler;
    res = CoCreateInstance(iPreviewHandlerClsid, 
                           nullptr, 
                           CLSCTX_LOCAL_SERVER, 
                           IID_IPreviewHandler, 
                           reinterpret_cast<LPVOID*>(&iPreviewHandler));
    checkHresult(res);
    return(iPreviewHandler);
}

int wmain(int argc, wchar_t *argv[]){
    try{
        if(argc != 2){
            return(1);
        }
        HRESULT res;

        res = CoInitialize(nullptr);
        checkHresult(res);

        std::filesystem::path filePath(argv[1]);
        filePath.make_preferred();

        //Instantiate the preview handler for the specified file type
        IPreviewHandler *iPreviewHandler = getIPreviewHandlerInterfaceForType(filePath.extension());

        IInitializeWithStream *iInitializeWithStream;
        IInitializeWithFile *iInitializeWithFile;

        iPreviewHandler->QueryInterface(IID_IInitializeWithStream, reinterpret_cast<LPVOID*>(&iInitializeWithStream));
        iPreviewHandler->QueryInterface(IID_IInitializeWithFile, reinterpret_cast<LPVOID*>(&iInitializeWithFile));

        //Initialize preview handler, preferably with a stream
        if(iInitializeWithStream){
            IStream *iStream;
            res = SHCreateStreamOnFileEx(filePath.c_str(), STGM_READ | STGM_SHARE_DENY_WRITE, 0, false, nullptr, &iStream);
            checkHresult(res);
            res = iInitializeWithStream->Initialize(iStream, STGM_READ);
            checkHresult(res);
            std::cout << "Initialized with Stream\n";
        }else if(iInitializeWithFile){
            res = iInitializeWithFile->Initialize(filePath.c_str(), STGM_READ);
            checkHresult(res);
            std::cout << "Initialized with File\n";
        }else{
            checkHresult(E_NOINTERFACE);
        }

        //create basic window
        WNDCLASSW wndClass;
        wndClass.style = 0;
        wndClass.lpfnWndProc = DefWindowProcW;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
        wndClass.hInstance = GetModuleHandleA(nullptr);
        wndClass.hIcon = nullptr;
        wndClass.hCursor = nullptr;
        wndClass.hbrBackground = nullptr;
        wndClass.lpszMenuName = nullptr;
        wndClass.lpszClassName = L"test";

        ATOM wndAtom = RegisterClassW(&wndClass);
        if(wndAtom == 0){
            checkHresult(HRESULT_FROM_WIN32(GetLastError()));
        }
        HWND window = CreateWindowExW(0, 
                                      L"test", 
                                      L"", 
                                      WS_VISIBLE, 
                                      CW_USEDEFAULT, 
                                      CW_USEDEFAULT, 
                                      CW_USEDEFAULT, 
                                      CW_USEDEFAULT, 
                                      0, 
                                      0, 
                                      wndClass.hInstance, 
                                      nullptr);
        if(window == nullptr){
            checkHresult(HRESULT_FROM_WIN32(GetLastError()));
        }

        ShowWindow(window, SW_NORMAL);

        RECT rect;
        GetClientRect(window, &rect);
        res = iPreviewHandler->SetWindow(window, &rect);
        checkHresult(res);
        res = iPreviewHandler->DoPreview();

        MSG msg;
        while(GetMessageW(&msg, nullptr, 0, 0) > 0){
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }catch(std::runtime_error err){
        std::cout << err.what();
    }
}

你只需要添加一个SetRect https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/nf-shobjidl_core-ipreviewhandler-setrect初始化后调用:

RECT rect;
GetClientRect(window, &rect);
iPreviewHandler->SetWindow(window, &rect);
iPreviewHandler->DoPreview();

// add this
iPreviewHandler->SetRect(&rect);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何正确使用和实例化现有预览处理程序 的相关文章

随机推荐