1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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.
31 const OUString
& GetSofficeExe()
33 static const OUString s_sPath
= []() {
35 wchar_t sPath
[EXTENDED_MAX_PATH
];
36 if (GetModuleFileNameW(nullptr, sPath
, std::size(sPath
)) == 0)
38 wchar_t* pSlashPos
= wcsrchr(sPath
, L
'\\');
39 if (pSlashPos
== nullptr)
41 wcscpy(pSlashPos
+ 1, L
"soffice.exe");
42 result
= o3tl::toU(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
61 return Translate::get(pResId
, s_pLocale
);
64 INT_PTR CALLBACK
EditOrRODlgproc(HWND hDlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
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
88 WORD nId
= LOWORD(wParam
);
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
)
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
= {};
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
);
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
))
180 case Answer::ReadOnly
:
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;
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)
196 const LPWSTR
* argv
= CommandLineToArgvW(GetCommandLineW(), &argc
);
198 return 2; // Wrong argument count
200 if (wcscmp(argv
[1], L
"CreateNewDocument") == 0)
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: */