/* -*- 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 "WindowsTestDebug.h" #include "nsCOMPtr.h" #include "nsIFile.h" #include "nsTArray.h" #include "nsXPCOM.h" namespace { typedef DWORD(WINAPI* RMSTARTSESSION)(DWORD*, DWORD, WCHAR[]); typedef DWORD(WINAPI* RMREGISTERRESOURCES)(DWORD, UINT, LPCWSTR[], UINT, RM_UNIQUE_PROCESS[], UINT, LPCWSTR[]); typedef DWORD(WINAPI* RMGETLIST)(DWORD, UINT*, UINT*, RM_PROCESS_INFO[], LPDWORD); typedef DWORD(WINAPI* RMENDSESSION)(DWORD); } // namespace namespace mozilla::widget { class WindowsDebugProcessData : public nsIWindowsDebugProcessData { public: NS_DECL_ISUPPORTS WindowsDebugProcessData(const wchar_t* aName, const wchar_t* aFilePath, unsigned long aPid) : mName(aName), mFilePath(aFilePath), mPid(aPid) {} NS_IMETHODIMP GetName(nsAString& aOut) { aOut = mName; return NS_OK; } NS_IMETHODIMP GetExecutablePath(nsAString& aOut) { aOut = mFilePath; return NS_OK; } NS_IMETHODIMP GetPid(uint32_t* aOut) { *aOut = mPid; return NS_OK; } private: virtual ~WindowsDebugProcessData() = default; nsString mName; nsString mFilePath; unsigned long mPid; }; NS_IMPL_ISUPPORTS(WindowsDebugProcessData, nsIWindowsDebugProcessData) NS_IMPL_ISUPPORTS(WindowsTestDebug, nsIWindowsTestDebug) WindowsTestDebug::WindowsTestDebug() {} WindowsTestDebug::~WindowsTestDebug() {} static nsReturnRef MakeRestartManager() { nsModuleHandle module(::LoadLibraryW(L"Rstrtmgr.dll")); (void)NS_WARN_IF(!module); return module.out(); } NS_IMETHODIMP WindowsTestDebug::ProcessesThatOpenedFile( const nsAString& aFilename, nsTArray>& aResult) { nsModuleHandle module(MakeRestartManager()); if (!module) { return NS_ERROR_NOT_AVAILABLE; } auto RmStartSession = reinterpret_cast( ::GetProcAddress(module, "RmStartSession")); if (NS_WARN_IF(!RmStartSession)) { return NS_ERROR_NOT_INITIALIZED; } auto RmRegisterResources = reinterpret_cast( ::GetProcAddress(module, "RmRegisterResources")); if (NS_WARN_IF(!RmRegisterResources)) { return NS_ERROR_NOT_INITIALIZED; } auto RmGetList = reinterpret_cast(::GetProcAddress(module, "RmGetList")); if (NS_WARN_IF(!RmGetList)) { return NS_ERROR_NOT_INITIALIZED; } auto RmEndSession = reinterpret_cast(::GetProcAddress(module, "RmEndSession")); if (NS_WARN_IF(!RmEndSession)) { return NS_ERROR_NOT_INITIALIZED; } WCHAR sessionKey[CCH_RM_SESSION_KEY + 1] = {0}; DWORD handle; if (NS_WARN_IF(FAILED(RmStartSession(&handle, 0, sessionKey)))) { return NS_ERROR_FAILURE; } auto endSession = MakeScopeExit( [&, handle]() { (void)NS_WARN_IF(FAILED(RmEndSession(handle))); }); LPCWSTR resources[] = {PromiseFlatString(aFilename).get()}; if (NS_WARN_IF(FAILED( RmRegisterResources(handle, 1, resources, 0, nullptr, 0, nullptr)))) { return NS_ERROR_FAILURE; } AutoTArray info; UINT numEntries; UINT numEntriesNeeded = 1; DWORD error = ERROR_MORE_DATA; DWORD reason = RmRebootReasonNone; while (error == ERROR_MORE_DATA) { info.SetLength(numEntriesNeeded); numEntries = numEntriesNeeded; error = RmGetList(handle, &numEntriesNeeded, &numEntries, &info[0], &reason); } if (NS_WARN_IF(error != ERROR_SUCCESS)) { return NS_ERROR_FAILURE; } for (UINT i = 0; i < numEntries; ++i) { nsAutoHandle otherProcess(::OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, info[i].Process.dwProcessId)); if (NS_WARN_IF(!otherProcess)) { continue; } WCHAR imageName[MAX_PATH]; DWORD imageNameLen = MAX_PATH; if (NS_WARN_IF(FAILED(::QueryFullProcessImageNameW( otherProcess, 0, imageName, &imageNameLen)))) { continue; } aResult.AppendElement(new WindowsDebugProcessData( info[i].strAppName, imageName, info[i].Process.dwProcessId)); } return NS_OK; } } // namespace mozilla::widget