diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /shell/source/win32/shlxthandler | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream/4%7.4.7.tar.xz libreoffice-upstream/4%7.4.7.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'shell/source/win32/shlxthandler')
33 files changed, 5849 insertions, 0 deletions
diff --git a/shell/source/win32/shlxthandler/classfactory.cxx b/shell/source/win32/shlxthandler/classfactory.cxx new file mode 100644 index 000000000..95da69252 --- /dev/null +++ b/shell/source/win32/shlxthandler/classfactory.cxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <global.hxx> +#include "classfactory.hxx" +#include <infotips.hxx> +#include <propsheets.hxx> +#include <columninfo.hxx> +#include <thumbviewer.hxx> +#include <shlxthdl.hxx> + + +LONG CClassFactory::s_ServerLocks = 0; + + +CClassFactory::CClassFactory(const CLSID& clsid) : + m_RefCnt(1), + m_Clsid(clsid) +{ + InterlockedIncrement(&g_DllRefCnt); +} + + +CClassFactory::~CClassFactory() +{ + InterlockedDecrement(&g_DllRefCnt); +} + + +// IUnknown methods + + +HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = nullptr; + + if (IID_IUnknown == riid || IID_IClassFactory == riid) + { + IUnknown* pUnk = this; + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + + return E_NOINTERFACE; +} + + +ULONG STDMETHODCALLTYPE CClassFactory::AddRef() +{ + return InterlockedIncrement(&m_RefCnt); +} + + +ULONG STDMETHODCALLTYPE CClassFactory::Release() +{ + LONG refcnt = InterlockedDecrement(&m_RefCnt); + + if (0 == refcnt) + delete this; + + return refcnt; +} + + +// IClassFactory methods + + +HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance( + IUnknown __RPC_FAR *pUnkOuter, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + if (pUnkOuter != nullptr) + return CLASS_E_NOAGGREGATION; + + IUnknown* pUnk = nullptr; + + if (CLSID_PROPERTYSHEET_HANDLER == m_Clsid) + pUnk = static_cast<IShellExtInit*>(new CPropertySheet()); + + else if (CLSID_INFOTIP_HANDLER == m_Clsid) + pUnk = static_cast<IQueryInfo*>(new CInfoTip()); + + else if (CLSID_COLUMN_HANDLER == m_Clsid) + pUnk = new CColumnInfo(); + + else if (CLSID_THUMBVIEWER_HANDLER == m_Clsid) + pUnk = static_cast<IExtractImage*>(new CThumbviewer()); + + if (nullptr == pUnk) + { + return E_OUTOFMEMORY; + } + + HRESULT hr = pUnk->QueryInterface(riid, ppvObject); + + // if QueryInterface failed the component will destroy itself + pUnk->Release(); + + return hr; +} + + +HRESULT STDMETHODCALLTYPE CClassFactory::LockServer(BOOL fLock) +{ + if (fLock) + InterlockedIncrement(&s_ServerLocks); + else + InterlockedDecrement(&s_ServerLocks); + + return S_OK; +} + + +bool CClassFactory::IsLocked() +{ + return (s_ServerLocks > 0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/classfactory.hxx b/shell/source/win32/shlxthandler/classfactory.hxx new file mode 100644 index 000000000..8dd01aa0e --- /dev/null +++ b/shell/source/win32/shlxthandler/classfactory.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_CLASSFACTORY_HXX +#define INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_CLASSFACTORY_HXX + +#include <objidl.h> + +class CClassFactory : public IClassFactory +{ +public: + explicit CClassFactory(const CLSID& clsid); + virtual ~CClassFactory(); + + + // IUnknown methods + + + virtual HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) override; + + virtual ULONG STDMETHODCALLTYPE AddRef() override; + + virtual ULONG STDMETHODCALLTYPE Release() override; + + + // IClassFactory methods + + + virtual HRESULT STDMETHODCALLTYPE CreateInstance( + IUnknown __RPC_FAR *pUnkOuter, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) override; + + virtual HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) override; + + static bool IsLocked(); + +private: + LONG m_RefCnt; + CLSID m_Clsid; + + static LONG s_ServerLocks; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/columninfo/columninfo.cxx b/shell/source/win32/shlxthandler/columninfo/columninfo.cxx new file mode 100644 index 000000000..81393140d --- /dev/null +++ b/shell/source/win32/shlxthandler/columninfo/columninfo.cxx @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <global.hxx> +#include <columninfo.hxx> +#include <fileextensions.hxx> +#include <metainforeader.hxx> +#include <utilities.hxx> +#include <config.hxx> + +#include <sal/macros.h> +#include <malloc.h> + +namespace /* private */ +{ + const SHCOLUMNINFO ColumnInfoTable[] = + { + {{PSGUID_SUMMARYINFORMATION, PIDSI_TITLE}, VT_BSTR, LVCFMT_LEFT, 30, SHCOLSTATE_TYPE_STR, L"Title", L"Title"}, + {{PSGUID_SUMMARYINFORMATION, PIDSI_AUTHOR}, VT_BSTR, LVCFMT_LEFT, 30, SHCOLSTATE_TYPE_STR, L"Author", L"Author"}, + {{PSGUID_SUMMARYINFORMATION, PIDSI_SUBJECT}, VT_BSTR, LVCFMT_LEFT, 30, SHCOLSTATE_TYPE_STR, L"Subject", L"Subject"}, + {{PSGUID_SUMMARYINFORMATION, PIDSI_KEYWORDS}, VT_BSTR, LVCFMT_LEFT, 30, SHCOLSTATE_TYPE_STR, L"Keywords", L"Keywords"}, + {{PSGUID_SUMMARYINFORMATION, PIDSI_COMMENTS}, VT_BSTR, LVCFMT_LEFT, 30, SHCOLSTATE_TYPE_STR, L"Comments", L"Comments"}, + {{PSGUID_SUMMARYINFORMATION, PIDSI_PAGECOUNT},VT_BSTR, LVCFMT_LEFT, 30, SHCOLSTATE_TYPE_STR, L"Pagecount", L"Pagecount"} + }; + + size_t ColumnInfoTableSize = SAL_N_ELEMENTS(ColumnInfoTable); + +bool IsOOFileExtension(wchar_t const * Extension) +{ + for (size_t i = 0; i < OOFileExtensionTableSize; i++) + { + if (0 == _wcsicmp(Extension, OOFileExtensionTable[i].ExtensionU)) + return true; + } + + return false; +} + +} + + +CColumnInfo::CColumnInfo(LONG RefCnt) : + m_RefCnt(RefCnt) +{ + InterlockedIncrement(&g_DllRefCnt); +} + + +CColumnInfo::~CColumnInfo() +{ + InterlockedDecrement(&g_DllRefCnt); +} + + +// IUnknown methods + + +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CColumnInfo::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = nullptr; + + if (IID_IUnknown == riid || IID_IColumnProvider == riid) + { + IUnknown* pUnk = this; + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + + return E_NOINTERFACE; +} + + +COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE CColumnInfo::AddRef() +{ + return InterlockedIncrement(&m_RefCnt); +} + + +COM_DECLSPEC_NOTHROW ULONG STDMETHODCALLTYPE CColumnInfo::Release() +{ + LONG refcnt = InterlockedDecrement(&m_RefCnt); + + if (0 == m_RefCnt) + delete this; + + return refcnt; +} + + +// IColumnProvider + + +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CColumnInfo::Initialize(LPCSHCOLUMNINIT /*psci*/) +{ + return S_OK; +} + +// Register all columns we support +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CColumnInfo::GetColumnInfo(DWORD dwIndex, SHCOLUMNINFO *psci) +{ + if (dwIndex >= ColumnInfoTableSize) + return S_FALSE; + + // Return information on each column we support. Return S_FALSE + // to indicate that we have returned information on all our + // columns. GetColumnInfo will be called repeatedly until S_FALSE + // or an error is returned + psci->scid.fmtid = ColumnInfoTable[dwIndex].scid.fmtid; + psci->scid.pid = ColumnInfoTable[dwIndex].scid.pid; + ZeroMemory(psci->wszTitle, sizeof(psci->wszTitle)); + wcsncpy(psci->wszTitle, ColumnInfoTable[dwIndex].wszTitle, + SAL_N_ELEMENTS(psci->wszTitle) - 1); + + return S_OK; +} + +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CColumnInfo::GetItemData(LPCSHCOLUMNID pscid, LPCSHCOLUMNDATA pscd, VARIANT *pvarData) +{ + if (IsOOFileExtension(pscd->pwszExt)) + { + try + { + std::wstring fname = getShortPathName( std::wstring( pscd->wszFile ) ); + + CMetaInfoReader meta_info_accessor(fname); + + VariantClear(pvarData); + + if (IsEqualGUID (pscid->fmtid, FMTID_SummaryInformation) && pscid->pid == PIDSI_TITLE) + { + pvarData->vt = VT_BSTR; + pvarData->bstrVal = SysAllocString(meta_info_accessor.getTagData( META_INFO_TITLE ).c_str()); + + return S_OK; + } + else if (IsEqualGUID (pscid->fmtid, FMTID_SummaryInformation) && pscid->pid == PIDSI_AUTHOR) + { + pvarData->vt = VT_BSTR; + pvarData->bstrVal = SysAllocString(meta_info_accessor.getTagData( META_INFO_AUTHOR).c_str()); + + return S_OK; + } + else if (IsEqualGUID (pscid->fmtid, FMTID_SummaryInformation) && pscid->pid == PIDSI_SUBJECT) + { + pvarData->vt = VT_BSTR; + pvarData->bstrVal = SysAllocString(meta_info_accessor.getTagData( META_INFO_SUBJECT).c_str()); + + return S_OK; + } + else if (IsEqualGUID (pscid->fmtid, FMTID_SummaryInformation) && pscid->pid == PIDSI_KEYWORDS) + { + pvarData->vt = VT_BSTR; + pvarData->bstrVal = SysAllocString(meta_info_accessor.getTagData( META_INFO_KEYWORDS).c_str()); + + return S_OK; + } + else if (IsEqualGUID (pscid->fmtid, FMTID_SummaryInformation) && pscid->pid == PIDSI_COMMENTS) + { + pvarData->vt = VT_BSTR; + pvarData->bstrVal = SysAllocString(meta_info_accessor.getTagData( META_INFO_DESCRIPTION).c_str()); + + return S_OK; + } + else if (IsEqualGUID (pscid->fmtid, FMTID_SummaryInformation) && pscid->pid == PIDSI_PAGECOUNT) + { + pvarData->vt = VT_BSTR; + pvarData->bstrVal = SysAllocString(meta_info_accessor.getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES).c_str()); + + return S_OK; + } + } + catch (const std::exception&) + { + return S_FALSE; + } + } + + return S_FALSE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/infotips/infotips.cxx b/shell/source/win32/shlxthandler/infotips/infotips.cxx new file mode 100644 index 000000000..af03f4a32 --- /dev/null +++ b/shell/source/win32/shlxthandler/infotips/infotips.cxx @@ -0,0 +1,365 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <global.hxx> +#include <infotips.hxx> +#include <shlxthdl.hxx> +#include <metainforeader.hxx> +#include <contentreader.hxx> +#include <utilities.hxx> +#include <registry.hxx> +#include <fileextensions.hxx> +#include <iso8601_converter.hxx> +#include <config.hxx> + +#include <resource.h> +#include <stdio.h> +#include <utility> +#include <stdlib.h> + + +#define MAX_STRING 80 +#define KB 1024.0 +const std::wstring WSPACE(SPACE); + + +CInfoTip::CInfoTip(LONG RefCnt) : + m_RefCnt(RefCnt) +{ + ZeroMemory(m_szFileName, sizeof(m_szFileName)); + InterlockedIncrement(&g_DllRefCnt); +} + + +CInfoTip::~CInfoTip() +{ + InterlockedDecrement(&g_DllRefCnt); +} + + +// IUnknown methods + + +HRESULT STDMETHODCALLTYPE CInfoTip::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = nullptr; + + IUnknown* pUnk = nullptr; + + if (IID_IUnknown == riid || IID_IQueryInfo == riid) + { + pUnk = static_cast<IQueryInfo*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + else if (IID_IPersistFile == riid) + { + pUnk = static_cast<IPersistFile*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + + return E_NOINTERFACE; +} + + +ULONG STDMETHODCALLTYPE CInfoTip::AddRef() +{ + return InterlockedIncrement(&m_RefCnt); +} + + +ULONG STDMETHODCALLTYPE CInfoTip::Release() +{ + LONG refcnt = InterlockedDecrement(&m_RefCnt); + + if (0 == m_RefCnt) + delete this; + + return refcnt; +} + +//********************helper functions for GetInfoTip functions********************** + +/** get file type information from registry. +*/ +static std::wstring getFileTypeInfo(const std::wstring& file_extension) +{ + wchar_t extKeyValue[MAX_STRING]; + wchar_t typeKeyValue[MAX_STRING]; + ::std::wstring sDot(L"."); + if (QueryRegistryKey(HKEY_CLASSES_ROOT, sDot.append(file_extension).c_str(), L"", extKeyValue, MAX_STRING)) + if (QueryRegistryKey( HKEY_CLASSES_ROOT, extKeyValue, L"",typeKeyValue, MAX_STRING)) + return typeKeyValue; + + return EMPTY_STRING; +} + +/** get file size. +*/ +static DWORD getSizeOfFile( wchar_t const * FileName ) +{ + HANDLE hFile = CreateFileW(FileName, // open file + GENERIC_READ, // open for reading + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, // share for all operations + nullptr, // no security + OPEN_EXISTING, // existing file only + FILE_ATTRIBUTE_NORMAL, // normal file + nullptr); // no attr. template + + if (hFile != INVALID_HANDLE_VALUE) + { + DWORD dwSize = GetFileSize( hFile, nullptr ); + CloseHandle( hFile ); + return dwSize; + } + + return INVALID_FILE_SIZE; +} + +/** format file size in to be more readable. +*/ +static std::wstring formatSizeOfFile( DWORD dwSize ) +{ + if ( dwSize < 1000 ) + { + char buffer[3]; + int dFileSize = dwSize; + + _itoa( dFileSize, buffer, 10 ); + return StringToWString( buffer ).append(StringToWString("B")); + } + + char *buffer=nullptr; + int decimal, sign; + double dFileSize = static_cast<double>(dwSize)/KB; + + buffer = _fcvt( dFileSize, 1, &decimal, &sign ); + + ::std::wstring wsTemp = StringToWString( buffer ); + int pos=decimal % 3; + ::std::wstring wsBuffer = wsTemp.substr( 0,pos); + + if ( decimal ) + for (;decimal - pos > 2;pos += 3) + { + if (pos) + wsBuffer.append(StringToWString(",")); + wsBuffer.append( wsTemp.substr( pos, 3) ); + } + else + wsBuffer.append(StringToWString("0")); + + wsBuffer.append(StringToWString(".")); + wsBuffer.append(wsTemp.substr( decimal, wsTemp.size()-decimal )); + wsBuffer.append(StringToWString("KB")); + + return wsBuffer; +} + + +/** get file size information. +*/ +static std::wstring getFileSizeInfo(wchar_t const * FileName) +{ + DWORD dwSize=getSizeOfFile(FileName); + if (dwSize != INVALID_FILE_SIZE) + return formatSizeOfFile( dwSize ); + + return EMPTY_STRING; +} + + +// IQueryInfo methods + + +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CInfoTip::GetInfoTip(DWORD /*dwFlags*/, PWSTR* ppwszTip) +{ + std::wstring msg; + const std::wstring CONST_SPACE(SPACE); + + //display File Type, no matter other info is loaded successfully or not. + std::wstring tmpTypeStr = getFileTypeInfo( get_file_name_extension(m_szFileName) ); + if ( tmpTypeStr != EMPTY_STRING ) + { + msg += GetResString(IDS_TYPE_COLON) + CONST_SPACE; + msg += tmpTypeStr; + } + + try + { + CMetaInfoReader meta_info_accessor(m_szFileName); + + //display document title; + if ( meta_info_accessor.getTagData( META_INFO_TITLE ).length() > 0) + { + if ( msg != EMPTY_STRING ) + msg += L"\n"; + msg += GetResString(IDS_TITLE_COLON) + CONST_SPACE; + msg += meta_info_accessor.getTagData( META_INFO_TITLE ); + } + else + { + if ( msg != EMPTY_STRING ) + msg += L"\n"; + msg += GetResString(IDS_TITLE_COLON) + CONST_SPACE; + msg += m_FileNameOnly; + } + + //display document author; + if ( meta_info_accessor.getTagData( META_INFO_AUTHOR ).length() > 0) + { + if ( msg != EMPTY_STRING ) + msg += L"\n"; + msg += GetResString( IDS_AUTHOR_COLON ) + CONST_SPACE; + msg += meta_info_accessor.getTagData( META_INFO_AUTHOR ); + } + + //display document subject; + if ( meta_info_accessor.getTagData( META_INFO_SUBJECT ).length() > 0) + { + if ( msg != EMPTY_STRING ) + msg += L"\n"; + msg += GetResString(IDS_SUBJECT_COLON) + CONST_SPACE; + msg += meta_info_accessor.getTagData( META_INFO_SUBJECT ); + } + + //display document description; + if ( meta_info_accessor.getTagData( META_INFO_DESCRIPTION ).length() > 0) + { + if ( msg != EMPTY_STRING ) + msg += L"\n"; + msg += GetResString( IDS_COMMENTS_COLON ) + CONST_SPACE; + msg += meta_info_accessor.getTagData( META_INFO_DESCRIPTION ); + } + + //display modified time formatted into locale representation. + if ( iso8601_date_to_local_date(meta_info_accessor.getTagData(META_INFO_MODIFIED )).length() > 0) + { + if ( msg != EMPTY_STRING ) + msg += L"\n"; + msg += GetResString( IDS_MODIFIED_COLON ) + CONST_SPACE; + msg += iso8601_date_to_local_date(meta_info_accessor.getTagData(META_INFO_MODIFIED )); + } + } + catch (const std::exception&) + { + } + + //display file size, no matter other information is loaded successfully or not. + std::wstring tmpSizeStr = getFileSizeInfo( m_szFileName ); + if ( tmpSizeStr != EMPTY_STRING ) + { + msg += L"\n"; + msg += GetResString( IDS_SIZE_COLON ) + CONST_SPACE; + msg += tmpSizeStr; + } + + + //finalize and assign the string. + LPMALLOC lpMalloc; + HRESULT hr = SHGetMalloc(&lpMalloc); + + if (SUCCEEDED(hr)) + { + size_t len = sizeof(wchar_t) * msg.length() + sizeof(wchar_t); + wchar_t* pMem = static_cast<wchar_t*>(lpMalloc->Alloc(len)); + + ZeroMemory(pMem, len); + + wcscpy_s(pMem, msg.length()+1, msg.c_str()); + + *ppwszTip = pMem; + lpMalloc->Release(); + + return S_OK; + } + + return E_FAIL; +} + + +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CInfoTip::GetInfoFlags(DWORD * /*pdwFlags*/ ) +{ + return E_NOTIMPL; +} + + +// IPersist methods + + +HRESULT STDMETHODCALLTYPE CInfoTip::GetClassID(CLSID* pClassID) +{ + *pClassID = CLSID_INFOTIP_HANDLER; + return S_OK; +} + + +// IPersistFile methods + + +HRESULT STDMETHODCALLTYPE CInfoTip::Load(LPCOLESTR pszFileName, DWORD /*dwMode*/) +{ + std::wstring fname = pszFileName; + + // there must be a '\' and there must even be an + // extension, else we would not have been called + std::wstring::iterator begin = fname.begin() + fname.find_last_of(L"\\") + 1; + std::wstring::iterator end = fname.end(); + + m_FileNameOnly = std::wstring(begin, end); + + fname = getShortPathName( fname ); + + // ZeroMemory because strncpy doesn't '\0'-terminates the destination + // string; reserve the last place in the buffer for the final '\0' + // that's why '(sizeof(m_szFileName) - 1)' + ZeroMemory(m_szFileName, sizeof(m_szFileName)); + wcsncpy(m_szFileName, fname.c_str(), (sizeof(m_szFileName)/sizeof(*m_szFileName) - 1)); + + return S_OK; +} + + +HRESULT STDMETHODCALLTYPE CInfoTip::IsDirty() +{ + return E_NOTIMPL; +} + + +HRESULT STDMETHODCALLTYPE CInfoTip::Save(LPCOLESTR /*pszFileName*/, BOOL /*fRemember*/) +{ + return E_NOTIMPL; +} + + +HRESULT STDMETHODCALLTYPE CInfoTip::SaveCompleted(LPCOLESTR /*pszFileName*/) +{ + return E_NOTIMPL; +} + + +HRESULT STDMETHODCALLTYPE CInfoTip::GetCurFile(LPOLESTR __RPC_FAR * /*ppszFileName*/) +{ + return E_NOTIMPL; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx b/shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx new file mode 100644 index 000000000..c45c69930 --- /dev/null +++ b/shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx @@ -0,0 +1,956 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +// File: ooofilt.cxx +// Contents: Filter Implementation for OpenOffice.Org Document using +// Indexing Service +// Summary: The LibreOffice filter reads OpenOffice.org XML files (with +// the extension .sxw .sxi, etc) and ODF files and extract +// their content, author, keywords,subject,comments and title +// to be filtered. + +// Platform: Windows 2000, Windows XP + +#include <contentreader.hxx> +#include <metainforeader.hxx> +#include <registry.hxx> +#include <fileextensions.hxx> + + +// Include file Purpose +// windows.h Win32 declarations +// string.h string wstring declarations +// filter.h IFilter interface declarations +// filterr.h FACILITY_ITF error definitions for IFilter +// ntquery.h Indexing Service declarations +// assert.h assertion function. +// ooofilt.hxx LibreOffice filter declarations +// propspec.hxx PROPSPEC + + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#include <string.h> +#include <filter.h> +#include <filterr.h> +#include <ntquery.h> +#include <assert.h> +#include "ooofilt.hxx" +#include <objidl.h> +#include <stdio.h> +#include "propspec.hxx" + +#include <stream_helper.hxx> + +#include <olectl.h> // declarations of DllRegisterServer/DllUnregisterServer + +//C------------------------------------------------------------------------- +// Class: COooFilter +// Summary: Implements LibreOffice filter class + +//M------------------------------------------------------------------------- +// Method: COooFilter::COooFilter +// Summary: Class constructor +// Arguments: void +// Purpose: Manages global instance count + +COooFilter::COooFilter() : + m_lRefs(1), + m_pContentReader(nullptr), + m_pMetaInfoReader(nullptr), + m_eState(FilterState::FilteringContent), + m_ulUnicodeBufferLen(0), + m_ulUnicodeCharsRead(0), + m_ulPropertyNum(0), + m_ulCurrentPropertyNum(0), + m_ulChunkID(1), + m_fContents(false), + m_fEof(false), + m_ChunkPosition(0), + m_cAttributes(0), + m_pAttributes(nullptr), + m_pStream(nullptr) + +{ + InterlockedIncrement( &g_lInstances ); +} +//M------------------------------------------------------------------------- +// Method: COooFilter::~COooFilter +// Summary: Class destructor +// Arguments: void +// Purpose: Manages global instance count and file handle + +COooFilter::~COooFilter() +{ + delete [] m_pAttributes; + delete m_pContentReader; + delete m_pMetaInfoReader; + delete m_pStream; + + InterlockedDecrement( &g_lInstances ); +} + +//M------------------------------------------------------------------------- +// Method: COooFilter::QueryInterface (IUnknown::QueryInterface) +// Summary: Queries for requested interface // Arguments: riid +// [in] Reference IID of requested interface +// ppvObject +// [out] Address that receives requested interface pointer +// Returns: S_OK +// Interface is supported +// E_NOINTERFACE +// Interface is not supported + +HRESULT STDMETHODCALLTYPE COooFilter::QueryInterface( + REFIID riid, + void ** ppvObject) +{ + IUnknown *pUnkTemp = nullptr; + if ( IID_IFilter == riid ) + pUnkTemp = static_cast<IFilter *>(this); + else if ( IID_IPersistFile == riid ) + pUnkTemp = static_cast<IPersistFile *>(this); + else if ( IID_IPersist == riid ) + pUnkTemp = static_cast<IPersistFile *>(this); + else if (IID_IPersistStream == riid) + pUnkTemp = static_cast<IPersistStream *>(this); + else if ( IID_IUnknown == riid ) + pUnkTemp = static_cast<IPersistFile *>(this); + else + { + *ppvObject = nullptr; + return E_NOINTERFACE; + } + *ppvObject = pUnkTemp; + pUnkTemp->AddRef(); + return S_OK; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::AddRef (IUnknown::AddRef) +// Summary: Increments interface refcount +// Arguments: void +// Returns: Value of incremented interface refcount + +ULONG STDMETHODCALLTYPE COooFilter::AddRef() +{ + return InterlockedIncrement( &m_lRefs ); +} +//M------------------------------------------------------------------------- +// Method: COooFilter::Release (IUnknown::Release) +// Summary: Decrements interface refcount, deleting if unreferenced +// Arguments: void +// Returns: Value of decremented interface refcount + +ULONG STDMETHODCALLTYPE COooFilter::Release() +{ + ULONG ulTmp = InterlockedDecrement( &m_lRefs ); + + if ( 0 == ulTmp ) + delete this; + return ulTmp; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::Init (IFilter::Init) +// Summary: Initializes LibreOffice filter instance +// Arguments: grfFlags +// [in] Flags for filter behavior +// cAttributes +// [in] Number attributes in array aAttributes +// aAttributes +// [in] Array of requested attribute strings +// pFlags +// [out] Pointer to return flags for additional properties +// Returns: S_OK +// Initialization succeeded +// E_FAIL +// File not previously loaded +// E_INVALIDARG +// Count and contents of attributes do not agree +// FILTER_E_ACCESS +// Unable to access file to be filtered +// FILTER_E_PASSWORD +// (not implemented) + +const int COUNT_ATTRIBUTES = 5; + +SCODE STDMETHODCALLTYPE COooFilter::Init( + ULONG grfFlags, + ULONG cAttributes, + FULLPROPSPEC const * aAttributes, + ULONG * pFlags) +{ + // Enumerate OLE properties, since any NTFS file can have them + *pFlags = IFILTER_FLAGS_OLE_PROPERTIES; + try + { + m_fContents = false; + m_ulPropertyNum = 0; + m_ulCurrentPropertyNum = 0; + if ( m_cAttributes > 0 ) + { + delete[] m_pAttributes; + m_pAttributes = nullptr; + m_cAttributes = 0; + } + if( 0 < cAttributes ) + { + // Filter properties specified in aAttributes + if ( nullptr == aAttributes ) + return E_INVALIDARG; + m_pAttributes = new CFullPropSpec[cAttributes]; + m_cAttributes = cAttributes; + // Is caller want to filter contents? + CFullPropSpec const *pAttrib = reinterpret_cast<CFullPropSpec const *>(aAttributes); + ULONG ulNumAttr; + for ( ulNumAttr = 0 ; ulNumAttr < cAttributes; ulNumAttr++ ) + { + if ( pAttrib[ulNumAttr].IsPropertyPropid() && + pAttrib[ulNumAttr].GetPropertyPropid() == PID_STG_CONTENTS && + pAttrib[ulNumAttr].GetPropSet() == guidStorage ) + { + m_fContents = true; + } + // save the requested properties. + m_pAttributes[ulNumAttr] = pAttrib[ulNumAttr]; + } + } + else if ( grfFlags & IFILTER_INIT_APPLY_INDEX_ATTRIBUTES ) + { + // Filter contents and all pseudo-properties + m_fContents = true; + + m_pAttributes = new CFullPropSpec[COUNT_ATTRIBUTES]; + m_cAttributes = COUNT_ATTRIBUTES; + m_pAttributes[0].SetPropSet( FMTID_SummaryInformation ); + m_pAttributes[0].SetProperty( PIDSI_AUTHOR ); + m_pAttributes[1].SetPropSet( FMTID_SummaryInformation ); + m_pAttributes[1].SetProperty( PIDSI_TITLE ); + m_pAttributes[2].SetPropSet( FMTID_SummaryInformation ); + m_pAttributes[2].SetProperty( PIDSI_SUBJECT ); + m_pAttributes[3].SetPropSet( FMTID_SummaryInformation ); + m_pAttributes[3].SetProperty( PIDSI_KEYWORDS ); + m_pAttributes[4].SetPropSet( FMTID_SummaryInformation ); + m_pAttributes[4].SetProperty( PIDSI_COMMENTS ); + } + else if ( 0 == grfFlags ) + { + // Filter only contents + m_fContents = true; + } + else + m_fContents = false; + // Re-initialize + if ( m_fContents ) + { + m_fEof = false; + m_eState = FilterState::FilteringContent; + m_ulUnicodeCharsRead = 0; + m_ChunkPosition = 0; + } + else + { + m_fEof = true; + m_eState = FilterState::FilteringProperty; + } + m_ulChunkID = 1; + } + catch (const std::exception&) + { + return E_FAIL; + } + + return S_OK; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::GetChunk (IFilter::GetChunk) +// Summary: Gets the next chunk +// Arguments: ppStat +// [out] Pointer to description of current chunk +// Returns: S_OK +// Chunk was successfully retrieved +// E_FAIL +// Character conversion failed +// FILTER_E_ACCESS +// General access failure occurred +// FILTER_E_END_OF_CHUNKS +// Previous chunk was the last chunk +// FILTER_E_EMBEDDING_UNAVAILABLE +// (not implemented) +// FILTER_E_LINK_UNAVAILABLE +// (not implemented) +// FILTER_E_PASSWORD +// (not implemented) + +SCODE STDMETHODCALLTYPE COooFilter::GetChunk(STAT_CHUNK * pStat) +{ + for(;;) + { + switch ( m_eState ) + { + case FilterState::FilteringContent: + { + if( m_ChunkPosition == m_pContentReader ->getChunkBuffer().size() ) + { + m_ulUnicodeBufferLen=0; + m_fEof = true; + } + + if ( !m_fContents || m_fEof ) + { + m_eState = FilterState::FilteringProperty; + continue; + } + m_pwsBuffer = m_pContentReader -> getChunkBuffer()[m_ChunkPosition].second; + m_ulUnicodeBufferLen = static_cast<ULONG>(m_pwsBuffer.length()); + DWORD ChunkLCID = LocaleSetToLCID( m_pContentReader -> getChunkBuffer()[m_ChunkPosition].first ); + // Set chunk description + pStat->idChunk = m_ulChunkID; + pStat->breakType = CHUNK_NO_BREAK; + pStat->flags = CHUNK_TEXT; + pStat->locale = ChunkLCID; + pStat->attribute.guidPropSet = guidStorage; + pStat->attribute.psProperty.ulKind = PRSPEC_PROPID; + pStat->attribute.psProperty.propid = PID_STG_CONTENTS; + pStat->idChunkSource = m_ulChunkID; + pStat->cwcStartSource = 0; + pStat->cwcLenSource = 0; + m_ulUnicodeCharsRead = 0; + m_ulChunkID++; + m_ChunkPosition++; + return S_OK; + } + case FilterState::FilteringProperty: + { + if ( m_cAttributes == 0 ) + return FILTER_E_END_OF_CHUNKS; + while( !( ( m_pAttributes[m_ulPropertyNum].IsPropertyPropid() ) && + ( m_pAttributes[m_ulPropertyNum].GetPropSet() == FMTID_SummaryInformation ) )|| + ( ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_AUTHOR ) && + ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_TITLE ) && + ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_SUBJECT ) && + ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_KEYWORDS ) && + ( m_pAttributes[m_ulPropertyNum].GetPropertyPropid() != PIDSI_COMMENTS ) ) ) + { + if ( m_ulPropertyNum < m_cAttributes ) + m_ulPropertyNum++; + else + break; + } + if ( m_ulPropertyNum == m_cAttributes) + return FILTER_E_END_OF_CHUNKS; + else + { + // Set chunk description + pStat->idChunk = m_ulChunkID; + pStat->breakType = CHUNK_EOS; + pStat->flags = CHUNK_VALUE; + pStat->locale = GetSystemDefaultLCID(); + pStat->attribute.guidPropSet = FMTID_SummaryInformation; + pStat->attribute.psProperty.ulKind = PRSPEC_PROPID; + pStat->attribute.psProperty.propid = m_pAttributes[m_ulPropertyNum].GetPropertyPropid(); + pStat->idChunkSource = m_ulChunkID; + pStat->cwcStartSource = 0; + pStat->cwcLenSource = 0; + m_ulCurrentPropertyNum = m_ulPropertyNum; + m_ulPropertyNum++; + m_ulChunkID++; + return S_OK; + } + } + }//switch(...) + }//for(;;) +} +//M------------------------------------------------------------------------- +// Method: COooFilter::GetText (IFilter::GetText) +// Summary: Retrieves UNICODE text for index +// Arguments: pcwcBuffer +// [in] Pointer to size of UNICODE buffer +// [out] Pointer to count of UNICODE characters returned +// awcBuffer +// [out] Pointer to buffer to receive UNICODE text +// Returns: S_OK +// Text successfully retrieved, but text remains in chunk +// FILTER_E_NO_MORE_TEXT +// All of the text in the current chunk has been returned +// FILTER_S_LAST_TEXT +// Next call to GetText will return FILTER_E_NO_MORE_TEXT + +SCODE STDMETHODCALLTYPE COooFilter::GetText(ULONG * pcwcBuffer, WCHAR * awcBuffer) +{ + switch ( m_eState ) + { + case FilterState::FilteringProperty: + return FILTER_E_NO_TEXT; + case FilterState::FilteringContent: + { + if ( !m_fContents || 0 == m_ulUnicodeBufferLen ) + { + *pcwcBuffer = 0; + return FILTER_E_NO_MORE_TEXT; + } + // Copy UNICODE characters in chunk buffer to output UNICODE buffer + ULONG ulToCopy = min( *pcwcBuffer, m_ulUnicodeBufferLen - m_ulUnicodeCharsRead ); + wmemcpy( awcBuffer, m_pwsBuffer.c_str() + m_ulUnicodeCharsRead, ulToCopy ); + ZeroMemory( + awcBuffer + ulToCopy, (*pcwcBuffer - ulToCopy) * sizeof (WCHAR)); + m_ulUnicodeCharsRead += ulToCopy; + *pcwcBuffer = ulToCopy; + if ( m_ulUnicodeBufferLen == m_ulUnicodeCharsRead ) + { + m_ulUnicodeCharsRead = 0; + m_ulUnicodeBufferLen = 0; + return FILTER_S_LAST_TEXT; + } + return S_OK; + } + } + return E_FAIL; // Should not happen! +} +//M------------------------------------------------------------------------- +// Method: GetMetaInfoNameFromPropertyId +// Summary: helper function to convert PropertyID into respective +// MetaInfo names. +// Arguments: ulPropID +// [in] property ID +// Returns: corresponding metainfo names. + + +static ::std::wstring GetMetaInfoNameFromPropertyId( ULONG ulPropID ) +{ + switch ( ulPropID ) + { + case PIDSI_AUTHOR: return META_INFO_AUTHOR; + case PIDSI_TITLE: return META_INFO_TITLE; + case PIDSI_SUBJECT: return META_INFO_SUBJECT; + case PIDSI_KEYWORDS: return META_INFO_KEYWORDS; + case PIDSI_COMMENTS: return META_INFO_DESCRIPTION; + default: return EMPTY_STRING; + } +} +//M------------------------------------------------------------------------- +// Method: COooFilter::GetValue (IFilter::GetValue) +// Summary: Retrieves properties for index +// Arguments: ppPropValue +// [out] Address that receives pointer to property value +// Returns: FILTER_E_NO_VALUES +// Always +// FILTER_E_NO_MORE_VALUES +// (not implemented) + + +SCODE STDMETHODCALLTYPE COooFilter::GetValue(PROPVARIANT ** ppPropValue) +{ + if (m_eState == FilterState::FilteringContent) + return FILTER_E_NO_VALUES; + else // m_eState == FilteringProperty + { + if ( m_cAttributes == 0 || ( m_ulCurrentPropertyNum == m_ulPropertyNum ) ) + return FILTER_E_NO_MORE_VALUES; + PROPVARIANT *pPropVar = static_cast<PROPVARIANT *>(CoTaskMemAlloc( sizeof (PROPVARIANT) )); + if ( pPropVar == nullptr ) + return E_OUTOFMEMORY; + ::std::wstring wsTagName= GetMetaInfoNameFromPropertyId( m_pAttributes[m_ulCurrentPropertyNum].GetPropertyPropid() ); + if ( wsTagName == EMPTY_STRING ) + return FILTER_E_NO_VALUES; + ::std::wstring wsTagData = m_pMetaInfoReader->getTagData(wsTagName); + pPropVar->vt = VT_LPWSTR; + size_t cw = wsTagData.length() + 1; // reserve one for the '\0' + pPropVar->pwszVal = static_cast<WCHAR*>( CoTaskMemAlloc(cw*sizeof(WCHAR)) ); + if (pPropVar->pwszVal == nullptr) + { + CoTaskMemFree(pPropVar); + return E_OUTOFMEMORY; + } + wmemcpy(pPropVar->pwszVal, wsTagData.c_str(), cw); + *ppPropValue = pPropVar; + m_ulCurrentPropertyNum = m_ulPropertyNum; + return S_OK; + } +} +//M------------------------------------------------------------------------- +// Method: COooFilter::BindRegion (IFilter::BindRegion) +// Summary: Creates moniker or other interface for indicated text +// Arguments: origPos +// [in] Description of text location and extent +// riid +// [in] Reference IID of specified interface +// ppunk +// [out] Address that receives requested interface pointer +// Returns: E_NOTIMPL +// Always +// FILTER_W_REGION_CLIPPED +// (not implemented) + + +SCODE STDMETHODCALLTYPE COooFilter::BindRegion( + FILTERREGION /*origPos*/, + REFIID /*riid*/, + void ** /*ppunk*/) +{ + // BindRegion is currently reserved for future use + return E_NOTIMPL; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::GetClassID (IPersist::GetClassID) +// Summary: Retrieves the class id of the filter class +// Arguments: pClassID +// [out] Pointer to the class ID of the filter +// Returns: S_OK +// Always +// E_FAIL +// (not implemented) + +HRESULT STDMETHODCALLTYPE COooFilter::GetClassID(CLSID * pClassID) +{ + *pClassID = CLSID_COooFilter; + return S_OK; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::IsDirty (IPersistFile::IsDirty) +// Summary: Checks whether file has changed since last save +// Arguments: void +// Returns: S_FALSE +// Always +// S_OK +// (not implemented) + +HRESULT STDMETHODCALLTYPE COooFilter::IsDirty() +{ + // File is opened read-only and never changes + return S_FALSE; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::Load (IPersistFile::Load) +// Summary: Opens and initializes the specified file +// Arguments: pszFileName +// [in] Pointer to zero-terminated string +// of absolute path of file to open +// dwMode +// [in] Access mode to open the file +// Returns: S_OK +// File was successfully loaded +// E_OUTOFMEMORY +// File could not be loaded due to insufficient memory +// E_FAIL +// (not implemented) + +HRESULT STDMETHODCALLTYPE COooFilter::Load(LPCOLESTR pszFileName, DWORD /*dwMode*/) +{ + // Load just sets the filename for GetChunk to read and ignores the mode + m_pwszFileName = getShortPathName( pszFileName ); + + // Open the file previously specified in call to IPersistFile::Load and get content. + try + { + delete m_pMetaInfoReader; + m_pMetaInfoReader = new CMetaInfoReader(m_pwszFileName); + + delete m_pContentReader; + m_pContentReader = new CContentReader(m_pwszFileName, m_pMetaInfoReader->getDefaultLocale()); + } + catch (const std::exception&) + { + return E_FAIL; + } + return S_OK; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::Save (IPersistFile::Save) +// Summary: Saves a copy of the current file being filtered +// Arguments: pszFileName +// [in] Pointer to zero-terminated string of +// absolute path of where to save file +// fRemember +// [in] Whether the saved copy is made the current file +// Returns: E_FAIL +// Always +// S_OK +// (not implemented) + +HRESULT STDMETHODCALLTYPE COooFilter::Save(LPCOLESTR /*pszFileName*/, BOOL /*fRemember*/) +{ + // File is opened read-only; saving it is an error + return E_FAIL; +} +//M------------------------------------------------------------------------- +// Method: COooFilter::SaveCompleted (IPersistFile::SaveCompleted) +// Summary: Determines whether a file save is completed +// Arguments: pszFileName +// [in] Pointer to zero-terminated string of +// absolute path where file was previously saved +// Returns: S_OK +// Always + +HRESULT STDMETHODCALLTYPE COooFilter::SaveCompleted(LPCOLESTR /*pszFileName*/) +{ + // File is opened read-only, so "save" is always finished + return S_OK; +} + +//M------------------------------------------------------------------------- +// Method: COooFilter::Load (IPersistStream::Load) +// Summary: Initializes an object from the stream where it was previously saved +// Arguments: pStm +// [in] Pointer to stream from which object should be loaded +// Returns: S_OK +// E_OUTOFMEMORY +// E_FAIL + +HRESULT STDMETHODCALLTYPE COooFilter::Load(IStream *pStm) +{ + m_pStream = new BufferStream(pStm); + try + { + delete m_pMetaInfoReader; + m_pMetaInfoReader = new CMetaInfoReader(m_pStream); + + delete m_pContentReader; + m_pContentReader = new CContentReader(m_pStream, m_pMetaInfoReader->getDefaultLocale()); + } + catch (const std::exception&) + { + return E_FAIL; + } + return S_OK; +} + +//M------------------------------------------------------------------------- +// Method: COooFilter::GetSizeMax (IPersistStream::GetSizeMax) +// Summary: Returns the size in bytes of the stream needed to save the object. +// Arguments: pcbSize +// [out] Pointer to a 64 bit unsigned int indicating the size needed +// Returns: E_NOTIMPL + +HRESULT STDMETHODCALLTYPE COooFilter::GetSizeMax(ULARGE_INTEGER * /*pcbSize*/) +{ + return E_NOTIMPL; +} + +//M------------------------------------------------------------------------- +// Method: COooFilter::Save (IPersistStream::Save) +// Summary: Save object to specified stream +// Arguments: pStm +// [in] Pointer to stream +// fClearDirty +// [in] Indicates whether to clear dirty flag +// Returns: E_NOTIMPL + +HRESULT STDMETHODCALLTYPE COooFilter::Save(IStream * /*pStm*/, BOOL ) +{ + return E_NOTIMPL; +} + +//M------------------------------------------------------------------------- +// Method: COooFilter::GetCurFile (IPersistFile::GetCurFile) +// Summary: Returns a copy of the current file name +// Arguments: ppszFileName +// [out] Address to receive pointer to zero-terminated +// string for absolute path to current file +// Returns: S_OK +// A valid absolute path was successfully returned +// S_FALSE +// (not implemented) +// E_OUTOFMEMORY +// Operation failed due to insufficient memory +// E_FAIL +// Operation failed due to some reason +// other than insufficient memory + +HRESULT STDMETHODCALLTYPE COooFilter::GetCurFile(LPOLESTR * ppszFileName) +{ + if ( EMPTY_STRING == m_pwszFileName ) + return E_FAIL; + else + *ppszFileName = const_cast<LPWSTR>(m_pwszFileName.c_str()); + return S_OK; +} + +//M------------------------------------------------------------------------- +// Method: COooFilterCF::COooFilterCF +// Summary: Class factory constructor +// Arguments: void +// Purpose: Manages global instance count + +COooFilterCF::COooFilterCF() : + m_lRefs(1) +{ + InterlockedIncrement( &g_lInstances ); +} +//M------------------------------------------------------------------------- +// Method: COooFilterCF::~COooFilterCF +// Summary: Class factory destructor +// Arguments: void +// Purpose: Manages global instance count + +COooFilterCF::~COooFilterCF() +{ + InterlockedDecrement( &g_lInstances ); +} +//M------------------------------------------------------------------------- +// Method: COooFilterCF::QueryInterface (IUnknown::QueryInterface) +// Summary: Queries for requested interface +// Arguments: riid +// [in] Reference IID of requested interface +// ppvObject +// [out] Address that receives requested interface pointer +// Returns: S_OK +// Interface is supported +// E_NOINTERFACE +// Interface is not supported + +HRESULT STDMETHODCALLTYPE COooFilterCF::QueryInterface(REFIID riid, void ** ppvObject) +{ + IUnknown *pUnkTemp; + + if ( IID_IClassFactory == riid ) + pUnkTemp = this; + else if ( IID_IUnknown == riid ) + pUnkTemp = this; + else + { + *ppvObject = nullptr; + return E_NOINTERFACE; + } + *ppvObject = pUnkTemp; + pUnkTemp->AddRef(); + return S_OK; +} +//M------------------------------------------------------------------------- +// Method: COooFilterCF::AddRef (IUnknown::AddRef) +// Summary: Increments interface refcount +// Arguments: void +// Returns: Value of incremented interface refcount + +ULONG STDMETHODCALLTYPE COooFilterCF::AddRef() +{ + return InterlockedIncrement( &m_lRefs ); +} +//M------------------------------------------------------------------------- +// Method: COooFilterCF::Release (IUnknown::Release) +// Summary: Decrements interface refcount, deleting if unreferenced +// Arguments: void +// Returns: Value of decremented refcount + +ULONG STDMETHODCALLTYPE COooFilterCF::Release() +{ + ULONG ulTmp = InterlockedDecrement( &m_lRefs ); + + if ( 0 == ulTmp ) + delete this; + return ulTmp; +} +//M------------------------------------------------------------------------- +// Method: COooFilterCF::CreateInstance (IClassFactory::CreateInstance) +// Summary: Creates new LibreOffice filter object +// Arguments: pUnkOuter +// [in] Pointer to IUnknown interface of aggregating object +// riid +// [in] Reference IID of requested interface +// ppvObject +// [out] Address that receives requested interface pointer +// Returns: S_OK +// LibreOffice filter object was successfully created +// CLASS_E_NOAGGREGATION +// pUnkOuter parameter was non-NULL +// E_NOINTERFACE +// (not implemented) +// E_OUTOFMEMORY +// LibreOffice filter object could not be created +// due to insufficient memory +// E_UNEXPECTED +// Unsuccessful due to an unexpected condition + +HRESULT STDMETHODCALLTYPE COooFilterCF::CreateInstance( + IUnknown * pUnkOuter, + REFIID riid, + void * * ppvObject) +{ + COooFilter *pIUnk = nullptr; + if ( nullptr != pUnkOuter ) + return CLASS_E_NOAGGREGATION; + pIUnk = new COooFilter(); + if ( SUCCEEDED( pIUnk->QueryInterface( riid , ppvObject ) ) ) + { + // Release extra refcount from QueryInterface + pIUnk->Release(); + } + else + { + delete pIUnk; + return E_UNEXPECTED; + } + return S_OK; +} + +//M------------------------------------------------------------------------- +// Method: COooFilterCF::LockServer (IClassFactory::LockServer) +// Summary: Forces/allows filter class to remain loaded/be unloaded +// Arguments: fLock +// [in] TRUE to lock, FALSE to unlock +// Returns: S_OK +// Always +// E_FAIL +// (not implemented) +// E_OUTOFMEMORY +// (not implemented) +// E_UNEXPECTED +// (not implemented) + +HRESULT STDMETHODCALLTYPE COooFilterCF::LockServer(BOOL fLock) +{ + if( fLock ) + InterlockedIncrement( &g_lInstances ); + else + InterlockedDecrement( &g_lInstances ); + return S_OK; +} +//+------------------------------------------------------------------------- +// DLL: ooofilt.dll +// Summary: Implements Dynamic Link Library functions for LibreOffice filter + +//F------------------------------------------------------------------------- +// Function: DllMain +// Summary: Called from C-Runtime on process/thread attach/detach +// Arguments: hInstance +// [in] Handle to the DLL +// fdwReason +// [in] Reason for calling DLL entry point +// lpReserve +// [in] Details of DLL initialization and cleanup +// Returns: TRUE +// Always + +extern "C" BOOL WINAPI DllMain( + HINSTANCE hInstance, + DWORD fdwReason, + LPVOID /*lpvReserved*/ +) +{ + if ( DLL_PROCESS_ATTACH == fdwReason ) + DisableThreadLibraryCalls( hInstance ); + return TRUE; +} +//F------------------------------------------------------------------------- +// Function: DllGetClassObject +// Summary: Create LibreOffice filter class factory object +// Arguments: cid +// [in] Class ID of class that class factory creates +// iid +// [in] Reference IID of requested class factory interface +// ppvObj +// [out] Address that receives requested interface pointer +// Returns: S_OK +// Class factory object was created successfully +// CLASS_E_CLASSNOTAVAILABLE +// DLL does not support the requested class +// E_INVALIDARG +// (not implemented +// E_OUTOFMEMORY +// Insufficient memory to create the class factory object +// E_UNEXPECTED +// Unsuccessful due to an unexpected condition + +extern "C" HRESULT STDMETHODCALLTYPE DllGetClassObject( + REFCLSID cid, + REFIID iid, + LPVOID * ppvObj +) +{ + COooFilterCF* pImpl = nullptr; + IUnknown *pResult = nullptr; + + if ( CLSID_COooFilter == cid ) + { + pImpl = new COooFilterCF; + pResult = pImpl; + } + else + return CLASS_E_CLASSNOTAVAILABLE; + if( SUCCEEDED( pResult->QueryInterface( iid, ppvObj ) ) ) + // Release extra refcount from QueryInterface + pResult->Release(); + else + { + delete pImpl; + return E_UNEXPECTED; + } + return S_OK; +} +//F------------------------------------------------------------------------- +// Function: DllCanUnloadNow +// Summary: Indicates whether it is possible to unload DLL +// Arguments: void +// Returns: S_OK +// DLL can be unloaded now +// S_FALSE +// DLL must remain loaded + +extern "C" HRESULT STDMETHODCALLTYPE DllCanUnloadNow() +{ + if ( 0 >= g_lInstances ) + return S_OK; + else + return S_FALSE; +} +//F------------------------------------------------------------------------- +// Function: DllRegisterServer +// DllUnregisterServer +// Summary: Registers and unregisters DLL server +// Returns: DllRegisterServer +// S_OK +// Registration was successful +// SELFREG_E_CLASS +// Registration was unsuccessful +// SELFREG_E_TYPELIB +// (not implemented) +// E_OUTOFMEMORY +// (not implemented) +// E_UNEXPECTED +// (not implemented) +// DllUnregisterServer +// S_OK +// Unregistration was successful +// S_FALSE +// Unregistration was successful, but other +// entries still exist for the DLL's classes +// SELFREG_E_CLASS +// (not implemented) +// SELFREG_E_TYPELIB +// (not implemented) +// E_OUTOFMEMORY +// (not implemented) +// E_UNEXPECTED +// (not implemented) + +STDAPI DllRegisterServer() +{ + return S_OK; +} + + +STDAPI DllUnregisterServer() +{ + return S_OK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/ooofilt/ooofilt.def b/shell/source/win32/shlxthandler/ooofilt/ooofilt.def new file mode 100644 index 000000000..d731a151f --- /dev/null +++ b/shell/source/win32/shlxthandler/ooofilt/ooofilt.def @@ -0,0 +1,5 @@ +EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx b/shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx new file mode 100644 index 000000000..c178452ff --- /dev/null +++ b/shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_OOOFILT_OOOFILT_HXX +#define INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_OOOFILT_OOOFILT_HXX + +#include <types.hxx> + +//+------------------------------------------------------------------------- +// Contents: LibreOffice filter declarations +// Platform: Windows 2000, Windows XP + +//+------------------------------------------------------------------------- + +class CContentReader; +class CMetaInfoReader; +class CFullPropSpec; + +LONG g_lInstances = 0; // Global count of COooFilter and COooFilterCF instances +GUID const guidStorage = PSGUID_STORAGE; // GUID for storage property set + +//C------------------------------------------------------------------------- +// Class: COooFilter +// Purpose: Implements interfaces of LibreOffice filter + +// OooFilter Class ID +// {7BC0E710-5703-45be-A29D-5D46D8B39262} +GUID const CLSID_COooFilter = +{ + 0x7bc0e710, + 0x5703, + 0x45be, + { 0xa2, 0x9d, 0x5d, 0x46, 0xd8, 0xb3, 0x92, 0x62 } +}; + +// LibreOffice Persistent Handler Class ID +// {7BC0E713-5703-45be-A29D-5D46D8B39262} +const CLSID CLSID_PERSISTENT_HANDLER = +{0x7bc0e713, 0x5703, 0x45be, {0xa2, 0x9d, 0x5d, 0x46, 0xd8, 0xb3, 0x92, 0x62}}; + +// LibreOffice Persistent Handler Addin Registered Class ID +// {89BCB740-6119-101A-BCB7-00DD010655AF} +const CLSID CLSID_PERSISTENT_HANDLER_ADDIN = +{0x89bcb740, 0x6119, 0x101a, {0xbc, 0xb7, 0x00, 0xdd, 0x01, 0x06, 0x55, 0xaf}}; + +// LibreOffice Filter Handler Class ID +// {7BC0E710-5703-45be-A29D-5D46D8B39262} +const CLSID CLSID_FILTER_HANDLER = +{0x7bc0e710, 0x5703, 0x45be, {0xa2, 0x9d, 0x5d, 0x46, 0xd8, 0xb3, 0x92, 0x62}}; + +enum class FilterState +{ + FilteringContent, // Filtering the content property + FilteringProperty // Filtering the pseudo property +}; +class COooFilter : public IFilter, public IPersistFile, public IPersistStream +{ +public: + // From IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void ** ppvObject) override; + virtual ULONG STDMETHODCALLTYPE AddRef() override; + virtual ULONG STDMETHODCALLTYPE Release() override; + + // From IFilter + virtual SCODE STDMETHODCALLTYPE Init( + ULONG grfFlags, + ULONG cAttributes, + FULLPROPSPEC const * aAttributes, + ULONG * pFlags) override; + virtual SCODE STDMETHODCALLTYPE GetChunk( + STAT_CHUNK * pStat) override; + virtual SCODE STDMETHODCALLTYPE GetText( + ULONG * pcwcBuffer, + WCHAR * awcBuffer) override; + + virtual SCODE STDMETHODCALLTYPE GetValue( + PROPVARIANT ** ppPropValue) override; + + virtual SCODE STDMETHODCALLTYPE BindRegion( + FILTERREGION origPos, + REFIID riid, + void ** ppunk) override; + + // From IPersistFile + virtual HRESULT STDMETHODCALLTYPE GetClassID( + CLSID * pClassID) override; + virtual HRESULT STDMETHODCALLTYPE IsDirty() override; + virtual HRESULT STDMETHODCALLTYPE Load( + LPCOLESTR pszFileName, + DWORD dwMode) override; + virtual HRESULT STDMETHODCALLTYPE Save( + LPCOLESTR pszFileName, + BOOL fRemember) override; + + virtual HRESULT STDMETHODCALLTYPE SaveCompleted( + LPCOLESTR pszFileName) override; + + virtual HRESULT STDMETHODCALLTYPE GetCurFile( + LPOLESTR * ppszFileName) override; + + // From IPersistStream + virtual HRESULT STDMETHODCALLTYPE Load( + IStream *pStm) override; + + virtual HRESULT STDMETHODCALLTYPE Save( + IStream *pStm, + BOOL fClearDirty) override; + + virtual HRESULT STDMETHODCALLTYPE GetSizeMax( + ULARGE_INTEGER *pcbSize) override; + + +private: + friend class COooFilterCF; + + COooFilter(); + virtual ~COooFilter(); + + LONG m_lRefs; // Reference count + CContentReader * m_pContentReader; // A content reader that retrieves document content. + CMetaInfoReader * m_pMetaInfoReader; // A metainfo reader that retrieves document metainfo. + FilterState m_eState; // State of filtering + ::std::wstring m_pwszFileName; // Name of input file to filter + ULONG m_ulUnicodeBufferLen; // UNICODE Characters read from file to chunk buffer + ULONG m_ulUnicodeCharsRead; // UNICODE Characters read from chunk buffer + ULONG m_ulPropertyNum; // Number of properties that has been processed + ULONG m_ulCurrentPropertyNum; // Current Property that is processing; + ULONG m_ulChunkID; // Current chunk id + bool m_fContents; // TRUE if contents requested + bool m_fEof; // TRUE if end of file reached + ::std::wstring m_pwsBuffer; // Buffer to save UNICODE content from ChunkBuffer. + ULONG m_ChunkPosition; // Chunk pointer to specify the current Chunk; + ULONG m_cAttributes; // Count of attributes + CFullPropSpec * m_pAttributes; // Attributes to filter + StreamInterface * m_pStream; + +}; + +//C------------------------------------------------------------------------- +// Class: COooFilterCF +// Purpose: Implements class factory for LibreOffice filter + + +class COooFilterCF : public IClassFactory +{ +public: + // From IUnknown + virtual HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, + void ** ppvObject) override; + + virtual ULONG STDMETHODCALLTYPE AddRef() override; + virtual ULONG STDMETHODCALLTYPE Release() override; + + // From IClassFactory + virtual HRESULT STDMETHODCALLTYPE CreateInstance( + IUnknown * pUnkOuter, + REFIID riid, void ** ppvObject) override; + + virtual HRESULT STDMETHODCALLTYPE LockServer( + BOOL fLock) override; + +private: + friend HRESULT STDMETHODCALLTYPE DllGetClassObject( + REFCLSID cid, + REFIID iid, + LPVOID * ppvObj); + + COooFilterCF(); + virtual ~COooFilterCF(); + + LONG m_lRefs; // Reference count +}; + +#endif // INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_OOOFILT_OOOFILT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/ooofilt/propspec.cxx b/shell/source/win32/shlxthandler/ooofilt/propspec.cxx new file mode 100644 index 000000000..f03cef033 --- /dev/null +++ b/shell/source/win32/shlxthandler/ooofilt/propspec.cxx @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +//+------------------------------------------------------------------------- +// File: propspec.cxx +// Contents: C++ wrappers for FULLPROPSPEC + +#include <sal/config.h> + +#include <new> + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <filter.h> + +#include "propspec.hxx" + +//refer to ms-help://MS.VSCC/MS.MSDNVS.2052/com/stgasstg_7agk.htm +//FMTID_SummaryInformation +//GUID CLSID_SummaryInformation = { +// 0xF29F85E0, +// 0x4FF9, +// 0x1068, +// { 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9 } +//}; +//+------------------------------------------------------------------------- +// Member: CFullPropSpec::CFullPropSpec, public +// Synopsis: Default constructor +// Effects: Defines property with null guid and propid 0 + + +CFullPropSpec::CFullPropSpec() +{ + _psProperty.ulKind = PRSPEC_PROPID; + _psProperty.propid = 0; +} +//+------------------------------------------------------------------------- +// Member: CFullPropSpec::CFullPropSpec, public +// Synopsis: Construct propid based propspec +// Arguments: [guidPropSet] -- Property set +// [pidProperty] -- Property + +CFullPropSpec::CFullPropSpec( GUID const & guidPropSet, PROPID pidProperty ) : + _guidPropSet( guidPropSet ) +{ + _psProperty.ulKind = PRSPEC_PROPID; + _psProperty.propid = pidProperty; +} +//+------------------------------------------------------------------------- +// Member: CFullPropSpec::CFullPropSpec, public +// Synopsis: Construct name based propspec +// Arguments: [guidPropSet] -- Property set +// [wcsProperty] -- Property + +CFullPropSpec::CFullPropSpec( GUID const & guidPropSet, + WCHAR const * wcsProperty ) : + _guidPropSet( guidPropSet ) +{ + _psProperty.ulKind = PRSPEC_PROPID; + SetProperty( wcsProperty ); +} +//+------------------------------------------------------------------------- +// Member: CFullPropSpec::CFullPropSpec, public +// Synopsis: Copy constructor +// Arguments: [src] -- Source property spec + +CFullPropSpec::CFullPropSpec( CFullPropSpec const & src ) : + _guidPropSet( src._guidPropSet ) +{ + _psProperty.ulKind = src._psProperty.ulKind; + if ( _psProperty.ulKind == PRSPEC_LPWSTR ) + { + if ( src._psProperty.lpwstr ) + { + _psProperty.ulKind = PRSPEC_PROPID; + SetProperty( src._psProperty.lpwstr ); + } + else + _psProperty.lpwstr = nullptr; + } + else + { + _psProperty.propid = src._psProperty.propid; + } +} + +//+------------------------------------------------------------------------- +// Member: CFullPropSpec::operator=, public +// Synopsis: Assignment operator +// Arguments: [Property] -- Source property + +CFullPropSpec & CFullPropSpec::operator=( CFullPropSpec const & Property ) +{ + if (this != &Property) + { + // Clean up. + this->CFullPropSpec::~CFullPropSpec(); + + ::new (this) CFullPropSpec( Property ); + } + return *this; +} + +CFullPropSpec::~CFullPropSpec() +{ + if ( _psProperty.ulKind == PRSPEC_LPWSTR && + _psProperty.lpwstr ) + { + CoTaskMemFree( _psProperty.lpwstr ); + } +} + +void CFullPropSpec::SetProperty( PROPID pidProperty ) +{ + if ( _psProperty.ulKind == PRSPEC_LPWSTR && + nullptr != _psProperty.lpwstr ) + { + CoTaskMemFree( _psProperty.lpwstr ); + } + _psProperty.ulKind = PRSPEC_PROPID; + _psProperty.propid = pidProperty; +} +BOOL CFullPropSpec::SetProperty( WCHAR const * wcsProperty ) +{ + if ( _psProperty.ulKind == PRSPEC_LPWSTR && + nullptr != _psProperty.lpwstr ) + { + CoTaskMemFree( _psProperty.lpwstr ); + } + _psProperty.ulKind = PRSPEC_LPWSTR; + int len = static_cast<int>( (wcslen( wcsProperty ) + 1) * sizeof( WCHAR ) ); + _psProperty.lpwstr = static_cast<WCHAR *>(CoTaskMemAlloc( len )); + if ( nullptr != _psProperty.lpwstr ) + { + memcpy( _psProperty.lpwstr, + wcsProperty, + len ); + return TRUE; + } + else + { + _psProperty.lpwstr = nullptr; + return FALSE; + } +} +bool CFullPropSpec::operator==( CFullPropSpec const & prop ) const +{ + if ( memcmp( &prop._guidPropSet, + &_guidPropSet, + sizeof( _guidPropSet ) ) != 0 || + prop._psProperty.ulKind != _psProperty.ulKind ) + { + return false; + } + switch( _psProperty.ulKind ) + { + case PRSPEC_LPWSTR: + return( _wcsicmp( GetPropertyName(), prop.GetPropertyName() ) == 0 ); + case PRSPEC_PROPID: + return( GetPropertyPropid() == prop.GetPropertyPropid() ); + default: + return false; + } +} +bool CFullPropSpec::operator!=( CFullPropSpec const & prop ) const +{ + if (*this == prop) + return false; + else + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/ooofilt/propspec.hxx b/shell/source/win32/shlxthandler/ooofilt/propspec.hxx new file mode 100644 index 000000000..f9e1fc289 --- /dev/null +++ b/shell/source/win32/shlxthandler/ooofilt/propspec.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_OOOFILT_PROPSPEC_HXX +#define INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_OOOFILT_PROPSPEC_HXX + +//+------------------------------------------------------------------------- +// File: propspec.hxx +// Contents: C++ wrapper(s) for FULLPROPSPEC + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> +#include <ole2.h> +#include <ntquery.h> +//+------------------------------------------------------------------------- +// Declare: CLSID_SummaryInformation, GUID +// CLSID_Storage, GUID +// Contents: Definitions of OpenOffice.org Document properties + + +//+------------------------------------------------------------------------- +// Class: CFullPropertySpec +// Purpose: Describes full (PropertySet\Property) name of a property. + + +class CFullPropSpec +{ +public: + CFullPropSpec(); + CFullPropSpec( GUID const & guidPropSet, PROPID pidProperty ); + CFullPropSpec( GUID const & guidPropSet, WCHAR const * wcsProperty ); + // Validity check + inline BOOL IsValid() const; + + // Copy constructors/assignment/clone + CFullPropSpec( CFullPropSpec const & Property ); + CFullPropSpec & operator=( CFullPropSpec const & Property ); + ~CFullPropSpec(); + // Memory allocation + void * operator new( size_t size ); + void operator delete( void * p ); + inline FULLPROPSPEC * CastToStruct(); + inline FULLPROPSPEC const * CastToStruct() const; + // Comparators + bool operator==( CFullPropSpec const & prop ) const; + bool operator!=( CFullPropSpec const & prop ) const; + // Member variable access + inline void SetPropSet( GUID const & guidPropSet ); + inline GUID const & GetPropSet() const; + + void SetProperty( PROPID pidProperty ); + BOOL SetProperty( WCHAR const * wcsProperty ); + inline WCHAR const * GetPropertyName() const; + inline PROPID GetPropertyPropid() const; + inline PROPSPEC GetPropSpec() const; + inline BOOL IsPropertyName() const; + inline BOOL IsPropertyPropid() const; +private: + GUID _guidPropSet = {}; + PROPSPEC _psProperty; +}; +// Inline methods for CFullPropSpec +inline void * CFullPropSpec::operator new( size_t size ) +{ + void * p = CoTaskMemAlloc( size ); + return p; +} +inline void CFullPropSpec::operator delete( void * p ) +{ + if ( p ) + CoTaskMemFree( p ); +} +inline BOOL CFullPropSpec::IsValid() const +{ + return ( _psProperty.ulKind == PRSPEC_PROPID || + nullptr != _psProperty.lpwstr ); +} +inline void CFullPropSpec::SetPropSet( GUID const & guidPropSet ) +{ + _guidPropSet = guidPropSet; +} +inline GUID const & CFullPropSpec::GetPropSet() const +{ + return _guidPropSet; +} +inline PROPSPEC CFullPropSpec::GetPropSpec() const +{ + return _psProperty; +} +inline WCHAR const * CFullPropSpec::GetPropertyName() const +{ + return _psProperty.lpwstr; +} +inline PROPID CFullPropSpec::GetPropertyPropid() const +{ + return _psProperty.propid; +} +inline BOOL CFullPropSpec::IsPropertyName() const +{ + return _psProperty.ulKind == PRSPEC_LPWSTR; +} +inline BOOL CFullPropSpec::IsPropertyPropid() const +{ + return _psProperty.ulKind == PRSPEC_PROPID; +} + +#endif // INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_OOOFILT_PROPSPEC_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx b/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx new file mode 100644 index 000000000..76578ba70 --- /dev/null +++ b/shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#include <stdio.h> +#include <objidl.h> +#include <stream_helper.hxx> + +BufferStream::BufferStream(IStream *str) : + stream(str) +{ + // These next few lines work around the "Seek pointer" bug found on Vista. + char cBuf[20]; + unsigned long nCount; + ULARGE_INTEGER nNewPosition; + LARGE_INTEGER nMove; + nMove.QuadPart = 0; + stream->Seek( nMove, STREAM_SEEK_SET, &nNewPosition ); + stream->Read( cBuf, 20, &nCount ); +} + +BufferStream::~BufferStream() +{ +} + +unsigned long BufferStream::sread (unsigned char *buf, unsigned long size) +{ + unsigned long newsize; + HRESULT hr; + + hr = stream->Read (buf, size, &newsize); + if (hr == S_OK) + return newsize; + else + return static_cast<unsigned long>(0); +} + +long BufferStream::stell () +{ + HRESULT hr; + LARGE_INTEGER Move; + ULARGE_INTEGER NewPosition; + Move.QuadPart = 0; + NewPosition.QuadPart = 0; + + hr = stream->Seek (Move, STREAM_SEEK_CUR, &NewPosition); + if (hr == S_OK) + return static_cast<long>(NewPosition.QuadPart); + else + return -1; +} + +long BufferStream::sseek (long offset, int origin) +{ + HRESULT hr; + LARGE_INTEGER Move; + DWORD dwOrigin; + Move.QuadPart = static_cast<__int64>(offset); + + switch (origin) + { + case SEEK_CUR: + dwOrigin = STREAM_SEEK_CUR; + break; + case SEEK_END: + dwOrigin = STREAM_SEEK_END; + break; + case SEEK_SET: + dwOrigin = STREAM_SEEK_SET; + break; + default: + return -1; + } + + hr = stream->Seek (Move, dwOrigin, nullptr); + if (hr == S_OK) + return 0; + else + return -1; +} + +FileStream::FileStream(const Filepath_char_t *filename) : + file(nullptr) +{ + // fdo#67534: avoid locking to not interfere with soffice opening the file + file = _wfsopen(filename, L"rb", _SH_DENYNO); +} + +FileStream::~FileStream() +{ + if (file) + fclose(file); +} + +unsigned long FileStream::sread (unsigned char *buf, unsigned long size) +{ + if (file) + return static_cast<unsigned long>(fread(buf, 1, size, file)); + return 0; +} + +long FileStream::stell () +{ + if (file) + return ftell(file); + return -1; +} + +long FileStream::sseek (long offset, int origin) +{ + if (file) + return fseek(file, offset, origin); + return -1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx b/shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx new file mode 100644 index 000000000..49a8b8d06 --- /dev/null +++ b/shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx @@ -0,0 +1,432 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <global.hxx> +#include <propertyhdl.hxx> +#include <fileextensions.hxx> +#include <metainforeader.hxx> +#include <utilities.hxx> +#include <config.hxx> + +#include <propkey.h> +#include <propvarutil.h> +#include <sal/macros.h> + +#include <malloc.h> +#include <strsafe.h> + +#include <stream_helper.hxx> + + +// Module global + +LONG g_DllRefCnt = 0; +static HINSTANCE g_hModule = nullptr; + +const PROPERTYKEY g_rgPROPERTIES[] = +{ + PKEY_Title, + PKEY_Author, + PKEY_Subject, + PKEY_Keywords, + PKEY_Comment +}; + +size_t const gPropertyTableSize = SAL_N_ELEMENTS(g_rgPROPERTIES); + + +CPropertyHdl::CPropertyHdl( LONG nRefCnt ) : + m_RefCnt( nRefCnt ), + m_pCache( nullptr ) +{ + OutputDebugStringFormatW( L"CPropertyHdl: CTOR\n" ); + InterlockedIncrement( &g_DllRefCnt ); +} + + +CPropertyHdl::~CPropertyHdl() +{ + if ( m_pCache ) + { + m_pCache->Release(); + m_pCache = nullptr; + } + InterlockedDecrement( &g_DllRefCnt ); +} + + +// IUnknown methods + +HRESULT STDMETHODCALLTYPE CPropertyHdl::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = nullptr; + + if (IID_IUnknown == riid || IID_IPropertyStore == riid) + { + OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (IID_IPropertyStore)\n" ); + IUnknown* pUnk = static_cast<IPropertyStore*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + else if (IID_IPropertyStoreCapabilities == riid) + { + OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (IID_IPropertyStoreCapabilities)\n" ); + IUnknown* pUnk = static_cast<IPropertyStore*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + else if (IID_IInitializeWithStream == riid) + { + OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (IID_IInitializeWithStream)\n" ); + IUnknown* pUnk = static_cast<IInitializeWithStream*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + OutputDebugStringFormatW( L"CPropertyHdl: QueryInterface (something different)\n" ); + + return E_NOINTERFACE; +} + + +ULONG STDMETHODCALLTYPE CPropertyHdl::AddRef() +{ + return InterlockedIncrement( &m_RefCnt ); +} + + +ULONG STDMETHODCALLTYPE CPropertyHdl::Release() +{ + LONG refcnt = InterlockedDecrement( &m_RefCnt ); + + if ( 0 == m_RefCnt ) + delete this; + + return refcnt; +} + + +// IPropertyStore + +HRESULT STDMETHODCALLTYPE CPropertyHdl::GetCount( DWORD *pcProps ) +{ + HRESULT hr = E_UNEXPECTED; + if ( m_pCache && pcProps ) + { + hr = m_pCache->GetCount( pcProps ); + } + + return hr; +} + + +HRESULT STDMETHODCALLTYPE CPropertyHdl::GetAt( DWORD iProp, PROPERTYKEY *pKey ) +{ + HRESULT hr = E_UNEXPECTED; + if ( m_pCache ) + { + hr = m_pCache->GetAt( iProp, pKey ); + } + + return hr; +} + + +HRESULT STDMETHODCALLTYPE CPropertyHdl::GetValue( REFPROPERTYKEY key, PROPVARIANT *pPropVar ) +{ + HRESULT hr = E_UNEXPECTED; + if ( m_pCache ) + { + hr = m_pCache->GetValue( key, pPropVar ); + } + + return hr; +} + + +HRESULT STDMETHODCALLTYPE +CPropertyHdl::SetValue(REFPROPERTYKEY /*key*/, REFPROPVARIANT /*propVar*/) +{ + HRESULT hr = E_UNEXPECTED; + if ( m_pCache ) + { + hr = STG_E_ACCESSDENIED; + } + return hr; +} + + +HRESULT STDMETHODCALLTYPE CPropertyHdl::Commit() +{ + return S_OK; +} + + +// IPropertyStore + +HRESULT STDMETHODCALLTYPE +CPropertyHdl::IsPropertyWritable(REFPROPERTYKEY /*key*/) +{ + // We start with read only properties only + return S_FALSE; +} + + +// IInitializeWithStream + +HRESULT STDMETHODCALLTYPE CPropertyHdl::Initialize( IStream *pStream, DWORD grfMode ) +{ + if ( grfMode & STGM_READWRITE ) + return STG_E_ACCESSDENIED; + + if ( !m_pCache ) + { + if ( FAILED( PSCreateMemoryPropertyStore( IID_PPV_ARGS( &m_pCache ) ) ) ) + OutputDebugStringFormatW( L"CPropertyHdl::Initialize: PSCreateMemoryPropertyStore failed" ); + + BufferStream tmpStream(pStream); + + CMetaInfoReader *pMetaInfoReader = nullptr; + + try + { + pMetaInfoReader = new CMetaInfoReader( &tmpStream ); + LoadProperties( pMetaInfoReader ); + delete pMetaInfoReader; + } + catch (const std::exception& e) + { + // To output 8-bit string using unicode version of formatting functions, use capital %S type + // see https://msdn.microsoft.com/en-us/library/hf4y5e3w + OutputDebugStringFormatW( L"CPropertyHdl::Initialize: Caught exception [%S]", e.what() ); + return E_FAIL; + } + } + + return S_OK; +} + +namespace { + +HRESULT GetItemData( CMetaInfoReader *pMetaInfoReader, UINT nIndex, PROPVARIANT *pVarData ) +{ + switch (nIndex) { + case 0: { + pVarData->vt = VT_BSTR; + pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() ); + OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Title=%s.\n", pMetaInfoReader->getTagData( META_INFO_TITLE ).c_str() ); + return S_OK; + } + case 1: { + pVarData->vt = VT_BSTR; + pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() ); + OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Author=%s.\n", pMetaInfoReader->getTagData( META_INFO_AUTHOR ).c_str() ); + return S_OK; + } + case 2: { + pVarData->vt = VT_BSTR; + pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() ); + OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Subject=%s.\n", pMetaInfoReader->getTagData( META_INFO_SUBJECT ).c_str() ); + return S_OK; + } + case 3: { + pVarData->vt = VT_BSTR; + pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() ); + OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Keywords=%s.\n", pMetaInfoReader->getTagData( META_INFO_KEYWORDS ).c_str() ); + return S_OK; + } + case 4: { + pVarData->vt = VT_BSTR; + pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() ); + OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Description=%s.\n", pMetaInfoReader->getTagData( META_INFO_DESCRIPTION ).c_str() ); + return S_OK; + } + case 5: { + pVarData->vt = VT_BSTR; + pVarData->bstrVal = SysAllocString( pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() ); + OutputDebugStringFormatW( L"CPropertyHdl::GetItemData: Pages=%s.\n", pMetaInfoReader->getTagAttribute( META_INFO_DOCUMENT_STATISTIC, META_INFO_PAGES ).c_str() ); + return S_OK; + } + } + + return S_FALSE; +} + +} + +void CPropertyHdl::LoadProperties( CMetaInfoReader *pMetaInfoReader ) +{ + OutputDebugStringFormatW( L"CPropertyHdl: LoadProperties\n" ); + PROPVARIANT propvarValues; + + for ( UINT i = 0; i < UINT(gPropertyTableSize); ++i ) + { + PropVariantClear( &propvarValues ); + HRESULT hr = GetItemData( pMetaInfoReader, i, &propvarValues); + if (hr == S_OK) + { + // coerce the value(s) to the appropriate type for the property key + hr = PSCoerceToCanonicalValue( g_rgPROPERTIES[i], &propvarValues ); + if (SUCCEEDED(hr)) + { + // cache the value(s) loaded + hr = m_pCache->SetValueAndState( g_rgPROPERTIES[i], &propvarValues, PSC_NORMAL ); + } + } + } +} + +// CClassFactory + + +LONG CClassFactory::s_ServerLocks = 0; + + +CClassFactory::CClassFactory( const CLSID& clsid ) : + m_RefCnt(1), + m_Clsid(clsid) +{ + InterlockedIncrement( &g_DllRefCnt ); +} + + +CClassFactory::~CClassFactory() +{ + InterlockedDecrement( &g_DllRefCnt ); +} + + +// IUnknown methods + +HRESULT STDMETHODCALLTYPE CClassFactory::QueryInterface( REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject ) +{ + *ppvObject = nullptr; + + if ( IID_IUnknown == riid || IID_IClassFactory == riid ) + { + IUnknown* pUnk = this; + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + + return E_NOINTERFACE; +} + + +ULONG STDMETHODCALLTYPE CClassFactory::AddRef() +{ + return InterlockedIncrement( &m_RefCnt ); +} + + +ULONG STDMETHODCALLTYPE CClassFactory::Release() +{ + LONG refcnt = InterlockedDecrement( &m_RefCnt ); + + if (0 == refcnt) + delete this; + + return refcnt; +} + + +// IClassFactory methods + +HRESULT STDMETHODCALLTYPE CClassFactory::CreateInstance( + IUnknown __RPC_FAR *pUnkOuter, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject) +{ + if ( pUnkOuter != nullptr ) + return CLASS_E_NOAGGREGATION; + + IUnknown* pUnk = nullptr; + + if ( CLSID_PROPERTY_HANDLER == m_Clsid ) + pUnk = static_cast<IPropertyStore*>( new CPropertyHdl() ); + + if (nullptr == pUnk) + { + return E_OUTOFMEMORY; + } + + HRESULT hr = pUnk->QueryInterface( riid, ppvObject ); + + // if QueryInterface failed the component will destroy itself + pUnk->Release(); + + return hr; +} + + +HRESULT STDMETHODCALLTYPE CClassFactory::LockServer( BOOL fLock ) +{ + if ( fLock ) + InterlockedIncrement( &s_ServerLocks ); + else + InterlockedDecrement( &s_ServerLocks ); + + return S_OK; +} + + +bool CClassFactory::IsLocked() +{ + return ( s_ServerLocks > 0 ); +} + + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + OutputDebugStringFormatW( L"DllGetClassObject.\n" ); + *ppv = nullptr; + + if ( rclsid != CLSID_PROPERTY_HANDLER ) + return CLASS_E_CLASSNOTAVAILABLE; + + if ( (riid != IID_IUnknown) && (riid != IID_IClassFactory) ) + return E_NOINTERFACE; + + IUnknown* pUnk = new CClassFactory( rclsid ); + *ppv = pUnk; + return S_OK; +} + + +STDAPI DllCanUnloadNow() +{ + OutputDebugStringFormatW( L"DllCanUnloadNow.\n" ); + if (CClassFactory::IsLocked() || g_DllRefCnt > 0) + return S_FALSE; + + return S_OK; +} + + +BOOL WINAPI DllMain( HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/ ) +{ + OutputDebugStringFormatW( L"DllMain.\n" ); + g_hModule = hInst; + return TRUE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/prophdl/propertyhdl.def b/shell/source/win32/shlxthandler/prophdl/propertyhdl.def new file mode 100644 index 000000000..22b670b3c --- /dev/null +++ b/shell/source/win32/shlxthandler/prophdl/propertyhdl.def @@ -0,0 +1,3 @@ +EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
diff --git a/shell/source/win32/shlxthandler/propsheets/document_statistic.cxx b/shell/source/win32/shlxthandler/propsheets/document_statistic.cxx new file mode 100644 index 000000000..6a27e1ab1 --- /dev/null +++ b/shell/source/win32/shlxthandler/propsheets/document_statistic.cxx @@ -0,0 +1,145 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "document_statistic.hxx" +#include <utilities.hxx> +#include <metainforeader.hxx> +#include <resource.h> +#include <fileextensions.hxx> +#include <config.hxx> +#include <iso8601_converter.hxx> + +const bool READONLY = false; + +document_statistic_reader_ptr create_document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor) +{ + File_Type_t file_type = get_file_type(document_name); + + if (WRITER == file_type) + return document_statistic_reader_ptr(new writer_document_statistic_reader(document_name, meta_info_accessor)); + else if (CALC == file_type) + return document_statistic_reader_ptr(new calc_document_statistic_reader(document_name, meta_info_accessor)); + else + return document_statistic_reader_ptr(new draw_impress_math_document_statistic_reader(document_name, meta_info_accessor)); +} + + +document_statistic_reader::document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor) : + document_name_(document_name), + meta_info_accessor_(meta_info_accessor) +{} + +document_statistic_reader::~document_statistic_reader() +{} + +void document_statistic_reader::read(statistic_group_list_t* group_list) +{ + group_list->clear(); + fill_description_section(meta_info_accessor_, group_list); + fill_origin_section(meta_info_accessor_, group_list); +} + +std::wstring document_statistic_reader::get_document_name() const +{ + return document_name_; +} + +void document_statistic_reader::fill_origin_section(CMetaInfoReader *meta_info_accessor, statistic_group_list_t* group_list) +{ + statistic_item_list_t il; + + il.push_back(statistic_item(GetResString(IDS_AUTHOR), meta_info_accessor->getTagData( META_INFO_AUTHOR ), READONLY)); + + il.push_back(statistic_item(GetResString(IDS_MODIFIED), + iso8601_date_to_local_date(meta_info_accessor->getTagData(META_INFO_MODIFIED )), READONLY)); + + il.push_back(statistic_item(GetResString(IDS_DOCUMENT_NUMBER), meta_info_accessor->getTagData( META_INFO_DOCUMENT_NUMBER ), READONLY)); + + il.push_back(statistic_item(GetResString(IDS_EDITING_TIME), + iso8601_duration_to_local_duration(meta_info_accessor->getTagData( META_INFO_EDITING_TIME )), READONLY)); + + group_list->push_back(statistic_group_t(GetResString(IDS_ORIGIN), il)); +} + +writer_document_statistic_reader::writer_document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor) : + document_statistic_reader(document_name, meta_info_accessor) +{} + +void writer_document_statistic_reader::fill_description_section(CMetaInfoReader *meta_info_accessor, statistic_group_list_t* group_list) +{ + statistic_item_list_t il; + + il.push_back(statistic_item(GetResString(IDS_TITLE), meta_info_accessor->getTagData( META_INFO_TITLE ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_COMMENTS), meta_info_accessor->getTagData( META_INFO_DESCRIPTION ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_SUBJECT), meta_info_accessor->getTagData( META_INFO_SUBJECT ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_KEYWORDS), meta_info_accessor->getTagData(META_INFO_KEYWORDS ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_PAGES), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_PAGES) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_TABLES), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_TABLES) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_GRAPHICS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_DRAWS) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_OLE_OBJECTS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_OBJECTS) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_PARAGRAPHS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_PARAGRAPHS) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_WORDS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_WORDS) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_CHARACTERS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_CHARACTERS) , READONLY)); + + group_list->push_back(statistic_group_t(GetResString(IDS_DESCRIPTION), il)); +} + +calc_document_statistic_reader::calc_document_statistic_reader( + const std::wstring& document_name, CMetaInfoReader* meta_info_accessor) : + document_statistic_reader(document_name, meta_info_accessor) +{} + +void calc_document_statistic_reader::fill_description_section( + CMetaInfoReader *meta_info_accessor,statistic_group_list_t* group_list) +{ + statistic_item_list_t il; + + il.push_back(statistic_item(GetResString(IDS_TITLE), meta_info_accessor->getTagData( META_INFO_TITLE ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_COMMENTS), meta_info_accessor->getTagData( META_INFO_DESCRIPTION ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_SUBJECT), meta_info_accessor->getTagData( META_INFO_SUBJECT ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_KEYWORDS), meta_info_accessor->getTagData(META_INFO_KEYWORDS ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_TABLES), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_TABLES) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_CELLS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_CELLS) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_OLE_OBJECTS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_OBJECTS) , READONLY)); + + group_list->push_back(statistic_group_t(GetResString(IDS_DESCRIPTION), il)); +} + +draw_impress_math_document_statistic_reader::draw_impress_math_document_statistic_reader( + const std::wstring& document_name, CMetaInfoReader* meta_info_accessor) : + document_statistic_reader(document_name, meta_info_accessor) +{} + +void draw_impress_math_document_statistic_reader::fill_description_section( + CMetaInfoReader *meta_info_accessor, statistic_group_list_t* group_list) +{ + statistic_item_list_t il; + + il.push_back(statistic_item(GetResString(IDS_TITLE), meta_info_accessor->getTagData( META_INFO_TITLE ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_COMMENTS), meta_info_accessor->getTagData( META_INFO_DESCRIPTION ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_SUBJECT), meta_info_accessor->getTagData( META_INFO_SUBJECT ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_KEYWORDS), meta_info_accessor->getTagData(META_INFO_KEYWORDS ), READONLY)); + il.push_back(statistic_item(GetResString(IDS_PAGES), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_PAGES) , READONLY)); + il.push_back(statistic_item(GetResString(IDS_OLE_OBJECTS), meta_info_accessor->getTagAttribute( META_INFO_DOCUMENT_STATISTIC,META_INFO_OBJECTS) , READONLY)); + + group_list->push_back(statistic_group_t(GetResString(IDS_DESCRIPTION), il)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/propsheets/document_statistic.hxx b/shell/source/win32/shlxthandler/propsheets/document_statistic.hxx new file mode 100644 index 000000000..e6f0dc5dc --- /dev/null +++ b/shell/source/win32/shlxthandler/propsheets/document_statistic.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_PROPSHEETS_DOCUMENT_STATISTIC_HXX +#define INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_PROPSHEETS_DOCUMENT_STATISTIC_HXX + +#include <utility> +#include <string> +#include <memory> +#include <vector> +#include <metainforeader.hxx> + + +struct statistic_item +{ + statistic_item(); + + statistic_item( + const std::wstring& title, + const std::wstring& value, + bool editable) : + title_(title), + value_(value), + editable_(editable) + {} + + std::wstring title_; + std::wstring value_; + bool editable_; +}; + + +typedef std::vector<statistic_item> statistic_item_list_t; +typedef std::pair<std::wstring, statistic_item_list_t> statistic_group_t; +typedef std::vector<statistic_group_t> statistic_group_list_t; + + +class document_statistic_reader; +typedef std::unique_ptr<document_statistic_reader> document_statistic_reader_ptr; + +document_statistic_reader_ptr create_document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); + + +class document_statistic_reader +{ +public: + virtual ~document_statistic_reader(); + + void read(statistic_group_list_t* group_list); + + std::wstring get_document_name() const; + +protected: + document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); + + virtual void fill_description_section(CMetaInfoReader *meta_info_accessor,statistic_group_list_t* group_list) = 0; + + virtual void fill_origin_section( CMetaInfoReader *meta_info_accessor,statistic_group_list_t* group_list); + +private: + std::wstring document_name_; + CMetaInfoReader* meta_info_accessor_; + + friend document_statistic_reader_ptr create_document_statistic_reader( + const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); +}; + + +class writer_document_statistic_reader : public document_statistic_reader +{ +protected: + writer_document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); + + virtual void fill_description_section(CMetaInfoReader *meta_info_accessor, statistic_group_list_t* group_list) override; + + friend document_statistic_reader_ptr create_document_statistic_reader( + const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); +}; + + +class calc_document_statistic_reader : public document_statistic_reader +{ +protected: + calc_document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); + + virtual void fill_description_section( CMetaInfoReader *meta_info_accessor,statistic_group_list_t* group_list) override; + + friend document_statistic_reader_ptr create_document_statistic_reader( + const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); +}; + + +class draw_impress_math_document_statistic_reader : public document_statistic_reader +{ +protected: + draw_impress_math_document_statistic_reader(const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); + + virtual void fill_description_section(CMetaInfoReader *meta_info_accessor, statistic_group_list_t* group_list) override; + + friend document_statistic_reader_ptr create_document_statistic_reader( + const std::wstring& document_name, CMetaInfoReader* meta_info_accessor); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/propsheets/listviewbuilder.cxx b/shell/source/win32/shlxthandler/propsheets/listviewbuilder.cxx new file mode 100644 index 000000000..5f0705c74 --- /dev/null +++ b/shell/source/win32/shlxthandler/propsheets/listviewbuilder.cxx @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "listviewbuilder.hxx" +#include "document_statistic.hxx" +#include <utilities.hxx> +#include <config.hxx> +#include <global.hxx> + +#include <commctrl.h> +#include <resource.h> + +// Unicode-only defines to break dependence on UNICODE define +#if !defined ListView_InsertColumnW +#define ListView_InsertColumnW(hwnd, iCol, pcol) \ + static_cast<int>(SNDMSG((hwnd), LVM_INSERTCOLUMNW, WPARAM(int(iCol)), reinterpret_cast<LPARAM>(pcol))) +#endif + +#if !defined ListView_InsertItemW +#define ListView_InsertItemW(hwnd, pitem) \ + static_cast<int>(SNDMSG((hwnd), LVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(pitem))) +#endif + +#if !defined ListView_SetItemW +#define ListView_SetItemW(hwnd, pitem) \ + static_cast<bool>(SNDMSG((hwnd), LVM_SETITEMW, 0, reinterpret_cast<LPARAM>(pitem))) +#endif + + +list_view_builder_ptr create_list_view_builder( + HWND hwnd_lv, const std::wstring& col1, const std::wstring& col2) +{ + return list_view_builder_ptr(new list_view_builder(hwnd_lv, col1, col2)); +} + + +list_view_builder::list_view_builder( + HWND hwnd_list_view, + const std::wstring& column1_title, + const std::wstring& column2_title) : + row_index_(-1), + hwnd_list_view_(hwnd_list_view), + column1_title_(column1_title), + column2_title_(column2_title), + group_count_(-1), + row_count_(0) +{ +} + + +list_view_builder::~list_view_builder() +{ +} + + +void list_view_builder::build(statistic_group_list_t& gl) +{ + setup_list_view(); + + for (const auto& group : gl) + { + if (!group.second.empty()) + insert_group(group.first); + + for (const auto& item : group.second) + insert_item(item.title_, item.value_, item.editable_); + } +} + + +void list_view_builder::setup_list_view() +{ + HIMAGELIST h_ils = ImageList_Create(16,15,ILC_MASK, 7, 0); + HBITMAP h_bmp = LoadBitmapW(GetCurrentModuleHandle(), MAKEINTRESOURCEW(IDB_PROPERTY_IMAGES)); + ImageList_AddMasked(h_ils, h_bmp, RGB(255, 0, 255)); + + (void) ListView_SetImageList(hwnd_list_view_, h_ils, LVSIL_SMALL); + + std::wstring header = GetResString(IDS_PROPERTY); + + LVCOLUMNW lvc; + lvc.mask = LVCF_FMT | + LVCF_WIDTH | + LVCF_TEXT | + LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = const_cast<wchar_t*>(header.c_str()); + lvc.cx = 120; + lvc.fmt = LVCFMT_LEFT; + + ListView_InsertColumnW(hwnd_list_view_, 0, &lvc); + lvc.iSubItem = 1; + header = GetResString(IDS_PROPERTY_VALUE); + lvc.pszText = const_cast<wchar_t*>(header.c_str()); + ListView_InsertColumnW(hwnd_list_view_, 1, &lvc); + ListView_EnableGroupView(hwnd_list_view_, TRUE); +} + + +void list_view_builder::insert_group(const std::wstring& name) +{ + LVGROUP lvg; + + ZeroMemory(&lvg, sizeof(lvg)); + + lvg.cbSize = sizeof(lvg); + lvg.mask = LVGF_HEADER | LVGF_STATE | LVGF_GROUPID; + lvg.pszHeader = const_cast<wchar_t*>(name.c_str()); + lvg.cchHeader = static_cast<int>(name.size() + 1); + lvg.iGroupId = ++group_count_; + lvg.state = LVGS_NORMAL; + lvg.uAlign = LVGA_HEADER_CENTER; + + ListView_InsertGroup(get_list_view(), row_count_++, &lvg); +} + + +void list_view_builder::insert_item(const std::wstring& title, const std::wstring& value, bool is_editable) +{ + LVITEMW lvi; + + lvi.iItem = ++row_index_; + lvi.iSubItem = 0; + lvi.mask = LVIF_TEXT | LVIF_GROUPID; + lvi.state = 0; + lvi.stateMask = 0; + lvi.pszText = const_cast<wchar_t*>(title.c_str()); + lvi.iGroupId = group_count_; + + if (title.length() > 0) + { + lvi.mask |= LVIF_IMAGE; + + if (is_editable) + lvi.iImage = 4; + else + lvi.iImage = 3; + } + + ListView_InsertItemW(get_list_view(), &lvi); + + lvi.mask = LVIF_TEXT; + lvi.iSubItem = 1; + lvi.pszText = const_cast<wchar_t*>(value.c_str()); + + ListView_SetItemW(get_list_view(), &lvi); + + row_count_++; +} + + +HWND list_view_builder::get_list_view() const +{ + return hwnd_list_view_; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/propsheets/listviewbuilder.hxx b/shell/source/win32/shlxthandler/propsheets/listviewbuilder.hxx new file mode 100644 index 000000000..689da439d --- /dev/null +++ b/shell/source/win32/shlxthandler/propsheets/listviewbuilder.hxx @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_PROPSHEETS_LISTVIEWBUILDER_HXX +#define INCLUDED_SHELL_SOURCE_WIN32_SHLXTHANDLER_PROPSHEETS_LISTVIEWBUILDER_HXX + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#include <string> +#include <memory> +#include "document_statistic.hxx" + + +class list_view_builder; +typedef std::unique_ptr<list_view_builder> list_view_builder_ptr; + +// factory method for list_view_builder +list_view_builder_ptr create_list_view_builder( + HWND hwnd_lv, const std::wstring& col1, const std::wstring& col2); + + +class list_view_builder +{ +public: + virtual ~list_view_builder(); + + void build(statistic_group_list_t& gl); + +protected: + list_view_builder( + HWND hwnd_list_view, + const std::wstring& column1_title, + const std::wstring& column2_title); + + virtual void setup_list_view(); + virtual void insert_group(const std::wstring& title); + virtual void insert_item(const std::wstring& title, const std::wstring& value, bool is_editable); + + HWND get_list_view() const; +private: + int row_index_; + HWND hwnd_list_view_; + std::wstring column1_title_; + std::wstring column2_title_; + int group_count_; + int row_count_; + + friend list_view_builder_ptr create_list_view_builder(HWND hwnd_lv, const std::wstring& col1, const std::wstring& col2); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/propsheets/propsheets.cxx b/shell/source/win32/shlxthandler/propsheets/propsheets.cxx new file mode 100644 index 000000000..48a125d58 --- /dev/null +++ b/shell/source/win32/shlxthandler/propsheets/propsheets.cxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config.hxx> +#include <global.hxx> + +#include <propsheets.hxx> +#include <utilities.hxx> +#include <resource.h> +#include "listviewbuilder.hxx" + +#include <shellapi.h> + +#include <sal/macros.h> + +#include <memory> +#include <string> +#include <vector> +#include <utility> +#include <strsafe.h> + + +/*--------------------------------------------- + INFO - INFO - INFO - INFO - INFO - INFO + + See MSDN "Using Windows XP Visual Styles" + for hints how to enable the new common + control library for our property sheet. + + INFO - INFO - INFO - INFO - INFO - INFO +----------------------------------------------*/ + + +CPropertySheet::CPropertySheet(LONG RefCnt) : + m_RefCnt(RefCnt) +{ + OutputDebugStringFormatW(L"CPropertySheet::CTor [%d], [%ld]", m_RefCnt, g_DllRefCnt ); + InterlockedIncrement(&g_DllRefCnt); +} + + +CPropertySheet::~CPropertySheet() +{ + OutputDebugStringFormatW(L"CPropertySheet::DTor [%d], [%ld]", m_RefCnt, g_DllRefCnt ); + InterlockedDecrement(&g_DllRefCnt); +} + + +// IUnknown methods + + +HRESULT STDMETHODCALLTYPE CPropertySheet::QueryInterface( + REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = nullptr; + + IUnknown* pUnk = nullptr; + if (IID_IUnknown == riid || IID_IShellExtInit == riid) + { + pUnk = static_cast<IShellExtInit*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + else if (IID_IShellPropSheetExt == riid) + { + pUnk = static_cast<IShellPropSheetExt*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + + return E_NOINTERFACE; +} + + +ULONG STDMETHODCALLTYPE CPropertySheet::AddRef() +{ + OutputDebugStringFormatW(L"CPropertySheet::AddRef [%d]", m_RefCnt ); + return InterlockedIncrement(&m_RefCnt); +} + + +ULONG STDMETHODCALLTYPE CPropertySheet::Release() +{ + OutputDebugStringFormatW(L"CPropertySheet::Release [%d]", m_RefCnt ); + LONG refcnt = InterlockedDecrement(&m_RefCnt); + + if (0 == refcnt) + delete this; + + return refcnt; +} + + +// IShellExtInit + + +HRESULT STDMETHODCALLTYPE CPropertySheet::Initialize( + LPCITEMIDLIST /*pidlFolder*/, IDataObject * lpdobj, HKEY /*hkeyProgID*/) +{ + InitCommonControls(); + + STGMEDIUM medium; + FORMATETC fe = {CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; + + HRESULT hr = lpdobj->GetData(&fe, &medium); + + // save the file name + if (SUCCEEDED(hr) && + (1 == DragQueryFileW( + static_cast<HDROP>(medium.hGlobal), + 0xFFFFFFFF, + nullptr, + 0))) + { + UINT size = DragQueryFileW( static_cast<HDROP>(medium.hGlobal), 0, nullptr, 0 ); + if ( size != 0 ) + { + auto buffer = std::make_unique<WCHAR[]>( size + 1 ); + UINT result_size = DragQueryFileW( static_cast<HDROP>(medium.hGlobal), + 0, buffer.get(), size + 1 ); + if ( result_size != 0 ) + { + std::wstring fname = getShortPathName( buffer.get() ); + ZeroMemory( m_szFileName, sizeof( m_szFileName ) ); + wcsncpy( m_szFileName, fname.c_str(), ( SAL_N_ELEMENTS( m_szFileName ) - 1 ) ); + hr = S_OK; + } + else + hr = E_INVALIDARG; + } + else + hr = E_INVALIDARG; + } + else + hr = E_INVALIDARG; + + ReleaseStgMedium(&medium); + + return hr; +} + + +// IShellPropSheetExt + + +HRESULT STDMETHODCALLTYPE CPropertySheet::AddPages(LPFNSVADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) +{ + std::wstring proppage_header; + + PROPSHEETPAGEW psp; + ZeroMemory(&psp, sizeof(psp)); + + // add the summary property page + psp.dwSize = sizeof(psp); + psp.dwFlags = PSP_DEFAULT | PSP_USETITLE | PSP_USECALLBACK; + psp.hInstance = GetCurrentModuleHandle(); + psp.lParam = reinterpret_cast<LPARAM>(this); + psp.pfnCallback = reinterpret_cast<LPFNPSPCALLBACKW>(CPropertySheet::PropPageSummaryCallback); + + HPROPSHEETPAGE hPage = nullptr; + + // add the statistics property page + proppage_header = GetResString(IDS_PROPPAGE_STATISTICS_TITLE); + + psp.pszTemplate = MAKEINTRESOURCEW(IDD_PROPPAGE_STATISTICS); + psp.pszTitle = proppage_header.c_str(); + psp.pfnDlgProc = reinterpret_cast<DLGPROC>(CPropertySheet::PropPageStatisticsProc); + + hPage = CreatePropertySheetPageW(&psp); + + if (hPage) + { + if (lpfnAddPage(hPage, lParam)) + AddRef(); + else + DestroyPropertySheetPage(hPage); + } + + // always return success else no property sheet will be displayed at all + return NOERROR; +} + + +HRESULT STDMETHODCALLTYPE CPropertySheet::ReplacePage( + EXPPS /*uPageID*/, LPFNSVADDPROPSHEETPAGE /*lpfnReplaceWith*/, LPARAM /*lParam*/) +{ + return E_NOTIMPL; +} + + +UINT CALLBACK CPropertySheet::PropPageSummaryCallback( + HWND /*hwnd*/, UINT uMsg, LPPROPSHEETPAGE ppsp) +{ + CPropertySheet* pImpl = + reinterpret_cast<CPropertySheet*>(ppsp->lParam); + + // release this instance, acquired in the AddPages method + if (PSPCB_RELEASE == uMsg) + { + pImpl->Release(); + } + + return TRUE; +} + + +bool CALLBACK CPropertySheet::PropPageSummaryProc(HWND hwnd, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam) +{ + switch (uiMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE psp = reinterpret_cast<LPPROPSHEETPAGE>(lParam); + CPropertySheet* pImpl = reinterpret_cast<CPropertySheet*>(psp->lParam); + pImpl->InitPropPageSummary(hwnd, psp); + return true; + } + } + + return false; +} + + +BOOL CALLBACK CPropertySheet::PropPageStatisticsProc(HWND hwnd, UINT uiMsg, WPARAM /*wParam*/, LPARAM lParam) +{ + switch (uiMsg) + { + case WM_INITDIALOG: + { + LPPROPSHEETPAGE psp = reinterpret_cast<LPPROPSHEETPAGE>(lParam); + CPropertySheet* pImpl = reinterpret_cast<CPropertySheet*>(psp->lParam); + pImpl->InitPropPageStatistics(hwnd, psp); + return TRUE; + } + } + + return FALSE; +} + +void CPropertySheet::InitPropPageSummary(HWND hwnd, LPPROPSHEETPAGE /*lppsp*/) +{ + try + { + CMetaInfoReader metaInfo(m_szFileName); + + SetWindowTextW(GetDlgItem(hwnd,IDC_TITLE), metaInfo.getTagData( META_INFO_TITLE ).c_str() ); + SetWindowTextW(GetDlgItem(hwnd,IDC_AUTHOR), metaInfo.getTagData( META_INFO_AUTHOR ).c_str() ); + SetWindowTextW(GetDlgItem(hwnd,IDC_SUBJECT), metaInfo.getTagData( META_INFO_SUBJECT ).c_str() ); + SetWindowTextW(GetDlgItem(hwnd,IDC_KEYWORDS), metaInfo.getTagData( META_INFO_KEYWORDS ).c_str() ); + + // comments read from meta.xml use "\n" for return, but this will not displayable in Edit control, add + // "\r" before "\n" to form "\r\n" in order to display return in Edit control. + std::wstring tempStr = metaInfo.getTagData( META_INFO_DESCRIPTION ); + std::wstring::size_type itor = tempStr.find ( L"\n" , 0 ); + while (itor != std::wstring::npos) + { + tempStr.insert(itor, L"\r"); + itor = tempStr.find(L"\n", itor + 2); + } + SetWindowTextW(GetDlgItem(hwnd,IDC_COMMENTS), tempStr.c_str()); + } + catch (const std::exception&) + { + } +} + + +void CPropertySheet::InitPropPageStatistics(HWND hwnd, LPPROPSHEETPAGE /*lppsp*/) +{ + try + { + CMetaInfoReader metaInfo(m_szFileName); + + document_statistic_reader_ptr doc_stat_reader = create_document_statistic_reader(m_szFileName, &metaInfo); + + statistic_group_list_t sgl; + doc_stat_reader->read(&sgl); + + list_view_builder_ptr lv_builder = create_list_view_builder( + GetDlgItem(hwnd, IDC_STATISTICSLIST), + GetResString(IDS_PROPERTY), + GetResString(IDS_PROPERTY_VALUE)); + + lv_builder->build(sgl); + } + catch (const std::exception&) + { + } +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/res/ctrylnglist.txt b/shell/source/win32/shlxthandler/res/ctrylnglist.txt new file mode 100644 index 000000000..ec2196e4d --- /dev/null +++ b/shell/source/win32/shlxthandler/res/ctrylnglist.txt @@ -0,0 +1,29 @@ +1 LANG_ENGLISH SUBLANG_ENGLISH_US +3 LANG_PORTUGUESE SUBLANG_PORTUGUESE +4 LANG_GERMAN SUBLANG_GERMAN +7 LANG_RUSSIAN SUBLANG_DEFAULT +30 LANG_GREEK SUBLANG_DEFAULT +31 LANG_DUTCH SUBLANG_DUTCH +33 LANG_FRENCH SUBLANG_FRENCH +34 LANG_SPANISH SUBLANG_SPANISH +35 LANG_FINNISH SUBLANG_DEFAULT +36 LANG_HUNGARIAN SUBLANG_DEFAULT +39 LANG_ITALIAN SUBLANG_ITALIAN +42 LANG_CZECH SUBLANG_DEFAULT +43 LANG_SLOVAK SUBLANG_DEFAULT +44 LANG_ENGLISH SUBLANG_ENGLISH_UK +45 LANG_DANISH SUBLANG_DEFAULT +46 LANG_SWEDISH SUBLANG_SWEDISH +47 LANG_NORWEGIAN SUBLANG_NORWEGIAN_BOKMAL +48 LANG_POLISH SUBLANG_DEFAULT +49 LANG_GERMAN SUBLANG_DEFAULT +55 LANG_PORTUGUESE SUBLANG_PORTUGUESE_BRAZILIAN +81 LANG_JAPANESE SUBLANG_DEFAULT +82 LANG_KOREAN SUBLANG_KOREAN +86 LANG_CHINESE SUBLANG_CHINESE_SIMPLIFIED +88 LANG_CHINESE SUBLANG_CHINESE_TRADITIONAL +90 LANG_TURKISH SUBLANG_DEFAULT +96 LANG_ARABIC SUBLANG_DEFAULT +97 LANG_HEBREW SUBLANG_DEFAULT +37 LANG_CATALAN SUBLANG_DEFAULT +66 LANG_THAI SUBLANG_DEFAULT diff --git a/shell/source/win32/shlxthandler/res/prop_img.bmp b/shell/source/win32/shlxthandler/res/prop_img.bmp Binary files differnew file mode 100644 index 000000000..1849a8bb6 --- /dev/null +++ b/shell/source/win32/shlxthandler/res/prop_img.bmp diff --git a/shell/source/win32/shlxthandler/res/rcfooter.txt b/shell/source/win32/shlxthandler/res/rcfooter.txt new file mode 100644 index 000000000..ce333b32a --- /dev/null +++ b/shell/source/win32/shlxthandler/res/rcfooter.txt @@ -0,0 +1,4 @@ + + +IDP_SIGNET RCDATA "signet.png" + diff --git a/shell/source/win32/shlxthandler/res/rcheader.txt b/shell/source/win32/shlxthandler/res/rcheader.txt new file mode 100644 index 000000000..42fb81ee5 --- /dev/null +++ b/shell/source/win32/shlxthandler/res/rcheader.txt @@ -0,0 +1,10 @@ +#include <winresrc.h> +#define LB_ADDSTRING (WM_USER+1) +#define CB_ADDSTRING (WM_USER+3) +#define IDC_STATIC (-1) + +#include "resource.h" + +MANIFEST_RESOURCE_ID RT_MANIFEST "shlxthdl.manifest" + +IDB_PROPERTY_IMAGES BITMAP "prop_img.bmp" diff --git a/shell/source/win32/shlxthandler/res/rctmpl.txt b/shell/source/win32/shlxthandler/res/rctmpl.txt new file mode 100644 index 000000000..c48d7f61f --- /dev/null +++ b/shell/source/win32/shlxthandler/res/rctmpl.txt @@ -0,0 +1,88 @@ +// +// This file is part of the LibreOffice project. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// This file incorporates work covered by the following license notice: +// +// Licensed to the Apache Software Foundation (ASF) under one or more +// contributor license agreements. See the NOTICE file distributed +// with this work for additional information regarding copyright +// ownership. The ASF licenses this file to you under the Apache +// License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of +// the License at http://www.apache.org/licenses/LICENSE-2.0 . +// + +// Dialog + +IDD_PROPPAGE_SUMMARY DIALOGEX 0, 0, 222, 211 +STYLE WS_CHILD +FONT 8, "MS Sans Serif" +BEGIN + LTEXT %TITLE_COLON% ,IDC_STATIC,7,14,39,10 + LTEXT %AUTHOR_COLON% ,IDC_STATIC,7,31,47,10 + LTEXT %SUBJECT_COLON% ,IDC_STATIC,7,47,39,10 + LTEXT %KEYWORDS_COLON% ,IDC_STATIC,7,94,49,10 + EDITTEXT IDC_TITLE,63,12,154,12,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER,WS_EX_CLIENTEDGE + EDITTEXT IDC_AUTHOR,63,29,154,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER, + WS_EX_CLIENTEDGE + EDITTEXT IDC_SUBJECT,63,46,154,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER, + WS_EX_CLIENTEDGE + EDITTEXT IDC_KEYWORDS,64,93,154,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER, + WS_EX_CLIENTEDGE + CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,7,75,211,1 + EDITTEXT IDC_COMMENTS,64,111,154,83,ES_MULTILINE | ES_LEFT | ES_READONLY | ES_WANTRETURN | + NOT WS_BORDER | WS_VSCROLL,WS_EX_CLIENTEDGE + LTEXT %COMMENTS_COLON% ,IDC_STATIC,7,112,49,10 +END + +IDD_PROPPAGE_STATISTICS DIALOG DISCARDABLE 0, 0, 222, 215 +STYLE WS_CHILD +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "",IDC_STATISTICSLIST,"SysListView32",LVS_REPORT | + WS_BORDER | WS_TABSTOP,6,7,214,186 +END + +// String Table + +STRINGTABLE DISCARDABLE +BEGIN + IDS_TITLE %TITLE% + IDS_TITLE_COLON %TITLE_COLON% + IDS_SUBJECT %SUBJECT% + IDS_SUBJECT_COLON %SUBJECT_COLON% + IDS_AUTHOR %AUTHOR% + IDS_AUTHOR_COLON %AUTHOR_COLON% + IDS_KEYWORDS %KEYWORDS% + IDS_COMMENTS %COMMENTS% + IDS_COMMENTS_COLON %COMMENTS_COLON% + IDS_PAGES %PAGES% + IDS_TABLES %TABLES% + IDS_GRAPHICS %GRAPHICS% + IDS_OBJECTS %OBJECTS% + IDS_OLE_OBJECTS %OLE_OBJECTS% + IDS_PARAGRAPHS %PARAGRAPHS% + IDS_WORDS %WORDS% + IDS_CHARACTERS %CHARACTERS% + IDS_ROWS %ROWS% + IDS_ORIGIN %ORIGIN% + IDS_VERSION %VERSION% + IDS_SHEETS %SHEETS% + IDS_CELLS %CELLS% + IDS_MODIFIED %MODIFIED% + IDS_MODIFIED_COLON %MODIFIED_COLON% + IDS_DOCUMENT_NUMBER %DOCUMENT_NUMBER% + IDS_EDITING_TIME %EDITING_TIME% + IDS_PROPPAGE_STATISTICS_TITLE %STATISTICS_TITLE% + IDS_PROPPAGE_SUMMARY_TITLE %SUMMARY_TITLE% + IDS_PROPERTY %PROPERTY% + IDS_PROPERTY_VALUE %PROPERTY_VALUE% + IDS_DESCRIPTION %DESCRIPTION% + IDS_SIZE_COLON %SIZE_COLON% + IDS_TYPE_COLON %TYPE_COLON% +END diff --git a/shell/source/win32/shlxthandler/res/shlxthdl.manifest b/shell/source/win32/shlxthandler/res/shlxthdl.manifest new file mode 100644 index 000000000..36131a343 --- /dev/null +++ b/shell/source/win32/shlxthandler/res/shlxthdl.manifest @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> +<assemblyIdentity version="1.0.0.0" processorArchitecture="x86" name="LibreOffice.shlxthdl" type="win32" /> +<description>LibreOffice Shell Extension</description> +<dependency> +<dependentAssembly> +<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" + publicKeyToken="6595b64144ccf1df" language="*"/> +</dependentAssembly> +</dependency> +</assembly> diff --git a/shell/source/win32/shlxthandler/res/shlxthdl.rc b/shell/source/win32/shlxthandler/res/shlxthdl.rc new file mode 100644 index 000000000..4c3433738 --- /dev/null +++ b/shell/source/win32/shlxthandler/res/shlxthdl.rc @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "shlxthdl_impl.rc" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/res/shlxthdl.ulf b/shell/source/win32/shlxthandler/res/shlxthdl.ulf new file mode 100644 index 000000000..57a286605 --- /dev/null +++ b/shell/source/win32/shlxthandler/res/shlxthdl.ulf @@ -0,0 +1,148 @@ +[%TITLE%] +en-US = "Title" + +[%TITLE_COLON%] +en-US = "Title:" + +[%SUBJECT%] +en-US = "Subject" + +[%SUBJECT_COLON%] +en-US = "Subject:" + +[%AUTHOR%] +en-US = "Author" + +[%AUTHOR_COLON%] +en-US = "Author:" + +[%KEYWORDS%] +en-US = "Keywords" + +[%KEYWORDS_COLON%] +en-US = "Keywords:" + +[%COMMENTS%] +en-US = "Comments" + +[%COMMENTS_COLON%] +en-US = "Comments:" + +[%PAGES%] +en-US = "Pages" + +[%TABLES%] +en-US = "Tables" + +[%GRAPHICS%] +en-US = "Images" + +[%OBJECTS%] +en-US = "Objects" + +[%OLE_OBJECTS%] +en-US = "OLE Objects" + +[%PARAGRAPHS%] +en-US = "Paragraphs" + +[%WORDS%] +en-US = "Words" + +[%CHARACTERS%] +en-US = "Characters" + +[%ROWS%] +en-US = "Lines" + +[%ORIGIN%] +en-US = "Origin" + +[%VERSION%] +en-US = "Version" + +[%SHEETS%] +en-US = "Sheets" + +[%CELLS%] +en-US = "Cells" + +[%STATISTICS_TITLE%] +en-US = "Document Statistics" + +[%SUMMARY_TITLE%] +en-US = "Summary" + +[%PROPERTY%] +en-US = "Property" + +[%PROPERTY_VALUE%] +en-US = "Value" + +[%MODIFIED%] +en-US = "Modified" + +[%MODIFIED_COLON%] +en-US = "Modified:" + +[%DOCUMENT_NUMBER%] +en-US = "Revision number" + +[%DOCUMENT_NUMBER_COLON%] +en-US = "Revision number:" + +[%EDITING_TIME%] +en-US = "Total editing time" + +[%EDITING_TIME_COLON%] +en-US = "Total editing time:" + +[%DESCRIPTION%] +en-US = "Description" + +[%DESCRIPTION_COLON%] +en-US = "Description:" + +[%SIZE_COLON%] +en-US = "Size:" + +[%TYPE_COLON%] +en-US = "Type:" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shell/source/win32/shlxthandler/res/signet.png b/shell/source/win32/shlxthandler/res/signet.png Binary files differnew file mode 100644 index 000000000..bccaaff81 --- /dev/null +++ b/shell/source/win32/shlxthandler/res/signet.png diff --git a/shell/source/win32/shlxthandler/shlxthdl.cxx b/shell/source/win32/shlxthandler/shlxthdl.cxx new file mode 100644 index 000000000..9a5b8a379 --- /dev/null +++ b/shell/source/win32/shlxthandler/shlxthdl.cxx @@ -0,0 +1,409 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config.hxx> +#include <global.hxx> +#include <shlxthdl.hxx> +#include "classfactory.hxx" +#include <registry.hxx> +#include <fileextensions.hxx> +#include <utilities.hxx> + +#include <string> +#include <shlobj.h> + +#include <olectl.h> // declarations of DllRegisterServer/DllUnregisterServer + +// Module global + +LONG g_DllRefCnt = 0; +HINSTANCE g_hModule = nullptr; + +namespace /* private */ +{ + const wchar_t* const GUID_PLACEHOLDER = L"{GUID}"; + const wchar_t* const EXTENSION_PLACEHOLDER = L"{EXT}"; + const wchar_t* const FORWARDKEY_PLACEHOLDER = L"{FWDKEY}"; + + const wchar_t* const CLSID_ENTRY = L"CLSID\\{GUID}\\InProcServer32"; + const wchar_t* const SHELLEX_IID_ENTRY = L"{EXT}\\shellex\\{GUID}"; + const wchar_t* const SHELLEX_ENTRY = L"{EXT}\\shellex"; + const wchar_t* const FORWARD_PROPSHEET_MYPROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers\\MyPropSheet1"; + const wchar_t* const FORWARD_PROPSHEET_ENTRY = L"{FWDKEY}\\shellex\\PropertySheetHandlers"; + const wchar_t* const FORWARD_SHELLEX_ENTRY = L"{FWDKEY}\\shellex"; + + const wchar_t* const SHELL_EXTENSION_APPROVED_KEY_NAME = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"; + + + // "String Placeholder" -> + // "String Replacement" + + void SubstitutePlaceholder(std::wstring& String, const std::wstring& Placeholder, const std::wstring& Replacement) + { + std::wstring::size_type idx = String.find(Placeholder); + std::wstring::size_type len = Placeholder.length(); + + while (std::wstring::npos != idx) + { + String.replace(idx, len, Replacement); + idx = String.find(Placeholder); + } + } + + /* Make the registry entry + HKCR\CLSID\{GUID} + InProcServer32 = Path\shlxthdl.dll + ThreadingModel = Apartment + */ + HRESULT RegisterComComponent(const wchar_t* FilePath, const CLSID& Guid) + { + std::wstring ClsidEntry = CLSID_ENTRY; + SubstitutePlaceholder(ClsidEntry, GUID_PLACEHOLDER, ClsidToString(Guid)); + + if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"", FilePath)) + return E_FAIL; + + if (!SetRegistryKey(HKEY_CLASSES_ROOT, ClsidEntry.c_str(), L"ThreadingModel", L"Apartment")) + return E_FAIL; + + return S_OK; + } + + HRESULT UnregisterComComponent(const CLSID& Guid) + { + std::wstring tmp = L"CLSID\\"; + tmp += ClsidToString(Guid); + return DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()) ? S_OK : E_FAIL; + } + + HRESULT RegisterColumnHandler(const wchar_t* ModuleFileName) + { + if (FAILED(RegisterComComponent(ModuleFileName, CLSID_COLUMN_HANDLER))) + return E_FAIL; + + std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\"; + tmp += ClsidToString(CLSID_COLUMN_HANDLER); + + return SetRegistryKey( + HKEY_CLASSES_ROOT, + tmp.c_str(), + L"", + COLUMN_HANDLER_DESCRIPTIVE_NAME) ? S_OK : E_FAIL; + } + + HRESULT UnregisterColumnHandler() + { + std::wstring tmp = L"Folder\\shellex\\ColumnHandlers\\"; + tmp += ClsidToString(CLSID_COLUMN_HANDLER); + + if (!DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str())) + return E_FAIL; + + return UnregisterComComponent(CLSID_COLUMN_HANDLER); + } + + HRESULT RegisterInfotipHandler(const wchar_t* ModuleFileName) + { + if (FAILED(RegisterComComponent(ModuleFileName, CLSID_INFOTIP_HANDLER))) + return E_FAIL; + + std::wstring iid = ClsidToString(IID_IQueryInfo); + std::wstring tmp; + + for(size_t i = 0; i < OOFileExtensionTableSize; i++) + { + tmp = SHELLEX_IID_ENTRY; + SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU); + SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); + + if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_INFOTIP_HANDLER).c_str())) + return E_FAIL; + } + return S_OK; + } + + HRESULT UnregisterInfotipHandler() + { + std::wstring iid = ClsidToString(IID_IQueryInfo); + std::wstring tmp; + + for (size_t i = 0; i < OOFileExtensionTableSize; i++) + { + tmp = SHELLEX_IID_ENTRY; + + SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU); + SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); + + DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); + + // if there are no further subkey below .ext\\shellex + // delete the whole subkey + tmp = SHELLEX_ENTRY; + SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU); + + bool HasSubKeys = true; + if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys) + DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); + } + return UnregisterComComponent(CLSID_INFOTIP_HANDLER); + } + + HRESULT RegisterPropSheetHandler(const wchar_t* ModuleFileName) + { + std::wstring FwdKeyEntry; + + if (FAILED(RegisterComComponent(ModuleFileName, CLSID_PROPERTYSHEET_HANDLER))) + return E_FAIL; + + for (size_t i = 0; i < OOFileExtensionTableSize; i++) + { + FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY; + SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); + + if (!SetRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), L"", ClsidToString(CLSID_PROPERTYSHEET_HANDLER).c_str())) + return E_FAIL; + } + return S_OK; + } + + HRESULT UnregisterPropSheetHandler() + { + std::wstring FwdKeyEntry; + + for (size_t i = 0; i < OOFileExtensionTableSize; i++) + { + FwdKeyEntry = FORWARD_PROPSHEET_MYPROPSHEET_ENTRY; + SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); + + DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); + + FwdKeyEntry = FORWARD_PROPSHEET_ENTRY; + SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); + + bool HasSubKeys = true; + if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys) + DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); + + FwdKeyEntry = FORWARD_SHELLEX_ENTRY; + SubstitutePlaceholder(FwdKeyEntry, FORWARDKEY_PLACEHOLDER, OOFileExtensionTable[i].RegistryForwardKey); + + HasSubKeys = true; + if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str(), HasSubKeys) && !HasSubKeys) + DeleteRegistryKey(HKEY_CLASSES_ROOT, FwdKeyEntry.c_str()); + } + + return UnregisterComComponent(CLSID_PROPERTYSHEET_HANDLER); + } + + HRESULT RegisterThumbviewerHandler(const wchar_t* ModuleFileName) + { + if (FAILED(RegisterComComponent(ModuleFileName, CLSID_THUMBVIEWER_HANDLER))) + return E_FAIL; + + std::wstring iid = ClsidToString(IID_IExtractImage); + std::wstring tmp; + + for(size_t i = 0; i < OOFileExtensionTableSize; i++) + { + tmp = SHELLEX_IID_ENTRY; + + SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU); + SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); + + if (!SetRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), L"", ClsidToString(CLSID_THUMBVIEWER_HANDLER).c_str())) + return E_FAIL; + } + return S_OK; + } + + HRESULT UnregisterThumbviewerHandler() + { + std::wstring iid = ClsidToString(IID_IExtractImage); + std::wstring tmp; + + for (size_t i = 0; i < OOFileExtensionTableSize; i++) + { + tmp = SHELLEX_IID_ENTRY; + + SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU); + SubstitutePlaceholder(tmp, GUID_PLACEHOLDER, iid); + + DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); + + // if there are no further subkey below .ext\\shellex + // delete the whole subkey + tmp = SHELLEX_ENTRY; + SubstitutePlaceholder(tmp, EXTENSION_PLACEHOLDER, OOFileExtensionTable[i].ExtensionU); + + bool HasSubKeys = true; + if (HasSubkeysRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str(), HasSubKeys) && !HasSubKeys) + DeleteRegistryKey(HKEY_CLASSES_ROOT, tmp.c_str()); + } + return UnregisterComComponent(CLSID_THUMBVIEWER_HANDLER); + } + + /** Approving/Unapproving the Shell Extension, it's important under Windows + NT/2000/XP, see MSDN: Creating Shell Extension Handlers */ + HRESULT ApproveShellExtension(const CLSID& clsid, const std::wstring& Description) + { + bool bRet = SetRegistryKey( + HKEY_LOCAL_MACHINE, + SHELL_EXTENSION_APPROVED_KEY_NAME, + ClsidToString(clsid).c_str(), + Description.c_str()); + + return bRet ? S_OK : E_FAIL; + } + + HRESULT UnapproveShellExtension(const CLSID& Clsid) + { + HKEY hkey; + + LONG rc = RegOpenKeyW( + HKEY_LOCAL_MACHINE, + SHELL_EXTENSION_APPROVED_KEY_NAME, + &hkey); + + if (ERROR_SUCCESS == rc) + { + rc = RegDeleteValueW( + hkey, + ClsidToString(Clsid).c_str()); + + rc |= RegCloseKey(hkey); + } + + return rc == ERROR_SUCCESS ? S_OK : E_FAIL; + } + +} // namespace /* private */ + + +// COM exports + + +STDAPI DllRegisterServer() +{ + WCHAR ModuleFileName[MAX_PATH]; + + GetModuleFileNameW( + GetCurrentModuleHandle(), + ModuleFileName, + sizeof(ModuleFileName)/sizeof(ModuleFileName[0])); + + HRESULT hr = S_OK; + + if (SUCCEEDED(RegisterColumnHandler(ModuleFileName))) + ApproveShellExtension(CLSID_COLUMN_HANDLER, COLUMN_HANDLER_DESCRIPTIVE_NAME); + else + hr = E_FAIL; + + if (SUCCEEDED(RegisterInfotipHandler(ModuleFileName))) + ApproveShellExtension(CLSID_INFOTIP_HANDLER, INFOTIP_HANDLER_DESCRIPTIVE_NAME); + else + hr = E_FAIL; + + if (SUCCEEDED(RegisterPropSheetHandler(ModuleFileName))) + ApproveShellExtension(CLSID_PROPERTYSHEET_HANDLER, PROPSHEET_HANDLER_DESCRIPTIVE_NAME); + else + hr = E_FAIL; + + if (SUCCEEDED(RegisterThumbviewerHandler(ModuleFileName))) + ApproveShellExtension(CLSID_THUMBVIEWER_HANDLER, THUMBVIEWER_HANDLER_DESCRIPTIVE_NAME); + else + hr = E_FAIL; + + // notify the Shell that something has changed + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return hr; +} + +STDAPI DllUnregisterServer() +{ + HRESULT hr = S_OK; + + if (FAILED(UnregisterColumnHandler())) + hr = E_FAIL; + + UnapproveShellExtension(CLSID_COLUMN_HANDLER); + + if (FAILED(UnregisterInfotipHandler())) + hr = E_FAIL; + + UnapproveShellExtension(CLSID_INFOTIP_HANDLER); + + if (FAILED(UnregisterPropSheetHandler())) + hr = E_FAIL; + + UnapproveShellExtension(CLSID_PROPERTYSHEET_HANDLER); + + if (FAILED(UnregisterThumbviewerHandler())) + hr = E_FAIL; + + UnapproveShellExtension(CLSID_THUMBVIEWER_HANDLER); + + // notify the Shell that something has changed + SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr); + + return hr; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + *ppv = nullptr; + + if ((rclsid != CLSID_INFOTIP_HANDLER) && + (rclsid != CLSID_COLUMN_HANDLER) && + (rclsid != CLSID_PROPERTYSHEET_HANDLER) && + (rclsid != CLSID_THUMBVIEWER_HANDLER)) + return CLASS_E_CLASSNOTAVAILABLE; + + if ((riid != IID_IUnknown) && (riid != IID_IClassFactory)) + return E_NOINTERFACE; + + if ( rclsid == CLSID_INFOTIP_HANDLER ) + OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_INFOTIP_HANDLER\n" ); + else if ( rclsid == CLSID_COLUMN_HANDLER ) + OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_COLUMN_HANDLER\n" ); + else if ( rclsid == CLSID_PROPERTYSHEET_HANDLER ) + OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_PROPERTYSHEET_HANDLER\n" ); + else if ( rclsid == CLSID_THUMBVIEWER_HANDLER ) + OutputDebugStringFormatW( L"DllGetClassObject: Create CLSID_THUMBVIEWER_HANDLER\n" ); + + IUnknown* pUnk = new CClassFactory(rclsid); + *ppv = pUnk; + return S_OK; +} + +STDAPI DllCanUnloadNow() +{ + if (CClassFactory::IsLocked() || g_DllRefCnt > 0) + return S_FALSE; + + return S_OK; +} + +BOOL WINAPI DllMain(HINSTANCE hInst, ULONG /*ul_reason_for_call*/, LPVOID /*lpReserved*/) +{ + g_hModule = hInst; + return TRUE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/shlxthdl.def b/shell/source/win32/shlxthandler/shlxthdl.def new file mode 100644 index 000000000..d731a151f --- /dev/null +++ b/shell/source/win32/shlxthandler/shlxthdl.def @@ -0,0 +1,5 @@ +EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx b/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx new file mode 100644 index 000000000..657664ff5 --- /dev/null +++ b/shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx @@ -0,0 +1,500 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef DONT_HAVE_GDIPLUS + + +#include <global.hxx> + +#include <thumbviewer.hxx> +#include <shlxthdl.hxx> +#include <registry.hxx> +#include <fileextensions.hxx> +#include <config.hxx> +#include <zipfile.hxx> +#include <utilities.hxx> + +#include <resource.h> + +#include <stdio.h> +#include <utility> +#include <stdlib.h> + +#include <shellapi.h> + +#include <memory> + +namespace internal +{ + /* The signet.png used for thumbnails of signed documents + is contained as resource in this module, the resource + id is 2000 */ + static void LoadSignetImageFromResource(ZipFile::ZipContentBuffer_t& buffer) + { + HRSRC hrc = FindResourceW(g_hModule, L"#2000", reinterpret_cast<LPWSTR>(RT_RCDATA)); + DWORD size = SizeofResource(g_hModule, hrc); + HGLOBAL hglob = LoadResource(g_hModule, hrc); + char* data = static_cast<char*>(LockResource(hglob)); + buffer = ZipFile::ZipContentBuffer_t(data, data + size); + } + + static bool IsSignedDocument(const ZipFile* zipfile) + { + return zipfile->HasContent("META-INF/documentsignatures.xml"); + } + + static Gdiplus::Point CalcSignetPosition( + const Gdiplus::Rect& canvas, const Gdiplus::Rect& thumbnail_border, const Gdiplus::Rect& signet) + { + int x = 0; + int y = 0; + int hoffset = canvas.GetRight() - thumbnail_border.GetRight(); + int voffset = canvas.GetBottom() - thumbnail_border.GetBottom(); + + if (hoffset > voffset) + { + x = thumbnail_border.GetRight() - signet.GetRight() + min(signet.GetRight() / 2, hoffset); + y = thumbnail_border.GetBottom() - signet.GetBottom(); + } + else + { + x = thumbnail_border.GetRight() - signet.GetRight(); + y = thumbnail_border.GetBottom() - signet.GetBottom() + min(signet.GetBottom() / 2, voffset); + } + + return Gdiplus::Point(x,y); + } +} + +namespace { + +Gdiplus::Rect CalcScaledAspectRatio(const Gdiplus::Rect& src, const Gdiplus::Rect& dest) +{ + Gdiplus::Rect result; + if (src.Width >= src.Height) + result = Gdiplus::Rect(0, 0, dest.Width, src.Height * dest.Width / src.Width); + else + result = Gdiplus::Rect(0, 0, src.Width * dest.Height / src.Height, dest.Height); + + return result; +} + +class StreamOnZipBuffer final : public IStream +{ +public: + explicit StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer); + + // IUnknown + virtual ULONG STDMETHODCALLTYPE AddRef() override; + virtual ULONG STDMETHODCALLTYPE Release() override; + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) override; + + // IStream + virtual HRESULT STDMETHODCALLTYPE Read(void *pv, ULONG cb, ULONG *pcbRead) override; + virtual HRESULT STDMETHODCALLTYPE Write(void const *pv, ULONG cb, ULONG *pcbWritten) override; + virtual HRESULT STDMETHODCALLTYPE Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition) override; + virtual HRESULT STDMETHODCALLTYPE SetSize(ULARGE_INTEGER libNewSize) override; + virtual HRESULT STDMETHODCALLTYPE CopyTo(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) override; + virtual HRESULT STDMETHODCALLTYPE Commit(DWORD grfCommitFlags) override; + virtual HRESULT STDMETHODCALLTYPE Revert() override; + virtual HRESULT STDMETHODCALLTYPE LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) override; + virtual HRESULT STDMETHODCALLTYPE UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) override; + virtual HRESULT STDMETHODCALLTYPE Stat(STATSTG *pstatstg, DWORD grfStatFlag) override; + virtual HRESULT STDMETHODCALLTYPE Clone(IStream **ppstm) override; + +private: + LONG ref_count_; + const ZipFile::ZipContentBuffer_t& ref_zip_buffer_; + size_t pos_; +}; + +} + +StreamOnZipBuffer::StreamOnZipBuffer(const ZipFile::ZipContentBuffer_t& zip_buffer) : + ref_count_(1), + ref_zip_buffer_(zip_buffer), + pos_(0) +{ +} + +// IUnknown methods + +ULONG STDMETHODCALLTYPE StreamOnZipBuffer::AddRef() +{ + return InterlockedIncrement(&ref_count_); +} + +ULONG STDMETHODCALLTYPE StreamOnZipBuffer::Release() +{ + LONG refcnt = InterlockedDecrement(&ref_count_); + + if (0 == ref_count_) + delete this; + + return refcnt; +} + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = nullptr; + IUnknown* pUnk = nullptr; + + if ((IID_IUnknown == riid) || (IID_IStream == riid)) + { + pUnk = this; + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + return E_NOINTERFACE; +} + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Read(void *pv, ULONG cb, ULONG *pcbRead) +{ + if (pv == nullptr) + return STG_E_INVALIDPOINTER; + + size_t size = ref_zip_buffer_.size(); + + if (pos_ > size) + return S_FALSE; + + char* p = static_cast<char*>(pv); + ULONG read = 0; + + for ( ;(pos_ < size) && (cb > 0); pos_++, cb--, read++) + *p++ = ref_zip_buffer_[pos_]; + + if (pcbRead) + *pcbRead = read; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *) +{ + __int64 size = static_cast<__int64>(ref_zip_buffer_.size()); + __int64 p = 0; + + switch (dwOrigin) + { + case STREAM_SEEK_SET: + break; + case STREAM_SEEK_CUR: + p = static_cast<__int64>(pos_); + break; + case STREAM_SEEK_END: + p = size - 1; + break; + } + + HRESULT hr = STG_E_INVALIDFUNCTION; + + p += dlibMove.QuadPart; + + if ( ( p >= 0 ) && (p < size) ) + { + pos_ = static_cast<size_t>(p); + hr = S_OK; + } + return hr; +} + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Stat(STATSTG *pstatstg, DWORD grfStatFlag) +{ + if (pstatstg == nullptr) + return STG_E_INVALIDPOINTER; + + ZeroMemory(pstatstg, sizeof(STATSTG)); + + if (grfStatFlag == STATFLAG_DEFAULT) + { + size_t sz = 4 * sizeof(wchar_t); + wchar_t* name = static_cast<wchar_t*>(CoTaskMemAlloc(sz)); + ZeroMemory(name, sz); + memcpy(name, L"png", 3 * sizeof(wchar_t)); + pstatstg->pwcsName = name; + } + + pstatstg->type = STGTY_LOCKBYTES; + + ULARGE_INTEGER uli; + uli.LowPart = static_cast<DWORD>(ref_zip_buffer_.size()); + uli.HighPart = 0; + + pstatstg->cbSize = uli; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Write(void const *, ULONG, ULONG *) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::SetSize(ULARGE_INTEGER) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::CopyTo(IStream *, ULARGE_INTEGER, ULARGE_INTEGER *, ULARGE_INTEGER *) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Commit(DWORD) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Revert() +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::LockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::UnlockRegion(ULARGE_INTEGER, ULARGE_INTEGER, DWORD) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE StreamOnZipBuffer::Clone(IStream **) +{ return E_NOTIMPL; } + + +CThumbviewer::CThumbviewer(LONG RefCnt) : + ref_count_(RefCnt) +{ + InterlockedIncrement(&g_DllRefCnt); + + thumbnail_size_.cx = 0; + thumbnail_size_.cy = 0; + + Gdiplus::GdiplusStartupInput gdiplusStartupInput; + Gdiplus::GdiplusStartup(&gdiplus_token_, &gdiplusStartupInput, nullptr); + + ZipFile::ZipContentBuffer_t img_data; + internal::LoadSignetImageFromResource(img_data); + IStream* stream = new StreamOnZipBuffer(img_data); + signet_ = new Gdiplus::Bitmap(stream, TRUE); + stream->Release(); +} + +CThumbviewer::~CThumbviewer() +{ + delete signet_; + Gdiplus::GdiplusShutdown(gdiplus_token_); + InterlockedDecrement(&g_DllRefCnt); +} + +// IUnknown methods + +HRESULT STDMETHODCALLTYPE CThumbviewer::QueryInterface(REFIID riid, void __RPC_FAR *__RPC_FAR *ppvObject) +{ + *ppvObject = nullptr; + IUnknown* pUnk = nullptr; + + if ((IID_IUnknown == riid) || (IID_IPersistFile == riid)) + { + pUnk = static_cast<IPersistFile*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + else if (IID_IExtractImage == riid) + { + pUnk = static_cast<IExtractImage*>(this); + pUnk->AddRef(); + *ppvObject = pUnk; + return S_OK; + } + return E_NOINTERFACE; +} + +ULONG STDMETHODCALLTYPE CThumbviewer::AddRef() +{ + return InterlockedIncrement(&ref_count_); +} + +ULONG STDMETHODCALLTYPE CThumbviewer::Release() +{ + LONG refcnt = InterlockedDecrement(&ref_count_); + + if (0 == ref_count_) + delete this; + + return refcnt; +} + +// IExtractImage2 methods + +const std::string THUMBNAIL_CONTENT = "Thumbnails/thumbnail.png"; + +HRESULT STDMETHODCALLTYPE CThumbviewer::Extract(HBITMAP *phBmpImage) +{ + HRESULT hr = E_FAIL; + + try + { + std::wstring fname = getShortPathName( filename_ ); + std::unique_ptr<ZipFile> zipfile( new ZipFile( fname ) ); + + if (zipfile->HasContent(THUMBNAIL_CONTENT)) + { + ZipFile::ZipContentBuffer_t thumbnail; + zipfile->GetUncompressedContent(THUMBNAIL_CONTENT, thumbnail); + IStream* stream = new StreamOnZipBuffer(thumbnail); + + Gdiplus::Bitmap thumbnail_png(stream, TRUE); + + if ((thumbnail_png.GetHeight() == 0) || (thumbnail_png.GetWidth() == 0)) + { + stream->Release(); + return E_FAIL; + } + + HWND hwnd = GetDesktopWindow(); + HDC hdc = GetDC(hwnd); + HDC memDC = CreateCompatibleDC(hdc); + + if (memDC) + { + UINT offset = 3; // reserve a little border space + + Gdiplus::Rect canvas(0, 0, thumbnail_size_.cx, thumbnail_size_.cy); + Gdiplus::Rect canvas_thumbnail(offset, offset, thumbnail_size_.cx - 2 * offset, thumbnail_size_.cy - 2 * offset); + + Gdiplus::Rect scaledRect = CalcScaledAspectRatio( + Gdiplus::Rect(0, 0, thumbnail_png.GetWidth(), thumbnail_png.GetHeight()), canvas_thumbnail); + + struct { + BITMAPINFOHEADER bi; + DWORD ct[256]; + } dib; + + ZeroMemory(&dib, sizeof(dib)); + + dib.bi.biSize = sizeof(BITMAPINFOHEADER); + dib.bi.biWidth = thumbnail_size_.cx; + dib.bi.biHeight = thumbnail_size_.cy; + dib.bi.biPlanes = 1; + dib.bi.biBitCount = static_cast<WORD>(color_depth_); + dib.bi.biCompression = BI_RGB; + + LPVOID lpBits; + HBITMAP hMemBmp = CreateDIBSection(memDC, reinterpret_cast<LPBITMAPINFO>(&dib), DIB_RGB_COLORS, &lpBits, nullptr, 0); + HGDIOBJ hOldObj = SelectObject(memDC, hMemBmp); + + Gdiplus::Graphics graphics(memDC); + Gdiplus::Pen blackPen(Gdiplus::Color(255, 0, 0, 0), 1); + + Gdiplus::SolidBrush whiteBrush(Gdiplus::Color(255, 255, 255, 255)); + graphics.FillRectangle(&whiteBrush, canvas); + + scaledRect.X = (canvas.Width - scaledRect.Width) / 2; + scaledRect.Y = (canvas.Height - scaledRect.Height) / 2; + + Gdiplus::Rect border_rect(scaledRect.X, scaledRect.Y, scaledRect.Width, scaledRect.Height); + graphics.DrawRectangle(&blackPen, border_rect); + + scaledRect.X += 1; + scaledRect.Y += 1; + scaledRect.Width -= 1; + scaledRect.Height -= 1; + + graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic); + Gdiplus::Status stat = graphics.DrawImage( + &thumbnail_png, scaledRect, 0 , 0, + thumbnail_png.GetWidth(), thumbnail_png.GetHeight(), Gdiplus::UnitPixel); + + /* Add a signet sign to the thumbnail of signed documents */ + if (internal::IsSignedDocument(zipfile.get())) + { + double SCALING_FACTOR = 0.6; + Gdiplus::Rect signet_scaled( + 0, 0, static_cast<INT>(signet_->GetWidth() * SCALING_FACTOR), static_cast<INT>(signet_->GetHeight() * SCALING_FACTOR)); + Gdiplus::Point pos_signet = internal::CalcSignetPosition(canvas_thumbnail, border_rect, signet_scaled); + Gdiplus::Rect dest(pos_signet.X, pos_signet.Y, signet_scaled.GetRight(), signet_scaled.GetBottom()); + + stat = graphics.DrawImage( + signet_, dest, + 0, 0, signet_->GetWidth(), signet_->GetHeight(), + Gdiplus::UnitPixel); + } + + if (stat == Gdiplus::Ok) + { + *phBmpImage = hMemBmp; + hr = NOERROR; + } + + SelectObject(memDC, hOldObj); + DeleteDC(memDC); + } + + ReleaseDC(hwnd, hdc); + stream->Release(); + } + } + catch(std::exception&) + { + OutputDebugStringFormatW( L"CThumbviewer Extract ERROR!\n" ); + hr = E_FAIL; + } + return hr; +} + +HRESULT STDMETHODCALLTYPE CThumbviewer::GetLocation( + LPWSTR pszPathBuffer, DWORD cchMax, DWORD *pdwPriority, const SIZE *prgSize, DWORD dwRecClrDepth, DWORD *pdwFlags) +{ + if ((prgSize == nullptr) || (pdwFlags == nullptr) || ((*pdwFlags & IEIFLAG_ASYNC) && (pdwPriority == nullptr))) + return E_INVALIDARG; + + thumbnail_size_ = *prgSize; + color_depth_ = dwRecClrDepth; + + *pdwFlags = IEIFLAG_CACHE; // we don't cache the image + + wcsncpy(pszPathBuffer, filename_.c_str(), cchMax); + + return NOERROR; +} + +// IPersist methods + +HRESULT STDMETHODCALLTYPE CThumbviewer::GetClassID(CLSID* pClassID) +{ + *pClassID = CLSID_THUMBVIEWER_HANDLER; + return S_OK; +} + +// IPersistFile methods + +HRESULT STDMETHODCALLTYPE CThumbviewer::Load(LPCOLESTR pszFileName, DWORD) +{ + filename_ = pszFileName; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CThumbviewer::IsDirty() +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE CThumbviewer::Save(LPCOLESTR, BOOL) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE CThumbviewer::SaveCompleted(LPCOLESTR) +{ return E_NOTIMPL; } + +HRESULT STDMETHODCALLTYPE CThumbviewer::GetCurFile(LPOLESTR __RPC_FAR*) +{ return E_NOTIMPL; } + + +#endif // DONT_HAVE_GDIPLUS + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/util/fileextensions.cxx b/shell/source/win32/shlxthandler/util/fileextensions.cxx new file mode 100644 index 000000000..57c8068ef --- /dev/null +++ b/shell/source/win32/shlxthandler/util/fileextensions.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <algorithm> +#include <fileextensions.hxx> +#include <rtl/character.hxx> +#include <sal/macros.h> + + +const std::wstring WRITER_FILE_EXTENSIONS = L"sxwstwsxgodtottodm"; +const std::wstring CALC_FILE_EXTENSIONS = L"sxcstcodsots"; +const std::wstring DRAW_FILE_EXTENSIONS = L"sxdstdodgotg"; +const std::wstring IMPRESS_FILE_EXTENSIONS = L"sxistiodpotp"; +const std::wstring MATH_FILE_EXTENSIONS = L"sxmodf"; +const std::wstring WEB_FILE_EXTENSIONS = L"oth"; +const std::wstring DATABASE_FILE_EXTENSIONS = L"odb"; + +const FileExtensionEntry OOFileExtensionTable[] = { + { ".sxw", L".sxw", L"soffice.StarWriterDocument.6" }, + { ".sxc", L".sxc", L"soffice.StarCalcDocument.6" }, + { ".sxi", L".sxi", L"soffice.StarImpressDocument.6" }, + { ".sxd", L".sxd", L"soffice.StarDrawDocument.6" }, + { ".sxm", L".sxm", L"soffice.StarMathDocument.6" }, + { ".stw", L".stw", L"soffice.StarWriterTemplate.6" }, + { ".sxg", L".sxg", L"soffice.StarWriterGlobalDocument.6" }, + { ".std", L".std", L"soffice.StarDrawTemplate.6" }, + { ".sti", L".sti", L"soffice.StarImpressTemplate.6" }, + { ".stc", L".stc", L"soffice.StarCalcTemplate.6" }, + { ".odt", L".odt", L"LibreOffice.WriterDocument.1" }, + { ".ott", L".ott", L"LibreOffice.WriterTemplate.1" }, + { ".odm", L".odm", L"LibreOffice.WriterGlobalDocument.1" }, + { ".oth", L".oth", L"LibreOffice.WriterWebTemplate.1" }, + { ".ods", L".ods", L"LibreOffice.CalcDocument.1" }, + { ".ots", L".ots", L"LibreOffice.CalcTemplate.1" }, + { ".odg", L".odg", L"LibreOffice.DrawDocument.1" }, + { ".otg", L".otg", L"LibreOffice.DrawTemplate.1" }, + { ".odp", L".odp", L"LibreOffice.ImpressDocument.1" }, + { ".otp", L".otp", L"LibreOffice.ImpressTemplate.1" }, + { ".odf", L".odf", L"LibreOffice.MathDocument.1" }, + { ".odb", L".odb", L"LibreOffice.DatabaseDocument.1" } + }; + + +const size_t OOFileExtensionTableSize = SAL_N_ELEMENTS(OOFileExtensionTable); + + +/** Return the extension of a file + name without the '.' +*/ +Filepath_t get_file_name_extension(const Filepath_t& file_name) +{ + std::wstring::size_type idx = file_name.find_last_of(L"."); + + if (std::wstring::npos != idx++) + return std::wstring(file_name.begin() + idx, file_name.end()); + + return std::wstring(); +} + + +/** Return the type of a file +*/ + +File_Type_t get_file_type(const Filepath_t& file_name) +{ + std::wstring fext = get_file_name_extension(file_name); + std::transform( + fext.begin(), fext.end(), fext.begin(), + [](wchar_t c) { + return rtl::toAsciiLowerCase(c); }); + + if (std::wstring::npos != WRITER_FILE_EXTENSIONS.find(fext)) + return WRITER; + else if (std::wstring::npos != CALC_FILE_EXTENSIONS.find(fext)) + return CALC; + else if (std::wstring::npos != DRAW_FILE_EXTENSIONS.find(fext)) + return DRAW; + else if (std::wstring::npos != IMPRESS_FILE_EXTENSIONS.find(fext)) + return IMPRESS; + else if (std::wstring::npos != MATH_FILE_EXTENSIONS.find(fext)) + return MATH; + else if (std::wstring::npos != WEB_FILE_EXTENSIONS.find(fext)) + return WEB; + else if (std::wstring::npos != DATABASE_FILE_EXTENSIONS.find(fext)) + return DATABASE; + else + return UNKNOWN; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/util/iso8601_converter.cxx b/shell/source/win32/shlxthandler/util/iso8601_converter.cxx new file mode 100644 index 000000000..c0415deb9 --- /dev/null +++ b/shell/source/win32/shlxthandler/util/iso8601_converter.cxx @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <stdlib.h> + +#include <iso8601_converter.hxx> +#include <utilities.hxx> + +#include <sstream> +#include <iomanip> + +#include <rtl/character.hxx> + +/* Converts ISO 8601 compliant date/time + representation to the representation + conforming to the current locale +*/ +std::wstring iso8601_date_to_local_date(const std::wstring& isoDate ) +{ + ::std::wstring ws8601DateTime(isoDate); + + // Get rid of the optional milliseconds part if it exists. + // Function accepts date/time as a combined date/time string in extended ISO8601 format, + // which is yyyy-mm-ddThh:mm:ss[.mmm]. Last part is the optional "fraction of second" part, + // that's why we cut off at 19. + if (ws8601DateTime.length() > 19) + { + ws8601DateTime.erase(19, ::std::basic_string<char>::npos); + } + + if ( ws8601DateTime.length() == 19 ) + { + std::string asDateTime = WStringToString( ws8601DateTime ); + SYSTEMTIME DateTime; + DateTime.wYear = static_cast<unsigned short>(strtol( asDateTime.substr( 0, 4 ).c_str(), nullptr, 10 )); + DateTime.wMonth = static_cast<unsigned short>(strtol( asDateTime.substr( 5, 2 ).c_str(), nullptr, 10 )); + DateTime.wDayOfWeek = 0; + DateTime.wDay = static_cast<unsigned short>(strtol( asDateTime.substr( 8, 2 ).c_str(), nullptr, 10 )); + DateTime.wHour = static_cast<unsigned short>(strtol( asDateTime.substr( 11,2 ).c_str(), nullptr, 10 )); + DateTime.wMinute = static_cast<unsigned short>(strtol( asDateTime.substr( 14,2 ).c_str(), nullptr, 10 )); + DateTime.wSecond = static_cast<unsigned short>(strtol( asDateTime.substr( 17,2 ).c_str(), nullptr, 10 )); + DateTime.wMilliseconds = 0; + + //get Date info from structure + WCHAR DateBuffer[ MAX_PATH ]; + int DateSize = GetDateFormatW( + LOCALE_SYSTEM_DEFAULT, + 0, + &DateTime, + nullptr, + DateBuffer, + MAX_PATH ); + + if ( DateSize ) + ws8601DateTime.assign(DateBuffer); + else + ws8601DateTime = StringToWString( asDateTime ); + + //get Time info from structure + WCHAR TimeBuffer[ MAX_PATH ]; + + int TimeSize = GetTimeFormatW( + LOCALE_SYSTEM_DEFAULT, + 0, + &DateTime, + nullptr, + TimeBuffer, + MAX_PATH ); + + if ( TimeSize ) + { + ws8601DateTime.append(L" "); + ws8601DateTime.append(TimeBuffer); + } + else + ws8601DateTime = StringToWString( asDateTime ); + } + + return ws8601DateTime; +} + + +/* Converts ISO 8601 conform duration + representation to the representation + conforming to the current locale + + Expect format PTnHnMnS according to + ISO 8601 where n is arbitrary number + of digits +*/ + +std::wstring iso8601_duration_to_local_duration(const std::wstring& iso8601duration) +{ + std::wstring days; + std::wstring hours; + std::wstring minutes; + std::wstring seconds; + + std::wstring num; + + for (const auto& w_ch : iso8601duration) + { + if (rtl::isAsciiDigit(w_ch)) // wchar_t is unsigned under MSVC + { + num += w_ch; + } + else + { + if (w_ch == L'D' || w_ch == L'd') + days = num; + else if (w_ch == L'H' || w_ch == L'h') + hours = num; + else if (w_ch == L'M' || w_ch == L'm') + minutes = num; + else if (w_ch == L'S' || w_ch == L's') + seconds = num; + + num.clear(); + } + } + + if (days.length() > 0) + { + int h = (_wtoi(days.c_str()) * 24) + _wtoi(hours.c_str()); + wchar_t buff[10]; + _itow(h, buff, 10); + hours = buff; + } + + std::wostringstream oss; + oss << std::setw(2) << std::setfill(wchar_t('0')) << hours << L":" << + std::setw(2) << std::setfill(wchar_t('0')) << minutes << L":" << + std::setw(2) << std::setfill(wchar_t('0')) << seconds; + return oss.str(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/util/registry.cxx b/shell/source/win32/shlxthandler/util/registry.cxx new file mode 100644 index 000000000..cc42c092e --- /dev/null +++ b/shell/source/win32/shlxthandler/util/registry.cxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#include <malloc.h> +#include <registry.hxx> + +#include <objbase.h> + +bool SetRegistryKey(HKEY RootKey, const Filepath_char_t* KeyName, const Filepath_char_t* ValueName, const Filepath_char_t* Value) +{ + HKEY hSubKey; + + // open or create the desired key + wchar_t dummy[] = L""; + int rc = RegCreateKeyExW( + RootKey, KeyName, 0, dummy, REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hSubKey, nullptr); + + if (ERROR_SUCCESS == rc) + { + rc = RegSetValueExW( + hSubKey, ValueName, 0, REG_SZ, reinterpret_cast<const BYTE*>(Value), + static_cast<DWORD>((wcslen(Value) + 1) * sizeof(*Value))); + + RegCloseKey(hSubKey); + } + + return (ERROR_SUCCESS == rc); +} + + +bool DeleteRegistryKey(HKEY RootKey, const Filepath_char_t* KeyName) +{ + HKEY hKey; + + int rc = RegOpenKeyExW( + RootKey, + KeyName, + 0, + KEY_READ | DELETE, + &hKey); + + if ( rc == ERROR_FILE_NOT_FOUND ) + return true; + + if (ERROR_SUCCESS == rc) + { + wchar_t* SubKey; + DWORD nMaxSubKeyLen; + + rc = RegQueryInfoKeyW( + hKey, nullptr, nullptr, nullptr, nullptr, + &nMaxSubKeyLen, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + + nMaxSubKeyLen++; // space for trailing '\0' + + SubKey = static_cast<wchar_t*>( + _alloca(nMaxSubKeyLen*sizeof(wchar_t))); + + while (ERROR_SUCCESS == rc) + { + DWORD nLen = nMaxSubKeyLen; + + rc = RegEnumKeyExW( + hKey, + 0, // always index zero + SubKey, + &nLen, + nullptr, nullptr, nullptr, nullptr); + + if (ERROR_NO_MORE_ITEMS == rc) + { + rc = RegDeleteKeyW(RootKey, KeyName); + break; + } + else if (rc == ERROR_SUCCESS) + { + DeleteRegistryKey(hKey, SubKey); + } + + } // while + + RegCloseKey(hKey); + + } // if + + return (ERROR_SUCCESS == rc); +} + +/** May be used to determine if the specified registry key has subkeys + The function returns true on success else if an error occurs false +*/ +bool HasSubkeysRegistryKey(HKEY RootKey, const Filepath_char_t* KeyName, /* out */ bool& bResult) +{ + HKEY hKey; + + LONG rc = RegOpenKeyExW(RootKey, KeyName, 0, KEY_READ, &hKey); + + if (ERROR_SUCCESS == rc) + { + DWORD nSubKeys = 0; + + rc = RegQueryInfoKeyW(hKey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + + RegCloseKey(hKey); + bResult = (nSubKeys > 0); + } + + return (ERROR_SUCCESS == rc); +} + +// Convert a CLSID to a char string. +Filepath_t ClsidToString(const CLSID& clsid) +{ + // Get CLSID + LPOLESTR wszCLSID = nullptr; + StringFromCLSID(clsid, &wszCLSID); + + std::wstring sResult = wszCLSID; + + // Free memory. + CoTaskMemFree(wszCLSID) ; + + return sResult; +} + + +bool QueryRegistryKey(HKEY RootKey, const Filepath_char_t* KeyName, const Filepath_char_t* ValueName, Filepath_char_t *pszData, DWORD dwBufLen) +{ + HKEY hKey; + + int rc = RegOpenKeyExW( + RootKey, + KeyName, + 0, + KEY_READ, + &hKey); + + if (ERROR_SUCCESS == rc) + { + DWORD dwBytes = dwBufLen * sizeof(*pszData); + rc = RegQueryValueExW( + hKey, ValueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(pszData),&dwBytes); + + RegCloseKey(hKey); + } + + return (ERROR_SUCCESS == rc); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/shell/source/win32/shlxthandler/util/utilities.cxx b/shell/source/win32/shlxthandler/util/utilities.cxx new file mode 100644 index 000000000..27bf12c21 --- /dev/null +++ b/shell/source/win32/shlxthandler/util/utilities.cxx @@ -0,0 +1,565 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <memory> + +#include <config.hxx> +#include <global.hxx> +#include <utilities.hxx> + +// constants + + +const size_t MAX_RES_STRING = 1024; +const wchar_t SPACE_CHAR = L' '; + +static std::wstring StringToWString(const std::string& String, int codepage) +{ + int len = MultiByteToWideChar( + codepage, 0, String.c_str(), -1, nullptr, 0); + + wchar_t* buff = static_cast<wchar_t*>( + _alloca(len * sizeof(wchar_t))); + + MultiByteToWideChar( + codepage, 0, String.c_str(), -1, buff, len); + + return std::wstring(buff); +} + +static std::string WStringToString(const std::wstring& String, int codepage) +{ + int len = WideCharToMultiByte( + codepage, 0, String.c_str(), -1, nullptr, 0, nullptr, nullptr); + + char* buff = static_cast<char*>( + _alloca(len * sizeof(char))); + + WideCharToMultiByte( + codepage, 0, String.c_str(), -1, buff, len, nullptr, nullptr); + + return std::string(buff); +} + + +std::wstring StringToWString(const std::string& String) +{ + return StringToWString(String, CP_ACP); +} + + +std::string WStringToString(const std::wstring& String) +{ + return WStringToString(String, CP_ACP); +} + + +std::wstring UTF8ToWString(const std::string& String) +{ + return StringToWString(String, CP_UTF8); +} + + +std::wstring GetResString(int ResId) +{ + wchar_t szResStr[MAX_RES_STRING]; + + int rc = LoadStringW( GetCurrentModuleHandle(), ResId, szResStr, sizeof(szResStr) ); + + OutputDebugStringFormatW( L"GetResString: read %d chars\n", rc ); + // OSL_ENSURE(rc, "String resource not found"); + + return std::wstring(szResStr); +} + + +/** helper function to judge if the string is only has spaces. + @returns + <TRUE>if the provided string contains only but at least one space + character else <FALSE/>. +*/ + +bool HasOnlySpaces(const std::wstring& String) +{ + if ( String.length() == 0 ) + return false; + + const wchar_t* p = String.c_str(); + + while (*p) + { + if (*p++ != SPACE_CHAR) + return false; + } + + return true; +} + + +/** helper function to convert windows paths to short form. + @returns + shortened path. +*/ + +std::wstring getShortPathName( const std::wstring& aLongName ) +{ + std::wstring shortName = aLongName; + DWORD length = GetShortPathNameW( aLongName.c_str(), nullptr, 0 ); + + if ( length != 0 ) + { + auto buffer = std::make_unique<WCHAR[]>( length+1 ); + length = GetShortPathNameW( aLongName.c_str(), buffer.get(), length ); + if ( length != 0 ) + shortName = std::wstring( buffer.get() ); + } + return shortName; +} + + +/** convert LocaleSet pair into Microsoft List of Locale ID (LCID) + according to ISO-639 and ISO-3166. + http://etext.lib.virginia.edu/tei/iso639.html + http://nl.ijs.si/gnusl/cee/std/ISO_3166.html + @param + Locale, LocaleSet + @returns + Windows Locale Identifier corresponding to input LocaleSet. + @Usage Sample + LocaleSet_t myDefaultLocale( ::std::wstring( L"zh" ),::std::wstring(L"HK") ); + DWORD myLCID = LocaleSetToLCID( myDefaultLocale ); + wchar_t buffer[20]; + _ultow( myLCID, buffer, 16 ); + MessageBox( NULL, buffer,L"the LCID is:",MB_OK ); +*/ + +LCID LocaleSetToLCID( const LocaleSet_t & Locale ) +{ + if ( EMPTY_LOCALE == Locale ) + return GetSystemDefaultLCID(); + + USHORT usPrimaryLang= LANG_NEUTRAL; + USHORT usSubLang=SUBLANG_DEFAULT; + + ::std::wstring wsLanguage(Locale.first); + ::std::wstring wsCountry(Locale.second); + + if ( wsLanguage == L"ar" ) + { + usPrimaryLang = LANG_ARABIC; // Arabic 01 + + if ( wsCountry == L"SA" ) + usSubLang = SUBLANG_ARABIC_SAUDI_ARABIA; // Arabic (Saudi Arabia) + else if ( wsCountry == L"IQ" ) + usSubLang = SUBLANG_ARABIC_IRAQ; // Arabic (Iraq) + else if ( wsCountry == L"EG" ) + usSubLang = SUBLANG_ARABIC_EGYPT; // Arabic (Egypt) + else if ( wsCountry == L"LY" ) + usSubLang = SUBLANG_ARABIC_LIBYA; // Arabic (Libya) + else if ( wsCountry == L"DZ" ) + usSubLang = SUBLANG_ARABIC_ALGERIA; // Arabic (Algeria) + else if ( wsCountry == L"MA" ) + usSubLang = SUBLANG_ARABIC_MOROCCO; // Arabic (Morocco) + else if ( wsCountry == L"TN" ) + usSubLang = SUBLANG_ARABIC_TUNISIA; // Arabic (Tunisia) + else if ( wsCountry == L"OM" ) + usSubLang = SUBLANG_ARABIC_OMAN; // Arabic (Oman) + else if ( wsCountry == L"YE" ) + usSubLang = SUBLANG_ARABIC_YEMEN; // Arabic (Yemen) + else if ( wsCountry == L"SY" ) + usSubLang = SUBLANG_ARABIC_SYRIA; // Arabic (Syria) + else if ( wsCountry == L"JO" ) + usSubLang = SUBLANG_ARABIC_JORDAN; // Arabic (Jordan) + else if ( wsCountry == L"LB" ) + usSubLang = SUBLANG_ARABIC_LEBANON; // Arabic (Lebanon) + else if ( wsCountry == L"KW" ) + usSubLang = SUBLANG_ARABIC_KUWAIT; // Arabic (Kuwait) + else if ( wsCountry == L"AE" ) + usSubLang = SUBLANG_ARABIC_UAE; // Arabic (U.A.E.) + else if ( wsCountry == L"BH" ) + usSubLang = SUBLANG_ARABIC_BAHRAIN; // Arabic (Bahrain) + else if ( wsCountry == L"QA" ) + usSubLang = SUBLANG_ARABIC_QATAR; // Arabic (Qatar) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"bg" ) + usPrimaryLang = LANG_BULGARIAN; //Bulgarian 02 + else if ( wsLanguage == L"ca" ) + usPrimaryLang = LANG_CATALAN; //Catalan 03 + else if ( wsLanguage == L"zh" ) + { + usPrimaryLang = LANG_CHINESE; //Chinese + if ( wsCountry == L"TW" ) + usSubLang = SUBLANG_CHINESE_TRADITIONAL; // Chinese (Traditional) + else if ( wsCountry == L"CN" ) + usSubLang = SUBLANG_CHINESE_SIMPLIFIED; // Chinese (Simplified) + else if ( wsCountry == L"HK" ) + usSubLang = SUBLANG_CHINESE_HONGKONG; // Chinese (Hong Kong SAR, PRC) + else if ( wsCountry == L"SG" ) + usSubLang = SUBLANG_CHINESE_SINGAPORE; // Chinese (Singapore) + else if ( wsCountry == L"MO" ) + usSubLang = SUBLANG_CHINESE_MACAU; // Chinese (Macau SAR) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"cs" ) + usPrimaryLang = LANG_CZECH; //Czech + else if ( wsLanguage == L"da" ) + usPrimaryLang = LANG_DANISH; //Danish + else if ( wsLanguage == L"de" ) + { + usPrimaryLang = LANG_GERMAN; //German + if ( wsCountry == L"DE" ) + usSubLang = SUBLANG_GERMAN; // German + else if ( wsCountry == L"CH" ) + usSubLang = SUBLANG_GERMAN_SWISS; // German (Swiss) + else if ( wsCountry == L"AT" ) + usSubLang = SUBLANG_GERMAN_AUSTRIAN; // German (Austrian) + else if ( wsCountry == L"LU" ) + usSubLang = SUBLANG_GERMAN_LUXEMBOURG; // German (Luxembourg) + else if ( wsCountry == L"LI" ) + usSubLang = SUBLANG_GERMAN_LIECHTENSTEIN; // German (Liechtenstein) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"el" ) + usPrimaryLang = LANG_GREEK; //Greek + else if ( wsLanguage == L"en" ) + { + usPrimaryLang = LANG_ENGLISH; //English + if ( wsCountry == L"US" ) + usSubLang = SUBLANG_ENGLISH_US; // English (US) + else if ( wsCountry == L"GB" ) + usSubLang = SUBLANG_ENGLISH_UK; // English (UK) + else if ( wsCountry == L"AU" ) + usSubLang = SUBLANG_ENGLISH_AUS; // English (Australian) + else if ( wsCountry == L"CA" ) + usSubLang = SUBLANG_ENGLISH_CAN; // English (Canadian) + else if ( wsCountry == L"NZ" ) + usSubLang = SUBLANG_ENGLISH_NZ; // English (New Zealand) + else if ( wsCountry == L"IE" ) + usSubLang = SUBLANG_ENGLISH_EIRE; // English (Ireland) + else if ( wsCountry == L"ZA" ) + usSubLang = SUBLANG_ENGLISH_SOUTH_AFRICA; // English (South Africa) + else if ( wsCountry == L"JM" ) + usSubLang = SUBLANG_ENGLISH_JAMAICA; // English (Jamaica) + else if ( wsCountry == L"GD" ) + usSubLang = SUBLANG_ENGLISH_CARIBBEAN; // English (Caribbean) Grenada + else if ( wsCountry == L"BZ" ) + usSubLang = SUBLANG_ENGLISH_BELIZE; // English (Belize) + else if ( wsCountry == L"TT" ) + usSubLang = SUBLANG_ENGLISH_TRINIDAD; // English (Trinidad) + else if ( wsCountry == L"ZW" ) + usSubLang = SUBLANG_ENGLISH_ZIMBABWE; // English (Zimbabwe) + else if ( wsCountry == L"PH" ) + usSubLang = SUBLANG_ENGLISH_PHILIPPINES; // English (Philippines) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"es" ) + { + usPrimaryLang = LANG_SPANISH; //Spanish + if ( wsCountry == L"MX" ) + usSubLang = SUBLANG_SPANISH_MEXICAN; // Spanish (Mexican) + else if ( wsCountry == L"ES" ) + usSubLang = SUBLANG_SPANISH_MODERN; // Spanish (Spain) + else if ( wsCountry == L"GT" ) + usSubLang = SUBLANG_SPANISH_GUATEMALA; // Spanish (Guatemala) + else if ( wsCountry == L"CR" ) + usSubLang = SUBLANG_SPANISH_COSTA_RICA; // Spanish (Costa Rica) + else if ( wsCountry == L"PA" ) + usSubLang = SUBLANG_SPANISH_PANAMA; // Spanish (Panama) + else if ( wsCountry == L"DO" ) + usSubLang = SUBLANG_SPANISH_DOMINICAN_REPUBLIC; // Spanish (Dominican Republic) + else if ( wsCountry == L"VE" ) + usSubLang = SUBLANG_SPANISH_VENEZUELA; // Spanish (Venezuela) + else if ( wsCountry == L"CO" ) + usSubLang = SUBLANG_SPANISH_COLOMBIA; // Spanish (Colombia) + else if ( wsCountry == L"PE" ) + usSubLang = SUBLANG_SPANISH_PERU; // Spanish (Peru) + else if ( wsCountry == L"AR" ) + usSubLang = SUBLANG_SPANISH_ARGENTINA; // Spanish (Argentina) + else if ( wsCountry == L"EC" ) + usSubLang = SUBLANG_SPANISH_ECUADOR; // Spanish (Ecuador) + else if ( wsCountry == L"CL" ) + usSubLang = SUBLANG_SPANISH_CHILE; // Spanish (Chile) + else if ( wsCountry == L"UY" ) + usSubLang = SUBLANG_SPANISH_URUGUAY; // Spanish (Uruguay) + else if ( wsCountry == L"PY" ) + usSubLang = SUBLANG_SPANISH_PARAGUAY; // Spanish (Paraguay) + else if ( wsCountry == L"BO" ) + usSubLang = SUBLANG_SPANISH_BOLIVIA; // Spanish (Bolivia) + else if ( wsCountry == L"SV" ) + usSubLang = SUBLANG_SPANISH_EL_SALVADOR; // Spanish (El Salvador) + else if ( wsCountry == L"HN" ) + usSubLang = SUBLANG_SPANISH_HONDURAS; // Spanish (Honduras) + else if ( wsCountry == L"NI" ) + usSubLang = SUBLANG_SPANISH_NICARAGUA; // Spanish (Nicaragua) + else if ( wsCountry == L"PR" ) + usSubLang = SUBLANG_SPANISH_PUERTO_RICO; // Spanish (Puerto Rico) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"fi" ) + usPrimaryLang = LANG_FINNISH; //Finnish + else if ( wsLanguage == L"fr" ) + { + usPrimaryLang = LANG_FRENCH; //French + if ( wsCountry == L"FR" ) + usSubLang = SUBLANG_FRENCH; // French + else if ( wsCountry == L"BE" ) + usSubLang = SUBLANG_FRENCH_BELGIAN; // French (Belgian) + else if ( wsCountry == L"CA" ) + usSubLang = SUBLANG_FRENCH_CANADIAN; // French (Canadian) + else if ( wsCountry == L"CH" ) + usSubLang = SUBLANG_FRENCH_SWISS; // French (Swiss) + else if ( wsCountry == L"LU" ) + usSubLang = SUBLANG_FRENCH_LUXEMBOURG; // French (Luxembourg) + else if ( wsCountry == L"MC" ) + usSubLang = SUBLANG_FRENCH_MONACO; // French (Monaco) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"iw" ) + usPrimaryLang = LANG_HEBREW; //Hebrew + else if ( wsLanguage == L"hu" ) + usPrimaryLang = LANG_HUNGARIAN; //Hungarian + else if ( wsLanguage == L"is" ) + usPrimaryLang = LANG_ICELANDIC; //Icelandic + else if ( wsLanguage == L"it" ) + { + usPrimaryLang = LANG_ITALIAN; //Italian + if ( wsCountry == L"IT" ) + usSubLang = SUBLANG_ITALIAN; // Italian + else if ( wsCountry == L"CH" ) + usSubLang = SUBLANG_ITALIAN_SWISS; // Italian (Swiss) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"ja" ) + usPrimaryLang = LANG_JAPANESE; //Japanese + else if ( wsLanguage == L"ko" ) + { + usPrimaryLang = LANG_KOREAN; //Korean + if ( wsCountry == L"KR" ) + usSubLang = SUBLANG_KOREAN; // Korean + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"nl" ) + { + usPrimaryLang = LANG_DUTCH; //Dutch + if ( wsCountry == L"NL" ) + usSubLang = SUBLANG_DUTCH; // Dutch + else if ( wsCountry == L"BE" ) + usSubLang = SUBLANG_DUTCH_BELGIAN; // Dutch (Belgian) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"no" ) + { + usPrimaryLang = LANG_NORWEGIAN; //Norwegian + if ( wsCountry == L"NO" ) + usSubLang = SUBLANG_NORWEGIAN_BOKMAL; // Norwegian (Bokmal) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"pl" ) + usPrimaryLang = LANG_POLISH; //Polish + else if ( wsLanguage == L"pt" ) + { + usPrimaryLang = LANG_PORTUGUESE; //Portuguese + if ( wsCountry == L"BR" ) + usSubLang = SUBLANG_PORTUGUESE_BRAZILIAN; // Portuguese (Brazil) + else if ( wsCountry == L"PT" ) + usSubLang = SUBLANG_PORTUGUESE; // Portuguese (Portugal) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"ro" ) + usPrimaryLang = LANG_ROMANIAN; //Romanian + else if ( wsLanguage == L"ru" ) + usPrimaryLang = LANG_RUSSIAN; //Russian + else if ( wsLanguage == L"hr" ) + usPrimaryLang = LANG_CROATIAN; //Croatian + else if ( wsLanguage == L"sr" ) + { + usPrimaryLang = LANG_SERBIAN; //Serbian + if ( wsCountry == L"VA" ) + usSubLang = SUBLANG_SERBIAN_LATIN; // Serbian (Latin) + else if ( wsCountry == L"HR" ) + usSubLang = SUBLANG_SERBIAN_CYRILLIC; // Serbian (Cyrillic) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"sk" ) + usPrimaryLang = LANG_SLOVAK; //Slovak + else if ( wsLanguage == L"sq" ) + usPrimaryLang = LANG_ALBANIAN; //Albanian + else if ( wsLanguage == L"sv" ) + { + usPrimaryLang = LANG_SWEDISH; //Swedish + if ( wsCountry == L"SE" ) + usSubLang = SUBLANG_SWEDISH; // Swedish + else if ( wsCountry == L"FI" ) + usSubLang = SUBLANG_SWEDISH_FINLAND; // Swedish (Finland) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"th" ) + usPrimaryLang = LANG_THAI; //Thai + else if ( wsLanguage == L"tr" ) + usPrimaryLang = LANG_TURKISH; //Turkish + else if ( wsLanguage == L"ur" ) + { + usPrimaryLang = LANG_URDU; //Urdu + if ( wsCountry == L"PK" ) + usSubLang = SUBLANG_URDU_PAKISTAN; // Urdu (Pakistan) + else if ( wsCountry == L"IN" ) + usSubLang = SUBLANG_URDU_INDIA; // Urdu (India) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"in" ) + usPrimaryLang = LANG_INDONESIAN; //Indonesian + else if ( wsLanguage == L"uk" ) + usPrimaryLang = LANG_UKRAINIAN; //Ukrainian + else if ( wsLanguage == L"be" ) + usPrimaryLang = LANG_BELARUSIAN; //Belarusian + else if ( wsLanguage == L"sl" ) + usPrimaryLang = LANG_SLOVENIAN; //Slovenian + else if ( wsLanguage == L"et" ) + usPrimaryLang = LANG_ESTONIAN; //Estonian + else if ( wsLanguage == L"lv" ) + usPrimaryLang = LANG_LATVIAN; //Latvian + else if ( wsLanguage == L"lt" ) + { + usPrimaryLang = LANG_LITHUANIAN; //Lithuanian + if ( wsCountry == L"LT" ) + usSubLang = SUBLANG_LITHUANIAN; // Lithuanian + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"fa" ) + usPrimaryLang = LANG_FARSI; //Farsi + else if ( wsLanguage == L"vi" ) + usPrimaryLang = LANG_VIETNAMESE; //Vietnamese + else if ( wsLanguage == L"hy" ) + usPrimaryLang = LANG_ARMENIAN; //Armenian + else if ( wsLanguage == L"az" ) + usPrimaryLang = LANG_AZERI; //Azeri + else if ( wsLanguage == L"eu" ) + usPrimaryLang = LANG_BASQUE; //Basque + else if ( wsLanguage == L"mk" ) + usPrimaryLang = LANG_MACEDONIAN; //FYRO Macedonian + else if ( wsLanguage == L"af" ) + usPrimaryLang = LANG_AFRIKAANS; //Afrikaans + else if ( wsLanguage == L"ka" ) + usPrimaryLang = LANG_GEORGIAN; //Georgian + else if ( wsLanguage == L"fo" ) + usPrimaryLang = LANG_FAEROESE; //Faeroese + else if ( wsLanguage == L"hi" ) + usPrimaryLang = LANG_HINDI; //Hindi + else if ( wsLanguage == L"ms" ) + { + usPrimaryLang = LANG_MALAY; //Malay + if ( wsCountry == L"MY" ) + usSubLang = SUBLANG_MALAY_MALAYSIA; // Malay (Malaysia) + else if ( wsCountry == L"BN" ) + usSubLang = SUBLANG_MALAY_BRUNEI_DARUSSALAM; // Malay (Brunei Darassalam) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"kk" ) + usPrimaryLang = LANG_KAZAK; //Kazakh + else if ( wsLanguage == L"ky" ) + usPrimaryLang = LANG_KYRGYZ; //Kyrgyz + else if ( wsLanguage == L"sw" ) + usPrimaryLang = LANG_SWAHILI; //Swahili + else if ( wsLanguage == L"uz" ) + { + usPrimaryLang = LANG_UZBEK; //Uzbek + if ( wsCountry == L"UZ" ) + usSubLang = SUBLANG_UZBEK_LATIN; // Uzbek (Latin) + else if ( wsCountry == L"DE" ) + usSubLang = SUBLANG_UZBEK_CYRILLIC; // Uzbek (Cyrillic) + else + usSubLang = SUBLANG_DEFAULT; //default sub language + } + else if ( wsLanguage == L"tt" ) + usPrimaryLang = LANG_TATAR; //Tatar + else if ( wsLanguage == L"bn" ) + usPrimaryLang = LANG_BENGALI; //Not supported. + else if ( wsLanguage == L"pa" ) + usPrimaryLang = LANG_PUNJABI; //Punjabi + else if ( wsLanguage == L"gu" ) + usPrimaryLang = LANG_GUJARATI; //Gujarati + else if ( wsLanguage == L"or" ) + usPrimaryLang = LANG_ORIYA; //Not supported. + else if ( wsLanguage == L"ta" ) + usPrimaryLang = LANG_TAMIL; //Tamil + else if ( wsLanguage == L"te" ) + usPrimaryLang = LANG_TELUGU; //Telugu + else if ( wsLanguage == L"kn" ) + usPrimaryLang = LANG_KANNADA; //Kannada + else if ( wsLanguage == L"ml" ) + usPrimaryLang = LANG_MALAYALAM; //Not supported. + else if ( wsLanguage == L"as" ) + usPrimaryLang = LANG_ASSAMESE; //Not supported. + else if ( wsLanguage == L"mr" ) + usPrimaryLang = LANG_MARATHI; //Marathi + else if ( wsLanguage == L"sa" ) + usPrimaryLang = LANG_SANSKRIT; //Sanskrit + else if ( wsLanguage == L"mn" ) + usPrimaryLang = LANG_MONGOLIAN; //Mongolian + else if ( wsLanguage == L"gl" ) + usPrimaryLang = LANG_GALICIAN; //Galician + else if ( wsLanguage == L"sd" ) + usPrimaryLang = LANG_SINDHI; //Not supported. + else if ( wsLanguage == L"ks" ) + usPrimaryLang = LANG_KASHMIRI; //Not supported. + else if ( wsLanguage == L"ne" ) + usPrimaryLang = LANG_NEPALI; //Not supported. + else + return GetSystemDefaultLCID(); //System Default Locale + + return MAKELCID( MAKELANGID( usPrimaryLang, usSubLang ), SORT_DEFAULT ); +} + +// The function is defined in the static library, and thus its address is local to current module +HMODULE GetCurrentModuleHandle() +{ + HMODULE h{}; + + if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast<LPCWSTR>(&GetCurrentModuleHandle), &h) + == 0) + { + const DWORD dwError = GetLastError(); + OutputDebugStringFormatW( + L"GetCurrentModuleHandle: GetModuleHandleExW failed, error is 0x%X", dwError); + } + return h; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |