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 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(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 #include +#include #include #include @@ -18,11 +19,12 @@ namespace { - -// Returns S_OK if successful -HRESULT LOStart(const wchar_t* sModeArg, const wchar_t* sFilePath) +template +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(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(&sMsgBuf), - 0, nullptr); + if (!CreateProcessW(nullptr, pCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) + return HRESULT_FROM_WIN32(GetLastError()); - size_t nBufSize = wcslen(sMsgBuf) + 100; - std::vector sDisplayBuf(nBufSize); - swprintf(sDisplayBuf.data(), nBufSize, L"Could not start LibreOffice. Error is 0x%08X:\n\n%s", dwError, sMsgBuf); - HeapFree(GetProcessHeap(), 0, sMsgBuf); + WaitForSingleObject(pi.hProcess, INFINITE); + DWORD nExitCode; + const bool bGotExitCode = GetExitCodeProcess(pi.hProcess, &nExitCode); + const DWORD nGetExitCodeError = GetLastError(); - // Report the error to user and return error - MessageBoxW(nullptr, sDisplayBuf.data(), nullptr, MB_ICONERROR); - return HRESULT_FROM_WIN32(dwError); - } 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 + +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 +#include + +#include +#include +#include +#include +#include +#include +#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(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(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(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(&sMsgBuf), 0, nullptr); + + size_t nBufSize = wcslen(sMsgBuf) + 100; + std::vector 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 // declaration of DllInstall -namespace { - +namespace +{ HANDLE g_hModule; -} +HMODULE GetHModule() { return static_cast(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(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(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(g_hModule), szFile, MAX_PATH) == 0) + if (GetModuleFileNameW(GetHModule(), szFile, MAX_PATH) == 0) return HRESULT_FROM_WIN32(GetLastError()); HRESULT hr = RegisterTypeLib(pTypeLib, szFile, nullptr);