platform: added custom utility to get list of running processes on Windows, it works faster than standard wmic.exe (RIDER-IC-CR-2)

This commit is contained in:
Artem Bukhonov
2016-07-22 12:47:34 +03:00
committed by nik
parent d29500f89b
commit b5c364bf53
7 changed files with 389 additions and 9 deletions

Binary file not shown.

View File

@@ -0,0 +1,6 @@
*.opensdf
*.suo
*.sdf
Debug
Release
ipch

View File

@@ -0,0 +1,22 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2013
VisualStudioVersion = 12.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinProcessListHelper", "WinProcessListHelper\WinProcessFetcherNative.vcxproj", "{3AA23150-835F-4EB4-A0DB-92BD17F31E40}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3AA23150-835F-4EB4-A0DB-92BD17F31E40}.Debug|Win32.ActiveCfg = Debug|Win32
{3AA23150-835F-4EB4-A0DB-92BD17F31E40}.Debug|Win32.Build.0 = Debug|Win32
{3AA23150-835F-4EB4-A0DB-92BD17F31E40}.Release|Win32.ActiveCfg = Release|Win32
{3AA23150-835F-4EB4-A0DB-92BD17F31E40}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{3AA23150-835F-4EB4-A0DB-92BD17F31E40}</ProjectGuid>
<RootNamespace>WinProcessListHelper</RootNamespace>
<ProjectName>WinProcessListHelper</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v120</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,193 @@
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
int main(int argc, char **argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if (FAILED(hres))
{
cout << "Failed to initialize COM library. Error code = 0x"
<< hex << hres << endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = CoInitializeSecurity(
nullptr,
-1, // COM authentication
nullptr, // Authentication services
nullptr, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
nullptr, // Authentication info
EOAC_NONE, // Additional capabilities
nullptr // Reserved
);
if (FAILED(hres))
{
cout << "Failed to initialize security. Error code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = nullptr;
hres = CoCreateInstance(
CLSID_WbemLocator,
nullptr,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, reinterpret_cast<LPVOID *>(&pLoc));
if (FAILED(hres))
{
cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< hex << hres << endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = nullptr;
// Connect to the root\cimv2 namespace with
// the current user and obtain pointer pSvc
// to make IWbemServices calls.
hres = pLoc->ConnectServer(
_bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace
nullptr, // User name. NULL = current user
nullptr, // User password. NULL = current
nullptr, // Locale. NULL indicates current
NULL, // Security flags.
nullptr, // Authority (for example, Kerberos)
nullptr, // Context object
&pSvc // pointer to IWbemServices proxy
);
if (FAILED(hres))
{
cout << "Could not connect. Error code = 0x"
<< hex << hres << endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
//cout << "Connected to ROOT\\CIMV2 WMI namespace" << endl;
// Step 5: --------------------------------------------------
// Set security levels on the proxy -------------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
nullptr, // Server principal name
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
nullptr, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
cout << "Could not set proxy blanket. Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 6: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// For example, get the name of the operating system
IEnumWbemClassObject* pEnumerator = nullptr;
hres = pSvc->ExecQuery(
bstr_t("WQL"),
bstr_t("SELECT * FROM Win32_Process"),
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
nullptr,
&pEnumerator);
if (FAILED(hres))
{
cout << "Query for processes failed."
<< " Error code = 0x"
<< hex << hres << endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: -------------------------------------------------
// Get the data from the query in step 6 -------------------
IWbemClassObject *pclsObj = nullptr;
ULONG uReturn = 0;
int i = 0;
while (pEnumerator)
{
i++;
HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1,
&pclsObj, &uReturn);
if (0 == uReturn)
{
break;
}
VARIANT vtId;
pclsObj->Get(L"ProcessId", 0, &vtId, nullptr, nullptr);
wprintf_s(L"%d\n", vtId.intVal);
VARIANT vtName;
pclsObj->Get(L"Name", 0, &vtName, nullptr, nullptr);
if (vtName.bstrVal != nullptr)
wprintf_s(L"%ls\n", vtName.bstrVal);
else
wprintf_s(L"\n");
VARIANT vtCmd;
pclsObj->Get(L"CommandLine", 0, &vtCmd, nullptr, nullptr);
if (vtCmd.bstrVal != nullptr)
wprintf_s(L"%ls\n", vtCmd.bstrVal);
else
wprintf_s(L"\n");
VariantClear(&vtId);
VariantClear(&vtName);
VariantClear(&vtCmd);
pclsObj->Release();
}
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
pEnumerator->Release();
CoUninitialize();
return 0; // Program successfully completed.
}

View File

@@ -21,6 +21,7 @@ import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.ProcessInfo;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.execution.util.ExecUtil;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
@@ -32,10 +33,7 @@ import gnu.trove.TIntObjectHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -44,6 +42,7 @@ import java.util.List;
public class ProcessListUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.process.impl.ProcessListUtil");
private static final String WIN_PROCESS_LIST_HELPER_FILENAME = "WinProcessListHelper.exe";
@NotNull
public static ProcessInfo[] getProcessList() {
@@ -55,6 +54,9 @@ public class ProcessListUtil {
private static List<ProcessInfo> doGetProcessList() {
List<ProcessInfo> result;
if (SystemInfo.isWindows) {
result = getProcessList_WinNativeFetcher();
if (result != null) return result;
LOG.info("Cannot get process list via NativeFetcher, fallback to wmic");
result = getProcessList_WindowsWMIC();
if (result != null) return result;
@@ -90,7 +92,7 @@ public class ProcessListUtil {
ProcessOutput processOutput = ExecUtil.execAndGetOutput(new GeneralCommandLine(command));
int exitCode = processOutput.getExitCode();
if (exitCode != 0) {
LOG.error("Cannot get process list, 'ps' exited with code " + exitCode + ", stdout:\n"
LOG.error("Cannot get process list, command '" + StringUtil.join(command, " ") +"' exited with code " + exitCode + ", stdout:\n"
+ processOutput.getStdout()
+ "\nstderr:\n"
+ processOutput.getStderr());
@@ -253,6 +255,69 @@ public class ProcessListUtil {
}
}
private static List<ProcessInfo> getProcessList_WinNativeFetcher() {
try {
File nativeFetcher = findNativeFetcher();
return parseCommandOutput(Collections.singletonList(nativeFetcher.getAbsolutePath()), ProcessListUtil::parseWinNativeFetcherOutput);
} catch (FileNotFoundException e) {
LOG.error(e);
return null;
}
}
private static List<ProcessInfo> parseWinNativeFetcherOutput(String output) throws IllegalStateException {
String[] strings = StringUtil.splitByLines(output, false);
ArrayList<ProcessInfo> result = new ArrayList<>();
int processCount = strings.length / 3;
for (int i = 0; i < processCount; i++) {
int offset = i * 3;
int id = StringUtil.parseInt(strings[offset], -1);
if (id == -1 || id == 0)
continue;
String name = strings[offset + 1];
if (StringUtil.isEmpty(name))
continue;
String commandLine = strings[offset + 2];
String args = "";
if (commandLine.isEmpty()) {
commandLine = name;
}
else {
args = findArgs(commandLine, name);
}
result.add(new ProcessInfo(id, commandLine, name, args));
}
return result;
}
private static String findArgs(String commandLine, String name) {
List<String> commandLineList = StringUtil.splitHonorQuotes(commandLine, ' ');
if (commandLineList.isEmpty())
return "";
String first = StringUtil.unquoteString(commandLineList.get(0));
if (StringUtil.endsWithIgnoreCase(first, name)) {
List<String> argsList = commandLineList.subList(1, commandLineList.size());
return StringUtil.join(argsList, " ");
}
return "";
}
private static File findNativeFetcher() throws FileNotFoundException {
String prefix = "win";
String[] dirs = {
PathManager.getBinPath(),
PathManager.getHomePath() + "/ultimate/community/bin/" + prefix,
PathManager.getHomePath() + "/community/bin/" + prefix,
PathManager.getBinPath() + '/' + prefix
};
for (String dir : dirs) {
File file = new File(dir, WIN_PROCESS_LIST_HELPER_FILENAME);
if (file.exists() && file.isFile())
return file;
}
throw new FileNotFoundException(String.format("%s was not found at: %s", WIN_PROCESS_LIST_HELPER_FILENAME, String.join(",", (CharSequence[]) dirs)));
}
@Nullable
static List<ProcessInfo> getProcessList_WindowsWMIC() {
return parseCommandOutput(Arrays.asList("wmic.exe", "path", "win32_process", "get", "Caption,Processid,Commandline,ExecutablePath"),
@@ -294,10 +359,7 @@ public class ProcessListUtil {
commandLine = name;
}
else {
int nameIndex = StringUtil.indexOfIgnoreCase(commandLine, name, 0);
if (nameIndex != -1) {
args = commandLine.substring(nameIndex + name.length()).trim();
}
args = findArgs(commandLine, name);
}
result.add(new ProcessInfo(pid, commandLine, name, args, executablePath));