summaryrefslogtreecommitdiffstats
path: root/toolkit/components/aboutthirdparty/AboutThirdParty_TestMethods.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/aboutthirdparty/AboutThirdParty_TestMethods.cpp')
-rw-r--r--toolkit/components/aboutthirdparty/AboutThirdParty_TestMethods.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/toolkit/components/aboutthirdparty/AboutThirdParty_TestMethods.cpp b/toolkit/components/aboutthirdparty/AboutThirdParty_TestMethods.cpp
new file mode 100644
index 0000000000..b52ba49eac
--- /dev/null
+++ b/toolkit/components/aboutthirdparty/AboutThirdParty_TestMethods.cpp
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AboutThirdParty.h"
+
+#include <windows.h>
+#include <shlobj.h>
+#include <shobjidl.h>
+
+namespace {
+
+class FileDialogEventsForTesting final : public IFileDialogEvents {
+ mozilla::Atomic<uint32_t> mRefCnt;
+ const nsString mTargetName;
+ RefPtr<IShellItem> mTargetDir;
+
+ ~FileDialogEventsForTesting() = default;
+
+ public:
+ FileDialogEventsForTesting(const nsAString& aTargetName,
+ IShellItem* aTargetDir)
+ : mRefCnt(0),
+ mTargetName(PromiseFlatString(aTargetName)),
+ mTargetDir(aTargetDir) {}
+
+ // IUnknown
+
+ STDMETHODIMP QueryInterface(REFIID aRefIID, void** aResult) {
+ if (!aResult) {
+ return E_INVALIDARG;
+ }
+
+ if (aRefIID == IID_IFileDialogEvents) {
+ RefPtr ref(static_cast<IFileDialogEvents*>(this));
+ ref.forget(aResult);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef() { return ++mRefCnt; }
+
+ STDMETHODIMP_(ULONG) Release() {
+ ULONG result = --mRefCnt;
+ if (!result) {
+ delete this;
+ }
+ return result;
+ }
+
+ // IFileDialogEvents
+
+ STDMETHODIMP OnFileOk(IFileDialog*) { return E_NOTIMPL; }
+ STDMETHODIMP OnFolderChanging(IFileDialog*, IShellItem*) { return E_NOTIMPL; }
+ STDMETHODIMP OnShareViolation(IFileDialog*, IShellItem*,
+ FDE_SHAREVIOLATION_RESPONSE*) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP OnTypeChange(IFileDialog*) { return E_NOTIMPL; }
+ STDMETHODIMP OnOverwrite(IFileDialog*, IShellItem*, FDE_OVERWRITE_RESPONSE*) {
+ return E_NOTIMPL;
+ }
+ STDMETHODIMP OnFolderChange(IFileDialog*) { return E_NOTIMPL; }
+ STDMETHODIMP OnSelectionChange(IFileDialog* aDialog) {
+ if (::GetModuleHandleW(mTargetName.get())) {
+ aDialog->Close(S_OK);
+ } else {
+ // This sends a notification which is processed asynchronously. Calling
+ // SetFolder from OnSelectionChange gives the main thread some cycles to
+ // process other window messages, while calling SetFolder from
+ // OnFolderChange causes freeze. Thus we can safely wait until a common
+ // dialog loads a shell extension without blocking UI.
+ aDialog->SetFolder(mTargetDir);
+ }
+
+ return E_NOTIMPL;
+ }
+};
+
+} // anonymous namespace
+
+namespace mozilla {
+
+NS_IMETHODIMP AboutThirdParty::OpenAndCloseFileDialogForTesting(
+ const nsAString& aModuleName, const nsAString& aInitialDir,
+ const nsAString& aFilter) {
+ // Notify the shell of a new icon handler which should have been registered
+ // by the test script.
+ ::SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);
+
+ RefPtr<IFileOpenDialog> dialog;
+ if (FAILED(::CoCreateInstance(CLSID_FileOpenDialog, nullptr,
+ CLSCTX_INPROC_SERVER, IID_IFileOpenDialog,
+ getter_AddRefs(dialog)))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ const nsString& filter = PromiseFlatString(aFilter);
+ COMDLG_FILTERSPEC fileFilter = {L"Test Target", filter.get()};
+ if (FAILED(dialog->SetFileTypes(1, &fileFilter))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ RefPtr<IShellItem> folder;
+ if (FAILED(::SHCreateItemFromParsingName(PromiseFlatString(aInitialDir).get(),
+ nullptr, IID_IShellItem,
+ getter_AddRefs(folder)))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ // Need to send a first notification outside FileDialogEventsForTesting.
+ if (FAILED(dialog->SetFolder(folder))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ RefPtr events(new FileDialogEventsForTesting(aModuleName, folder));
+
+ DWORD cookie;
+ if (FAILED(dialog->Advise(events, &cookie))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ if (FAILED(dialog->Show(nullptr))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ if (FAILED(dialog->Unadvise(cookie))) {
+ return NS_ERROR_UNEXPECTED;
+ }
+
+ return NS_OK;
+}
+
+} // namespace mozilla