簡體   English   中英

如何正確使用和實例化現有的預覽處理程序

[英]How to Properly Use and Instantiate existing Preview Handlers

我正在嘗試使用現有的預覽處理程序來顯示文件的預覽。

我編寫了一個簡單的測試程序來 1) 找到給定文件的預覽處理程序的 CLSID,2) 實例化預覽處理程序,3) 通過流或文件初始化它,以及 4) 在基本窗口上呈現預覽。

這行得通。 或多或少。

它適用於 adobe acrobat reader 提供的 pdf 預覽處理程序,但不適用於 windows 提供的 pdf 預覽處理程序 (CLSID {3A84F9C2-6164-485C-A7D9-4B27F8AC009E} ,由邊緣在 PdfPreviewHandler.dll 中提供,只是以供參考)。 (它不會在任何地方失敗,它只是不起作用並且不會呈現預覽,請參閱圖像)。 windows提供的pdf預覽處理程序 acrobat reader pdf 處理程序

用於 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調用:

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

// add this
iPreviewHandler->SetRect(&rect);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM