我正在嘗試使用現有的預覽處理程式來顯示檔案的預覽。
我撰寫了一個簡單的測驗程式來 1) 找到給定檔案的預覽處理程式的 CLSID,2) 實體化預覽處理程式,3) 通過流或檔案初始化它,以及 4) 在基本視窗上呈現預覽。
這行得通。或多或少。
它適用于 adobe acrobat reader 提供的 pdf 預覽處理程式,但不適用于 windows 提供的 pdf 預覽處理程式(CLSID {3A84F9C2-6164-485C-A7D9-4B27F8AC009E},由 edge 在 PdfPreviewHandler.dll 中提供,僅供參考)。(它不會在任何地方失敗,它只是不起作用并且不會呈現預覽,請參閱影像)。

用于 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();
}
}
uj5u.com熱心網友回復:
您只需要在初始化后添加一個SetRect呼叫:
RECT rect;
GetClientRect(window, &rect);
iPreviewHandler->SetWindow(window, &rect);
iPreviewHandler->DoPreview();
// add this
iPreviewHandler->SetRect(&rect);
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/483816.html
