summaryrefslogtreecommitdiffstats
path: root/shell/source/win32/shlxthandler
diff options
context:
space:
mode:
Diffstat (limited to 'shell/source/win32/shlxthandler')
-rw-r--r--shell/source/win32/shlxthandler/classfactory.cxx137
-rw-r--r--shell/source/win32/shlxthandler/classfactory.hxx65
-rw-r--r--shell/source/win32/shlxthandler/columninfo/columninfo.cxx198
-rw-r--r--shell/source/win32/shlxthandler/infotips/infotips.cxx365
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/ooofilt.cxx956
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/ooofilt.def5
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/ooofilt.hxx195
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/propspec.cxx192
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/propspec.hxx127
-rw-r--r--shell/source/win32/shlxthandler/ooofilt/stream_helper.cxx137
-rw-r--r--shell/source/win32/shlxthandler/prophdl/propertyhdl.cxx432
-rw-r--r--shell/source/win32/shlxthandler/prophdl/propertyhdl.def3
-rw-r--r--shell/source/win32/shlxthandler/propsheets/document_statistic.cxx145
-rw-r--r--shell/source/win32/shlxthandler/propsheets/document_statistic.hxx122
-rw-r--r--shell/source/win32/shlxthandler/propsheets/listviewbuilder.cxx175
-rw-r--r--shell/source/win32/shlxthandler/propsheets/listviewbuilder.hxx72
-rw-r--r--shell/source/win32/shlxthandler/propsheets/propsheets.cxx308
-rw-r--r--shell/source/win32/shlxthandler/res/ctrylnglist.txt29
-rw-r--r--shell/source/win32/shlxthandler/res/prop_img.bmpbin0 -> 958 bytes
-rw-r--r--shell/source/win32/shlxthandler/res/rcfooter.txt4
-rw-r--r--shell/source/win32/shlxthandler/res/rcheader.txt10
-rw-r--r--shell/source/win32/shlxthandler/res/rctmpl.txt88
-rw-r--r--shell/source/win32/shlxthandler/res/shlxthdl.manifest11
-rw-r--r--shell/source/win32/shlxthandler/res/shlxthdl.rc12
-rw-r--r--shell/source/win32/shlxthandler/res/shlxthdl.ulf148
-rw-r--r--shell/source/win32/shlxthandler/res/signet.pngbin0 -> 4836 bytes
-rw-r--r--shell/source/win32/shlxthandler/shlxthdl.cxx409
-rw-r--r--shell/source/win32/shlxthandler/shlxthdl.def5
-rw-r--r--shell/source/win32/shlxthandler/thumbviewer/thumbviewer.cxx500
-rw-r--r--shell/source/win32/shlxthandler/util/fileextensions.cxx106
-rw-r--r--shell/source/win32/shlxthandler/util/iso8601_converter.cxx155
-rw-r--r--shell/source/win32/shlxthandler/util/registry.cxx173
-rw-r--r--shell/source/win32/shlxthandler/util/utilities.cxx565
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
new file mode 100644
index 000000000..1849a8bb6
--- /dev/null
+++ b/shell/source/win32/shlxthandler/res/prop_img.bmp
Binary files differ
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
new file mode 100644
index 000000000..bccaaff81
--- /dev/null
+++ b/shell/source/win32/shlxthandler/res/signet.png
Binary files differ
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: */