cid#1607171 Data race condition
[LibreOffice.git] / shell / source / win32 / spsupp / spsuppHelper.cxx
blob5867a5ea393d524d2cc1c8aa3dfff81b4d18813d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #include <prewin.h>
11 #include <postwin.h>
13 #include <comphelper/windowserrorstring.hxx>
14 #include <i18nlangtag/languagetag.hxx>
15 #include <o3tl/char16_t2wchar_t.hxx>
16 #include <osl/file.hxx>
17 #include <rtl/bootstrap.hxx>
18 #include <spsuppStrings.hrc>
19 #include <systools/win32/extended_max_path.hxx>
20 #include <unotools/resmgr.hxx>
21 #include "res/spsuppDlg.h"
23 // Since we need to show localized messages to user before starting LibreOffice, we need to
24 // bootstrap part of LO (l10n machinery). This implies loading some LO libraries, and since
25 // there are ActiveX controls for both x86 and x64 for use in corresponding clients, they
26 // can't both load the libraries that exist only for one architecture, like sal. Thus we need
27 // a dedicated helper process, which is launched by ActiveX, and handle user interactions.
29 namespace
31 const OUString& GetSofficeExe()
33 static const OUString s_sPath = []() {
34 OUString result;
35 wchar_t sPath[EXTENDED_MAX_PATH];
36 if (GetModuleFileNameW(nullptr, sPath, std::size(sPath)) == 0)
37 return result;
38 wchar_t* pSlashPos = wcsrchr(sPath, L'\\');
39 if (pSlashPos == nullptr)
40 return result;
41 wcscpy(pSlashPos + 1, L"soffice.exe");
42 result = o3tl::toU(sPath);
43 return result;
44 }();
45 return s_sPath;
48 OUString GetString(TranslateId pResId)
50 static const std::locale s_pLocale = [] {
51 // Initialize soffice bootstrap: see getIniFileName_Impl for reference
52 OUString sPath = GetSofficeExe();
53 if (const sal_Int32 nDotPos = sPath.lastIndexOf('.'); nDotPos >= 0)
55 sPath = sPath.replaceAt(nDotPos, sPath.getLength() - nDotPos, SAL_CONFIGFILE(u""));
56 if (osl::FileBase::getFileURLFromSystemPath(sPath, sPath) == osl::FileBase::E_None)
57 rtl::Bootstrap::setIniFilename(sPath);
59 return Translate::Create("shell", LanguageTag("")); // Use system language
60 }();
61 return Translate::get(pResId, s_pLocale);
64 INT_PTR CALLBACK EditOrRODlgproc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
66 switch (Msg)
68 case WM_INITDIALOG:
70 if (const wchar_t* sFilePath = reinterpret_cast<const wchar_t*>(lParam))
72 OUString sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_TITLE);
73 SetWindowTextW(hDlg, o3tl::toW(sMsg.getStr()));
74 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_MESSAGE)
75 .replaceFirst("%DOCNAME", o3tl::toU(sFilePath));
76 SetWindowTextW(GetDlgItem(hDlg, IDC_EDIT_OR_RO), o3tl::toW(sMsg.getStr()));
77 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_VIEW);
78 SetWindowTextW(GetDlgItem(hDlg, ID_RO), o3tl::toW(sMsg.getStr()));
79 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_EDIT);
80 SetWindowTextW(GetDlgItem(hDlg, ID_EDIT), o3tl::toW(sMsg.getStr()));
81 sMsg = GetString(RID_STR_SP_VIEW_OR_EDIT_CANCEL);
82 SetWindowTextW(GetDlgItem(hDlg, IDCANCEL), o3tl::toW(sMsg.getStr()));
84 return TRUE; // set default focus
86 case WM_COMMAND:
88 WORD nId = LOWORD(wParam);
89 switch (nId)
91 case IDCANCEL:
92 case ID_RO:
93 case ID_EDIT:
94 EndDialog(hDlg, nId);
95 return TRUE;
97 break;
100 return FALSE;
103 enum class Answer
105 Cancel,
106 ReadOnly,
107 Edit
110 Answer AskIfUserWantsToEdit(const wchar_t* sFilePath)
112 Answer res = Answer::Cancel;
113 INT_PTR nResult = DialogBoxParamW(nullptr, MAKEINTRESOURCEW(IDD_EDIT_OR_RO), nullptr,
114 EditOrRODlgproc, reinterpret_cast<LPARAM>(sFilePath));
115 if (nResult == ID_RO)
116 res = Answer::ReadOnly;
117 else if (nResult == ID_EDIT)
118 res = Answer::Edit;
119 return res;
122 // Returns ERROR_SUCCESS or Win32 error code
123 DWORD LOStart(const wchar_t* sModeArg, const wchar_t* sFilePath)
125 OUString sCmdLine = "\"" + GetSofficeExe() + "\" " + o3tl::toU(sModeArg) + " \""
126 + o3tl::toU(sFilePath) + "\"";
127 LPWSTR pCmdLine = const_cast<LPWSTR>(o3tl::toW(sCmdLine.getStr()));
129 STARTUPINFOW si = {};
130 si.cb = sizeof si;
131 si.dwFlags = STARTF_USESHOWWINDOW;
132 si.wShowWindow = SW_SHOW;
133 PROCESS_INFORMATION pi{};
134 if (!CreateProcessW(nullptr, pCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi))
136 DWORD dwError = GetLastError();
137 const OUString sErrorMsg = "Could not start LibreOffice. Error is 0x"
138 + OUString::number(dwError, 16) + ":\n\n"
139 + WindowsErrorString(dwError);
141 // Report the error to user and return error
142 MessageBoxW(nullptr, o3tl::toW(sErrorMsg.getStr()), nullptr, MB_ICONERROR);
143 return dwError;
145 CloseHandle(pi.hProcess);
146 CloseHandle(pi.hThread);
147 return ERROR_SUCCESS;
150 int CreateNewDocument(LPCWSTR TemplateLocation, LPCWSTR /*DefaultSaveLocation*/)
152 // TODO: resolve the program from varProgID (nullptr -> default?)
153 DWORD nResult = LOStart(L"-n", TemplateLocation);
154 return nResult == ERROR_SUCCESS ? 0 : 2;
157 // UseLocalCopy would be either "0" or "1", denoting boolean value
158 int EditDocument(LPCWSTR DocumentLocation, LPCWSTR /*UseLocalCopy*/, LPCWSTR /*varProgID*/)
160 // TODO: resolve the program from varProgID (nullptr -> default?)
161 DWORD nResult = LOStart(L"-o", DocumentLocation);
162 return nResult == ERROR_SUCCESS ? 0 : 2;
165 // Possible values for OpenType
167 // "0" When checked out, or when the document library does not require check out, the user can read or edit the document
168 // "1" When another user has checked it out, the user can only read the document
169 // "2" When the current user has checked it out, the user can only edit the document
170 // "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
171 // "4" When the current user has checked it out, the user can only edit the local copy of the document
172 int ViewDocument(LPCWSTR DocumentLocation, LPCWSTR OpenType, LPCWSTR varProgID)
174 if (wcscmp(OpenType, L"0") == 0)
176 switch (AskIfUserWantsToEdit(DocumentLocation))
178 case Answer::Cancel:
179 return 1;
180 case Answer::ReadOnly:
181 break;
182 case Answer::Edit:
183 return EditDocument(DocumentLocation, L"0", varProgID);
186 // TODO: resolve the program from varProgID (nullptr -> default?)
187 DWORD nResult = LOStart(L"--view", DocumentLocation);
188 return nResult == ERROR_SUCCESS ? 0 : 2;
190 } // namespace
192 // Returns 0 on success, 1 when operation wasn't performed because user cancelled, 2 on an error
193 int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
195 int argc = 0;
196 const LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
197 if (argc < 2)
198 return 2; // Wrong argument count
200 if (wcscmp(argv[1], L"CreateNewDocument") == 0)
202 if (argc != 4)
203 return 2; // Wrong argument count
204 return CreateNewDocument(argv[2], argv[3]);
207 if (wcscmp(argv[1], L"ViewDocument") == 0)
209 if (argc != 4 && argc != 5)
210 return 2; // Wrong argument count
211 LPCWSTR pProgId = argc == 5 ? argv[4] : nullptr;
212 return ViewDocument(argv[2], argv[3], pProgId);
215 if (wcscmp(argv[1], L"EditDocument") == 0)
217 if (argc != 4 && argc != 5)
218 return 2; // Wrong argument count
219 LPCWSTR pProgId = argc == 5 ? argv[4] : nullptr;
220 return EditDocument(argv[2], argv[3], pProgId);
223 return 2; // Wrong command
226 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */