[英]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 中提供,只是以供參考)。 (它不會在任何地方失敗,它只是不起作用並且不會呈現預覽,請參閱圖像)。
用於 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.