LibreOffice Module shell (master) 1
spsuppHelper.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3* This file is part of the LibreOffice project.
4*
5* This Source Code Form is subject to the terms of the Mozilla Public
6* License, v. 2.0. If a copy of the MPL was not distributed with this
7* file, You can obtain one at http://mozilla.org/MPL/2.0/.
8*/
9
10#include <prewin.h>
11#include <postwin.h>
12
16#include <osl/file.hxx>
17#include <rtl/bootstrap.hxx>
18#include <spsuppStrings.hrc>
19#include <unotools/resmgr.hxx>
20#include "res/spsuppDlg.h"
21
22// Since we need to show localized messages to user before starting LibreOffice, we need to
23// bootstrap part of LO (l10n machinery). This implies loading some LO libraries, and since
24// there are ActiveX controls for both x86 and x64 for use in corresponding clients, they
25// can't both load the libraries that exist only for one architecture, like sal. Thus we need
26// a dedicated helper process, which is launched by ActiveX, and handle user interactions.
27
28namespace
29{
30const OUString& GetSofficeExe()
31{
32 static const OUString s_sPath = []() {
33 OUString result;
34 wchar_t sPath[MAX_PATH];
35 if (GetModuleFileNameW(nullptr, sPath, MAX_PATH) == 0)
36 return result;
37 wchar_t* pSlashPos = wcsrchr(sPath, L'\\');
38 if (pSlashPos == nullptr)
39 return result;
40 wcscpy(pSlashPos + 1, L"soffice.exe");
41 result = o3tl::toU(sPath);
42 return result;
43 }();
44 return s_sPath;
45}
46
47OUString GetString(TranslateId pResId)
48{
49 static const std::locale s_pLocale = [] {
50 // Initialize soffice bootstrap: see getIniFileName_Impl for reference
51 OUString sPath = GetSofficeExe();
52 if (const sal_Int32 nDotPos = sPath.lastIndexOf('.'); nDotPos >= 0)
53 {
54 sPath = sPath.replaceAt(nDotPos, sPath.getLength() - nDotPos, SAL_CONFIGFILE(u""));
55 if (osl::FileBase::getFileURLFromSystemPath(sPath, sPath) == osl::FileBase::E_None)
56 rtl::Bootstrap::setIniFilename(sPath);
57 }
58 return Translate::Create("shell", LanguageTag("")); // Use system language
59 }();
60 return Translate::get(pResId, s_pLocale);
61}
62
63INT_PTR CALLBACK EditOrRODlgproc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
64{
65 switch (Msg)
66 {
67 case WM_INITDIALOG:
68 {
69 if (const wchar_t* sFilePath = reinterpret_cast<const wchar_t*>(lParam))
70 {
71 OUString sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_TITLE);
72 SetWindowTextW(hDlg, o3tl::toW(sMsg.getStr()));
73 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_MESSAGE)
74 .replaceFirst("%DOCNAME", o3tl::toU(sFilePath));
75 SetWindowTextW(GetDlgItem(hDlg, IDC_EDIT_OR_RO), o3tl::toW(sMsg.getStr()));
76 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_VIEW);
77 SetWindowTextW(GetDlgItem(hDlg, ID_RO), o3tl::toW(sMsg.getStr()));
78 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_EDIT);
79 SetWindowTextW(GetDlgItem(hDlg, ID_EDIT), o3tl::toW(sMsg.getStr()));
80 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_CANCEL);
81 SetWindowTextW(GetDlgItem(hDlg, IDCANCEL), o3tl::toW(sMsg.getStr()));
82 }
83 return TRUE; // set default focus
84 }
85 case WM_COMMAND:
86 {
87 WORD nId = LOWORD(wParam);
88 switch (nId)
89 {
90 case IDCANCEL:
91 case ID_RO:
92 case ID_EDIT:
93 EndDialog(hDlg, nId);
94 return TRUE;
95 }
96 break;
97 }
98 }
99 return FALSE;
100}
101
102enum class Answer
103{
104 Cancel,
105 ReadOnly,
106 Edit
107};
108
109Answer AskIfUserWantsToEdit(const wchar_t* sFilePath)
110{
111 Answer res = Answer::Cancel;
112 INT_PTR nResult = DialogBoxParamW(nullptr, MAKEINTRESOURCEW(IDD_EDIT_OR_RO), nullptr,
113 EditOrRODlgproc, reinterpret_cast<LPARAM>(sFilePath));
114 if (nResult == ID_RO)
115 res = Answer::ReadOnly;
116 else if (nResult == ID_EDIT)
117 res = Answer::Edit;
118 return res;
119}
120
121// Returns ERROR_SUCCESS or Win32 error code
122DWORD LOStart(const wchar_t* sModeArg, const wchar_t* sFilePath)
123{
124 OUString sCmdLine = "\"" + GetSofficeExe() + "\" " + o3tl::toU(sModeArg) + " \""
125 + o3tl::toU(sFilePath) + "\"";
126 LPWSTR pCmdLine = const_cast<LPWSTR>(o3tl::toW(sCmdLine.getStr()));
127
128 STARTUPINFOW si = {};
129 si.cb = sizeof si;
130 si.dwFlags = STARTF_USESHOWWINDOW;
131 si.wShowWindow = SW_SHOW;
132 PROCESS_INFORMATION pi{};
133 if (!CreateProcessW(nullptr, pCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi))
134 {
135 DWORD dwError = GetLastError();
136 const OUString sErrorMsg = "Could not start LibreOffice. Error is 0x"
137 + OUString::number(dwError, 16) + ":\n\n"
138 + WindowsErrorString(dwError);
139
140 // Report the error to user and return error
141 MessageBoxW(nullptr, o3tl::toW(sErrorMsg.getStr()), nullptr, MB_ICONERROR);
142 return dwError;
143 }
144 CloseHandle(pi.hProcess);
145 CloseHandle(pi.hThread);
146 return ERROR_SUCCESS;
147}
148
149int CreateNewDocument(LPCWSTR TemplateLocation, LPCWSTR /*DefaultSaveLocation*/)
150{
151 // TODO: resolve the program from varProgID (nullptr -> default?)
152 DWORD nResult = LOStart(L"-n", TemplateLocation);
153 return nResult == ERROR_SUCCESS ? 0 : 2;
154}
155
156// UseLocalCopy would be either "0" or "1", denoting boolean value
157int EditDocument(LPCWSTR DocumentLocation, LPCWSTR /*UseLocalCopy*/, LPCWSTR /*varProgID*/)
158{
159 // TODO: resolve the program from varProgID (nullptr -> default?)
160 DWORD nResult = LOStart(L"-o", DocumentLocation);
161 return nResult == ERROR_SUCCESS ? 0 : 2;
162}
163
164// Possible values for OpenType
165//
166// "0" When checked out, or when the document library does not require check out, the user can read or edit the document
167// "1" When another user has checked it out, the user can only read the document
168// "2" When the current user has checked it out, the user can only edit the document
169// "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
170// "4" When the current user has checked it out, the user can only edit the local copy of the document
171int ViewDocument(LPCWSTR DocumentLocation, LPCWSTR OpenType, LPCWSTR varProgID)
172{
173 if (wcscmp(OpenType, L"0") == 0)
174 {
175 switch (AskIfUserWantsToEdit(DocumentLocation))
176 {
177 case Answer::Cancel:
178 return 1;
179 case Answer::ReadOnly:
180 break;
181 case Answer::Edit:
182 return EditDocument(DocumentLocation, L"0", varProgID);
183 }
184 }
185 // TODO: resolve the program from varProgID (nullptr -> default?)
186 DWORD nResult = LOStart(L"--view", DocumentLocation);
187 return nResult == ERROR_SUCCESS ? 0 : 2;
188}
189} // namespace
190
191// Returns 0 on success, 1 when operation wasn't performed because user cancelled, 2 on an error
192int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
193{
194 int argc = 0;
195 const LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
196 if (argc < 2)
197 return 2; // Wrong argument count
198
199 if (wcscmp(argv[1], L"CreateNewDocument") == 0)
200 {
201 if (argc != 4)
202 return 2; // Wrong argument count
203 return CreateNewDocument(argv[2], argv[3]);
204 }
205
206 if (wcscmp(argv[1], L"ViewDocument") == 0)
207 {
208 if (argc != 4 && argc != 5)
209 return 2; // Wrong argument count
210 LPCWSTR pProgId = argc == 5 ? argv[4] : nullptr;
211 return ViewDocument(argv[2], argv[3], pProgId);
212 }
213
214 if (wcscmp(argv[1], L"EditDocument") == 0)
215 {
216 if (argc != 4 && argc != 5)
217 return 2; // Wrong argument count
218 LPCWSTR pProgId = argc == 5 ? argv[4] : nullptr;
219 return EditDocument(argv[2], argv[3], pProgId);
220 }
221
222 return 2; // Wrong command
223}
224
225/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define SAL_CONFIGFILE(name)
virtual void EndDialog(sal_Int32 nResult) override
#define TRUE
#define FALSE
#define MAX_PATH
unsigned short WORD
Definition: lngconvex.cxx:25
OUString GetString(int nId)
std::locale Create(std::string_view aPrefixName, const LanguageTag &rLocale)
OUString get(TranslateId sContextAndId, const std::locale &loc)
#define CALLBACK
sal_Int16 nId
#define IDD_EDIT_OR_RO
Definition: spsuppDlg.h:10
#define ID_RO
Definition: spsuppDlg.h:12
#define IDC_EDIT_OR_RO
Definition: spsuppDlg.h:14
#define ID_EDIT
Definition: spsuppDlg.h:13
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
Any result