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 <unotools/resmgr.hxx>
20 #include "res/spsuppDlg.h"
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.
30 const OUString
& GetSofficeExe()
32 static const OUString s_sPath
= []() {
34 wchar_t sPath
[MAX_PATH
];
35 if (GetModuleFileNameW(nullptr, sPath
, MAX_PATH
) == 0)
37 wchar_t* pSlashPos
= wcsrchr(sPath
, L
'\\');
38 if (pSlashPos
== nullptr)
40 wcscpy(pSlashPos
+ 1, L
"soffice.exe");
41 result
= o3tl::toU(sPath
);
47 OUString
GetString(TranslateId pResId
)
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)
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
);
58 return Translate::Create("shell", LanguageTag("")); // Use system language
60 return Translate::get(pResId
, s_pLocale
);
63 INT_PTR CALLBACK
EditOrRODlgproc(HWND hDlg
, UINT Msg
, WPARAM wParam
, LPARAM lParam
)
69 if (const wchar_t* sFilePath
= reinterpret_cast<const wchar_t*>(lParam
))
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()));
83 return TRUE
; // set default focus
87 WORD nId
= LOWORD(wParam
);
109 Answer
AskIfUserWantsToEdit(const wchar_t* sFilePath
)
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
)
121 // Returns ERROR_SUCCESS or Win32 error code
122 DWORD
LOStart(const wchar_t* sModeArg
, const wchar_t* sFilePath
)
124 OUString sCmdLine
= "\"" + GetSofficeExe() + "\" " + o3tl::toU(sModeArg
) + " \""
125 + o3tl::toU(sFilePath
) + "\"";
126 LPWSTR pCmdLine
= const_cast<LPWSTR
>(o3tl::toW(sCmdLine
.getStr()));
128 STARTUPINFOW 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
))
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
);
140 // Report the error to user and return error
141 MessageBoxW(nullptr, o3tl::toW(sErrorMsg
.getStr()), nullptr, MB_ICONERROR
);
144 CloseHandle(pi
.hProcess
);
145 CloseHandle(pi
.hThread
);
146 return ERROR_SUCCESS
;
149 int CreateNewDocument(LPCWSTR TemplateLocation
, LPCWSTR
/*DefaultSaveLocation*/)
151 // TODO: resolve the program from varProgID (nullptr -> default?)
152 DWORD nResult
= LOStart(L
"-n", TemplateLocation
);
153 return nResult
== ERROR_SUCCESS
? 0 : 2;
156 // UseLocalCopy would be either "0" or "1", denoting boolean value
157 int EditDocument(LPCWSTR DocumentLocation
, LPCWSTR
/*UseLocalCopy*/, LPCWSTR
/*varProgID*/)
159 // TODO: resolve the program from varProgID (nullptr -> default?)
160 DWORD nResult
= LOStart(L
"-o", DocumentLocation
);
161 return nResult
== ERROR_SUCCESS
? 0 : 2;
164 // Possible values for OpenType
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
171 int ViewDocument(LPCWSTR DocumentLocation
, LPCWSTR OpenType
, LPCWSTR varProgID
)
173 if (wcscmp(OpenType
, L
"0") == 0)
175 switch (AskIfUserWantsToEdit(DocumentLocation
))
179 case Answer::ReadOnly
:
182 return EditDocument(DocumentLocation
, L
"0", varProgID
);
185 // TODO: resolve the program from varProgID (nullptr -> default?)
186 DWORD nResult
= LOStart(L
"--view", DocumentLocation
);
187 return nResult
== ERROR_SUCCESS
? 0 : 2;
191 // Returns 0 on success, 1 when operation wasn't performed because user cancelled, 2 on an error
192 int WINAPI
wWinMain(HINSTANCE
, HINSTANCE
, LPWSTR
, int)
195 const LPWSTR
* argv
= CommandLineToArgvW(GetCommandLineW(), &argc
);
197 return 2; // Wrong argument count
199 if (wcscmp(argv
[1], L
"CreateNewDocument") == 0)
202 return 2; // Wrong argument count
203 return CreateNewDocument(argv
[2], argv
[3]);
206 if (wcscmp(argv
[1], L
"ViewDocument") == 0)
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
);
214 if (wcscmp(argv
[1], L
"EditDocument") == 0)
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
);
222 return 2; // Wrong command
225 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */