Repository.mk                                  |    2 
 shell/AllLangMoTarget_shell.mk                 |   11 +
 shell/Executable_spsupp_helper.mk              |   37 ++++
 shell/Module_shell.mk                          |    6 
 shell/WinResTarget_spsupp_dlg.mk               |   14 +
 shell/inc/spsupp/spsuppServ.hpp                |    2 
 shell/inc/spsupp/spsuppStrings.hrc             |   23 ++
 shell/source/win32/spsupp/COMOpenDocuments.cxx |  113 ++++++------
 shell/source/win32/spsupp/res/spsuppDlg.h      |   27 ++
 shell/source/win32/spsupp/res/spsuppDlg.rc     |   29 +++
 shell/source/win32/spsupp/spsuppHelper.cxx     |  231 +++++++++++++++++++++++++
 shell/source/win32/spsupp/spsuppServ.cxx       |   17 -
 12 files changed, 453 insertions(+), 59 deletions(-)

New commits:
commit f60cc89ec35f8b1bf56e9f69ef15143fd002c409
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Tue May 7 21:22:08 2019 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri May 17 19:15:02 2019 +0200

    SharePoint: Add dialog to choose opening in read-only or edit mode.
    
    ViewDocument3 method takes OpenType parameter, which allows to decide
    if user can choose opening the document read-only or to edit.
    
    Since we need to show localizable strings, we need to bootstrap part
    of LO (l10n), which is impossible when e.g. 64-bit ActiveX DLL tries
    to load installed 32-bit sal DLLs. Thus, we need a separate helper
    .exe, which architecture matches the rest of installed LO, and which
    handles user interaction.
    
    Change-Id: I0ad53ba64272fb84728d2221e3dc85d3eefdda68
    Reviewed-on: https://gerrit.libreoffice.org/72355
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/Repository.mk b/Repository.mk
index d9654e717025..a88b0f282897 100644
--- a/Repository.mk
+++ b/Repository.mk
@@ -208,6 +208,7 @@ $(eval $(call 
gb_Helper_register_executables_for_install,OOO,ooo, \
        ) \
        $(if $(filter WNT,$(OS)), \
                senddoc \
+               spsupp_helper \
        ) \
        $(if $(filter OPENCL,$(BUILD_TYPE)),opencltest) \
 ))
@@ -1120,6 +1121,7 @@ $(eval $(call gb_Helper_register_mos,\
        scc \
        sd \
        sfx \
+       shell \
        sm \
        svl \
        svt \
diff --git a/shell/AllLangMoTarget_shell.mk b/shell/AllLangMoTarget_shell.mk
new file mode 100644
index 000000000000..41285974e3b7
--- /dev/null
+++ b/shell/AllLangMoTarget_shell.mk
@@ -0,0 +1,11 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+
+$(eval $(call gb_AllLangMoTarget_AllLangMoTarget,shell))
+
+# vim: set noet sw=4 ts=4:
diff --git a/shell/Executable_spsupp_helper.mk 
b/shell/Executable_spsupp_helper.mk
new file mode 100644
index 000000000000..5daeff28da56
--- /dev/null
+++ b/shell/Executable_spsupp_helper.mk
@@ -0,0 +1,37 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_Executable_Executable,spsupp_helper))
+
+$(eval $(call gb_Executable_set_targettype_gui,spsupp_helper,YES))
+
+$(eval $(call gb_Executable_set_include,spsupp_helper,\
+    -I$(SRCDIR)/shell/inc/spsupp \
+    $$(INCLUDE) \
+))
+
+$(eval $(call gb_Executable_use_sdk_api,spsupp_helper))
+
+$(eval $(call gb_Executable_use_libraries,spsupp_helper,\
+       i18nlangtag \
+       sal \
+       utl \
+))
+
+$(eval $(call gb_Executable_add_exception_objects,spsupp_helper,\
+    shell/source/win32/spsupp/spsuppHelper \
+))
+
+$(eval $(call gb_Executable_add_nativeres,spsupp_helper,spsupp_dlg))
+
+$(eval $(call gb_Executable_use_system_win32_libs,spsupp_helper,\
+    shell32 \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/shell/Module_shell.mk b/shell/Module_shell.mk
index 2aeb69177a13..c0c42cc5bea5 100644
--- a/shell/Module_shell.mk
+++ b/shell/Module_shell.mk
@@ -43,6 +43,7 @@ $(eval $(call gb_Module_add_targets,shell,\
        Executable_senddoc \
        Library_smplmail \
        Library_wininetbe \
+       Executable_spsupp_helper \
 ))
 
 ifeq ($(COM),MSC)
@@ -57,6 +58,7 @@ $(eval $(call gb_Module_add_targets,shell,\
        CustomTarget_spsupp_idl \
        Library_spsupp \
        WinResTarget_spsupp \
+       WinResTarget_spsupp_dlg \
 ))
 
 $(eval $(call gb_Module_add_check_targets,shell,\
@@ -104,4 +106,8 @@ endif
 
 endif
 
+$(eval $(call gb_Module_add_l10n_targets,shell,\
+    AllLangMoTarget_shell \
+))
+
 # vim: set shiftwidth=4 tabstop=4 noexpandtab:
diff --git a/shell/WinResTarget_spsupp_dlg.mk b/shell/WinResTarget_spsupp_dlg.mk
new file mode 100644
index 000000000000..9880433c7826
--- /dev/null
+++ b/shell/WinResTarget_spsupp_dlg.mk
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# 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/.
+#
+
+$(eval $(call gb_WinResTarget_WinResTarget,spsupp_dlg))
+
+$(eval $(call 
gb_WinResTarget_set_rcfile,spsupp_dlg,shell/source/win32/spsupp/res/spsuppDlg))
+
+# vim: set shiftwidth=4 tabstop=4 noexpandtab:
diff --git a/shell/inc/spsupp/spsuppServ.hpp b/shell/inc/spsupp/spsuppServ.hpp
index e3c78dc3fa6b..7e4d2fc54cd9 100644
--- a/shell/inc/spsupp/spsuppServ.hpp
+++ b/shell/inc/spsupp/spsuppServ.hpp
@@ -13,7 +13,7 @@
 #include <objbase.h>
 
 ITypeLib* GetTypeLib();
-const wchar_t* GetLOPath();
+const wchar_t* GetHelperExe();
 
 #endif
 
diff --git a/shell/inc/spsupp/spsuppStrings.hrc 
b/shell/inc/spsupp/spsuppStrings.hrc
new file mode 100644
index 000000000000..dc96fbb89459
--- /dev/null
+++ b/shell/inc/spsupp/spsuppStrings.hrc
@@ -0,0 +1,23 @@
+/* -*- 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/.
+ */
+
+#ifndef INCLUDED_SHELL_INC_SPSUPP_STRINGS_HRC
+#define INCLUDED_SHELL_INC_SPSUPP_STRINGS_HRC
+
+#define NC_(Context, String) reinterpret_cast<char const *>(Context "\004" 
u8##String)
+
+#define RID_STR_SP_VIEW_OR_EDIT_TITLE   NC_("RID_STR_SP_VIEW_OR_EDIT_TITLE", 
"Open Document")
+#define RID_STR_SP_VIEW_OR_EDIT_MESSAGE NC_("RID_STR_SP_VIEW_OR_EDIT_MESSAGE", 
"You are opening document\n\n  %DOCNAME\n\nDo you want to open it to view or to 
edit?")
+#define RID_STR_SP_VIEW_OR_EDIT_VIEW    NC_("RID_STR_SP_VIEW_OR_EDIT_VIEW", 
"View")
+#define RID_STR_SP_VIEW_OR_EDIT_EDIT    NC_("RID_STR_SP_VIEW_OR_EDIT_EDIT", 
"Edit")
+#define RID_STR_SP_VIEW_OR_EDIT_CANCEL  NC_("RID_STR_SP_VIEW_OR_EDIT_CANCEL", 
"Cancel")
+
+#endif          // INCLUDED_SHELL_INC_SPSUPP_STRINGS_HRC
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/shell/source/win32/spsupp/COMOpenDocuments.cxx 
b/shell/source/win32/spsupp/COMOpenDocuments.cxx
index 2e6b8cfad8ec..92ad732bfda0 100644
--- a/shell/source/win32/spsupp/COMOpenDocuments.cxx
+++ b/shell/source/win32/spsupp/COMOpenDocuments.cxx
@@ -10,6 +10,7 @@
 #include <sal/config.h>
 
 #include <cstring>
+#include <string>
 #include <vector>
 
 #include <COMOpenDocuments.hpp>
@@ -18,11 +19,12 @@
 
 namespace
 {
-
-// Returns S_OK if successful
-HRESULT LOStart(const wchar_t* sModeArg, const wchar_t* sFilePath)
+template<class... Args>
+HRESULT LOStart(Args... args)
 {
-    const wchar_t* sProgram = GetLOPath();
+    auto quote = [](const std::wstring& s) { return L"\"" + s + L"\""; };
+    std::wstring sCmdLine((quote(GetHelperExe()) + ... + (L" " + 
quote(args))));
+    LPWSTR pCmdLine = const_cast<LPWSTR>(sCmdLine.c_str());
 
     STARTUPINFOW si;
     std::memset(&si, 0, sizeof si);
@@ -30,39 +32,57 @@ HRESULT LOStart(const wchar_t* sModeArg, const wchar_t* 
sFilePath)
     si.dwFlags = STARTF_USESHOWWINDOW;
     si.wShowWindow = SW_SHOW;
     PROCESS_INFORMATION pi = {};
-    const size_t cchCommandLine = 32768;
-    wchar_t sCommandLine[cchCommandLine];
-    swprintf(sCommandLine, cchCommandLine, L"\"%s\" %s \"%s\"", sProgram, 
sModeArg, sFilePath);
-    if (CreateProcessW(nullptr, sCommandLine, nullptr, nullptr, FALSE, 0, 
nullptr, nullptr, &si, &pi) == FALSE)
-    {
-        DWORD dwError = GetLastError();
-        wchar_t* sMsgBuf = nullptr;
-        FormatMessageW(
-            FORMAT_MESSAGE_ALLOCATE_BUFFER |
-            FORMAT_MESSAGE_FROM_SYSTEM |
-            FORMAT_MESSAGE_IGNORE_INSERTS,
-            nullptr,
-            dwError,
-            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-            reinterpret_cast<LPWSTR>(&sMsgBuf),
-            0, nullptr);
-
-        size_t nBufSize = wcslen(sMsgBuf) + 100;
-        std::vector<wchar_t> sDisplayBuf(nBufSize);
-        swprintf(sDisplayBuf.data(), nBufSize, L"Could not start LibreOffice. 
Error is 0x%08X:\n\n%s", dwError, sMsgBuf);
-        HeapFree(GetProcessHeap(), 0, sMsgBuf);
-
-        // Report the error to user and return error
-        MessageBoxW(nullptr, sDisplayBuf.data(), nullptr, MB_ICONERROR);
-        return HRESULT_FROM_WIN32(dwError);
-    }
+    if (!CreateProcessW(nullptr, pCmdLine, nullptr, nullptr, FALSE, 0, 
nullptr, nullptr, &si, &pi))
+        return HRESULT_FROM_WIN32(GetLastError());
+
+    WaitForSingleObject(pi.hProcess, INFINITE);
+    DWORD nExitCode;
+    const bool bGotExitCode = GetExitCodeProcess(pi.hProcess, &nExitCode);
+    const DWORD nGetExitCodeError = GetLastError();
+
     CloseHandle(pi.hProcess);
     CloseHandle(pi.hThread);
-    return S_OK;
+
+    if (!bGotExitCode)
+        return HRESULT_FROM_WIN32(nGetExitCodeError);
+    if (nExitCode == 0)
+        return S_OK;
+    if (nExitCode == 1)
+        return S_FALSE;
+    return E_FAIL;
 }
 
 VARIANT_BOOL toVBool(bool b) { return b ? VARIANT_TRUE : VARIANT_FALSE; }
 
+HRESULT ImplCreateNewDocument(IDispatch* /*pdisp*/, BSTR bstrTemplateLocation,
+                              BSTR bstrDefaultSaveLocation, VARIANT_BOOL* 
pbResult)
+{
+    HRESULT hr = LOStart(L"CreateNewDocument", bstrTemplateLocation, 
bstrDefaultSaveLocation);
+    *pbResult = toVBool(hr == S_OK);
+    return hr;
+}
+
+HRESULT ImplEditDocument(IDispatch* /*pdisp*/, BSTR bstrDocumentLocation,
+                         VARIANT_BOOL fUseLocalCopy, const VARIANT& varProgID,
+                         VARIANT_BOOL* pbResult)
+{
+    const wchar_t* sUseLocalCopy = (fUseLocalCopy == VARIANT_FALSE) ? L"0" : 
L"1";
+    const wchar_t* sProgId = (varProgID.vt == VT_BSTR) ? varProgID.bstrVal : 
L"";
+    HRESULT hr = LOStart(L"EditDocument", bstrDocumentLocation, sUseLocalCopy, 
sProgId);
+    *pbResult = toVBool(hr == S_OK);
+    return hr;
+}
+
+HRESULT ImplViewDocument(IDispatch* /*pdisp*/, BSTR bstrDocumentLocation, int 
OpenType,
+                         const VARIANT& varProgID, VARIANT_BOOL* pbResult)
+{
+    wchar_t sOpenType[16]{};
+    swprintf(sOpenType, L"%d", OpenType);
+    const wchar_t* sProgId = (varProgID.vt == VT_BSTR) ? varProgID.bstrVal : 
L"";
+    HRESULT hr = LOStart(L"ViewDocument", bstrDocumentLocation, sOpenType, 
sProgId);
+    *pbResult = toVBool(hr == S_OK);
+    return hr;
+}
 } // namespace
 
 long COMOpenDocuments::m_nObjCount = 0;
@@ -224,17 +244,15 @@ STDMETHODIMP COMOpenDocuments::EditDocument2(
 
 // Creates a document based on the specified document template and window 
object
 STDMETHODIMP COMOpenDocuments::CreateNewDocument2(
-    IDispatch* /*pdisp*/,             // An Object that represents the window 
from which the CreateNewDocument2 method is being activated
+    IDispatch* pdisp,                 // An Object that represents the window 
from which the CreateNewDocument2 method is being activated
     BSTR bstrTemplateLocation,        // A string that contains the URL of the 
document template from which the document is created, or the programmatic 
identifier (progID) of the application to invoke when creating the document
-    BSTR /*bstrDefaultSaveLocation*/, // A string that contains the path that 
specifies a suggested default location for saving the new document
+    BSTR bstrDefaultSaveLocation,     // A string that contains the path that 
specifies a suggested default location for saving the new document
     VARIANT_BOOL* pbResult)           // true if the document creation 
succeeds; otherwise false
 {
     if (!pbResult)
         return E_POINTER;
     // TODO: resolve the program from varProgID (nullptr -> default?)
-    HRESULT hr = LOStart(L"-n", bstrTemplateLocation);
-    *pbResult = toVBool(SUCCEEDED(hr));
-    return hr;
+    return ImplCreateNewDocument(pdisp, bstrTemplateLocation, 
bstrDefaultSaveLocation, pbResult);
 }
 
 // Used with the OpenDocuments.CreateNewDocument2 method to determine
@@ -276,18 +294,15 @@ STDMETHODIMP COMOpenDocuments::PromptedOnLastOpen(
 // 3 When the document is not checked out and the document library requires 
that documents be checked out to be edited, the user can only read the 
document, or check it out and edit it
 // 4 When the current user has checked it out, the user can only edit the 
local copy of the document
 STDMETHODIMP COMOpenDocuments::ViewDocument3(
-    IDispatch* /*pdisp*/,      // An Object that represents the window from 
which the ViewDocument3 method is being activated
+    IDispatch* pdisp,          // An Object that represents the window from 
which the ViewDocument3 method is being activated
     BSTR bstrDocumentLocation, // A string that contains the URL of the 
document to open for reading
-    int /*OpenType*/,          // A Long integer that specifies the rights for 
opening the document
-    VARIANT /*varProgID*/,     // An optional string that contains the ProgID 
of the application with which to open the document. If this argument is 
omitted, the default viewer for the document is used
+    int OpenType,              // A Long integer that specifies the rights for 
opening the document
+    VARIANT varProgID,         // An optional string that contains the ProgID 
of the application with which to open the document. If this argument is 
omitted, the default viewer for the document is used
     VARIANT_BOOL *pbResult)    // true if the document was successfully 
opened; otherwise false
 {
     if (!pbResult)
         return E_POINTER;
-    // TODO: resolve the program from varProgID (nullptr -> default?)
-    HRESULT hr = LOStart(L"--view", bstrDocumentLocation);
-    *pbResult = toVBool(SUCCEEDED(hr));
-    return hr;
+    return ImplViewDocument(pdisp, bstrDocumentLocation, OpenType, varProgID, 
pbResult);
 }
 
 // Checks in the specified document to a library
@@ -340,18 +355,16 @@ STDMETHODIMP COMOpenDocuments::CheckoutDocumentPrompt(
 // or with the specified editor based on the specified window object,
 // and specifies whether to use a local copy
 STDMETHODIMP COMOpenDocuments::EditDocument3(
-    IDispatch* /*pdisp*/,           // An Object that represents the window 
from which the EditDocument3 method is being activated
+    IDispatch* pdisp,               // An Object that represents the window 
from which the EditDocument3 method is being activated
     BSTR bstrDocumentLocation,      // A string that contains the URL of the 
document to open for editing
-    VARIANT_BOOL /*fUseLocalCopy*/, // true to use a local copy; otherwise 
false
-    VARIANT /*varProgID*/,          // An optional string that contains the 
ProgID of the application with which to edit the document. If this argument is 
omitted, the default editor for the document is used
-    VARIANT_BOOL *pbResult)     // true if the document was successfully 
opened; otherwise false
+    VARIANT_BOOL fUseLocalCopy,     // true to use a local copy; otherwise 
false
+    VARIANT varProgID,              // An optional string that contains the 
ProgID of the application with which to edit the document. If this argument is 
omitted, the default editor for the document is used
+    VARIANT_BOOL *pbResult)         // true if the document was successfully 
opened; otherwise false
 {
     if (!pbResult)
         return E_POINTER;
     // TODO: resolve the program from varProgID (nullptr -> default?)
-    HRESULT hr = LOStart(L"-o", bstrDocumentLocation);
-    *pbResult = toVBool(SUCCEEDED(hr));
-    return hr;
+    return ImplEditDocument(pdisp, bstrDocumentLocation, fUseLocalCopy, 
varProgID, pbResult);
 }
 
 // Creates a new blog post in the editing application
diff --git a/shell/source/win32/spsupp/res/spsuppDlg.h 
b/shell/source/win32/spsupp/res/spsuppDlg.h
new file mode 100644
index 000000000000..f4b6ccb34410
--- /dev/null
+++ b/shell/source/win32/spsupp/res/spsuppDlg.h
@@ -0,0 +1,27 @@
+/* -*- 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/.
+*/
+
+#define IDD_EDIT_OR_RO 101
+#define IDC_STATIC -1
+#define ID_RO 1000
+#define ID_EDIT 1001
+#define IDC_EDIT_OR_RO 1002
+
+// Next default values for new objects
+
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1002
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/shell/source/win32/spsupp/res/spsuppDlg.rc 
b/shell/source/win32/spsupp/res/spsuppDlg.rc
new file mode 100644
index 000000000000..a27974661f30
--- /dev/null
+++ b/shell/source/win32/spsupp/res/spsuppDlg.rc
@@ -0,0 +1,29 @@
+/* -*- 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 "spsuppDlg.h"
+// We need to include windows.h to use IDI_QUESTION
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT
+
+// Dialog
+
+IDD_EDIT_OR_RO DIALOGEX 0, 0, 309, 87
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | 
WS_SYSMENU
+CAPTION "Open Document"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    ICON            IDI_QUESTION,IDC_STATIC,7,7,21,20
+    LTEXT           "Do you want to open the document to view or to 
edit?",IDC_EDIT_OR_RO,36,7,266,44
+    DEFPUSHBUTTON   "View",ID_RO,91,66,77,14
+    PUSHBUTTON      "Edit",ID_EDIT,171,66,77,14
+    PUSHBUTTON      "Cancel",IDCANCEL,252,66,50,14
+END
diff --git a/shell/source/win32/spsupp/spsuppHelper.cxx 
b/shell/source/win32/spsupp/spsuppHelper.cxx
new file mode 100644
index 000000000000..0c4834f960e0
--- /dev/null
+++ b/shell/source/win32/spsupp/spsuppHelper.cxx
@@ -0,0 +1,231 @@
+/* -*- 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 <prewin.h>
+#include <postwin.h>
+
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <osl/file.hxx>
+#include <rtl/bootstrap.hxx>
+#include <spsuppStrings.hrc>
+#include <unotools/resmgr.hxx>
+#include "res/spsuppDlg.h"
+
+// Since we need to show localized messages to user before starting 
LibreOffice, we need to
+// bootstrap part of LO (l10n machinery). This implies loading some LO 
libraries, and since
+// there are ActiveX controls for both x86 and x64 for use in corresponding 
clients, they
+// can't both load the libraries that exist only for one architecture, like 
sal. Thus we need
+// a dedicated helper process, which is launched by ActiveX, and handle user 
interactions.
+
+namespace
+{
+const OUString& GetSofficeExe()
+{
+    static const OUString s_sPath = []() {
+        OUString result;
+        wchar_t sPath[MAX_PATH];
+        if (GetModuleFileNameW(nullptr, sPath, MAX_PATH) == 0)
+            return result;
+        wchar_t* pSlashPos = wcsrchr(sPath, L'\\');
+        if (pSlashPos == nullptr)
+            return result;
+        wcscpy(pSlashPos + 1, L"soffice.exe");
+        result = o3tl::toU(sPath);
+        return result;
+    }();
+    return s_sPath;
+}
+
+OUString GetString(const char* pResId)
+{
+    static const std::locale s_pLocale = [] {
+        // Initialize soffice bootstrap: see getIniFileName_Impl for reference
+        OUString sPath = GetSofficeExe();
+        if (const sal_Int32 nDotPos = sPath.lastIndexOf('.'); nDotPos >= 0)
+        {
+            sPath = sPath.replaceAt(nDotPos, sPath.getLength() - nDotPos, 
SAL_CONFIGFILE(""));
+            if (osl::FileBase::getFileURLFromSystemPath(sPath, sPath) == 
osl::FileBase::E_None)
+                rtl::Bootstrap::setIniFilename(sPath);
+        }
+        return Translate::Create("shell", LanguageTag("")); // Use system 
language
+    }();
+    return Translate::get(pResId, s_pLocale);
+}
+
+INT_PTR CALLBACK EditOrRODlgproc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM 
lParam)
+{
+    switch (Msg)
+    {
+        case WM_INITDIALOG:
+        {
+            if (const wchar_t* sFilePath = reinterpret_cast<const 
wchar_t*>(lParam))
+            {
+                OUString sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_TITLE);
+                SetWindowTextW(hDlg, o3tl::toW(sMsg.getStr()));
+                sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_MESSAGE)
+                           .replaceFirst("%DOCNAME", o3tl::toU(sFilePath));
+                SetWindowTextW(GetDlgItem(hDlg, IDC_EDIT_OR_RO), 
o3tl::toW(sMsg.getStr()));
+                sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_VIEW);
+                SetWindowTextW(GetDlgItem(hDlg, ID_RO), 
o3tl::toW(sMsg.getStr()));
+                sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_EDIT);
+                SetWindowTextW(GetDlgItem(hDlg, ID_EDIT), 
o3tl::toW(sMsg.getStr()));
+                sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_CANCEL);
+                SetWindowTextW(GetDlgItem(hDlg, IDCANCEL), 
o3tl::toW(sMsg.getStr()));
+            }
+            return TRUE; // set default focus
+        }
+        case WM_COMMAND:
+        {
+            WORD nId = LOWORD(wParam);
+            switch (nId)
+            {
+                case IDCANCEL:
+                case ID_RO:
+                case ID_EDIT:
+                    EndDialog(hDlg, nId);
+                    return TRUE;
+            }
+            break;
+        }
+    }
+    return FALSE;
+}
+
+enum class Answer
+{
+    Cancel,
+    ReadOnly,
+    Edit
+};
+
+Answer AskIfUserWantsToEdit(const wchar_t* sFilePath)
+{
+    Answer res = Answer::Cancel;
+    INT_PTR nResult = DialogBoxParamW(nullptr, 
MAKEINTRESOURCEW(IDD_EDIT_OR_RO), nullptr,
+                                      EditOrRODlgproc, 
reinterpret_cast<LPARAM>(sFilePath));
+    if (nResult == ID_RO)
+        res = Answer::ReadOnly;
+    else if (nResult == ID_EDIT)
+        res = Answer::Edit;
+    return res;
+}
+
+// Returns ERROR_SUCCESS or Win32 error code
+DWORD LOStart(const wchar_t* sModeArg, const wchar_t* sFilePath)
+{
+    OUString sCmdLine = "\"" + GetSofficeExe() + "\" " + 
OUString(o3tl::toU(sModeArg)) + " \""
+                        + OUString(o3tl::toU(sFilePath)) + "\"";
+    LPWSTR pCmdLine = const_cast<LPWSTR>(o3tl::toW(sCmdLine.getStr()));
+
+    STARTUPINFOW si;
+    std::memset(&si, 0, sizeof si);
+    si.cb = sizeof si;
+    si.dwFlags = STARTF_USESHOWWINDOW;
+    si.wShowWindow = SW_SHOW;
+    PROCESS_INFORMATION pi{};
+    if (!CreateProcessW(nullptr, pCmdLine, nullptr, nullptr, FALSE, 0, 
nullptr, nullptr, &si, &pi))
+    {
+        DWORD dwError = GetLastError();
+        wchar_t* sMsgBuf = nullptr;
+        FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
FORMAT_MESSAGE_FROM_SYSTEM
+                           | FORMAT_MESSAGE_IGNORE_INSERTS,
+                       nullptr, dwError, MAKELANGID(LANG_NEUTRAL, 
SUBLANG_DEFAULT),
+                       reinterpret_cast<LPWSTR>(&sMsgBuf), 0, nullptr);
+
+        size_t nBufSize = wcslen(sMsgBuf) + 100;
+        std::vector<wchar_t> sDisplayBuf(nBufSize);
+        swprintf(sDisplayBuf.data(), nBufSize,
+                 L"Could not start LibreOffice. Error is 0x%08X:\n\n%s", 
dwError, sMsgBuf);
+        HeapFree(GetProcessHeap(), 0, sMsgBuf);
+
+        // Report the error to user and return error
+        MessageBoxW(nullptr, sDisplayBuf.data(), nullptr, MB_ICONERROR);
+        return dwError;
+    }
+    CloseHandle(pi.hProcess);
+    CloseHandle(pi.hThread);
+    return ERROR_SUCCESS;
+}
+
+int CreateNewDocument(LPCWSTR TemplateLocation, LPCWSTR 
/*DefaultSaveLocation*/)
+{
+    // TODO: resolve the program from varProgID (nullptr -> default?)
+    DWORD nResult = LOStart(L"-n", TemplateLocation);
+    return nResult == ERROR_SUCCESS ? 0 : 2;
+}
+
+// UseLocalCopy would be either "0" or "1", denoting boolean value
+int EditDocument(LPCWSTR DocumentLocation, LPCWSTR /*UseLocalCopy*/, LPCWSTR 
/*varProgID*/)
+{
+    // TODO: resolve the program from varProgID (nullptr -> default?)
+    DWORD nResult = LOStart(L"-o", DocumentLocation);
+    return nResult == ERROR_SUCCESS ? 0 : 2;
+}
+
+// Possible values for OpenType
+//
+// "0" When checked out, or when the document library does not require check 
out, the user can read or edit the document
+// "1" When another user has checked it out, the user can only read the 
document
+// "2" When the current user has checked it out, the user can only edit the 
document
+// "3" When the document is not checked out and the document library requires 
that documents be checked out to be edited, the user can only read the 
document, or check it out and edit it
+// "4" When the current user has checked it out, the user can only edit the 
local copy of the document
+int ViewDocument(LPCWSTR DocumentLocation, LPCWSTR OpenType, LPCWSTR varProgID)
+{
+    if (wcscmp(OpenType, L"0") == 0)
+    {
+        switch (AskIfUserWantsToEdit(DocumentLocation))
+        {
+            case Answer::Cancel:
+                return 1;
+            case Answer::Edit:
+                return EditDocument(DocumentLocation, L"0", varProgID);
+        }
+    }
+    // TODO: resolve the program from varProgID (nullptr -> default?)
+    DWORD nResult = LOStart(L"--view", DocumentLocation);
+    return nResult == ERROR_SUCCESS ? 0 : 2;
+}
+} // namespace
+
+// Returns 0 on success, 1 when operation wasn't performed because user 
cancelled, 2 on an error
+int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
+{
+    int argc = 0;
+    const LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
+    if (argc < 2)
+        return 2; // Wrong argument count
+
+    if (wcscmp(argv[1], L"CreateNewDocument") == 0)
+    {
+        if (argc != 4)
+            return 2; // Wrong argument count
+        return CreateNewDocument(argv[2], argv[3]);
+    }
+
+    if (wcscmp(argv[1], L"ViewDocument") == 0)
+    {
+        if (argc != 4 && argc != 5)
+            return 2; // Wrong argument count
+        LPCWSTR pProgId = argc == 5 ? argv[4] : nullptr;
+        return ViewDocument(argv[2], argv[3], pProgId);
+    }
+
+    if (wcscmp(argv[1], L"EditDocument") == 0)
+    {
+        if (argc != 4 && argc != 5)
+            return 2; // Wrong argument count
+        LPCWSTR pProgId = argc == 5 ? argv[4] : nullptr;
+        return EditDocument(argv[2], argv[3], pProgId);
+    }
+
+    return 2; // Wrong command
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/shell/source/win32/spsupp/spsuppServ.cxx 
b/shell/source/win32/spsupp/spsuppServ.cxx
index f15f505fd730..64b2090c4cf9 100644
--- a/shell/source/win32/spsupp/spsuppServ.cxx
+++ b/shell/source/win32/spsupp/spsuppServ.cxx
@@ -28,11 +28,12 @@
 
 #include <shlwapi.h> // declaration of DllInstall
 
-namespace {
-
+namespace
+{
 HANDLE g_hModule;
 
-}
+HMODULE GetHModule() { return static_cast<HMODULE>(g_hModule); }
+} // namespace
 
 ITypeLib* GetTypeLib()
 {
@@ -40,7 +41,7 @@ ITypeLib* GetTypeLib()
     static ITypeLibGuard s_aITypeLibGuard = [] {
         ITypeLibGuard aITypeLibGuard(nullptr, [](IUnknown* p) { if (p) 
p->Release(); });
         wchar_t szFile[MAX_PATH];
-        if (GetModuleFileNameW(static_cast<HMODULE>(g_hModule), szFile, 
MAX_PATH) == 0)
+        if (GetModuleFileNameW(GetHModule(), szFile, MAX_PATH) == 0)
             return aITypeLibGuard;
         ITypeLib* pTypeLib;
         if (FAILED(LoadTypeLib(szFile, &pTypeLib)))
@@ -51,16 +52,16 @@ ITypeLib* GetTypeLib()
     return s_aITypeLibGuard.get();
 }
 
-const wchar_t* GetLOPath()
+const wchar_t* GetHelperExe()
 {
     static wchar_t* s_sPath = []() -> wchar_t* {
         static wchar_t sPath[MAX_PATH];
-        if (GetModuleFileNameW(static_cast<HMODULE>(g_hModule), sPath, 
MAX_PATH) == 0)
+        if (GetModuleFileNameW(GetHModule(), sPath, MAX_PATH) == 0)
             return nullptr;
         wchar_t* pSlashPos = wcsrchr(sPath, L'\\');
         if (pSlashPos == nullptr)
             return nullptr;
-        wcscpy(pSlashPos + 1, L"soffice.exe");
+        wcscpy(pSlashPos + 1, L"spsupp_helper.exe");
         return sPath;
     }();
     return s_sPath;
@@ -120,7 +121,7 @@ STDAPI DllRegisterServer(void)
         return ResultFromScode(SELFREG_E_TYPELIB);
 
     wchar_t szFile[MAX_PATH];
-    if (GetModuleFileNameW(static_cast<HMODULE>(g_hModule), szFile, MAX_PATH) 
== 0)
+    if (GetModuleFileNameW(GetHModule(), szFile, MAX_PATH) == 0)
         return HRESULT_FROM_WIN32(GetLastError());
 
     HRESULT hr = RegisterTypeLib(pTypeLib, szFile, nullptr);
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to