LibreOffice Module shell (master) 1
COMOpenDocuments.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 <sal/config.h>
11
12#include <cstring>
13#include <string>
14#include <vector>
15
16#include <COMOpenDocuments.hpp>
17#include <spsuppServ.hpp>
18#include <stdio.h>
19
20namespace
21{
22template<class... Args>
23HRESULT LOStart(Args... args)
24{
25 auto quote = [](const std::wstring& s) { return L"\"" + s + L"\""; };
26 std::wstring sCmdLine((quote(GetHelperExe()) + ... + (L" " + quote(args))));
27 LPWSTR pCmdLine = const_cast<LPWSTR>(sCmdLine.c_str());
28
29 STARTUPINFOW si = {};
30 si.cb = sizeof si;
31 si.dwFlags = STARTF_USESHOWWINDOW;
32 si.wShowWindow = SW_SHOW;
33 PROCESS_INFORMATION pi = {};
34 if (!CreateProcessW(nullptr, pCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi))
35 return HRESULT_FROM_WIN32(GetLastError());
36
37 WaitForSingleObject(pi.hProcess, INFINITE);
38 DWORD nExitCode;
39 const bool bGotExitCode = GetExitCodeProcess(pi.hProcess, &nExitCode);
40 const DWORD nGetExitCodeError = GetLastError();
41
42 CloseHandle(pi.hProcess);
43 CloseHandle(pi.hThread);
44
45 if (!bGotExitCode)
46 return HRESULT_FROM_WIN32(nGetExitCodeError);
47 if (nExitCode == 0)
48 return S_OK;
49 if (nExitCode == 1)
50 return S_FALSE;
51 return E_FAIL;
52}
53
54VARIANT_BOOL toVBool(bool b) { return b ? VARIANT_TRUE : VARIANT_FALSE; }
55
56HRESULT ImplCreateNewDocument(IDispatch* /*pdisp*/, BSTR bstrTemplateLocation,
57 BSTR bstrDefaultSaveLocation, VARIANT_BOOL* pbResult)
58{
59 HRESULT hr = LOStart(L"CreateNewDocument", bstrTemplateLocation, bstrDefaultSaveLocation);
60 *pbResult = toVBool(hr == S_OK);
61 return hr;
62}
63
64HRESULT ImplEditDocument(IDispatch* /*pdisp*/, BSTR bstrDocumentLocation,
65 VARIANT_BOOL fUseLocalCopy, const VARIANT& varProgID,
66 VARIANT_BOOL* pbResult)
67{
68 const wchar_t* sUseLocalCopy = (fUseLocalCopy == VARIANT_FALSE) ? L"0" : L"1";
69 const wchar_t* sProgId = (varProgID.vt == VT_BSTR) ? varProgID.bstrVal : L"";
70 HRESULT hr = LOStart(L"EditDocument", bstrDocumentLocation, sUseLocalCopy, sProgId);
71 *pbResult = toVBool(hr == S_OK);
72 return hr;
73}
74
75HRESULT ImplViewDocument(IDispatch* /*pdisp*/, BSTR bstrDocumentLocation, int OpenType,
76 const VARIANT& varProgID, VARIANT_BOOL* pbResult)
77{
78 wchar_t sOpenType[16]{};
79 swprintf(sOpenType, L"%d", OpenType);
80 const wchar_t* sProgId = (varProgID.vt == VT_BSTR) ? varProgID.bstrVal : L"";
81 HRESULT hr = LOStart(L"ViewDocument", bstrDocumentLocation, sOpenType, sProgId);
82 *pbResult = toVBool(hr == S_OK);
83 return hr;
84}
85} // namespace
86
88ITypeInfo* COMOpenDocuments::m_pTypeInfo = nullptr;
89
91{
92 ::InterlockedIncrement(&m_nObjCount);
93 if (m_pTypeInfo == nullptr)
94 {
95 ITypeLib* pITypeLib = GetTypeLib();
96 HRESULT hr = pITypeLib->GetTypeInfoOfGuid(__uuidof(IOWSNewDocument3), &m_pTypeInfo);
97 if (FAILED(hr))
98 throw Error(hr);
99 }
100}
101
103{
104 if (::InterlockedDecrement(&m_nObjCount) == 0 && m_pTypeInfo)
105 {
106 m_pTypeInfo->Release();
107 m_pTypeInfo = nullptr;
108 }
109}
110
111// IUnknown methods
112
113STDMETHODIMP COMOpenDocuments::QueryInterface(REFIID riid, void **ppvObject)
114{
115 *ppvObject = nullptr;
116 if (IsEqualIID(riid, __uuidof(IUnknown)) ||
117 IsEqualIID(riid, __uuidof(IDispatch)) ||
118 IsEqualIID(riid, __uuidof(IOWSNewDocument)) ||
119 IsEqualIID(riid, __uuidof(IOWSNewDocument2)) ||
120 IsEqualIID(riid, __uuidof(IOWSNewDocument3)))
121 {
122 *ppvObject = static_cast<IOWSNewDocument3*>(this);
123 }
124 else if (IsEqualIID(riid, __uuidof(IObjectSafety)))
125 {
126 *ppvObject = static_cast<IObjectSafety*>(this);
127 }
128 else
129 {
130 return E_NOINTERFACE;
131 }
132
133 static_cast<IUnknown*>(*ppvObject)->AddRef();
134 return S_OK;
135}
136
137// IDispatch methods
138
139STDMETHODIMP COMOpenDocuments::GetTypeInfoCount(UINT *pctinfo)
140{
141 if (pctinfo == nullptr)
142 return E_INVALIDARG;
143
144 *pctinfo = 1;
145 return S_OK;
146}
147
148STDMETHODIMP COMOpenDocuments::GetTypeInfo(UINT iTInfo, LCID /*lcid*/, ITypeInfo **ppTInfo)
149{
150 if (ppTInfo == nullptr)
151 return E_INVALIDARG;
152 *ppTInfo = nullptr;
153
154 if (iTInfo != 0)
155 return DISP_E_BADINDEX;
156
157 (*ppTInfo = m_pTypeInfo)->AddRef();
158 return S_OK;
159}
160
162 REFIID /*riid*/,
163 LPOLESTR *rgszNames,
164 UINT cNames,
165 LCID /*lcid*/,
166 DISPID *rgDispId)
167{
168 return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
169}
170
172 DISPID dispIdMember,
173 REFIID /*riid*/, // IID_NULL (see https://msdn.microsoft.com/en-us/library/windows/desktop/ms221479)
174 LCID /*lcid*/,
175 WORD wFlags,
176 DISPPARAMS *pDispParams,
177 VARIANT *pVarResult,
178 EXCEPINFO *pExcepInfo,
179 UINT *puArgErr)
180{
181 return DispInvoke(this, m_pTypeInfo, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
182}
183
184// IOWSNewDocument methods
185
186// Creates a document based on the specified document template
188 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
189 BSTR bstrDefaultSaveLocation, // A string that contains the path that specifies a suggested default location for saving the new document
190 VARIANT_BOOL *pbResult) // true if the document creation succeeds; otherwise false
191{
192 return CreateNewDocument2(nullptr, bstrTemplateLocation, bstrDefaultSaveLocation, pbResult);
193}
194
195// Opens the specified document for editing with its associated application
196// or with the specified editor
198 BSTR bstrDocumentLocation, // A string that contains the URL of the document to open for editing
199 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
200 VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
201{
202 return EditDocument3(nullptr, bstrDocumentLocation, FALSE, varProgID, pbResult);
203}
204
205// IOWSNewDocument2 methods
206
207// Opens the document for reading instead of editing, so that the document is not locked on the server
208//
209// Use the ViewDocument method to open a document in its appropriate application,
210// instead of inside of an application instance embedded within the browser
212 BSTR bstrDocumentLocation, // A string that contains the URL of the document to open for reading
213 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
214 VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
215{
216 return ViewDocument3(nullptr, bstrDocumentLocation, 0, varProgID, pbResult);
217}
218
219// Opens the document for reading instead of editing, so that the document
220// is not locked on the server and in a specified window
221//
222// Use the ViewDocument method to open a document in its appropriate application,
223// instead of inside of an application instance embedded within the browser
225 IDispatch *pdisp, // An Object that represents the window from which the ViewDocument2 method is being activated
226 BSTR bstrDocumentLocation, // A string that contains the URL of the document to open for reading
227 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
228 VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
229{
230 return ViewDocument3(pdisp, bstrDocumentLocation, 0, varProgID, pbResult);
231}
232
233// Opens the specified document for editing with its associated application
234// or with the specified editor based on the specified window object
236 IDispatch *pdisp, // An Object that represents the window from which the EditDocument2 method is being activated
237 BSTR bstrDocumentLocation, // A string that contains the URL of the document to open for editing
238 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
239 VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
240{
241 return EditDocument3(pdisp, bstrDocumentLocation, FALSE, varProgID, pbResult);
242}
243
244// Creates a document based on the specified document template and window object
246 IDispatch* pdisp, // An Object that represents the window from which the CreateNewDocument2 method is being activated
247 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
248 BSTR bstrDefaultSaveLocation, // A string that contains the path that specifies a suggested default location for saving the new document
249 VARIANT_BOOL* pbResult) // true if the document creation succeeds; otherwise false
250{
251 if (!pbResult)
252 return E_POINTER;
253 // TODO: resolve the program from varProgID (nullptr -> default?)
254 return ImplCreateNewDocument(pdisp, bstrTemplateLocation, bstrDefaultSaveLocation, pbResult);
255}
256
257// Used with the OpenDocuments.CreateNewDocument2 method to determine
258// whether the security dialog box that appears when a document is opened has already appeared
259//
260// If the PromptedOnLastOpen method returns true, the window containing the document library view
261// refreshes itself the next time it receives focus. One refresh can occur after the new document
262// is saved to the server
264 VARIANT_BOOL* pbResult) // true if the security dialog box that appears when a document is opened has already appeared; otherwise false
265{
266 // This method is used by SharePoint e.g. after calling ViewDocument3. Needs to be implemented,
267 // otherwise IE would show download bar ("Do you want to open Foo.xls?"), as if opening with
268 // LibreOffice failed, even if actually it succeeded.
269 if (!pbResult)
270 return E_POINTER;
271 // Returning true makes SharePoint library to refresh only when focused next time; false makes
272 // it refresh instantly. The JavaScript code involved is this:
273 // var fRefreshOnNextFocus=stsOpen.PromptedOnLastOpen();
274 // if (fRefreshOnNextFocus)
275 // window.onfocus=RefreshOnNextFocus;
276 // else
277 // SetWindowRefreshOnFocus();
278 // It seems to be no reason to require immediate refresh, so just return true.
279 *pbResult = VARIANT_TRUE;
280 return S_OK;
281}
282
283// IOWSNewDocument3 methods
284
285// Opens the document for reading instead of editing, so that the document
286// is not locked on the server in a specified window, and with a specified type
287//
288// The following table shows possible values for OpenType
289//
290// 0 When checked out, or when the document library does not require check out, the user can read or edit the document
291// 1 When another user has checked it out, the user can only read the document
292// 2 When the current user has checked it out, the user can only edit the document
293// 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
294// 4 When the current user has checked it out, the user can only edit the local copy of the document
296 IDispatch* pdisp, // An Object that represents the window from which the ViewDocument3 method is being activated
297 BSTR bstrDocumentLocation, // A string that contains the URL of the document to open for reading
298 int OpenType, // A Long integer that specifies the rights for opening the document
299 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
300 VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
301{
302 if (!pbResult)
303 return E_POINTER;
304 return ImplViewDocument(pdisp, bstrDocumentLocation, OpenType, varProgID, pbResult);
305}
306
307// Checks in the specified document to a library
309 BSTR /*bstrDocumentLocation*/, // A string that contains the URL of the document to check in
310 int /*CheckinType*/, // A Long that specifies the type of check-in, where 0 = minor check-in, 1 = major check-in, and 2 = overwrite check-in
311 BSTR /*CheckinComment*/, // A string that contains a comment for checking in the document
312 VARIANT_BOOL /*bKeepCheckout*/, // Optional. true to check in changes that have been made to the document yet keep the document checked out; otherwise, false. The default value is false
313 VARIANT_BOOL* /*pbResult*/) // true if the document is successfully checked in; otherwise, false
314{
315 // TODO
316 return E_NOTIMPL;
317}
318
319// Discards the check out of a document to the client computer and deletes the local draft
321 BSTR /*bstrDocumentLocationRaw*/, // A string that contains the URL of the document
322 VARIANT_BOOL* /*pbResult*/) // true if the operation to discard the local checkout of the document is successful; otherwise, false
323{
324 // TODO
325 return E_NOTIMPL;
326}
327
328// Deprecated. Returns E_NOTIMPL
330 BSTR /*SiteUrl*/,
331 BSTR /*FileName*/,
332 BSTR /*SessionId*/,
333 BSTR /*Cmd*/,
334 BSTR /*Sheet*/,
335 int /*Row*/,
336 int /*Column*/,
337 VARIANT /*varProgID*/)
338{
339 return E_NOTIMPL;
340}
341
342// Checks out a document from a library
344 BSTR /*bstrDocumentLocationRaw*/, // A string that contains the URL of the document to check out
345 VARIANT_BOOL /*fEditAfterCheckout*/, // true to open the document in an editing application; otherwise, false
346 VARIANT /*varProgID*/, // An optional string that contains the ProgID of the application that is used to work with the document. If this argument is omitted, the default application for the document is used
347 VARIANT_BOOL* /*pbResult*/) // true if the document is successfully checked out; otherwise, false
348{
349 // TODO
350 return E_NOTIMPL;
351}
352
353// Opens the specified document for editing with its associated application
354// or with the specified editor based on the specified window object,
355// and specifies whether to use a local copy
357 IDispatch* pdisp, // An Object that represents the window from which the EditDocument3 method is being activated
358 BSTR bstrDocumentLocation, // A string that contains the URL of the document to open for editing
359 VARIANT_BOOL fUseLocalCopy, // true to use a local copy; otherwise false
360 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
361 VARIANT_BOOL *pbResult) // true if the document was successfully opened; otherwise false
362{
363 if (!pbResult)
364 return E_POINTER;
365 // TODO: resolve the program from varProgID (nullptr -> default?)
366 return ImplEditDocument(pdisp, bstrDocumentLocation, fUseLocalCopy, varProgID, pbResult);
367}
368
369// Creates a new blog post in the editing application
371 BSTR /*bstrProviderId*/, // A string that contains the GUID of the blog provider
372 BSTR /*bstrBlogUrl*/, // A string that contains the absolute URL of the blog site
373 BSTR /*bstrBlogName*/) // A string that contains the GUID of the blog site and the GUID of the post list separated by the pound sign (#)
374{
375 return E_NOTIMPL;
376}
377
378// IObjectSafety methods
379
381 REFIID riid,
382 DWORD *pdwSupportedOptions,
383 DWORD *pdwEnabledOptions)
384{
385 IUnknown* pUnk;
386 HRESULT hr = QueryInterface(riid, reinterpret_cast<void**>(&pUnk));
387 if (FAILED(hr))
388 {
389 return hr;
390 }
391
392 // We know about it; release reference and return required information
393 pUnk->Release();
394 *pdwSupportedOptions = iSupportedOptionsMask;
395 *pdwEnabledOptions = m_iEnabledOptions;
396 return S_OK;
397}
398
400 REFIID riid,
401 DWORD dwOptionSetMask,
402 DWORD dwEnabledOptions)
403{
404 IUnknown* pUnk;
405 HRESULT hr = QueryInterface(riid, reinterpret_cast<void**>(&pUnk));
406 if (FAILED(hr))
407 {
408 return hr;
409 }
410 pUnk->Release();
411
412 // Are there unsupported options in mask?
413 if (dwOptionSetMask & ~iSupportedOptionsMask)
414 return E_FAIL;
415
416 m_iEnabledOptions = (m_iEnabledOptions & ~dwOptionSetMask) | (dwOptionSetMask & dwEnabledOptions);
417 return S_OK;
418}
419
420// Non-COM methods
421
423
424/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
HRESULT STDMETHODCALLTYPE EditDocument2(IDispatch *pdisp, BSTR bstrDocumentLocation, VARIANT varProgID, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override
HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) override
HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo) override
static ITypeInfo * m_pTypeInfo
HRESULT STDMETHODCALLTYPE PromptedOnLastOpen(VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE EditDocument3(IDispatch *pdisp, BSTR bstrDocumentLocation, VARIANT_BOOL fUseLocalCopy, VARIANT varProgID, VARIANT_BOOL *pbResult) override
static constexpr DWORD iSupportedOptionsMask
static LONG GetObjectCount()
virtual ~COMOpenDocuments() override
HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) override
HRESULT STDMETHODCALLTYPE DiscardLocalCheckout(BSTR bstrDocumentLocationRaw, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE EditDocument(BSTR bstrDocumentLocation, VARIANT varProgID, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE CheckinDocument(BSTR bstrDocumentLocation, int CheckinType, BSTR CheckinComment, VARIANT_BOOL bKeepCheckout, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions) override
HRESULT STDMETHODCALLTYPE GetInterfaceSafetyOptions(REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) override
HRESULT STDMETHODCALLTYPE CreateNewDocument(BSTR bstrTemplateLocation, BSTR bstrDefaultSaveLocation, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE NewBlogPost(BSTR bstrProviderId, BSTR bstrBlogUrl, BSTR bstrBlogName) override
HRESULT STDMETHODCALLTYPE ViewDocument(BSTR bstrDocumentLocation, VARIANT varProgID, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE CheckoutDocumentPrompt(BSTR bstrDocumentLocationRaw, VARIANT_BOOL fEditAfterCheckout, VARIANT varProgID, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE CreateNewDocument2(IDispatch *pdisp, BSTR bstrTemplateLocation, BSTR bstrDefaultSaveLocation, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE ViewInExcel(BSTR SiteUrl, BSTR FileName, BSTR SessionId, BSTR Cmd, BSTR Sheet, int Row, int Column, VARIANT varProgID) override
HRESULT STDMETHODCALLTYPE ViewDocument2(IDispatch *pdisp, BSTR bstrDocumentLocation, VARIANT varProgID, VARIANT_BOOL *pbResult) override
HRESULT STDMETHODCALLTYPE ViewDocument3(IDispatch *pdisp, BSTR bstrDocumentLocation, int OpenType, VARIANT varProgID, VARIANT_BOOL *pbResult) override
ULONG STDMETHODCALLTYPE AddRef() override
#define FALSE
unsigned short WORD
Definition: lngconvex.cxx:25
#define VT_BSTR
LONG
return hr
ITypeLib * GetTypeLib()
Definition: spsuppServ.cxx:38
const wchar_t * GetHelperExe()
Definition: spsuppServ.cxx:55