1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 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
|