Обработчик предварительного просмотра работает только тогда, когда приложение вызывается из Проводника.
Я сделал простое приложение, которое создает окно, а затем использует обработчики предварительного просмотра для отображения предварительного просмотра файла, переданного в качестве аргумента приложению, см. код ниже.
Это отлично работает, когда просто перетаскиваете файл для предварительного просмотра в файл .exe (или, альтернативно, просто жестко кодируете путь к файлу, а затем запускаете .exe непосредственно из проводника), но не работает почти для всех обработчиков предварительного просмотра при вызове это с терминала (powershell, cmd, что угодно) например./main.exe testfile.docx
. Он также терпит неудачу при попытке вызвать его из других процессов.
Описанная проблема возникает (среди прочего) для следующих обработчиков предварительного просмотра:
- Обработчик предварительного просмотра MS Office для файлов Excel, CLSID
{00020827-0000-0000-C000-000000000046}
- Обработчик предварительного просмотра MS Office для файлов Word, CLSID
{84F66100-FF7C-4fb4-B0C0-02CD7FB668FE}
- Обработчик предварительного просмотра Edge для файлов PDF, CLSID
{3A84F9C2-6164-485C-A7D9-4B27F8AC009E}
- Обработчик предварительного просмотра MS Office для файлов Power Point, CLSID
{65235197-874B-4A07-BDC5-E65EA825B718}
. Для обработчика предварительного просмотра в Power Point вызов инициализацииIInitializeWithFile
интерфейс не работаетhresult 0x86420003
Он отлично работает для следующих обработчиков предварительного просмотра:
- Windows предоставила обработчик предварительного просмотра для текстовых файлов, CLSID
{1531d583-8375-4d3f-b5fb-d23bbd169f22}
- Windows предоставила обработчик предварительного просмотра для файлов html, CLSID
{f8b8412b-dea3-4130-b36c-5e8be73106ac}
Когда я говорю «сбой», я имею в виду, что он просто не отображает предварительный просмотр, ни один из вызовов функций не завершается ошибкой. Смотрите изображения:
Файл excel test.xlsx перетаскивается в файл .exe, тот же результат при жестком кодировании пути к test.xlsx и простом запуске приложения из проводника:
Путь к test.xlsx передается в качестве аргумента командной строки (./main.exe ./test.xlsx
в пауэршелле):
Я не уверен, что может вызвать это или где даже начать искать или что искать, поэтому любой вклад в это будет оценен.
Примечание. Я задавал аналогичный вопрос несколько дней назад, но это была отдельная проблема.
Компилировать сcl /std:c++20 /EHsc main.cpp
, ожидает путь к файлу для предварительного просмотра в качестве первого параметра командной строки. Поскольку я немного использовал winrt, для этого требуется Windows 10.
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "WindowsApp.lib")
#pragma comment(lib, "Ole32.lib")
#include <iostream>
#include <string>
#include <string_view>
#include <array>
#include <filesystem>
#include <Windows.h>
#include <shlwapi.h>
#include <winrt/base.h>
#include <ShObjIdl.h>
class Preview{
winrt::com_ptr<IPreviewHandler> mPreviewHandler;
bool mIsActive = false;
bool mIsInitialized = false;
std::filesystem::path mFilePath;
HWND mHwnd;
RECT mRect;
public:
Preview(const std::filesystem::path& filePath, const HWND hwnd, const RECT& rect):
mFilePath(filePath), mHwnd(hwnd), mRect(rect){
createPreviewHandler();
initialize();
};
void setRect(const RECT& rect){
mPreviewHandler->SetRect(&rect);
mRect = rect;
}
void setWindow(const HWND hwnd, const RECT& rect){
mPreviewHandler->SetWindow(hwnd, &rect);
mHwnd = hwnd;
setRect(rect);
}
void startPreview(){
if(!mIsActive){
if(!mIsInitialized){
initialize();
}
mPreviewHandler->DoPreview();
setRect(mRect);
mIsActive = true;
}
}
void stopPreview(){
if(mIsActive){
mPreviewHandler->Unload();
mIsActive = false;
mIsInitialized = false;
}
}
private:
void createPreviewHandler(){
CLSID previewHandlerId = getShellExClsidForType(mFilePath.extension());
mPreviewHandler.capture(CoCreateInstance, previewHandlerId, nullptr, CLSCTX_LOCAL_SERVER);
}
CLSID getShellExClsidForType(const std::wstring& extension){
winrt::hresult res;
DWORD size;
std::array<wchar_t, 39> interfaceIdWstr;
size = StringFromGUID2(IID_IPreviewHandler, interfaceIdWstr.data(), interfaceIdWstr.size());
if(!size){
winrt::throw_hresult(HRESULT_FROM_WIN32(GetLastError()));
}
std::array<wchar_t, 39> exIdWstr;
res = AssocQueryStringW(ASSOCF_INIT_DEFAULTTOSTAR,
ASSOCSTR_SHELLEXTENSION,
extension.c_str(),
interfaceIdWstr.data(),
exIdWstr.data(),
&size);
winrt::check_hresult(res);
CLSID exId;
res = IIDFromString(exIdWstr.data(), &exId);
winrt::check_hresult(res);
return(exId);
}
void initialize(){
initializeFromPath(mFilePath);
setWindow(mHwnd, mRect);
mIsInitialized = true;
}
void initializeFromPath(const std::filesystem::path& filePath){
if(!initWithFile(filePath) && !initWithStream(filePath)){
winrt::throw_hresult(E_NOINTERFACE);
}
}
bool initWithFile(const std::filesystem::path& filePath){
if(!mPreviewHandler.try_as<IInitializeWithFile>()){
return(false);
}
winrt::check_hresult(mPreviewHandler.as<IInitializeWithFile>()->Initialize(filePath.c_str(), STGM_READ));
return(true);
}
bool initWithStream(const std::filesystem::path& filePath){
if(!mPreviewHandler.try_as<IInitializeWithStream>()){
return(false);
}
winrt::com_ptr<IStream> stream;
stream.capture([](LPCWSTR pszFile, DWORD grfMode, REFIID riid, void **ppstm)
{return(SHCreateStreamOnFileEx(pszFile, grfMode, 0, false, nullptr, reinterpret_cast<IStream**>(ppstm)));},
filePath.c_str(), STGM_READ | STGM_SHARE_DENY_WRITE | STGM_FAILIFTHERE);
winrt::check_hresult(mPreviewHandler.as<IInitializeWithStream>()->Initialize(stream.get(), STGM_READ));
return(true);
}
};
HMODULE getCurrentModule(){
HMODULE hModule;
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(LPCTSTR)getCurrentModule,
&hModule);
return(hModule);
}
LRESULT windowProc(HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam){
LPARAM ret = 0;
switch(msg){
case WM_CLOSE:
{
PostQuitMessage(0);
ret = 0;
}break;
default:
{
ret = DefWindowProc(hwnd, msg, wParam, lParam);
}break;
}
return(ret);
}
HWND createTestWindow(){
WNDCLASSW wndClass;
wndClass.style = 0;
wndClass.lpfnWndProc = windowProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = getCurrentModule();
wndClass.hIcon = nullptr;
wndClass.hCursor = nullptr;
wndClass.hbrBackground = nullptr;
wndClass.lpszMenuName = nullptr;
wndClass.lpszClassName = L"test";
ATOM wndAtom = RegisterClassW(&wndClass);
if(!wndAtom){
winrt::throw_hresult(HRESULT_FROM_WIN32(GetLastError()));
}
HWND window = CreateWindowExW(0,
L"Test",
L"",
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
0,
0,
wndClass.hInstance,
nullptr);
if(!window){
winrt::throw_hresult(HRESULT_FROM_WIN32(GetLastError()));
}
ShowWindow(window, SW_NORMAL);
return(window);
}
int main(int argc, char *argv[]){
try{
winrt::check_hresult(CoInitialize(nullptr));
if(!SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)){
winrt::throw_hresult(E_FAIL);
}
if(argc != 2){
return(1);
}
std::filesystem::path filePath(argv[1]);
HWND window = createTestWindow();
RECT rect;
GetClientRect(window, &rect);
Preview preview(filePath, window, rect);
preview.startPreview();
MSG msg;
while(GetMessageW(&msg, nullptr, 0, 0) != 0){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}catch(winrt::hresult_error err){
std::wcout << "0x" << std::hex << err.code() << " " << static_cast<std::wstring_view>(err.message());
}catch(...){}
}
1 ответ
ВызовGetFullPathName
наargv[1]
. Функции оболочки не могут анализировать относительный путь в pidl.